From d3f38ce56cb7d9a980f716e65ceb912f89b36f6b Mon Sep 17 00:00:00 2001 From: t895 Date: Sat, 23 Dec 2023 19:01:57 -0500 Subject: [PATCH] android: Migrate theme settings to ini --- .../features/settings/model/BooleanSetting.kt | 3 +- .../features/settings/model/IntSetting.kt | 4 +- .../features/settings/model/Settings.kt | 1 + .../settings/ui/SettingsFragmentPresenter.kt | 76 ++++++++----------- .../yuzu_emu/utils/DirectoryInitialization.kt | 33 ++++++++ .../org/yuzu/yuzu_emu/utils/PreferenceUtil.kt | 37 +++++++++ .../org/yuzu/yuzu_emu/utils/ThemeHelper.kt | 31 ++++---- .../app/src/main/jni/android_settings.h | 5 ++ 8 files changed, 128 insertions(+), 62 deletions(-) create mode 100644 src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/PreferenceUtil.kt diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt index 16f06cd0a..110d15f1c 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt @@ -18,7 +18,8 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting { RENDERER_REACTIVE_FLUSHING("use_reactive_flushing"), RENDERER_DEBUG("debug"), PICTURE_IN_PICTURE("picture_in_picture"), - USE_CUSTOM_RTC("custom_rtc_enabled"); + USE_CUSTOM_RTC("custom_rtc_enabled"), + BLACK_BACKGROUNDS("black_backgrounds"); override fun getBoolean(needsGlobal: Boolean): Boolean = NativeConfig.getBoolean(key, needsGlobal) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt index df760440f..b0193d83e 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt @@ -19,7 +19,9 @@ enum class IntSetting(override val key: String) : AbstractIntSetting { RENDERER_SCREEN_LAYOUT("screen_layout"), RENDERER_ASPECT_RATIO("aspect_ratio"), AUDIO_OUTPUT_ENGINE("output_engine"), - MAX_ANISOTROPY("max_anisotropy"); + MAX_ANISOTROPY("max_anisotropy"), + THEME("theme"), + THEME_MODE("theme_mode"); override fun getInt(needsGlobal: Boolean): Int = NativeConfig.getInt(key, needsGlobal) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt index 9551fc05e..360bdaf3e 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt @@ -54,6 +54,7 @@ object Settings { const val PREF_MENU_SETTINGS_SHOW_FPS = "EmulationMenuSettings_ShowFps" const val PREF_MENU_SETTINGS_SHOW_OVERLAY = "EmulationMenuSettings_ShowOverlay" + // Deprecated theme preference keys const val PREF_FIRST_APP_LAUNCH = "FirstApplicationLaunch" const val PREF_THEME = "Theme" const val PREF_THEME_MODE = "ThemeMode" diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt index db1a1076c..2ad2f4966 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt @@ -3,10 +3,8 @@ package org.yuzu.yuzu_emu.features.settings.ui -import android.content.SharedPreferences import android.os.Build import android.widget.Toast -import androidx.preference.PreferenceManager import org.yuzu.yuzu_emu.NativeLibrary import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.YuzuApplication @@ -29,9 +27,6 @@ class SettingsFragmentPresenter( ) { private var settingsList = ArrayList() - private val preferences: SharedPreferences - get() = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) - // Extension for altering settings list based on each setting's properties fun ArrayList.add(key: String) { val item = SettingsItem.settingsItems[key]!! @@ -170,25 +165,19 @@ class SettingsFragmentPresenter( private fun addThemeSettings(sl: ArrayList) { sl.apply { val theme: AbstractIntSetting = object : AbstractIntSetting { - override fun getInt(needsGlobal: Boolean): Int = - preferences.getInt(Settings.PREF_THEME, 0) - + override fun getInt(needsGlobal: Boolean): Int = IntSetting.THEME.getInt() override fun setInt(value: Int) { - preferences.edit() - .putInt(Settings.PREF_THEME, value) - .apply() + IntSetting.THEME.setInt(value) settingsViewModel.setShouldRecreate(true) } - override val key: String = Settings.PREF_THEME - override val isRuntimeModifiable: Boolean = false - override fun getValueAsString(needsGlobal: Boolean): String = getInt().toString() - override val defaultValue: Int = 0 - override fun reset() { - preferences.edit() - .putInt(Settings.PREF_THEME, defaultValue) - .apply() - } + override val key: String = IntSetting.THEME.key + override val isRuntimeModifiable: Boolean = IntSetting.THEME.isRuntimeModifiable + override fun getValueAsString(needsGlobal: Boolean): String = + IntSetting.THEME.getValueAsString() + + override val defaultValue: Int = IntSetting.THEME.defaultValue + override fun reset() = IntSetting.THEME.setInt(defaultValue) } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { @@ -214,24 +203,22 @@ class SettingsFragmentPresenter( } val themeMode: AbstractIntSetting = object : AbstractIntSetting { - override fun getInt(needsGlobal: Boolean): Int = - preferences.getInt(Settings.PREF_THEME_MODE, -1) - + override fun getInt(needsGlobal: Boolean): Int = IntSetting.THEME_MODE.getInt() override fun setInt(value: Int) { - preferences.edit() - .putInt(Settings.PREF_THEME_MODE, value) - .apply() + IntSetting.THEME_MODE.setInt(value) settingsViewModel.setShouldRecreate(true) } - override val key: String = Settings.PREF_THEME_MODE - override val isRuntimeModifiable: Boolean = false - override fun getValueAsString(needsGlobal: Boolean): String = getInt().toString() - override val defaultValue: Int = -1 + override val key: String = IntSetting.THEME_MODE.key + override val isRuntimeModifiable: Boolean = + IntSetting.THEME_MODE.isRuntimeModifiable + + override fun getValueAsString(needsGlobal: Boolean): String = + IntSetting.THEME_MODE.getValueAsString() + + override val defaultValue: Int = IntSetting.THEME_MODE.defaultValue override fun reset() { - preferences.edit() - .putInt(Settings.PREF_BLACK_BACKGROUNDS, defaultValue) - .apply() + IntSetting.THEME_MODE.setInt(defaultValue) settingsViewModel.setShouldRecreate(true) } } @@ -248,25 +235,24 @@ class SettingsFragmentPresenter( val blackBackgrounds: AbstractBooleanSetting = object : AbstractBooleanSetting { override fun getBoolean(needsGlobal: Boolean): Boolean = - preferences.getBoolean(Settings.PREF_BLACK_BACKGROUNDS, false) + BooleanSetting.BLACK_BACKGROUNDS.getBoolean() override fun setBoolean(value: Boolean) { - preferences.edit() - .putBoolean(Settings.PREF_BLACK_BACKGROUNDS, value) - .apply() + BooleanSetting.BLACK_BACKGROUNDS.setBoolean(value) settingsViewModel.setShouldRecreate(true) } - override val key: String = Settings.PREF_BLACK_BACKGROUNDS - override val isRuntimeModifiable: Boolean = false - override fun getValueAsString(needsGlobal: Boolean): String = - getBoolean().toString() + override val key: String = BooleanSetting.BLACK_BACKGROUNDS.key + override val isRuntimeModifiable: Boolean = + BooleanSetting.BLACK_BACKGROUNDS.isRuntimeModifiable - override val defaultValue: Boolean = false + override fun getValueAsString(needsGlobal: Boolean): String = + BooleanSetting.BLACK_BACKGROUNDS.getValueAsString() + + override val defaultValue: Boolean = BooleanSetting.BLACK_BACKGROUNDS.defaultValue override fun reset() { - preferences.edit() - .putBoolean(Settings.PREF_BLACK_BACKGROUNDS, defaultValue) - .apply() + BooleanSetting.BLACK_BACKGROUNDS + .setBoolean(BooleanSetting.BLACK_BACKGROUNDS.defaultValue) settingsViewModel.setShouldRecreate(true) } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt index 0197fd712..d4a9da06f 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt @@ -3,9 +3,14 @@ package org.yuzu.yuzu_emu.utils +import androidx.preference.PreferenceManager import java.io.IOException import org.yuzu.yuzu_emu.NativeLibrary import org.yuzu.yuzu_emu.YuzuApplication +import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting +import org.yuzu.yuzu_emu.features.settings.model.IntSetting +import org.yuzu.yuzu_emu.features.settings.model.Settings +import org.yuzu.yuzu_emu.utils.PreferenceUtil.migratePreference object DirectoryInitialization { private var userPath: String? = null @@ -17,6 +22,7 @@ object DirectoryInitialization { initializeInternalStorage() NativeLibrary.initializeSystem(false) NativeConfig.initializeGlobalConfig() + migrateSettings() areDirectoriesReady = true } } @@ -35,4 +41,31 @@ object DirectoryInitialization { e.printStackTrace() } } + + private fun migrateSettings() { + val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) + var saveConfig = false + val theme = preferences.migratePreference(Settings.PREF_THEME) + if (theme != null) { + IntSetting.THEME.setInt(theme) + saveConfig = true + } + + val themeMode = preferences.migratePreference(Settings.PREF_THEME_MODE) + if (themeMode != null) { + IntSetting.THEME_MODE.setInt(themeMode) + saveConfig = true + } + + val blackBackgrounds = + preferences.migratePreference(Settings.PREF_BLACK_BACKGROUNDS) + if (blackBackgrounds != null) { + BooleanSetting.BLACK_BACKGROUNDS.setBoolean(blackBackgrounds) + saveConfig = true + } + + if (saveConfig) { + NativeConfig.saveGlobalConfig() + } + } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/PreferenceUtil.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/PreferenceUtil.kt new file mode 100644 index 000000000..a233ba25c --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/PreferenceUtil.kt @@ -0,0 +1,37 @@ +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.yuzu.yuzu_emu.utils + +import android.content.SharedPreferences + +object PreferenceUtil { + /** + * Retrieves a shared preference value and then deletes the value in storage. + * @param key Associated key for the value in this preferences instance + * @return Typed value associated with [key]. Null if no such key exists. + */ + inline fun SharedPreferences.migratePreference(key: String): T? { + if (!this.contains(key)) { + return null + } + + val value: Any = when (T::class) { + String::class -> this.getString(key, "")!! + + Boolean::class -> this.getBoolean(key, false) + + Int::class -> this.getInt(key, 0) + + Float::class -> this.getFloat(key, 0f) + + Long::class -> this.getLong(key, 0) + + else -> throw IllegalStateException("Tried to migrate preference with invalid type!") + } + deletePreference(key) + return value as T + } + + fun SharedPreferences.deletePreference(key: String) = this.edit().remove(key).apply() +} diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ThemeHelper.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ThemeHelper.kt index f312e24cf..792f6a253 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ThemeHelper.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ThemeHelper.kt @@ -10,33 +10,26 @@ import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatDelegate import androidx.core.view.WindowCompat import androidx.core.view.WindowInsetsControllerCompat -import androidx.preference.PreferenceManager import kotlin.math.roundToInt import org.yuzu.yuzu_emu.R -import org.yuzu.yuzu_emu.YuzuApplication -import org.yuzu.yuzu_emu.features.settings.model.Settings +import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting +import org.yuzu.yuzu_emu.features.settings.model.IntSetting import org.yuzu.yuzu_emu.ui.main.ThemeProvider object ThemeHelper { const val SYSTEM_BAR_ALPHA = 0.9f - private const val DEFAULT = 0 - private const val MATERIAL_YOU = 1 - fun setTheme(activity: AppCompatActivity) { - val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) setThemeMode(activity) - when (preferences.getInt(Settings.PREF_THEME, 0)) { - DEFAULT -> activity.setTheme(R.style.Theme_Yuzu_Main) - MATERIAL_YOU -> activity.setTheme(R.style.Theme_Yuzu_Main_MaterialYou) + when (Theme.from(IntSetting.THEME.getInt())) { + Theme.Default -> activity.setTheme(R.style.Theme_Yuzu_Main) + Theme.MaterialYou -> activity.setTheme(R.style.Theme_Yuzu_Main_MaterialYou) } // Using a specific night mode check because this could apply incorrectly when using the // light app mode, dark system mode, and black backgrounds. Launching the settings activity // will then show light mode colors/navigation bars but with black backgrounds. - if (preferences.getBoolean(Settings.PREF_BLACK_BACKGROUNDS, false) && - isNightMode(activity) - ) { + if (BooleanSetting.BLACK_BACKGROUNDS.getBoolean() && isNightMode(activity)) { activity.setTheme(R.style.ThemeOverlay_Yuzu_Dark) } } @@ -60,8 +53,7 @@ object ThemeHelper { } fun setThemeMode(activity: AppCompatActivity) { - val themeMode = PreferenceManager.getDefaultSharedPreferences(activity.applicationContext) - .getInt(Settings.PREF_THEME_MODE, AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) + val themeMode = IntSetting.THEME_MODE.getInt() activity.delegate.localNightMode = themeMode val windowController = WindowCompat.getInsetsController( activity.window, @@ -95,3 +87,12 @@ object ThemeHelper { windowController.isAppearanceLightNavigationBars = false } } + +enum class Theme(val int: Int) { + Default(0), + MaterialYou(1); + + companion object { + fun from(int: Int): Theme = entries.firstOrNull { it.int == int } ?: Default + } +} diff --git a/src/android/app/src/main/jni/android_settings.h b/src/android/app/src/main/jni/android_settings.h index 3733f5a3c..1e4906b9a 100644 --- a/src/android/app/src/main/jni/android_settings.h +++ b/src/android/app/src/main/jni/android_settings.h @@ -33,6 +33,11 @@ struct Values { Settings::SwitchableSetting driver_path{linkage, "", "driver_path", Settings::Category::GpuDriver}; + + Settings::Setting theme{linkage, 0, "theme", Settings::Category::Android}; + Settings::Setting theme_mode{linkage, -1, "theme_mode", Settings::Category::Android}; + Settings::Setting black_backgrounds{linkage, false, "black_backgrounds", + Settings::Category::Android}; }; extern Values values;