From 4be0cd7f81b18ee9b10e5e1289c10fcc805c7ab0 Mon Sep 17 00:00:00 2001 From: Phil Oliver <3497406+poliver@users.noreply.github.com> Date: Mon, 18 Aug 2025 17:44:44 -0400 Subject: [PATCH] Migrate `UiState` prefs to repo (#2775) --- .../java/com/geeksville/mesh/model/UIState.kt | 73 ++++++++----------- .../mesh/util/SharedPreferenceExtensions.kt | 33 --------- 2 files changed, 31 insertions(+), 75 deletions(-) delete mode 100644 app/src/main/java/com/geeksville/mesh/util/SharedPreferenceExtensions.kt diff --git a/app/src/main/java/com/geeksville/mesh/model/UIState.kt b/app/src/main/java/com/geeksville/mesh/model/UIState.kt index f5f0ddd13..57f60a84d 100644 --- a/app/src/main/java/com/geeksville/mesh/model/UIState.kt +++ b/app/src/main/java/com/geeksville/mesh/model/UIState.kt @@ -18,12 +18,9 @@ package com.geeksville.mesh.model import android.app.Application -import android.content.SharedPreferences import android.net.Uri import android.os.RemoteException -import androidx.appcompat.app.AppCompatDelegate import androidx.compose.material3.SnackbarHostState -import androidx.core.content.edit import androidx.lifecycle.LiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.asLiveData @@ -42,6 +39,7 @@ import com.geeksville.mesh.Portnums import com.geeksville.mesh.Position import com.geeksville.mesh.R import com.geeksville.mesh.android.Logging +import com.geeksville.mesh.android.prefs.UiPrefs import com.geeksville.mesh.channel import com.geeksville.mesh.channelSet import com.geeksville.mesh.channelSettings @@ -67,7 +65,6 @@ import com.geeksville.mesh.ui.MainMenuAction import com.geeksville.mesh.ui.node.components.NodeMenuAction import com.geeksville.mesh.util.getShortDate import com.geeksville.mesh.util.positionToMeter -import com.geeksville.mesh.util.toggleBooleanPreference import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow @@ -199,17 +196,17 @@ constructor( private val quickChatActionRepository: QuickChatActionRepository, private val locationRepository: LocationRepository, firmwareReleaseRepository: FirmwareReleaseRepository, - private val preferences: SharedPreferences, + private val uiPrefs: UiPrefs, private val meshServiceNotifications: MeshServiceNotifications, ) : ViewModel(), Logging { - private val _theme = MutableStateFlow(preferences.getInt("theme", AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)) + private val _theme = MutableStateFlow(uiPrefs.theme) val theme: StateFlow = _theme.asStateFlow() fun setTheme(theme: Int) { _theme.value = theme - preferences.edit { putInt("theme", theme) } + uiPrefs.theme = theme } private val _lastTraceRouteTime = MutableStateFlow(null) @@ -322,50 +319,50 @@ constructor( private val nodeFilterText = MutableStateFlow("") private val nodeSortOption = - MutableStateFlow( - NodeSortOption.entries.getOrElse( - preferences.getInt("node-sort-option", NodeSortOption.VIA_FAVORITE.ordinal), - ) { - NodeSortOption.VIA_FAVORITE - }, - ) - private val includeUnknown = MutableStateFlow(preferences.getBoolean("include-unknown", false)) - private val showDetails = MutableStateFlow(preferences.getBoolean("show-details", false)) - private val onlyOnline = MutableStateFlow(preferences.getBoolean("only-online", false)) - private val onlyDirect = MutableStateFlow(preferences.getBoolean("only-direct", false)) + MutableStateFlow(NodeSortOption.entries.getOrElse(uiPrefs.nodeSortOption) { NodeSortOption.VIA_FAVORITE }) + private val includeUnknown = MutableStateFlow(uiPrefs.includeUnknown) + private val showDetails = MutableStateFlow(uiPrefs.showDetails) + private val onlyOnline = MutableStateFlow(uiPrefs.onlyOnline) + private val onlyDirect = MutableStateFlow(uiPrefs.onlyDirect) - private val _showIgnored = MutableStateFlow(preferences.getBoolean("show-ignored", false)) + private val _showIgnored = MutableStateFlow(uiPrefs.showIgnored) val showIgnored: StateFlow = _showIgnored - private val _showQuickChat = MutableStateFlow(preferences.getBoolean("show-quick-chat", false)) + private val _showQuickChat = MutableStateFlow(uiPrefs.showQuickChat) val showQuickChat: StateFlow = _showQuickChat - private val _hasShownNotPairedWarning = - MutableStateFlow(preferences.getBoolean(HAS_SHOWN_NOT_PAIRED_WARNING_PREF, false)) + private val _hasShownNotPairedWarning = MutableStateFlow(uiPrefs.hasShownNotPairedWarning) val hasShownNotPairedWarning: StateFlow = _hasShownNotPairedWarning.asStateFlow() fun suppressNoPairedWarning() { _hasShownNotPairedWarning.value = true - preferences.edit { putBoolean(HAS_SHOWN_NOT_PAIRED_WARNING_PREF, true) } + uiPrefs.hasShownNotPairedWarning = true } - fun toggleShowIgnored() = preferences.toggleBooleanPreference(_showIgnored, "show-ignored") + fun toggleShowIgnored() = toggle(_showIgnored) { uiPrefs.showIgnored = it } - fun toggleShowQuickChat() = preferences.toggleBooleanPreference(_showQuickChat, "show-quick-chat") + fun toggleShowQuickChat() = toggle(_showQuickChat) { uiPrefs.showQuickChat = it } fun setSortOption(sort: NodeSortOption) { nodeSortOption.value = sort - preferences.edit { putInt("node-sort-option", sort.ordinal) } + uiPrefs.nodeSortOption = sort.ordinal } - fun toggleShowDetails() = preferences.toggleBooleanPreference(showDetails, "show-details") + fun toggleShowDetails() = toggle(showDetails) { uiPrefs.showDetails = it } - fun toggleIncludeUnknown() = preferences.toggleBooleanPreference(includeUnknown, "include-unknown") + fun toggleIncludeUnknown() = toggle(includeUnknown) { uiPrefs.includeUnknown = it } - fun toggleOnlyOnline() = preferences.toggleBooleanPreference(onlyOnline, "only-online") + fun toggleOnlyOnline() = toggle(onlyOnline) { uiPrefs.onlyOnline = it } - fun toggleOnlyDirect() = preferences.toggleBooleanPreference(onlyDirect, "only-direct") + fun toggleOnlyDirect() = toggle(onlyDirect) { uiPrefs.onlyDirect = it } + + private fun toggle(state: MutableStateFlow, onChanged: (newValue: Boolean) -> Unit) { + (!state.value).let { toggled -> + state.update { toggled } + onChanged(toggled) + } + } data class NodeFilterState( val filterText: String, @@ -679,10 +676,6 @@ constructor( if (unreadCount == 0) meshServiceNotifications.cancelMessageNotification(contact) } - companion object { - const val HAS_SHOWN_NOT_PAIRED_WARNING_PREF = "has_shown_not_paired_warning" - } - // Connection state to our radio device val connectionState get() = radioConfigRepository.connectionState @@ -803,10 +796,7 @@ constructor( viewModelScope.launch { setProvideLocation(getProvidePref()) } } - private fun getProvidePref(): Boolean { - val value = preferences.getBoolean("provide-location-$myNodeNum", false) - return value - } + private fun getProvidePref(): Boolean = uiPrefs.shouldProvideNodeLocation(myNodeNum) private val _provideLocation = MutableStateFlow(getProvidePref()) val provideLocation: StateFlow @@ -814,7 +804,7 @@ constructor( fun setProvideLocation(value: Boolean) { viewModelScope.launch { - preferences.edit { putBoolean("provide-location-$myNodeNum", value) } + uiPrefs.setShouldProvideNodeLocation(myNodeNum, value) _provideLocation.value = value if (value) { meshService?.startProvideLocation() @@ -991,8 +981,7 @@ constructor( // region Main menu actions logic - private val _showAppIntro: MutableStateFlow = - MutableStateFlow(preferences.getBoolean("app_intro_completed", false).not()) + private val _showAppIntro: MutableStateFlow = MutableStateFlow(!uiPrefs.appIntroCompleted) val showAppIntro: StateFlow = _showAppIntro.asStateFlow() fun onMainMenuAction(action: MainMenuAction) { @@ -1006,7 +995,7 @@ constructor( // endregion fun onAppIntroCompleted() { - preferences.edit { putBoolean("app_intro_completed", true) } + uiPrefs.appIntroCompleted = true _showAppIntro.update { false } } } diff --git a/app/src/main/java/com/geeksville/mesh/util/SharedPreferenceExtensions.kt b/app/src/main/java/com/geeksville/mesh/util/SharedPreferenceExtensions.kt deleted file mode 100644 index 04158b755..000000000 --- a/app/src/main/java/com/geeksville/mesh/util/SharedPreferenceExtensions.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2025 Meshtastic LLC - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.geeksville.mesh.util - -import android.content.SharedPreferences -import androidx.core.content.edit -import kotlinx.coroutines.flow.MutableStateFlow - -fun SharedPreferences.toggleBooleanPreference( - state: MutableStateFlow, - key: String, - onChanged: (Boolean) -> Unit = {}, -) { - val newValue = !state.value - state.value = newValue - this.edit { putBoolean(key, newValue) } - onChanged(newValue) -}