From ec834fa379cfa2476e7a1d38c7b7402ebcaf2d79 Mon Sep 17 00:00:00 2001 From: w2sv Date: Wed, 12 Apr 2023 17:06:35 +0200 Subject: [PATCH] Fix stuff --- .../com/w2sv/wifiwidget/ui/NonAppliedState.kt | 52 +++++++++++++------ .../wifiwidget/ui/screens/home/HomeScreen.kt | 2 +- .../ui/screens/home/HomeScreenViewModel.kt | 6 +-- ...LocationAccessPermissionRationalDialog.kt} | 10 ++-- .../home/LocationAccessPermissionRequest.kt | 44 ++++++++-------- .../ui/screens/home/NavigationDrawer.kt | 2 +- .../home/widgetconfiguration/ButtonRow.kt | 4 +- .../WidgetConfigurationViewModel.kt | 18 +------ .../configcolumn/ColorSelection.kt | 1 + .../configcolumn/ConfigColumn.kt | 17 ++---- app/src/main/res/values/strings.xml | 1 - .../common/preferences/DataStoreRepository.kt | 6 +-- 12 files changed, 78 insertions(+), 85 deletions(-) rename app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/{LocationAccessPermissionDialog.kt => LocationAccessPermissionRationalDialog.kt} (93%) diff --git a/app/src/main/kotlin/com/w2sv/wifiwidget/ui/NonAppliedState.kt b/app/src/main/kotlin/com/w2sv/wifiwidget/ui/NonAppliedState.kt index d6c2a6f3..8d631f87 100644 --- a/app/src/main/kotlin/com/w2sv/wifiwidget/ui/NonAppliedState.kt +++ b/app/src/main/kotlin/com/w2sv/wifiwidget/ui/NonAppliedState.kt @@ -10,17 +10,19 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.merge +import kotlinx.coroutines.flow.transform import kotlinx.coroutines.launch abstract class NonAppliedState { val stateChanged = MutableStateFlow(false) - protected fun resetStateChanged() { + protected fun resetStateChanged(){ stateChanged.value = false } abstract val value: T - abstract suspend fun apply() + abstract suspend fun sync() abstract fun reset() } @@ -31,15 +33,16 @@ class NonAppliedSnapshotStateMap, V>( private val map: SnapshotStateMap = appliedFlowMap .getDeflowedMap() .getMutableStateMap(), - private val onApplyState: (Map) -> Unit = {} + private val onStateSynced: (Map) -> Unit = {} ) : NonAppliedState>(), MutableMap by map { override val value: Map get() = this - override suspend fun apply() { + override suspend fun sync() { dataStoreRepository.saveMap(value) - onApplyState(value) + onStateSynced(value) + dissimilarKeys.clear() resetStateChanged() } @@ -49,6 +52,7 @@ class NonAppliedSnapshotStateMap, V>( map[k] = v.first() } } + dissimilarKeys.clear() resetStateChanged() } @@ -70,7 +74,7 @@ class NonAppliedSnapshotStateMap, V>( class NonAppliedStateFlow( private val coroutineScope: CoroutineScope, private val appliedFlow: Flow, - private val updateAppliedState: (T) -> Unit + private val syncState: (T) -> Unit ) : NonAppliedState(), MutableStateFlow by MutableStateFlow( appliedFlow.getValueSynchronously() @@ -84,8 +88,8 @@ class NonAppliedStateFlow( } } - override suspend fun apply() { - updateAppliedState(value) + override suspend fun sync() { + syncState(value) resetStateChanged() } @@ -102,27 +106,41 @@ class CoherentNonAppliedStates( coroutineScope: CoroutineScope ) : List> by nonAppliedState.asList() { - val requiringUpdate = MutableStateFlow(false) + val stateChanged = MutableStateFlow(false) + + private val changedStateIndices = mutableSetOf() init { - forEach { - coroutineScope.launch { - it.stateChanged.collect { - requiringUpdate.value = any { it.stateChanged.value } + coroutineScope.launch { + mapIndexed { i, it -> it.stateChanged.transform { emit(it to i) } } + .merge() + .collect { (stateChanged, i) -> + if (stateChanged) { + changedStateIndices.add(i) + } else { + changedStateIndices.remove(i) + } + + this@CoherentNonAppliedStates.stateChanged.value = changedStateIndices.isNotEmpty() } - } } } - suspend fun apply() { + suspend fun sync() { forEach { - it.apply() + if (it.stateChanged.value) { + it.sync() + } } + changedStateIndices.clear() } fun reset() { forEach { - it.reset() + if (it.stateChanged.value) { + it.reset() + } } + changedStateIndices.clear() } } \ No newline at end of file diff --git a/app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/HomeScreen.kt b/app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/HomeScreen.kt index abed8656..904f0ab9 100644 --- a/app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/HomeScreen.kt +++ b/app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/HomeScreen.kt @@ -50,7 +50,7 @@ internal fun HomeScreen( } } viewModel.lapDialogTrigger.collectAsState().value?.let { - LocationAccessPermissionDialog(it) + LocationAccessPermissionRationalDialog(it) } viewModel.lapRequestTrigger.collectAsState().value?.let { LocationAccessPermissionRequest(it) diff --git a/app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/HomeScreenViewModel.kt b/app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/HomeScreenViewModel.kt index ffb9db2a..99756b3d 100644 --- a/app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/HomeScreenViewModel.kt +++ b/app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/HomeScreenViewModel.kt @@ -37,7 +37,7 @@ class HomeScreenViewModel @Inject constructor( dataStoreRepository.inAppTheme ) { viewModelScope.launch { - dataStoreRepository.saveEnum(it, PreferencesKey.IN_APP_THEME) + dataStoreRepository.saveEnum(PreferencesKey.IN_APP_THEME, it) } } @@ -79,8 +79,8 @@ class HomeScreenViewModel @Inject constructor( fun onLAPDialogAnswered() { viewModelScope.launch { dataStoreRepository.save( - true, - PreferencesKey.LOCATION_ACCESS_PERMISSION_DIALOG_ANSWERED + PreferencesKey.LOCATION_ACCESS_PERMISSION_DIALOG_ANSWERED, + true ) } } diff --git a/app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/LocationAccessPermissionDialog.kt b/app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/LocationAccessPermissionRationalDialog.kt similarity index 93% rename from app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/LocationAccessPermissionDialog.kt rename to app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/LocationAccessPermissionRationalDialog.kt index a4f7e27b..5829e699 100644 --- a/app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/LocationAccessPermissionDialog.kt +++ b/app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/LocationAccessPermissionRationalDialog.kt @@ -26,7 +26,7 @@ import com.w2sv.wifiwidget.ui.shared.WifiWidgetTheme @Composable private fun Prev() { WifiWidgetTheme { - LocationAccessPermissionDialog(Modifier, "Proceed without SSID", {}, {}) + LocationAccessPermissionRationalDialog(Modifier, "Proceed without SSID", {}, {}) } } @@ -36,7 +36,7 @@ enum class LocationAccessPermissionDialogTrigger { } @Composable -fun LocationAccessPermissionDialog( +fun LocationAccessPermissionRationalDialog( trigger: LocationAccessPermissionDialogTrigger, homeScreenViewModel: HomeScreenViewModel = viewModel(), widgetConfigurationViewModel: WidgetConfigurationViewModel = viewModel() @@ -45,7 +45,7 @@ fun LocationAccessPermissionDialog( when (trigger) { LocationAccessPermissionDialogTrigger.PinWidgetButtonPress -> { - LocationAccessPermissionDialog( + LocationAccessPermissionRationalDialog( dismissButtonText = stringResource(R.string.proceed_without_ssid), onConfirmButtonPressed = { homeScreenViewModel.lapRequestTrigger.value = trigger @@ -56,7 +56,7 @@ fun LocationAccessPermissionDialog( ) } - LocationAccessPermissionDialogTrigger.SSIDCheck -> LocationAccessPermissionDialog( + LocationAccessPermissionDialogTrigger.SSIDCheck -> LocationAccessPermissionRationalDialog( dismissButtonText = stringResource(R.string.never_mind), onConfirmButtonPressed = { homeScreenViewModel.lapRequestTrigger.value = trigger @@ -69,7 +69,7 @@ fun LocationAccessPermissionDialog( } @Composable -private fun LocationAccessPermissionDialog( +private fun LocationAccessPermissionRationalDialog( modifier: Modifier = Modifier, dismissButtonText: String, onConfirmButtonPressed: () -> Unit, diff --git a/app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/LocationAccessPermissionRequest.kt b/app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/LocationAccessPermissionRequest.kt index 1e1c1d52..abf0a376 100644 --- a/app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/LocationAccessPermissionRequest.kt +++ b/app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/LocationAccessPermissionRequest.kt @@ -6,7 +6,6 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource import androidx.lifecycle.viewmodel.compose.viewModel import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.rememberMultiplePermissionsState @@ -31,7 +30,7 @@ fun LocationAccessPermissionRequest( LocationAccessPermissionDialogTrigger.PinWidgetButtonPress -> LocationAccessPermissionRequest( onGranted = { widgetConfigurationViewModel.widgetPropertyStateMap[WifiProperty.SSID] = true - widgetConfigurationViewModel.widgetPropertyStateMap.apply() + widgetConfigurationViewModel.widgetPropertyStateMap.sync() WidgetProvider.pinWidget(context) }, onDenied = { @@ -70,32 +69,31 @@ private fun LocationAccessPermissionRequest( false -> onDenied() } homeScreenViewModel.lapRequestTrigger.reset() - homeScreenViewModel.dataStoreRepository.save( - true, - PreferencesKey.LOCATION_ACCESS_PERMISSION_REQUESTED_AT_LEAST_ONCE - ) } } ) - when (permissionState.allPermissionsGranted) { - true -> LaunchedEffect( - key1 = permissionState.permissions, - block = { onGranted() } - ) - - false -> { - if (permissionState.launchingSuppressed(homeScreenViewModel.lapRequestLaunchedAtLeastOnce)) { - context.showToast( - stringResource(R.string.go_to_app_settings_and_grant_location_access_permission), - Toast.LENGTH_LONG - ) + LaunchedEffect(key1 = permissionState.permissions) { + when (permissionState.allPermissionsGranted) { + true -> { + onGranted() homeScreenViewModel.lapRequestTrigger.reset() - } else { - LaunchedEffect( - key1 = permissionState.permissions, - block = { permissionState.launchMultiplePermissionRequest() } - ) + } + + false -> { + if (permissionState.launchingSuppressed(homeScreenViewModel.lapRequestLaunchedAtLeastOnce)) { + context.showToast( + context.getString(R.string.go_to_app_settings_and_grant_location_access_permission), + Toast.LENGTH_LONG + ) + homeScreenViewModel.lapRequestTrigger.reset() + } else { + permissionState.launchMultiplePermissionRequest() + homeScreenViewModel.dataStoreRepository.save( + PreferencesKey.LOCATION_ACCESS_PERMISSION_REQUESTED_AT_LEAST_ONCE, + true + ) + } } } } diff --git a/app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/NavigationDrawer.kt b/app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/NavigationDrawer.kt index 8a047625..1eaf039f 100644 --- a/app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/NavigationDrawer.kt +++ b/app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/NavigationDrawer.kt @@ -119,7 +119,7 @@ fun StatefulNavigationDrawer( onApplyButtonPress = { setShowThemeDialog(false) scope.launch { - homeScreenViewModel.inAppThemeState.apply() + homeScreenViewModel.inAppThemeState.sync() context.showToast("Updated Theme") } } diff --git a/app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/widgetconfiguration/ButtonRow.kt b/app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/widgetconfiguration/ButtonRow.kt index 3dae99c3..fbe01297 100644 --- a/app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/widgetconfiguration/ButtonRow.kt +++ b/app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/widgetconfiguration/ButtonRow.kt @@ -24,7 +24,7 @@ internal fun ButtonRow( ) { val context = LocalContext.current val scope = rememberCoroutineScope() - val applyButtonEnabled by widgetConfigurationViewModel.widgetConfigurationStates.requiringUpdate.collectAsState() + val applyButtonEnabled by widgetConfigurationViewModel.widgetConfigurationStates.stateChanged.collectAsState() ButtonRow( onCancel = { @@ -32,7 +32,7 @@ internal fun ButtonRow( }, onApply = { scope.launch { - widgetConfigurationViewModel.widgetConfigurationStates.apply() + widgetConfigurationViewModel.widgetConfigurationStates.sync() WidgetProvider.triggerDataRefresh(context) context.showToast(R.string.updated_widget_configuration) widgetConfigurationViewModel.showWidgetConfigurationDialog.value = false diff --git a/app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/widgetconfiguration/WidgetConfigurationViewModel.kt b/app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/widgetconfiguration/WidgetConfigurationViewModel.kt index d4ca56a7..f38b4240 100644 --- a/app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/widgetconfiguration/WidgetConfigurationViewModel.kt +++ b/app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/widgetconfiguration/WidgetConfigurationViewModel.kt @@ -56,7 +56,7 @@ class WidgetConfigurationViewModel @Inject constructor( dataStoreRepository.widgetTheme ) { viewModelScope.launch { - dataStoreRepository.saveEnum(it, PreferencesKey.WIDGET_THEME) + dataStoreRepository.saveEnum(PreferencesKey.WIDGET_THEME, it) } } @@ -83,7 +83,7 @@ class WidgetConfigurationViewModel @Inject constructor( dataStoreRepository.opacity ) { viewModelScope.launch { - dataStoreRepository.save(it, PreferencesKey.OPACITY) + dataStoreRepository.save(PreferencesKey.OPACITY, it) } } @@ -116,18 +116,4 @@ class WidgetConfigurationViewModel @Inject constructor( widgetConfigurationStates.reset() showWidgetConfigurationDialog.value = false } - - /** - * @return Boolean indicating whether change has been confirmed - */ - fun confirmAndSyncPropertyChange( - property: WifiProperty, - value: Boolean, - onChangeRejected: () -> Unit - ) { - when (value || widgetPropertyStateMap.values.count { true } != 1) { - true -> widgetPropertyStateMap[property] = value - false -> onChangeRejected() - } - } } \ No newline at end of file diff --git a/app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/widgetconfiguration/configcolumn/ColorSelection.kt b/app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/widgetconfiguration/configcolumn/ColorSelection.kt index 0526d141..e704ff42 100644 --- a/app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/widgetconfiguration/configcolumn/ColorSelection.kt +++ b/app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/widgetconfiguration/configcolumn/ColorSelection.kt @@ -55,6 +55,7 @@ private fun SectionCustomizationRow( viewModel: WidgetConfigurationViewModel = androidx.lifecycle.viewmodel.compose.viewModel() ) { val label = stringResource(id = widgetColorSection.labelRes) + Row( modifier = modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Start, diff --git a/app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/widgetconfiguration/configcolumn/ConfigColumn.kt b/app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/widgetconfiguration/configcolumn/ConfigColumn.kt index 1f4ba403..98035644 100644 --- a/app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/widgetconfiguration/configcolumn/ConfigColumn.kt +++ b/app/src/main/kotlin/com/w2sv/wifiwidget/ui/screens/home/widgetconfiguration/configcolumn/ConfigColumn.kt @@ -26,7 +26,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight @@ -34,7 +33,6 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.lifecycle.viewmodel.compose.viewModel -import com.w2sv.androidutils.extensions.showToast import com.w2sv.common.Theme import com.w2sv.common.WidgetColorSection import com.w2sv.common.WifiProperty @@ -70,8 +68,6 @@ fun ConfigColumn( val theme by widgetConfigurationViewModel.widgetThemeState.collectAsState() val opacity by widgetConfigurationViewModel.widgetOpacityState.collectAsState() - val context = LocalContext.current - Column( horizontalAlignment = Alignment.CenterHorizontally, modifier = modifier @@ -171,21 +167,16 @@ fun ConfigColumn( widgetConfigurationViewModel.widgetPropertyStateMap.getValue(property) }, onCheckedChange = { property, value -> - if (property == WifiProperty.SSID && value) { - when (homeScreenViewModel.lapDialogAnswered) { + when (property == WifiProperty.SSID && value) { + true -> when (homeScreenViewModel.lapDialogAnswered) { false -> homeScreenViewModel.lapDialogTrigger.value = LocationAccessPermissionDialogTrigger.SSIDCheck true -> homeScreenViewModel.lapRequestTrigger.value = LocationAccessPermissionDialogTrigger.SSIDCheck } - } else { - widgetConfigurationViewModel.confirmAndSyncPropertyChange( - property, - value - ) { - context.showToast(R.string.uncheck_all_properties_toast) - } + + false -> widgetConfigurationViewModel.widgetPropertyStateMap[property] = value } }, onInfoButtonClick = { widgetConfigurationViewModel.infoDialogProperty.value = it }) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 336e908a..a5ff6b2b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,7 +1,6 @@ WiFi Widget Pin Widget - You need to leave at least one property checked! Updated Widget Configuration Pinned Widget If you want your device\'s SSID to be displayed amongst the WiFi properties, you\'ll have to grant location access permission. diff --git a/common/src/main/kotlin/com/w2sv/common/preferences/DataStoreRepository.kt b/common/src/main/kotlin/com/w2sv/common/preferences/DataStoreRepository.kt index 3dc34091..b6309ec5 100644 --- a/common/src/main/kotlin/com/w2sv/common/preferences/DataStoreRepository.kt +++ b/common/src/main/kotlin/com/w2sv/common/preferences/DataStoreRepository.kt @@ -39,15 +39,15 @@ class DataStoreRepository @Inject constructor( it[PreferencesKey.OPACITY] ?: 1.0f } - suspend fun save(value: T, preferencesKey: Preferences.Key) { + suspend fun save(preferencesKey: Preferences.Key, value: T) { dataStore.edit { it[preferencesKey] = value } } suspend fun saveEnum( - enum: Enum<*>, - preferencesKey: Preferences.Key + preferencesKey: Preferences.Key, + enum: Enum<*> ) { dataStore.edit { it[preferencesKey] = enum.ordinal