From aadde1a65d6000ce21ef3fb48c6f2aba217295e8 Mon Sep 17 00:00:00 2001 From: Filippo Scognamiglio Date: Wed, 8 May 2024 23:58:18 +0200 Subject: [PATCH] Fix compatibility of shared preferences with previous version. Gracefully handle misplaced settings. --- .../gamemenu/GameMenuCoreOptionsFragment.kt | 93 ------------------- .../coreoptions/GameMenuCoreOptionsScreen.kt | 30 ++++-- .../savesync/SaveSyncSettingsScreen.kt | 2 +- .../CoreOptionsPreferenceHelper.kt | 2 +- .../app/shared/game/BaseGameActivity.kt | 8 +- .../app/utils/android/PreferenceStates.kt | 16 ---- .../app/utils/android/settings/States.kt | 25 +++-- .../SafeBooleanPreferenceSettingValueState.kt | 46 +++++++++ ...> SafeIndexPreferenceSettingValueState.kt} | 10 +- ...eStringsSetPreferenceSettingValueState.kt} | 10 +- .../utils/settings/SharedPreferenceUtils.kt | 27 ++++++ 11 files changed, 128 insertions(+), 141 deletions(-) delete mode 100644 lemuroid-app/src/main/java/com/swordfish/lemuroid/app/mobile/feature/gamemenu/GameMenuCoreOptionsFragment.kt delete mode 100644 lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/android/PreferenceStates.kt create mode 100644 lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/settings/SafeBooleanPreferenceSettingValueState.kt rename lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/settings/{IndexPreferenceSettingValueState.kt => SafeIndexPreferenceSettingValueState.kt} (79%) rename lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/settings/{StringsSetPreferenceSettingValueState.kt => SafeStringsSetPreferenceSettingValueState.kt} (77%) create mode 100644 lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/settings/SharedPreferenceUtils.kt diff --git a/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/mobile/feature/gamemenu/GameMenuCoreOptionsFragment.kt b/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/mobile/feature/gamemenu/GameMenuCoreOptionsFragment.kt deleted file mode 100644 index ba487527a7..0000000000 --- a/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/mobile/feature/gamemenu/GameMenuCoreOptionsFragment.kt +++ /dev/null @@ -1,93 +0,0 @@ -package com.swordfish.lemuroid.app.mobile.feature.gamemenu - -import android.content.Context -import android.os.Bundle -import android.view.View -import androidx.lifecycle.Lifecycle -import androidx.preference.PreferenceFragmentCompat -import com.swordfish.lemuroid.R -import com.swordfish.lemuroid.app.shared.GameMenuContract -import com.swordfish.lemuroid.app.shared.coreoptions.CoreOptionsPreferenceHelper -import com.swordfish.lemuroid.app.shared.coreoptions.LemuroidCoreOption -import com.swordfish.lemuroid.app.shared.input.InputDeviceManager -import com.swordfish.lemuroid.common.coroutines.launchOnState -import com.swordfish.lemuroid.lib.library.SystemCoreConfig -import com.swordfish.lemuroid.lib.library.db.entity.Game -import com.swordfish.lemuroid.lib.preferences.SharedPreferencesHelper -import dagger.android.support.AndroidSupportInjection -import java.security.InvalidParameterException -import javax.inject.Inject - -class GameMenuCoreOptionsFragment : PreferenceFragmentCompat() { - @Inject - lateinit var inputDeviceManager: InputDeviceManager - - override fun onAttach(context: Context) { - AndroidSupportInjection.inject(this) - super.onAttach(context) - } - - override fun onCreatePreferences( - savedInstanceState: Bundle?, - rootKey: String?, - ) { - preferenceManager.preferenceDataStore = - SharedPreferencesHelper.getSharedPreferencesDataStore(requireContext()) - addPreferencesFromResource(R.xml.empty_preference_screen) - } - - override fun onViewCreated( - view: View, - savedInstanceState: Bundle?, - ) { - super.onViewCreated(view, savedInstanceState) - - launchOnState(Lifecycle.State.CREATED) { - inputDeviceManager - .getGamePadsObservable() - .collect { updateScreen(it.size) } - } - } - - private fun updateScreen(connectedGamePads: Int) { - preferenceScreen.removeAll() - - val extras = activity?.intent?.extras - - val coreOptions = - extras?.getSerializable(GameMenuContract.EXTRA_CORE_OPTIONS) as Array? - ?: throw InvalidParameterException("Missing EXTRA_CORE_OPTIONS") - - val advancedCoreOptions = - extras?.getSerializable( - GameMenuContract.EXTRA_ADVANCED_CORE_OPTIONS, - ) as Array? - ?: throw InvalidParameterException("Missing EXTRA_ADVANCED_CORE_OPTIONS") - - val game = - extras?.getSerializable(GameMenuContract.EXTRA_GAME) as Game? - ?: throw InvalidParameterException("Missing EXTRA_GAME") - - val coreConfig = - extras?.getSerializable(GameMenuContract.EXTRA_SYSTEM_CORE_CONFIG) as SystemCoreConfig? - ?: throw InvalidParameterException("Missing EXTRA_SYSTEM_CORE_CONFIG") - - CoreOptionsPreferenceHelper.addPreferences( - preferenceScreen, - game.systemId, - coreOptions.toList(), - advancedCoreOptions.toList(), - ) - - CoreOptionsPreferenceHelper.addControllers( - preferenceScreen, - game.systemId, - coreConfig.coreID, - maxOf(1, connectedGamePads), - coreConfig.controllerConfigs, - ) - } - - @dagger.Module - class Module -} diff --git a/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/mobile/feature/gamemenu/coreoptions/GameMenuCoreOptionsScreen.kt b/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/mobile/feature/gamemenu/coreoptions/GameMenuCoreOptionsScreen.kt index 3858dcaf7a..67a0214cea 100644 --- a/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/mobile/feature/gamemenu/coreoptions/GameMenuCoreOptionsScreen.kt +++ b/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/mobile/feature/gamemenu/coreoptions/GameMenuCoreOptionsScreen.kt @@ -14,10 +14,13 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import com.swordfish.lemuroid.R import com.swordfish.lemuroid.app.mobile.feature.gamemenu.GameMenuActivity +import com.swordfish.lemuroid.app.shared.coreoptions.CoreOptionsPreferenceHelper import com.swordfish.lemuroid.app.shared.coreoptions.LemuroidCoreOption import com.swordfish.lemuroid.app.shared.settings.ControllerConfigsManager import com.swordfish.lemuroid.app.utils.android.settings.LemuroidSettingsGroup import com.swordfish.lemuroid.app.utils.android.settings.LemuroidSettingsList +import com.swordfish.lemuroid.app.utils.android.settings.LemuroidSettingsSwitch +import com.swordfish.lemuroid.app.utils.android.settings.booleanPreferenceState import com.swordfish.lemuroid.app.utils.android.settings.indexPreferenceState import com.swordfish.lemuroid.lib.core.CoreVariablesManager @@ -52,16 +55,23 @@ private fun CoreOptions( } for (coreOption in coreOptions) { - LemuroidSettingsList( - title = { Text(text = coreOption.getDisplayName(context)) }, - items = coreOption.getEntries(context), - state = - indexPreferenceState( - CoreVariablesManager.computeSharedPreferenceKey(coreOption.getKey(), systemID), - coreOption.getEntriesValues().first(), - coreOption.getEntriesValues(), - ), - ) + if (coreOption.getEntriesValues().toSet() == CoreOptionsPreferenceHelper.BOOLEAN_SET) { + LemuroidSettingsSwitch( + state = booleanPreferenceState(coreOption.getKey(), coreOption.getCurrentValue() == "enabled"), + title = { Text(text = coreOption.getDisplayName(context)) }, + ) + } else { + LemuroidSettingsList( + title = { Text(text = coreOption.getDisplayName(context)) }, + items = coreOption.getEntries(context), + state = + indexPreferenceState( + CoreVariablesManager.computeSharedPreferenceKey(coreOption.getKey(), systemID), + coreOption.getEntriesValues().first(), + coreOption.getEntriesValues(), + ), + ) + } } } diff --git a/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/mobile/feature/settings/savesync/SaveSyncSettingsScreen.kt b/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/mobile/feature/settings/savesync/SaveSyncSettingsScreen.kt index 4450cccb42..d26f430d84 100644 --- a/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/mobile/feature/settings/savesync/SaveSyncSettingsScreen.kt +++ b/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/mobile/feature/settings/savesync/SaveSyncSettingsScreen.kt @@ -16,7 +16,7 @@ import com.swordfish.lemuroid.app.utils.android.settings.LemuroidSettingsMenuLin import com.swordfish.lemuroid.app.utils.android.settings.LemuroidSettingsPage import com.swordfish.lemuroid.app.utils.android.settings.LemuroidSettingsSwitch import com.swordfish.lemuroid.app.utils.android.settings.booleanPreferenceState -import com.swordfish.lemuroid.app.utils.android.stringsSetPreferenceState +import com.swordfish.lemuroid.app.utils.android.settings.stringsSetPreferenceState @Composable fun SaveSyncSettingsScreen( diff --git a/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/shared/coreoptions/CoreOptionsPreferenceHelper.kt b/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/shared/coreoptions/CoreOptionsPreferenceHelper.kt index d1af43a589..df92ab1f1e 100644 --- a/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/shared/coreoptions/CoreOptionsPreferenceHelper.kt +++ b/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/shared/coreoptions/CoreOptionsPreferenceHelper.kt @@ -14,7 +14,7 @@ import com.swordfish.lemuroid.lib.core.CoreVariablesManager import com.swordfish.lemuroid.lib.library.CoreID object CoreOptionsPreferenceHelper { - private val BOOLEAN_SET = setOf("enabled", "disabled") + val BOOLEAN_SET = setOf("enabled", "disabled") fun addPreferences( preferenceScreen: PreferenceScreen, diff --git a/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/shared/game/BaseGameActivity.kt b/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/shared/game/BaseGameActivity.kt index 92de080664..4ceb144634 100644 --- a/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/shared/game/BaseGameActivity.kt +++ b/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/shared/game/BaseGameActivity.kt @@ -492,7 +492,13 @@ abstract class BaseGameActivity : ImmersiveActivity() { private fun getCoreOptions(): List { return retroGameView?.getVariables() - ?.map { CoreOption.fromLibretroDroidVariable(it) } ?: listOf() + ?.mapNotNull { + val coreOptionResult = + runCatching { + CoreOption.fromLibretroDroidVariable(it) + } + coreOptionResult.getOrNull() + } ?: listOf() } private fun updateCoreVariables(options: List) { diff --git a/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/android/PreferenceStates.kt b/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/android/PreferenceStates.kt deleted file mode 100644 index 2f5c591b42..0000000000 --- a/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/android/PreferenceStates.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.swordfish.lemuroid.app.utils.android - -import androidx.compose.runtime.Composable -import androidx.compose.ui.platform.LocalContext -import com.swordfish.lemuroid.app.utils.settings.rememberPreferenceStringsSetSettingState -import com.swordfish.lemuroid.lib.preferences.SharedPreferencesHelper - -@Composable -fun stringsSetPreferenceState( - key: String, - default: Set, -) = rememberPreferenceStringsSetSettingState( - key = key, - defaultValue = default, - preferences = SharedPreferencesHelper.getSharedPreferences(LocalContext.current), -) diff --git a/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/android/settings/States.kt b/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/android/settings/States.kt index 26559f144c..6146805228 100644 --- a/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/android/settings/States.kt +++ b/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/android/settings/States.kt @@ -3,25 +3,22 @@ package com.swordfish.lemuroid.app.utils.android.settings import androidx.compose.runtime.Composable import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource -import com.alorma.compose.settings.storage.disk.rememberPreferenceBooleanSettingState -import com.swordfish.lemuroid.app.utils.settings.rememberPreferenceIndexSettingState +import com.swordfish.lemuroid.app.utils.settings.rememberSafePreferenceBooleanSettingState +import com.swordfish.lemuroid.app.utils.settings.rememberSafePreferenceIndexSettingState +import com.swordfish.lemuroid.app.utils.settings.rememberSafePreferenceStringsSetSettingState import com.swordfish.lemuroid.lib.preferences.SharedPreferencesHelper @Composable fun booleanPreferenceState( id: Int, default: Boolean, -) = rememberPreferenceBooleanSettingState( - key = stringResource(id = id), - defaultValue = default, - preferences = SharedPreferencesHelper.getSharedPreferences(LocalContext.current), -) +) = booleanPreferenceState(stringResource(id = id), default) @Composable fun booleanPreferenceState( key: String, default: Boolean, -) = rememberPreferenceBooleanSettingState( +) = rememberSafePreferenceBooleanSettingState( key = key, defaultValue = default, preferences = SharedPreferencesHelper.getSharedPreferences(LocalContext.current), @@ -39,9 +36,19 @@ fun indexPreferenceState( key: String, default: String, values: List, -) = rememberPreferenceIndexSettingState( +) = rememberSafePreferenceIndexSettingState( key = key, values = values, defaultValue = default, preferences = SharedPreferencesHelper.getSharedPreferences(LocalContext.current), ) + +@Composable +fun stringsSetPreferenceState( + key: String, + default: Set, +) = rememberSafePreferenceStringsSetSettingState( + key = key, + defaultValue = default, + preferences = SharedPreferencesHelper.getSharedPreferences(LocalContext.current), +) diff --git a/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/settings/SafeBooleanPreferenceSettingValueState.kt b/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/settings/SafeBooleanPreferenceSettingValueState.kt new file mode 100644 index 0000000000..ac6743b2ca --- /dev/null +++ b/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/settings/SafeBooleanPreferenceSettingValueState.kt @@ -0,0 +1,46 @@ +package com.swordfish.lemuroid.app.utils.settings + +import android.content.SharedPreferences +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.platform.LocalContext +import androidx.core.content.edit +import androidx.preference.PreferenceManager +import com.alorma.compose.settings.storage.base.SettingValueState + +@Composable +fun rememberSafePreferenceBooleanSettingState( + key: String, + defaultValue: Boolean, + preferences: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(LocalContext.current), +): SafeBooleanPreferenceSettingValueState { + return remember { + SafeBooleanPreferenceSettingValueState( + preferences = preferences, + key = key, + defaultValue = defaultValue, + ) + } +} + +class SafeBooleanPreferenceSettingValueState( + private val preferences: SharedPreferences, + val key: String, + val defaultValue: Boolean = false, +) : SettingValueState { + private var _value by mutableStateOf(preferences.safeGetBoolean(key, defaultValue)) + + override var value: Boolean + set(value) { + _value = value + preferences.edit { putBoolean(key, value) } + } + get() = _value + + override fun reset() { + value = defaultValue + } +} diff --git a/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/settings/IndexPreferenceSettingValueState.kt b/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/settings/SafeIndexPreferenceSettingValueState.kt similarity index 79% rename from lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/settings/IndexPreferenceSettingValueState.kt rename to lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/settings/SafeIndexPreferenceSettingValueState.kt index dba2e57ef1..05694c3d7e 100644 --- a/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/settings/IndexPreferenceSettingValueState.kt +++ b/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/settings/SafeIndexPreferenceSettingValueState.kt @@ -12,24 +12,24 @@ import androidx.preference.PreferenceManager import com.alorma.compose.settings.storage.base.SettingValueState @Composable -fun rememberPreferenceIndexSettingState( +fun rememberSafePreferenceIndexSettingState( key: String, values: List, defaultValue: String, preferences: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(LocalContext.current), -): IndexPreferenceSettingValueState { +): SafeIndexPreferenceSettingValueState { return remember { - IndexPreferenceSettingValueState(preferences, key, values, defaultValue) + SafeIndexPreferenceSettingValueState(preferences, key, values, defaultValue) } } -class IndexPreferenceSettingValueState( +class SafeIndexPreferenceSettingValueState( private val preferences: SharedPreferences, val key: String, private val values: List, private val defaultValue: String, ) : SettingValueState { - private var _value by mutableStateOf(preferences.getString(key, defaultValue)) + private var _value by mutableStateOf(preferences.safeGetString(key, defaultValue)) override var value: Int set(index) { diff --git a/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/settings/StringsSetPreferenceSettingValueState.kt b/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/settings/SafeStringsSetPreferenceSettingValueState.kt similarity index 77% rename from lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/settings/StringsSetPreferenceSettingValueState.kt rename to lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/settings/SafeStringsSetPreferenceSettingValueState.kt index 9b14f6ccb0..0e1935e072 100644 --- a/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/settings/StringsSetPreferenceSettingValueState.kt +++ b/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/settings/SafeStringsSetPreferenceSettingValueState.kt @@ -12,22 +12,22 @@ import androidx.preference.PreferenceManager import com.alorma.compose.settings.storage.base.SettingValueState @Composable -fun rememberPreferenceStringsSetSettingState( +fun rememberSafePreferenceStringsSetSettingState( key: String, defaultValue: Set, preferences: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(LocalContext.current), -): StringsSetPreferenceSettingValueState { +): SafeStringsSetPreferenceSettingValueState { return remember { - StringsSetPreferenceSettingValueState(preferences, key, defaultValue) + SafeStringsSetPreferenceSettingValueState(preferences, key, defaultValue) } } -class StringsSetPreferenceSettingValueState( +class SafeStringsSetPreferenceSettingValueState( private val preferences: SharedPreferences, val key: String, private val defaultValue: Set, ) : SettingValueState> { - private var _value by mutableStateOf(preferences.getStringSet(key, defaultValue)!!) + private var _value by mutableStateOf(preferences.safeGetStringSet(key, defaultValue)!!) override var value: Set set(index) { diff --git a/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/settings/SharedPreferenceUtils.kt b/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/settings/SharedPreferenceUtils.kt new file mode 100644 index 0000000000..2793978445 --- /dev/null +++ b/lemuroid-app/src/main/java/com/swordfish/lemuroid/app/utils/settings/SharedPreferenceUtils.kt @@ -0,0 +1,27 @@ +package com.swordfish.lemuroid.app.utils.settings + +import android.content.SharedPreferences + +fun SharedPreferences.safeGetString( + key: String, + defValue: String?, +): String? { + val result = runCatching { getString(key, defValue) } + return result.getOrDefault(defValue) +} + +fun SharedPreferences.safeGetBoolean( + key: String, + defValue: Boolean, +): Boolean { + val result = runCatching { getBoolean(key, defValue) } + return result.getOrDefault(defValue) +} + +fun SharedPreferences.safeGetStringSet( + key: String, + defValue: Set?, +): Set? { + val result = runCatching { getStringSet(key, defValue) } + return result.getOrDefault(defValue) +}