Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 0.20.2-beta #69

Merged
merged 6 commits into from
Dec 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@ android {
minSdk = 29
targetSdk = 34
versionCode = (System.currentTimeMillis() / 1000).toInt()
versionName = "0.20.1-beta"
versionName = "0.20.2-beta"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"

buildConfigField("String", "REPORT_ISSUE_URL", "\"https://github.com/Semper-Viventem/MetaRadar/issues\"")
buildConfigField("String", "GITHUB_URL", "\"https://github.com/Semper-Viventem/MetaRadar\"")
buildConfigField("String", "GOOGLE_PLAY_URL", "\"https://play.google.com/store/apps/details?id=f.cking.software&pcampaignid=web_share\"")

buildConfigField("String", "DISTRIBUTION", "\"Not specified\"")
}
Expand Down
7 changes: 7 additions & 0 deletions app/src/main/java/f/cking/software/TheApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package f.cking.software
import android.app.Application
import f.cking.software.data.DataModule
import f.cking.software.domain.interactor.InteractorsModule
import f.cking.software.domain.interactor.SaveFirstAppLaunchTimeInteractor
import f.cking.software.ui.UiModule
import org.koin.android.ext.android.getKoin
import org.koin.android.ext.koin.androidContext
import org.koin.core.context.startKoin
import org.koin.core.context.stopKoin
Expand All @@ -16,6 +18,11 @@ class TheApp : Application() {
instance = this
initDi()
initTimber()
saveFirstLaunchTime()
}

private fun saveFirstLaunchTime() {
getKoin().get<SaveFirstAppLaunchTimeInteractor>().execute()
}

