mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
Pref fixes (#3175)
This commit is contained in:
parent
c5c433c165
commit
a1d9f926cb
7 changed files with 99 additions and 29 deletions
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.meshtastic.core.datastore
|
||||
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import androidx.datastore.preferences.core.booleanPreferencesKey
|
||||
import androidx.datastore.preferences.core.edit
|
||||
import androidx.datastore.preferences.core.intPreferencesKey
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
internal const val KEY_APP_INTRO_COMPLETED = "app_intro_completed"
|
||||
internal const val KEY_THEME = "theme"
|
||||
|
||||
@Singleton
|
||||
class UiPreferencesDataSource @Inject constructor(private val dataStore: DataStore<Preferences>) {
|
||||
|
||||
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
|
||||
|
||||
val appIntroCompleted: StateFlow<Boolean> = dataStore.prefStateFlow(key = APP_INTRO_COMPLETED, default = false)
|
||||
|
||||
// Default value for AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
|
||||
val theme: StateFlow<Int> = dataStore.prefStateFlow(key = THEME, default = -1)
|
||||
|
||||
fun setAppIntroCompleted(completed: Boolean) {
|
||||
dataStore.setPref(key = APP_INTRO_COMPLETED, value = completed)
|
||||
}
|
||||
|
||||
fun setTheme(value: Int) {
|
||||
dataStore.setPref(key = THEME, value = value)
|
||||
}
|
||||
|
||||
private fun <T : Any> DataStore<Preferences>.prefStateFlow(key: Preferences.Key<T>, default: T): StateFlow<T> =
|
||||
data.map { it[key] ?: default }.stateIn(scope = scope, started = SharingStarted.Lazily, initialValue = default)
|
||||
|
||||
private fun <T : Any> DataStore<Preferences>.setPref(key: Preferences.Key<T>, value: T) {
|
||||
scope.launch { edit { it[key] = value } }
|
||||
}
|
||||
|
||||
private companion object {
|
||||
val APP_INTRO_COMPLETED = booleanPreferencesKey(KEY_APP_INTRO_COMPLETED)
|
||||
val THEME = intPreferencesKey(KEY_THEME)
|
||||
}
|
||||
}
|
||||
|
|
@ -38,6 +38,8 @@ import dagger.hilt.components.SingletonComponent
|
|||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import org.meshtastic.core.datastore.KEY_APP_INTRO_COMPLETED
|
||||
import org.meshtastic.core.datastore.KEY_THEME
|
||||
import org.meshtastic.core.datastore.serializer.ChannelSetSerializer
|
||||
import org.meshtastic.core.datastore.serializer.LocalConfigSerializer
|
||||
import org.meshtastic.core.datastore.serializer.ModuleConfigSerializer
|
||||
|
|
@ -53,7 +55,15 @@ object DataStoreModule {
|
|||
fun providePreferencesDataStore(@ApplicationContext appContext: Context): DataStore<Preferences> =
|
||||
PreferenceDataStoreFactory.create(
|
||||
corruptionHandler = ReplaceFileCorruptionHandler(produceNewData = { emptyPreferences() }),
|
||||
migrations = listOf(SharedPreferencesMigration(appContext, USER_PREFERENCES_NAME)),
|
||||
migrations =
|
||||
listOf(
|
||||
SharedPreferencesMigration(context = appContext, sharedPreferencesName = USER_PREFERENCES_NAME),
|
||||
SharedPreferencesMigration(
|
||||
context = appContext,
|
||||
sharedPreferencesName = "ui-prefs",
|
||||
keysToMigrate = setOf(KEY_APP_INTRO_COMPLETED, KEY_THEME),
|
||||
),
|
||||
),
|
||||
scope = CoroutineScope(Dispatchers.IO + SupervisorJob()),
|
||||
produceFile = { appContext.preferencesDataStoreFile(USER_PREFERENCES_NAME) },
|
||||
)
|
||||
|
|
|
|||
|
|
@ -18,12 +18,10 @@
|
|||
package org.meshtastic.core.prefs.ui
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.core.content.edit
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import org.meshtastic.core.prefs.PrefDelegate
|
||||
import org.meshtastic.core.prefs.di.UiSharedPreferences
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
|
@ -31,10 +29,6 @@ import javax.inject.Inject
|
|||
import javax.inject.Singleton
|
||||
|
||||
interface UiPrefs {
|
||||
var theme: Int
|
||||
val themeFlow: StateFlow<Int>
|
||||
var appIntroCompleted: Boolean
|
||||
val appIntroCompletedFlow: StateFlow<Boolean>
|
||||
var hasShownNotPairedWarning: Boolean
|
||||
var nodeSortOption: Int
|
||||
var includeUnknown: Boolean
|
||||
|
|
@ -49,28 +43,15 @@ interface UiPrefs {
|
|||
fun setShouldProvideNodeLocation(nodeNum: Int, value: Boolean)
|
||||
}
|
||||
|
||||
const val KEY_THEME = "theme"
|
||||
const val KEY_APP_INTRO_COMPLETED = "app_intro_completed"
|
||||
|
||||
@Singleton
|
||||
class UiPrefsImpl @Inject constructor(@UiSharedPreferences private val prefs: SharedPreferences) : UiPrefs {
|
||||
|
||||
override var theme: Int by PrefDelegate(prefs, KEY_THEME, AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
|
||||
private var _themeFlow = MutableStateFlow(theme)
|
||||
override val themeFlow = _themeFlow.asStateFlow()
|
||||
|
||||
override var appIntroCompleted: Boolean by PrefDelegate(prefs, KEY_APP_INTRO_COMPLETED, false)
|
||||
private var _appIntroCompletedFlow = MutableStateFlow(appIntroCompleted)
|
||||
override val appIntroCompletedFlow = _appIntroCompletedFlow.asStateFlow()
|
||||
|
||||
// Maps nodeNum to a flow for the for the "provide-location-nodeNum" pref
|
||||
private val provideNodeLocationFlows = ConcurrentHashMap<Int, MutableStateFlow<Boolean>>()
|
||||
|
||||
private val sharedPreferencesListener =
|
||||
SharedPreferences.OnSharedPreferenceChangeListener { sharedPreferences, key ->
|
||||
when (key) {
|
||||
KEY_THEME -> _themeFlow.update { theme }
|
||||
KEY_APP_INTRO_COMPLETED -> _appIntroCompletedFlow.update { appIntroCompleted }
|
||||
// Check if the changed key is one of our node location keys
|
||||
else ->
|
||||
provideNodeLocationFlows.keys.forEach { nodeNum ->
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue