diff --git a/app/build.gradle.kts b/app/build.gradle.kts index e30842c..d9485fd 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -23,14 +23,14 @@ android { applicationId = "f.cking.software" minSdk = 29 targetSdk = 34 - versionCode = 1704045671 - versionName = "0.21.3-beta" + versionCode = 1704045672 + versionName = "0.21.4-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", "STORE_PAGE_URL", "\"Not specified\"") buildConfigField("String", "DISTRIBUTION", "\"Not specified\"") } @@ -83,6 +83,8 @@ android { versionCode = (System.currentTimeMillis() / 1000).toInt() buildConfigField("String", "DISTRIBUTION", "\"Github\"") + buildConfigField("Boolean", "STORE_RATING_IS_APPLICABLE", "false") + buildConfigField("String", "STORE_PAGE_URL", "\"https://github.com/Semper-Viventem/MetaRadar/releases?q=release+build\"") } create("googlePlay") { isDefault = false @@ -90,11 +92,14 @@ android { versionCode = (System.currentTimeMillis() / 1000).toInt() buildConfigField("String", "DISTRIBUTION", "\"Google play\"") + buildConfigField("Boolean", "STORE_RATING_IS_APPLICABLE", "true") + buildConfigField("String", "STORE_PAGE_URL", "\"https://play.google.com/store/apps/details?id=f.cking.software&pcampaignid=web_share\"") } create("fdroid") { isDefault = false dimension = "distribution" + buildConfigField("Boolean", "STORE_RATING_IS_APPLICABLE", "false") buildConfigField("String", "DISTRIBUTION", "\"F-Droid\"") } } @@ -155,7 +160,6 @@ dependencies { // compose implementation(libs.compose.ui) implementation(libs.compose.foundation) - implementation(libs.compose.material) implementation(libs.compose.tooling) implementation(libs.lifecycle.compose) implementation(libs.compose.activity) diff --git a/app/src/debug/res/drawable/ic_launcher_background_original.webp b/app/src/debug/res/drawable/ic_launcher_background_original.webp index ec49c5d..4c7da18 100644 Binary files a/app/src/debug/res/drawable/ic_launcher_background_original.webp and b/app/src/debug/res/drawable/ic_launcher_background_original.webp differ diff --git a/app/src/main/java/f/cking/software/data/helpers/PermissionHelper.kt b/app/src/main/java/f/cking/software/data/helpers/PermissionHelper.kt index f8dabdd..a77ff42 100644 --- a/app/src/main/java/f/cking/software/data/helpers/PermissionHelper.kt +++ b/app/src/main/java/f/cking/software/data/helpers/PermissionHelper.kt @@ -82,6 +82,10 @@ class PermissionHelper( return (BLE_PERMISSIONS + BACKGROUND_LOCATION).all { checkPermission(it) } } + fun checkLocationPermission(): Boolean { + return checkPermission(Manifest.permission.ACCESS_FINE_LOCATION) + } + private fun checkPermission(permission: String): Boolean { return ActivityCompat.checkSelfPermission( context, diff --git a/app/src/main/java/f/cking/software/ui/UiModule.kt b/app/src/main/java/f/cking/software/ui/UiModule.kt index 1f47e3e..b990daa 100644 --- a/app/src/main/java/f/cking/software/ui/UiModule.kt +++ b/app/src/main/java/f/cking/software/ui/UiModule.kt @@ -20,7 +20,7 @@ object UiModule { single { get() } viewModel { MainViewModel(get(), get(), get(), get(), get(), get()) } viewModel { DeviceListViewModel(get(), get(), get(), get(), get(), get(), get(), get()) } - viewModel { SettingsViewModel(get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get()) } + viewModel { SettingsViewModel(get(), 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()) } viewModel { SelectManufacturerViewModel(get()) } diff --git a/app/src/main/java/f/cking/software/ui/devicedetails/DeviceDetailsScreen.kt b/app/src/main/java/f/cking/software/ui/devicedetails/DeviceDetailsScreen.kt index fbc6787..5e95a33 100644 --- a/app/src/main/java/f/cking/software/ui/devicedetails/DeviceDetailsScreen.kt +++ b/app/src/main/java/f/cking/software/ui/devicedetails/DeviceDetailsScreen.kt @@ -50,7 +50,6 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.google.accompanist.flowlayout.FlowRow -import com.vanpra.composematerialdialogs.MaterialDialog import com.vanpra.composematerialdialogs.rememberMaterialDialogState import f.cking.software.R import f.cking.software.dateTimeStringFormat @@ -64,6 +63,7 @@ import f.cking.software.utils.graphic.MapView import f.cking.software.utils.graphic.RoundedBox import f.cking.software.utils.graphic.SystemNavbarSpacer import f.cking.software.utils.graphic.TagChip +import f.cking.software.utils.graphic.ThemedDialog import kotlinx.coroutines.isActive import org.koin.androidx.compose.koinViewModel import org.koin.core.parameter.parametersOf @@ -273,14 +273,14 @@ object DeviceDetailsScreen { ) { val dialogState = rememberMaterialDialogState() - MaterialDialog( + ThemedDialog( dialogState = dialogState, buttons = { negativeButton( text = stringResource(R.string.cancel), - textStyle = TextStyle(color = MaterialTheme.colorScheme.secondaryContainer) + textStyle = TextStyle(color = MaterialTheme.colorScheme.onSurface) ) { dialogState.hide() } - positiveButton(text = stringResource(R.string.confirm), textStyle = TextStyle(color = MaterialTheme.colorScheme.secondaryContainer)) { + positiveButton(text = stringResource(R.string.confirm), textStyle = TextStyle(color = MaterialTheme.colorScheme.onSurface)) { dialogState.hide() viewModel.onRemoveTagClick(deviceData, name) } @@ -318,12 +318,12 @@ object DeviceDetailsScreen { viewModel: DeviceDetailsViewModel, ) { val dialog = rememberMaterialDialogState() - MaterialDialog( + ThemedDialog( dialogState = dialog, buttons = { negativeButton( stringResource(R.string.cancel), - textStyle = TextStyle(color = MaterialTheme.colorScheme.secondaryContainer) + textStyle = TextStyle(color = MaterialTheme.colorScheme.onSurface) ) { dialog.hide() } }, ) { diff --git a/app/src/main/java/f/cking/software/ui/devicelist/DeviceListScreen.kt b/app/src/main/java/f/cking/software/ui/devicelist/DeviceListScreen.kt index 4014c27..00a424e 100644 --- a/app/src/main/java/f/cking/software/ui/devicelist/DeviceListScreen.kt +++ b/app/src/main/java/f/cking/software/ui/devicelist/DeviceListScreen.kt @@ -105,7 +105,7 @@ object DeviceListScreen { } } - if (viewModel.enjoyTheAppState != DeviceListViewModel.EnjoyTheAppState.NONE) { + if (viewModel.enjoyTheAppState != DeviceListViewModel.EnjoyTheAppState.None) { item { Spacer(modifier = Modifier.height(8.dp)) EnjoyTheApp(viewModel, viewModel.enjoyTheAppState) @@ -137,10 +137,10 @@ object DeviceListScreen { 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") + is DeviceListViewModel.EnjoyTheAppState.Question -> EnjoyTheAppQuestion(viewModel) + is DeviceListViewModel.EnjoyTheAppState.Like -> EnjoyTheAppLike(enjoyTheAppState, viewModel) + is DeviceListViewModel.EnjoyTheAppState.Dislike -> EnjoyTheAppDislike(viewModel) + is DeviceListViewModel.EnjoyTheAppState.None -> throw IllegalStateException("EnjoyTheAppState.NONE is not supported here") } } } @@ -171,17 +171,18 @@ object DeviceListScreen { } @Composable - private fun EnjoyTheAppLike(viewModel: DeviceListViewModel) { + private fun EnjoyTheAppLike(state: DeviceListViewModel.EnjoyTheAppState.Like, 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), color = MaterialTheme.colorScheme.onPrimary) - } - Spacer(modifier = Modifier.width(8.dp)) - Button(modifier = Modifier.weight(1f), onClick = { viewModel.onEnjoyTheAppRateGithubClick() }) { - Text(text = stringResource(R.string.rate_the_app_github), color = MaterialTheme.colorScheme.onPrimary) + state.actions.forEachIndexed { i, action -> + Button(modifier = Modifier.weight(1f), onClick = { viewModel.onRateButtonClick(action) }) { + Text(text = action.title, color = MaterialTheme.colorScheme.onPrimary) + } + if (i < state.actions.lastIndex) { + Spacer(modifier = Modifier.width(8.dp)) + } } } } diff --git a/app/src/main/java/f/cking/software/ui/devicelist/DeviceListViewModel.kt b/app/src/main/java/f/cking/software/ui/devicelist/DeviceListViewModel.kt index d1638db..b3b02c0 100644 --- a/app/src/main/java/f/cking/software/ui/devicelist/DeviceListViewModel.kt +++ b/app/src/main/java/f/cking/software/ui/devicelist/DeviceListViewModel.kt @@ -25,7 +25,7 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext class DeviceListViewModel( - context: Application, + private val context: Application, private val devicesRepository: DevicesRepository, private val filterCheckerImpl: FilterCheckerImpl, val router: Router, @@ -46,7 +46,7 @@ class DeviceListViewModel( DefaultFilters.isFavorite(context), ) ) - var enjoyTheAppState: EnjoyTheAppState by mutableStateOf(EnjoyTheAppState.NONE) + var enjoyTheAppState: EnjoyTheAppState by mutableStateOf(EnjoyTheAppState.None) private val generalComparator = Comparator { second, first -> when { @@ -152,38 +152,56 @@ class DeviceListViewModel( } private fun showEnjoyTheAppIfNeeded() { - if (enjoyTheAppState == EnjoyTheAppState.NONE + if (enjoyTheAppState is EnjoyTheAppState.None && checkNeedToShowEnjoyTheAppInteractor.execute() ) { - enjoyTheAppState = EnjoyTheAppState.QUESTION + enjoyTheAppState = EnjoyTheAppState.Question } } fun onEnjoyTheAppAnswered(answer: EnjoyTheAppAnswer) { enjoyTheAppState = when (answer) { - EnjoyTheAppAnswer.LIKE -> EnjoyTheAppState.LIKE - EnjoyTheAppAnswer.DISLIKE -> EnjoyTheAppState.DISLIKE + EnjoyTheAppAnswer.LIKE -> buildLikeTheAppState() + EnjoyTheAppAnswer.DISLIKE -> EnjoyTheAppState.Dislike EnjoyTheAppAnswer.ASK_LATER -> { enjoyTheAppAskLaterInteractor.execute() - EnjoyTheAppState.NONE + EnjoyTheAppState.None } } } - fun onEnjoyTheAppRatePlayStoreClick() { - settingsRepository.setEnjoyTheAppAnswered(true) - enjoyTheAppState = EnjoyTheAppState.NONE - intentHelper.openUrl(BuildConfig.GOOGLE_PLAY_URL) + private fun buildLikeTheAppState(): EnjoyTheAppState.Like { + val actions = mutableListOf() + if (BuildConfig.STORE_RATING_IS_APPLICABLE) { + actions.add( + EnjoyTheAppState.RateAppAction( + title = BuildConfig.DISTRIBUTION, + url = BuildConfig.STORE_PAGE_URL, + saveAnswer = true, + ) + ) + } + actions.add( + EnjoyTheAppState.RateAppAction( + title = context.getString(R.string.rate_the_app_github), + url = BuildConfig.GITHUB_URL, + saveAnswer = !BuildConfig.STORE_RATING_IS_APPLICABLE, + ) + ) + return EnjoyTheAppState.Like(actions) } - fun onEnjoyTheAppRateGithubClick() { - settingsRepository.setEnjoyTheAppAnswered(true) - intentHelper.openUrl(BuildConfig.GITHUB_URL) + fun onRateButtonClick(rateAction: EnjoyTheAppState.RateAppAction) { + if (rateAction.saveAnswer) { + settingsRepository.setEnjoyTheAppAnswered(true) + enjoyTheAppState = EnjoyTheAppState.None + } + intentHelper.openUrl(rateAction.url) } fun onEnjoyTheAppReportClick() { settingsRepository.setEnjoyTheAppAnswered(true) - enjoyTheAppState = EnjoyTheAppState.NONE + enjoyTheAppState = EnjoyTheAppState.None intentHelper.openUrl(BuildConfig.REPORT_ISSUE_URL) } @@ -209,8 +227,21 @@ class DeviceListViewModel( val filter: RadarProfile.Filter, ) - enum class EnjoyTheAppState { - NONE, QUESTION, LIKE, DISLIKE + sealed interface EnjoyTheAppState { + data object None : EnjoyTheAppState + data object Question : EnjoyTheAppState + + data class Like( + val actions: List + ) : EnjoyTheAppState + + data object Dislike : EnjoyTheAppState + + data class RateAppAction( + val title: String, + val url: String, + val saveAnswer: Boolean, + ) } enum class EnjoyTheAppAnswer { diff --git a/app/src/main/java/f/cking/software/ui/filter/SelectFilterScreen.kt b/app/src/main/java/f/cking/software/ui/filter/SelectFilterScreen.kt index 7b967e7..a2815a3 100644 --- a/app/src/main/java/f/cking/software/ui/filter/SelectFilterScreen.kt +++ b/app/src/main/java/f/cking/software/ui/filter/SelectFilterScreen.kt @@ -4,8 +4,10 @@ import android.widget.Toast import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll @@ -22,16 +24,20 @@ import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.input.nestedscroll.nestedScroll +import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import f.cking.software.R import f.cking.software.domain.model.RadarProfile -import f.cking.software.utils.graphic.BottomNavigationSpacer import f.cking.software.utils.graphic.GlassBottomSpace import f.cking.software.utils.graphic.SystemNavbarSpacer +import f.cking.software.utils.graphic.pxToDp import f.cking.software.utils.navigation.BackCommand import f.cking.software.utils.navigation.Router @@ -52,32 +58,9 @@ object SelectFilterScreen { AppBar(scrollBehavior) { router.navigate(BackCommand) } }, content = { paddings -> + var bottomBarHeight by mutableStateOf(0f) GlassBottomSpace( modifier = Modifier.fillMaxSize(), - bottomContent = { - val context = LocalContext.current - Button( - modifier = Modifier - .fillMaxWidth() - .padding(16.dp), - onClick = { - val filter = initialFilterState - .takeIf { it.isCorrect() } - ?.let { FilterUiMapper.mapToDomain(it) } - - if (filter != null) { - router.navigate(BackCommand) - onConfirm.invoke(filter) - } else { - Toast.makeText(context, context.getString(R.string.filter_is_not_valid), Toast.LENGTH_SHORT).show() - } - } - ) { - Text(text = stringResource(R.string.confirm), color = MaterialTheme.colorScheme.onPrimary) - } - - SystemNavbarSpacer() - }, globalContent = { Column( modifier = Modifier @@ -96,9 +79,37 @@ object SelectFilterScreen { onDeleteClick = { router.navigate(BackCommand) } ) } - BottomNavigationSpacer() + Spacer(modifier = Modifier.height(pxToDp(px = bottomBarHeight).dp)) + } + }, + bottomContent = { + val context = LocalContext.current + Column( + modifier = Modifier + .onGloballyPositioned { bottomBarHeight = it.size.height.toFloat() } + ) { + Button( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp), + onClick = { + val filter = initialFilterState + .takeIf { it.isCorrect() } + ?.let { FilterUiMapper.mapToDomain(it) } + + if (filter != null) { + router.navigate(BackCommand) + onConfirm.invoke(filter) + } else { + Toast.makeText(context, context.getString(R.string.filter_is_not_valid), Toast.LENGTH_SHORT).show() + } + } + ) { + Text(text = stringResource(R.string.confirm), color = MaterialTheme.colorScheme.onPrimary) + } + SystemNavbarSpacer() } - } + }, ) } ) diff --git a/app/src/main/java/f/cking/software/ui/filter/SelectFilterTypeScreen.kt b/app/src/main/java/f/cking/software/ui/filter/SelectFilterTypeScreen.kt index 8ae42da..94a3c8c 100644 --- a/app/src/main/java/f/cking/software/ui/filter/SelectFilterTypeScreen.kt +++ b/app/src/main/java/f/cking/software/ui/filter/SelectFilterTypeScreen.kt @@ -5,17 +5,17 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.material.Text import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.vanpra.composematerialdialogs.MaterialDialog import com.vanpra.composematerialdialogs.MaterialDialogState import f.cking.software.R +import f.cking.software.utils.graphic.ThemedDialog object SelectFilterTypeScreen { @@ -24,15 +24,14 @@ object SelectFilterTypeScreen { dialogState: MaterialDialogState, onSelected: (type: FilterUiState) -> Unit, ) { - - MaterialDialog( + ThemedDialog( dialogState = dialogState, buttons = { - negativeButton(stringResource(R.string.cancel), textStyle = TextStyle(color = MaterialTheme.colorScheme.secondaryContainer)) { dialogState.hide() } + negativeButton(stringResource(R.string.cancel), textStyle = TextStyle(color = MaterialTheme.colorScheme.onSurface)) { dialogState.hide() } } ) { LazyColumn { - FilterType.values().forEach { type -> + FilterType.entries.forEach { type -> item { TypeItem(item = type) { dialogState.hide() diff --git a/app/src/main/java/f/cking/software/ui/main/MainScreen.kt b/app/src/main/java/f/cking/software/ui/main/MainScreen.kt index eebfa4d..7354140 100644 --- a/app/src/main/java/f/cking/software/ui/main/MainScreen.kt +++ b/app/src/main/java/f/cking/software/ui/main/MainScreen.kt @@ -35,13 +35,13 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.vanpra.composematerialdialogs.MaterialDialog import com.vanpra.composematerialdialogs.MaterialDialogState import com.vanpra.composematerialdialogs.rememberMaterialDialogState import f.cking.software.R import f.cking.software.ui.GlobalUiState import f.cking.software.utils.graphic.GlassBottomNavBar import f.cking.software.utils.graphic.SystemNavbarSpacer +import f.cking.software.utils.graphic.ThemedDialog import org.koin.androidx.compose.koinViewModel @OptIn(ExperimentalMaterial3Api::class) @@ -80,11 +80,11 @@ object MainScreen { @Composable private fun LocationDisabledDialog(viewModel: MainViewModel) { - MaterialDialog( + ThemedDialog( dialogState = viewModel.showLocationDisabledDialog, buttons = { - negativeButton(stringResource(R.string.cancel), textStyle = TextStyle(color = MaterialTheme.colorScheme.secondaryContainer)) - positiveButton(stringResource(R.string.turn_on), textStyle = TextStyle(color = MaterialTheme.colorScheme.secondaryContainer)) { + negativeButton(stringResource(R.string.cancel), textStyle = TextStyle(color = MaterialTheme.colorScheme.onSurface)) + positiveButton(stringResource(R.string.turn_on), textStyle = TextStyle(color = MaterialTheme.colorScheme.onSurface)) { viewModel.onTurnOnLocationClick() } }, @@ -99,11 +99,11 @@ object MainScreen { @Composable private fun BluetoothDisabledDialog(viewModel: MainViewModel) { - MaterialDialog( + ThemedDialog( dialogState = viewModel.showBluetoothDisabledDialog, buttons = { - negativeButton(stringResource(R.string.cancel), textStyle = TextStyle(color = MaterialTheme.colorScheme.secondaryContainer)) - positiveButton(stringResource(R.string.turn_on), textStyle = TextStyle(color = MaterialTheme.colorScheme.secondaryContainer)) { + negativeButton(stringResource(R.string.cancel), textStyle = TextStyle(color = MaterialTheme.colorScheme.onSurface)) + positiveButton(stringResource(R.string.turn_on), textStyle = TextStyle(color = MaterialTheme.colorScheme.onSurface)) { viewModel.onTurnOnBluetoothClick() } }, @@ -215,14 +215,14 @@ object MainScreen { onDeclined: () -> Unit, ): MaterialDialogState { val state = rememberMaterialDialogState() - MaterialDialog( + ThemedDialog( dialogState = state, buttons = { - positiveButton(stringResource(id = R.string.confirm), textStyle = TextStyle(color = MaterialTheme.colorScheme.secondaryContainer)) { + positiveButton(stringResource(id = R.string.confirm), textStyle = TextStyle(color = MaterialTheme.colorScheme.onSurface)) { state.hide() onPassed.invoke() } - negativeButton(stringResource(id = R.string.decline), textStyle = TextStyle(color = MaterialTheme.colorScheme.secondaryContainer)) { + negativeButton(stringResource(id = R.string.decline), textStyle = TextStyle(color = MaterialTheme.colorScheme.onSurface)) { state.hide() onDeclined.invoke() } diff --git a/app/src/main/java/f/cking/software/ui/profiledetails/ProfileDetailsScreen.kt b/app/src/main/java/f/cking/software/ui/profiledetails/ProfileDetailsScreen.kt index f61dc17..a8fd5be 100644 --- a/app/src/main/java/f/cking/software/ui/profiledetails/ProfileDetailsScreen.kt +++ b/app/src/main/java/f/cking/software/ui/profiledetails/ProfileDetailsScreen.kt @@ -38,7 +38,6 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.vanpra.composematerialdialogs.MaterialDialog import com.vanpra.composematerialdialogs.rememberMaterialDialogState import f.cking.software.R import f.cking.software.ui.filter.FilterScreen @@ -47,6 +46,7 @@ import f.cking.software.ui.filter.SelectFilterTypeScreen import f.cking.software.utils.graphic.GlassSystemNavbar import f.cking.software.utils.graphic.RoundedBox import f.cking.software.utils.graphic.SystemNavbarSpacer +import f.cking.software.utils.graphic.ThemedDialog import org.koin.androidx.compose.koinViewModel import org.koin.core.parameter.parametersOf @@ -85,16 +85,16 @@ object ProfileDetailsScreen { private fun AppBar(viewModel: ProfileDetailsViewModel, scrollBehavior: TopAppBarScrollBehavior) { val discardChangesDialog = rememberMaterialDialogState() - MaterialDialog( + ThemedDialog( dialogState = discardChangesDialog, buttons = { negativeButton( stringResource(R.string.stay), - textStyle = TextStyle(color = MaterialTheme.colorScheme.secondaryContainer) + textStyle = TextStyle(color = MaterialTheme.colorScheme.onSurface) ) { discardChangesDialog.hide() } positiveButton( stringResource(R.string.discard_changes), - textStyle = TextStyle(color = MaterialTheme.colorScheme.secondaryContainer) + textStyle = TextStyle(color = MaterialTheme.colorScheme.onSurface) ) { discardChangesDialog.hide() viewModel.back() @@ -107,11 +107,11 @@ object ProfileDetailsScreen { } val deleteDialog = rememberMaterialDialogState() - MaterialDialog( + ThemedDialog( dialogState = deleteDialog, buttons = { - negativeButton(stringResource(R.string.cancel)) { deleteDialog.hide() } - positiveButton(stringResource(R.string.confirm)) { + negativeButton(stringResource(R.string.cancel), textStyle = TextStyle(color = MaterialTheme.colorScheme.onSurface)) { deleteDialog.hide() } + positiveButton(stringResource(R.string.confirm), textStyle = TextStyle(color = MaterialTheme.colorScheme.onSurface)) { deleteDialog.hide() viewModel.onRemoveClick() } diff --git a/app/src/main/java/f/cking/software/ui/settings/SettingsScreen.kt b/app/src/main/java/f/cking/software/ui/settings/SettingsScreen.kt index 6455f84..14a6f4b 100644 --- a/app/src/main/java/f/cking/software/ui/settings/SettingsScreen.kt +++ b/app/src/main/java/f/cking/software/ui/settings/SettingsScreen.kt @@ -30,7 +30,6 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.vanpra.composematerialdialogs.MaterialDialog import com.vanpra.composematerialdialogs.rememberMaterialDialogState import f.cking.software.BuildConfig import f.cking.software.R @@ -38,6 +37,7 @@ import f.cking.software.dateTimeStringFormat import f.cking.software.utils.graphic.BottomNavigationSpacer import f.cking.software.utils.graphic.FABSpacer import f.cking.software.utils.graphic.RoundedBox +import f.cking.software.utils.graphic.ThemedDialog import org.koin.androidx.compose.koinViewModel object SettingsScreen { @@ -132,14 +132,14 @@ object SettingsScreen { private fun RestoreDB(viewModel: SettingsViewModel) { val dialogState = rememberMaterialDialogState() - MaterialDialog( + ThemedDialog( dialogState = dialogState, buttons = { negativeButton( text = stringResource(R.string.cancel), - textStyle = TextStyle(color = MaterialTheme.colorScheme.secondaryContainer) + textStyle = TextStyle(color = MaterialTheme.colorScheme.onSurface) ) { dialogState.hide() } - positiveButton(text = stringResource(R.string.confirm), textStyle = TextStyle(color = MaterialTheme.colorScheme.secondaryContainer)) { + positiveButton(text = stringResource(R.string.confirm), textStyle = TextStyle(color = MaterialTheme.colorScheme.onSurface)) { dialogState.hide() viewModel.onRestoreDBClick() } @@ -164,14 +164,14 @@ object SettingsScreen { private fun BackupDB(viewModel: SettingsViewModel) { val dialogState = rememberMaterialDialogState() - MaterialDialog( + ThemedDialog( dialogState = dialogState, buttons = { negativeButton( text = stringResource(R.string.cancel), - textStyle = TextStyle(color = MaterialTheme.colorScheme.secondaryContainer) + textStyle = TextStyle(color = MaterialTheme.colorScheme.onSurface) ) { dialogState.hide() } - positiveButton(text = stringResource(R.string.confirm), textStyle = TextStyle(color = MaterialTheme.colorScheme.secondaryContainer)) { + positiveButton(text = stringResource(R.string.confirm), textStyle = TextStyle(color = MaterialTheme.colorScheme.onSurface)) { dialogState.hide() viewModel.onBackupDBClick() } @@ -200,7 +200,7 @@ object SettingsScreen { Image( modifier = Modifier .align(Alignment.CenterHorizontally) - .alpha(0.3f) + .alpha(0.1f) .width(30.dp), colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onSurface), painter = painterResource(id = R.drawable.cat_footprint), @@ -226,14 +226,14 @@ object SettingsScreen { val dialogState = rememberMaterialDialogState() - MaterialDialog( + ThemedDialog( dialogState = dialogState, buttons = { negativeButton( text = stringResource(R.string.cancel), - textStyle = TextStyle(color = MaterialTheme.colorScheme.secondaryContainer) + textStyle = TextStyle(color = MaterialTheme.colorScheme.onSurface) ) { dialogState.hide() } - positiveButton(text = stringResource(R.string.confirm), textStyle = TextStyle(color = MaterialTheme.colorScheme.secondaryContainer)) { + positiveButton(text = stringResource(R.string.confirm), textStyle = TextStyle(color = MaterialTheme.colorScheme.onSurface)) { dialogState.hide() viewModel.onClearLocationsClick() } diff --git a/app/src/main/java/f/cking/software/ui/settings/SettingsViewModel.kt b/app/src/main/java/f/cking/software/ui/settings/SettingsViewModel.kt index 3fd0852..ff08b59 100644 --- a/app/src/main/java/f/cking/software/ui/settings/SettingsViewModel.kt +++ b/app/src/main/java/f/cking/software/ui/settings/SettingsViewModel.kt @@ -12,6 +12,7 @@ import f.cking.software.BuildConfig import f.cking.software.R import f.cking.software.data.helpers.IntentHelper import f.cking.software.data.helpers.LocationProvider +import f.cking.software.data.helpers.PermissionHelper import f.cking.software.data.repo.LocationRepository import f.cking.software.data.repo.SettingsRepository import f.cking.software.domain.interactor.BackupDatabaseInteractor @@ -37,6 +38,7 @@ class SettingsViewModel( private val selectBackupFileInteractor: SelectBackupFileInteractor, private val restoreDatabaseInteractor: RestoreDatabaseInteractor, private val intentHelper: IntentHelper, + private val permissionHelper: PermissionHelper, ) : ViewModel() { private val TAG = "SettingsViewModel" @@ -84,7 +86,7 @@ class SettingsViewModel( if (locationProvider.isActive()) { locationProvider.stopLocationListening() locationProvider.startLocationFetching() - } else { + } else if (permissionHelper.checkLocationPermission()) { locationProvider.fetchOnce() } } diff --git a/app/src/main/java/f/cking/software/ui/tagdialog/TagDialog.kt b/app/src/main/java/f/cking/software/ui/tagdialog/TagDialog.kt index 971b2dd..114d550 100644 --- a/app/src/main/java/f/cking/software/ui/tagdialog/TagDialog.kt +++ b/app/src/main/java/f/cking/software/ui/tagdialog/TagDialog.kt @@ -21,12 +21,12 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.unit.dp import com.google.accompanist.flowlayout.FlowRow -import com.vanpra.composematerialdialogs.MaterialDialog import com.vanpra.composematerialdialogs.MaterialDialogState import com.vanpra.composematerialdialogs.rememberMaterialDialogState import f.cking.software.R import f.cking.software.data.repo.TagsRepository import f.cking.software.utils.graphic.TagChip +import f.cking.software.utils.graphic.ThemedDialog import kotlinx.coroutines.launch import org.koin.androidx.compose.getKoin @@ -38,10 +38,10 @@ object TagDialog { ): MaterialDialogState { val dialog = rememberMaterialDialogState() val inputState = remember { mutableStateOf("") } - MaterialDialog( + ThemedDialog( dialogState = dialog, buttons = { - negativeButton("Cancel", textStyle = TextStyle(color = MaterialTheme.colorScheme.secondaryContainer)) { dialog.hide() } + negativeButton("Cancel", textStyle = TextStyle(color = MaterialTheme.colorScheme.onSurface)) { dialog.hide() } }, onCloseRequest = { dialog.hide() }, ) { diff --git a/app/src/main/java/f/cking/software/utils/graphic/ComposeFunctions.kt b/app/src/main/java/f/cking/software/utils/graphic/ComposeFunctions.kt index 19bd1f0..6699f05 100644 --- a/app/src/main/java/f/cking/software/utils/graphic/ComposeFunctions.kt +++ b/app/src/main/java/f/cking/software/utils/graphic/ComposeFunctions.kt @@ -1,5 +1,6 @@ package f.cking.software.utils.graphic +import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.isSystemInDarkTheme @@ -11,9 +12,9 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.windowInsetsBottomHeight import androidx.compose.foundation.shape.CornerSize @@ -38,6 +39,7 @@ import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.clip import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.Shape import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.LocalContext @@ -52,11 +54,18 @@ import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.ui.viewinterop.AndroidView +import androidx.compose.ui.window.DialogProperties import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver import com.vanpra.composematerialdialogs.MaterialDialog +import com.vanpra.composematerialdialogs.MaterialDialogButtons +import com.vanpra.composematerialdialogs.MaterialDialogScope import com.vanpra.composematerialdialogs.MaterialDialogState +import com.vanpra.composematerialdialogs.datetime.date.DatePickerColors +import com.vanpra.composematerialdialogs.datetime.date.DatePickerDefaults import com.vanpra.composematerialdialogs.datetime.date.datepicker +import com.vanpra.composematerialdialogs.datetime.time.TimePickerColors +import com.vanpra.composematerialdialogs.datetime.time.TimePickerDefaults import com.vanpra.composematerialdialogs.datetime.time.timepicker import com.vanpra.composematerialdialogs.rememberMaterialDialogState import f.cking.software.R @@ -74,23 +83,32 @@ import kotlin.math.abs @Composable fun rememberDateDialog( initialDate: LocalDate = LocalDate.now(), + datePickerColors: DatePickerColors = DatePickerDefaults.colors( + headerBackgroundColor = MaterialTheme.colorScheme.primaryContainer, + headerTextColor = MaterialTheme.colorScheme.onPrimaryContainer, + calendarHeaderTextColor = MaterialTheme.colorScheme.onPrimaryContainer, + dateActiveBackgroundColor = MaterialTheme.colorScheme.primary, + dateActiveTextColor = MaterialTheme.colorScheme.onPrimary, + dateInactiveBackgroundColor = Color.Transparent, + dateInactiveTextColor = MaterialTheme.colorScheme.onSurface, + ), dateResult: (date: LocalDate) -> Unit, ): MaterialDialogState { val dialogState = rememberMaterialDialogState() - MaterialDialog( + ThemedDialog( dialogState = dialogState, buttons = { positiveButton( stringResource(R.string.ok), - textStyle = TextStyle(color = MaterialTheme.colorScheme.secondaryContainer) + textStyle = TextStyle(color = MaterialTheme.colorScheme.onSurface) ) { dialogState.hide() } negativeButton( stringResource(R.string.cancel), - textStyle = TextStyle(color = MaterialTheme.colorScheme.secondaryContainer) + textStyle = TextStyle(color = MaterialTheme.colorScheme.onSurface) ) { dialogState.hide() } }, ) { - datepicker(initialDate = initialDate) { localDate -> + datepicker(initialDate = initialDate, colors = datePickerColors) { localDate -> dateResult.invoke(localDate) } } @@ -100,29 +118,67 @@ fun rememberDateDialog( @Composable fun rememberTimeDialog( initialTime: LocalTime = LocalTime.now(), + timePickerColors: TimePickerColors = TimePickerDefaults.colors( + activeBackgroundColor = MaterialTheme.colorScheme.primary, + activeTextColor = MaterialTheme.colorScheme.onPrimary, + inactiveBackgroundColor = MaterialTheme.colorScheme.primaryContainer, + inactiveTextColor = MaterialTheme.colorScheme.onPrimaryContainer, + inactivePeriodBackground = Color.Transparent, + selectorColor = MaterialTheme.colorScheme.primary, + selectorTextColor = MaterialTheme.colorScheme.onPrimary, + headerTextColor = MaterialTheme.colorScheme.onSurface, + borderColor = Color.Transparent, + ), dateResult: (date: LocalTime) -> Unit, ): MaterialDialogState { val dialogState = rememberMaterialDialogState() - MaterialDialog( + ThemedDialog( dialogState = dialogState, buttons = { positiveButton( stringResource(R.string.ok), - textStyle = TextStyle(color = MaterialTheme.colorScheme.secondaryContainer) + textStyle = TextStyle(color = MaterialTheme.colorScheme.onSurface) ) { dialogState.hide() } negativeButton( stringResource(R.string.cancel), - textStyle = TextStyle(color = MaterialTheme.colorScheme.secondaryContainer) + textStyle = TextStyle(color = MaterialTheme.colorScheme.onSurface) ) { dialogState.hide() } }, ) { - timepicker(is24HourClock = true, initialTime = initialTime) { localDate -> + timepicker(is24HourClock = true, initialTime = initialTime, colors = timePickerColors) { localDate -> dateResult.invoke(localDate) } } return dialogState } +@Composable +fun ThemedDialog( + dialogState: MaterialDialogState = rememberMaterialDialogState(), + properties: DialogProperties = DialogProperties(), + backgroundColor: Color = MaterialTheme.colorScheme.surfaceContainerHighest, + shape: Shape = MaterialTheme.shapes.medium, + border: BorderStroke? = null, + elevation: Dp = 24.dp, + autoDismiss: Boolean = true, + onCloseRequest: (MaterialDialogState) -> Unit = { it.hide() }, + buttons: @Composable MaterialDialogButtons.() -> Unit = {}, + content: @Composable MaterialDialogScope.() -> Unit +) { + MaterialDialog( + dialogState = dialogState, + properties = properties, + backgroundColor = backgroundColor, + shape = shape, + border = border, + elevation = elevation, + autoDismiss = autoDismiss, + onCloseRequest = onCloseRequest, + buttons = buttons, + content = content + ) +} + @Composable fun ClickableField( modifier: Modifier = Modifier, @@ -427,7 +483,7 @@ fun FABSpacer() { @Composable fun SystemNavbarSpacer() { - Spacer(modifier = Modifier.windowInsetsBottomHeight(WindowInsets.navigationBars)) + Spacer(modifier = Modifier.windowInsetsBottomHeight(WindowInsets.systemBars)) } fun ColorScheme.surfaceEvaluated(evaluation: Dp = 3.dp): Color { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6597df8..d11b535 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -168,7 +168,6 @@ Not really Ask me later Glad to hear this, can you rate the app? - Google Play GitHub We are sorry to hear this. You can provide your feedback in the GitHub issues diff --git a/app/src/release/res/drawable/ic_launcher_background.jpg b/app/src/release/res/drawable/ic_launcher_background.jpg deleted file mode 100644 index b587fcd..0000000 Binary files a/app/src/release/res/drawable/ic_launcher_background.jpg and /dev/null differ diff --git a/app/src/release/res/drawable/ic_launcher_background.webp b/app/src/release/res/drawable/ic_launcher_background.webp new file mode 100644 index 0000000..4c7da18 Binary files /dev/null and b/app/src/release/res/drawable/ic_launcher_background.webp differ diff --git a/app/src/main/header.png b/metadata/en-US/images/header.png similarity index 100% rename from app/src/main/header.png rename to metadata/en-US/images/header.png diff --git a/app/src/main/ic_launcher-playstore.png b/metadata/en-US/images/ic_launcher-playstore.png similarity index 100% rename from app/src/main/ic_launcher-playstore.png rename to metadata/en-US/images/ic_launcher-playstore.png diff --git a/metadata/en-US/images/ic_launcher_background.webp b/metadata/en-US/images/ic_launcher_background.webp new file mode 100644 index 0000000..ec49c5d Binary files /dev/null and b/metadata/en-US/images/ic_launcher_background.webp differ