private fun initDi() {
Expand Down
19 changes: 19 additions & 0 deletions app/src/main/java/f/cking/software/data/repo/SettingsRepository.kt
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,30 @@ class SettingsRepository(
sharedPreferences.edit().putBoolean(KEY_RUN_ON_STARTUP, value).apply()
}

fun getFirstAppLaunchTime(): Long {
return sharedPreferences.getLong(KEY_FIRST_APP_LAUNCH_TIME, NO_APP_LAUNCH_TIME)
}

fun setFirstAppLaunchTime(value: Long) {
sharedPreferences.edit().putLong(KEY_FIRST_APP_LAUNCH_TIME, value).apply()
}

fun getEnjoyTheAppAnswered(): Boolean {
return sharedPreferences.getBoolean(KEY_ENJOY_THE_APP_ANSWERED, false)
}

fun setEnjoyTheAppAnswered(value: Boolean) {
sharedPreferences.edit().putBoolean(KEY_ENJOY_THE_APP_ANSWERED, value).apply()
}

companion object {
private const val KEY_GARBAGING_TIME = "key_garbaging_time"
private const val KEY_USE_GPS_ONLY = "key_use_gps_location_only"
private const val KEY_PERMISSIONS_INTRO_WAS_SHOWN = "key_permissions_intro_was_shown"
private const val KEY_RUN_ON_STARTUP = "key_run_on_startup"
private const val KEY_FIRST_APP_LAUNCH_TIME = "key_first_app_launch_time"
private const val KEY_ENJOY_THE_APP_ANSWERED = "key_enjoy_the_app_answered"

const val NO_APP_LAUNCH_TIME = -1L
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package f.cking.software.domain.interactor

import f.cking.software.data.repo.SettingsRepository
import java.util.concurrent.TimeUnit

class GetAppUsageDaysInteractor(
private val settingsRepository: SettingsRepository,
) {

fun execute(): Long {
val firstLaunchTime = settingsRepository.getFirstAppLaunchTime()

if (firstLaunchTime == SettingsRepository.NO_APP_LAUNCH_TIME) {
return 0
}

return (System.currentTimeMillis() - firstLaunchTime) / TimeUnit.DAYS.toMillis(1)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,7 @@ object InteractorsModule {
factory { AddTagToDeviceInteractor(get(), get()) }
factory { RemoveTagFromDeviceInteractor(get()) }
factory { ChangeFavoriteInteractor(get()) }
factory { GetAppUsageDaysInteractor(get()) }
factory { SaveFirstAppLaunchTimeInteractor(get()) }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package f.cking.software.domain.interactor

import f.cking.software.data.repo.SettingsRepository

class SaveFirstAppLaunchTimeInteractor(
private val settingsRepository: SettingsRepository
) {

fun execute() {
if (settingsRepository.getFirstAppLaunchTime() == SettingsRepository.NO_APP_LAUNCH_TIME) {
settingsRepository.setFirstAppLaunchTime(System.currentTimeMillis())
}
}
}
2 changes: 1 addition & 1 deletion app/src/main/java/f/cking/software/ui/UiModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ object UiModule {
single { RouterImpl() }
single<Router> { get<RouterImpl>() }
viewModel { MainViewModel(get(), get(), get(), get(), get(), get()) }
viewModel { DeviceListViewModel(get(), get(), get(), get()) }
viewModel { DeviceListViewModel(get(), get(), get(), get(), get(), get(), get()) }
viewModel { SettingsViewModel(get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get()) }
viewModel { ProfilesListViewModel(get(), get()) }
viewModel { ProfileDetailsViewModel(profileId = it[0], template = it[1], get(), get(), get(), get(), get()) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
Expand All @@ -14,6 +15,7 @@ import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.material.Button
import androidx.compose.material.Chip
import androidx.compose.material.ChipDefaults
import androidx.compose.material.ExperimentalMaterialApi
Expand All @@ -40,6 +42,7 @@ import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
Expand All @@ -51,6 +54,7 @@ import f.cking.software.utils.graphic.BottomSpacer
import f.cking.software.utils.graphic.ContentPlaceholder
import f.cking.software.utils.graphic.DeviceListItem
import f.cking.software.utils.graphic.Divider
import f.cking.software.utils.graphic.RoundedBox
import org.koin.androidx.compose.koinViewModel

object DeviceListScreen {
Expand Down Expand Up @@ -103,6 +107,13 @@ object DeviceListScreen {
}
}

if (viewModel.enjoyTheAppState != DeviceListViewModel.EnjoyTheAppState.NONE) {
item {
Spacer(modifier = Modifier.height(8.dp))
EnjoyTheApp(viewModel, viewModel.enjoyTheAppState)
}
}

list.mapIndexed { index, deviceData ->
item {
DeviceListItem(
Expand All @@ -124,12 +135,70 @@ object DeviceListScreen {
}
}

@Composable
private fun EnjoyTheApp(viewModel: DeviceListViewModel, enjoyTheAppState: DeviceListViewModel.EnjoyTheAppState) {
RoundedBox {
when (enjoyTheAppState) {
DeviceListViewModel.EnjoyTheAppState.QUESTION -> EnjoyTheAppQuestion(viewModel)
DeviceListViewModel.EnjoyTheAppState.LIKE -> EnjoyTheAppLike(viewModel)
DeviceListViewModel.EnjoyTheAppState.DISLIKE -> EnjoyTheAppDislike(viewModel)
DeviceListViewModel.EnjoyTheAppState.NONE -> throw IllegalStateException("EnjoyTheAppState.NONE is not supported here")
}
}
}

@Composable
private fun EnjoyTheAppQuestion(viewModel: DeviceListViewModel) {
Column {
Text(text = stringResource(R.string.enjoy_the_app_question), fontWeight = FontWeight.SemiBold)
Spacer(modifier = Modifier.height(8.dp))
Row {
Button(modifier = Modifier.weight(1f), onClick = { viewModel.onEnjoyTheAppAnswered(true) }) {
Text(text = stringResource(R.string.enjoy_the_app_yes))
}
Spacer(modifier = Modifier.width(8.dp))
Button(modifier = Modifier.weight(1f), onClick = { viewModel.onEnjoyTheAppAnswered(false) }) {
Text(text = stringResource(R.string.enjoy_the_app_not_really))
}
}
}
}

@Composable
private fun EnjoyTheAppLike(viewModel: DeviceListViewModel) {
Column {
Text(text = stringResource(R.string.rate_the_app), fontWeight = FontWeight.SemiBold)
Spacer(modifier = Modifier.height(8.dp))
Row {
Button(modifier = Modifier.weight(1f), onClick = { viewModel.onEnjoyTheAppRatePlayStoreClick() }) {
Text(text = stringResource(R.string.rate_the_app_google_play))
}
Spacer(modifier = Modifier.width(8.dp))
Button(modifier = Modifier.weight(1f), onClick = { viewModel.onEnjoyTheAppRateGithubClick() }) {
Text(text = stringResource(R.string.rate_the_app_github))
}
}
}
}

@Composable
private fun EnjoyTheAppDislike(viewModel: DeviceListViewModel) {
Column {
Text(text = stringResource(R.string.report_the_problem), fontWeight = FontWeight.SemiBold)
Spacer(modifier = Modifier.height(8.dp))
Button(modifier = Modifier.fillMaxWidth(), onClick = { viewModel.onEnjoyTheAppReportClick() }) {
Text(text = stringResource(R.string.report))
}
}
}

@OptIn(ExperimentalMaterialApi::class)
@Composable
fun Filters(viewModel: DeviceListViewModel) {
private fun Filters(viewModel: DeviceListViewModel) {
Surface(elevation = 4.dp) {
Column(
modifier = Modifier
.background(colorResource(id = R.color.primary_surface))
.fillMaxWidth()
) {
LazyRow(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import f.cking.software.BuildConfig
import f.cking.software.R
import f.cking.software.data.helpers.IntentHelper
import f.cking.software.data.repo.DevicesRepository
import f.cking.software.data.repo.SettingsRepository
import f.cking.software.domain.interactor.GetAppUsageDaysInteractor
import f.cking.software.domain.interactor.filterchecker.FilterCheckerImpl
import f.cking.software.domain.model.DeviceData
import f.cking.software.domain.model.ManufacturerInfo
Expand All @@ -24,6 +28,9 @@ class DeviceListViewModel(
private val devicesRepository: DevicesRepository,
private val filterCheckerImpl: FilterCheckerImpl,
val router: Router,
private val getAppUsageDaysInteractor: GetAppUsageDaysInteractor,
private val settingsRepository: SettingsRepository,
private val intentHelper: IntentHelper,
) : ViewModel() {

var devicesViewState by mutableStateOf(emptyList<DeviceData>())
Expand All @@ -37,6 +44,7 @@ class DeviceListViewModel(
DefaultFilters.isFavorite(context),
)
)
var enjoyTheAppState: EnjoyTheAppState by mutableStateOf(EnjoyTheAppState.NONE)

private val generalComparator = Comparator<DeviceData> { second, first ->
when {
Expand Down Expand Up @@ -133,10 +141,51 @@ class DeviceListViewModel(
devices
.filter { checkFilter(it, filter) && filterQuery(it, query) }
.sortedWith(generalComparator)
.apply {
if (size >= MIN_DEVICES_FOR_ENJOY_THE_APP) {
checkEnjoyTheApp()
}
}
}
}

private fun checkEnjoyTheApp() {
enjoyTheAppState = if (enjoyTheAppState == EnjoyTheAppState.NONE
&& !settingsRepository.getEnjoyTheAppAnswered()
&& getAppUsageDaysInteractor.execute() >= MIN_DAYS_FOR_ENJOY_THE_APP
) {
EnjoyTheAppState.QUESTION
} else {
EnjoyTheAppState.NONE
}
}

private fun filterQuery(device: DeviceData, query: String?): Boolean {
fun onEnjoyTheAppAnswered(answer: Boolean) {
enjoyTheAppState = if (answer) {
EnjoyTheAppState.LIKE
} else {
EnjoyTheAppState.DISLIKE
}
}

fun onEnjoyTheAppRatePlayStoreClick() {
settingsRepository.setEnjoyTheAppAnswered(true)
enjoyTheAppState = EnjoyTheAppState.NONE
intentHelper.openUrl(BuildConfig.GOOGLE_PLAY_URL)
}

fun onEnjoyTheAppRateGithubClick() {
settingsRepository.setEnjoyTheAppAnswered(true)
intentHelper.openUrl(BuildConfig.GITHUB_URL)
}

fun onEnjoyTheAppReportClick() {
settingsRepository.setEnjoyTheAppAnswered(true)
enjoyTheAppState = EnjoyTheAppState.NONE
intentHelper.openUrl(BuildConfig.REPORT_ISSUE_URL)
}

fun filterQuery(device: DeviceData, query: String?): Boolean {
return query?.takeIf { it.isNotBlank() }?.let { searchStr ->
(device.name?.contains(searchStr, true) ?: false)
|| (device.customName?.contains(searchStr, true) ?: false)
Expand All @@ -158,6 +207,10 @@ class DeviceListViewModel(
val filter: RadarProfile.Filter,
)

enum class EnjoyTheAppState {
NONE, QUESTION, LIKE, DISLIKE
}

object DefaultFilters {

fun notApple(context: Context) = FilterHolder(
Expand All @@ -172,4 +225,9 @@ class DeviceListViewModel(
filter = RadarProfile.Filter.IsFavorite(favorite = true)
)
}

companion object {
private const val MIN_DEVICES_FOR_ENJOY_THE_APP = 10
private const val MIN_DAYS_FOR_ENJOY_THE_APP = 3
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@ object ProfilesListScreen {
elevation = 4.dp,
) {
LazyRow(
modifier = Modifier.padding(vertical = 8.dp),
modifier = Modifier
.background(colorResource(id = R.color.primary_surface))
.padding(vertical = 8.dp),
) {
item {
Spacer(modifier = Modifier.width(8.dp))
Expand Down
Loading