android: Add theme picker
This commit is contained in:
		| @@ -107,6 +107,7 @@ class Settings { | |||||||
|         const val SECTION_RENDERER = "Renderer" |         const val SECTION_RENDERER = "Renderer" | ||||||
|         const val SECTION_AUDIO = "Audio" |         const val SECTION_AUDIO = "Audio" | ||||||
|         const val SECTION_CPU = "Cpu" |         const val SECTION_CPU = "Cpu" | ||||||
|  |         const val SECTION_THEME = "Theme" | ||||||
|  |  | ||||||
|         const val PREF_OVERLAY_INIT = "OverlayInit" |         const val PREF_OVERLAY_INIT = "OverlayInit" | ||||||
|         const val PREF_CONTROL_SCALE = "controlScale" |         const val PREF_CONTROL_SCALE = "controlScale" | ||||||
| @@ -134,6 +135,7 @@ class Settings { | |||||||
|         const val PREF_MENU_SETTINGS_SHOW_OVERLAY = "EmulationMenuSettings_ShowOverlay" |         const val PREF_MENU_SETTINGS_SHOW_OVERLAY = "EmulationMenuSettings_ShowOverlay" | ||||||
|  |  | ||||||
|         const val PREF_FIRST_APP_LAUNCH = "FirstApplicationLaunch" |         const val PREF_FIRST_APP_LAUNCH = "FirstApplicationLaunch" | ||||||
|  |         const val PREF_THEME = "Theme" | ||||||
|  |  | ||||||
|         private val configFileSectionsMap: MutableMap<String, List<String>> = HashMap() |         private val configFileSectionsMap: MutableMap<String, List<String>> = HashMap() | ||||||
|  |  | ||||||
|   | |||||||
| @@ -3,11 +3,15 @@ | |||||||
|  |  | ||||||
| package org.yuzu.yuzu_emu.features.settings.ui | package org.yuzu.yuzu_emu.features.settings.ui | ||||||
|  |  | ||||||
|  | import android.content.SharedPreferences | ||||||
|  | import android.os.Build | ||||||
| import android.text.TextUtils | import android.text.TextUtils | ||||||
| import androidx.appcompat.app.AppCompatActivity | import androidx.appcompat.app.AppCompatActivity | ||||||
|  | import androidx.preference.PreferenceManager | ||||||
| import org.yuzu.yuzu_emu.R | import org.yuzu.yuzu_emu.R | ||||||
|  | import org.yuzu.yuzu_emu.YuzuApplication | ||||||
|  | import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting | ||||||
| import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting | import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting | ||||||
| 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.IntSetting | ||||||
| import org.yuzu.yuzu_emu.features.settings.model.Settings | import org.yuzu.yuzu_emu.features.settings.model.Settings | ||||||
| import org.yuzu.yuzu_emu.features.settings.model.view.* | import org.yuzu.yuzu_emu.features.settings.model.view.* | ||||||
| @@ -21,12 +25,15 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) | |||||||
|     private val settingsActivity get() = fragmentView.activityView as AppCompatActivity |     private val settingsActivity get() = fragmentView.activityView as AppCompatActivity | ||||||
|     private val settings get() = fragmentView.activityView!!.settings |     private val settings get() = fragmentView.activityView!!.settings | ||||||
|  |  | ||||||
|  |     private lateinit var preferences: SharedPreferences | ||||||
|  |  | ||||||
|     fun onCreate(menuTag: String, gameId: String) { |     fun onCreate(menuTag: String, gameId: String) { | ||||||
|         this.gameId = gameId |         this.gameId = gameId | ||||||
|         this.menuTag = menuTag |         this.menuTag = menuTag | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fun onViewCreated() { |     fun onViewCreated() { | ||||||
|  |         preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) | ||||||
|         loadSettingsList() |         loadSettingsList() | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -55,6 +62,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) | |||||||
|             Settings.SECTION_SYSTEM -> addSystemSettings(sl) |             Settings.SECTION_SYSTEM -> addSystemSettings(sl) | ||||||
|             Settings.SECTION_RENDERER -> addGraphicsSettings(sl) |             Settings.SECTION_RENDERER -> addGraphicsSettings(sl) | ||||||
|             Settings.SECTION_AUDIO -> addAudioSettings(sl) |             Settings.SECTION_AUDIO -> addAudioSettings(sl) | ||||||
|  |             Settings.SECTION_THEME -> addThemeSettings(sl) | ||||||
|             else -> { |             else -> { | ||||||
|                 fragmentView.showToastMessage("Unimplemented menu", false) |                 fragmentView.showToastMessage("Unimplemented menu", false) | ||||||
|                 return |                 return | ||||||
| @@ -99,6 +107,14 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) | |||||||
|                     Settings.SECTION_AUDIO |                     Settings.SECTION_AUDIO | ||||||
|                 ) |                 ) | ||||||
|             ) |             ) | ||||||
|  |             add( | ||||||
|  |                 SubmenuSetting( | ||||||
|  |                     null, | ||||||
|  |                     R.string.preferences_theme, | ||||||
|  |                     0, | ||||||
|  |                     Settings.SECTION_THEME | ||||||
|  |                 ) | ||||||
|  |             ) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -300,4 +316,45 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) | |||||||
|             ) |             ) | ||||||
|         ) |         ) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     private fun addThemeSettings(sl: ArrayList<SettingsItem>) { | ||||||
|  |         settingsActivity.setTitle(R.string.preferences_theme) | ||||||
|  |         sl.apply { | ||||||
|  |             val theme: AbstractIntSetting = object : AbstractIntSetting { | ||||||
|  |                 override var int: Int | ||||||
|  |                     get() = preferences.getInt(Settings.PREF_THEME, 0) | ||||||
|  |                     set(value) { | ||||||
|  |                         preferences.edit().putInt(Settings.PREF_THEME, value).apply() | ||||||
|  |                         settingsActivity.recreate() | ||||||
|  |                     } | ||||||
|  |                 override val key: String? = null | ||||||
|  |                 override val section: String? = null | ||||||
|  |                 override val isRuntimeEditable: Boolean = true | ||||||
|  |                 override val valueAsString: String | ||||||
|  |                     get() = preferences.getInt(Settings.PREF_THEME, 0).toString() | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { | ||||||
|  |                 add( | ||||||
|  |                     SingleChoiceSetting( | ||||||
|  |                         theme, | ||||||
|  |                         R.string.change_app_theme, | ||||||
|  |                         0, | ||||||
|  |                         R.array.themeEntriesA12, | ||||||
|  |                         R.array.themeValuesA12 | ||||||
|  |                     ) | ||||||
|  |                 ) | ||||||
|  |             } else { | ||||||
|  |                 add( | ||||||
|  |                     SingleChoiceSetting( | ||||||
|  |                         theme, | ||||||
|  |                         R.string.change_app_theme, | ||||||
|  |                         0, | ||||||
|  |                         R.array.themeEntries, | ||||||
|  |                         R.array.themeValues | ||||||
|  |                     ) | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -39,12 +39,14 @@ import org.yuzu.yuzu_emu.model.HomeViewModel | |||||||
| import org.yuzu.yuzu_emu.utils.* | import org.yuzu.yuzu_emu.utils.* | ||||||
| import java.io.IOException | import java.io.IOException | ||||||
|  |  | ||||||
| class MainActivity : AppCompatActivity() { | class MainActivity : AppCompatActivity(), ThemeProvider { | ||||||
|     private lateinit var binding: ActivityMainBinding |     private lateinit var binding: ActivityMainBinding | ||||||
|  |  | ||||||
|     private val homeViewModel: HomeViewModel by viewModels() |     private val homeViewModel: HomeViewModel by viewModels() | ||||||
|     private val gamesViewModel: GamesViewModel by viewModels() |     private val gamesViewModel: GamesViewModel by viewModels() | ||||||
|  |  | ||||||
|  |     override var themeId: Int = 0 | ||||||
|  |  | ||||||
|     override fun onCreate(savedInstanceState: Bundle?) { |     override fun onCreate(savedInstanceState: Bundle?) { | ||||||
|         val splashScreen = installSplashScreen() |         val splashScreen = installSplashScreen() | ||||||
|         splashScreen.setKeepOnScreenCondition { !DirectoryInitialization.areDirectoriesReady } |         splashScreen.setKeepOnScreenCondition { !DirectoryInitialization.areDirectoriesReady } | ||||||
| @@ -166,6 +168,11 @@ class MainActivity : AppCompatActivity() { | |||||||
|         }.start() |         }.start() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     override fun onResume() { | ||||||
|  |         ThemeHelper.setCorrectTheme(this) | ||||||
|  |         super.onResume() | ||||||
|  |     } | ||||||
|  |  | ||||||
|     override fun onDestroy() { |     override fun onDestroy() { | ||||||
|         EmulationActivity.tryDismissRunningNotification(this) |         EmulationActivity.tryDismissRunningNotification(this) | ||||||
|         super.onDestroy() |         super.onDestroy() | ||||||
| @@ -180,6 +187,11 @@ class MainActivity : AppCompatActivity() { | |||||||
|             windowInsets |             windowInsets | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |     override fun setTheme(resId: Int) { | ||||||
|  |         super.setTheme(resId) | ||||||
|  |         themeId = resId | ||||||
|  |     } | ||||||
|  |  | ||||||
|     private fun hasExtension(path: String, extension: String): Boolean { |     private fun hasExtension(path: String, extension: String): Boolean { | ||||||
|         return path.substring(path.lastIndexOf(".") + 1).contains(extension) |         return path.substring(path.lastIndexOf(".") + 1).contains(extension) | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -0,0 +1,11 @@ | |||||||
|  | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||||||
|  | // SPDX-License-Identifier: GPL-2.0-or-later | ||||||
|  |  | ||||||
|  | package org.yuzu.yuzu_emu.ui.main | ||||||
|  |  | ||||||
|  | interface ThemeProvider { | ||||||
|  |     /** | ||||||
|  |      * Provides theme ID by overriding an activity's 'setTheme' method and returning that result | ||||||
|  |      */ | ||||||
|  |     var themeId: Int | ||||||
|  | } | ||||||
| @@ -10,15 +10,27 @@ import androidx.annotation.ColorInt | |||||||
| import androidx.appcompat.app.AppCompatActivity | import androidx.appcompat.app.AppCompatActivity | ||||||
| import androidx.core.content.ContextCompat | import androidx.core.content.ContextCompat | ||||||
| import androidx.core.view.WindowCompat | import androidx.core.view.WindowCompat | ||||||
| import com.google.android.material.color.MaterialColors | import androidx.preference.PreferenceManager | ||||||
| import org.yuzu.yuzu_emu.R | 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.ui.main.ThemeProvider | ||||||
| import kotlin.math.roundToInt | import kotlin.math.roundToInt | ||||||
|  |  | ||||||
| object ThemeHelper { | object ThemeHelper { | ||||||
|     const val SYSTEM_BAR_ALPHA = 0.9f |     const val SYSTEM_BAR_ALPHA = 0.9f | ||||||
|  |  | ||||||
|  |     private const val DEFAULT = 0 | ||||||
|  |     private const val MATERIAL_YOU = 1 | ||||||
|  |  | ||||||
|     @JvmStatic |     @JvmStatic | ||||||
|     fun setTheme(activity: AppCompatActivity) { |     fun setTheme(activity: AppCompatActivity) { | ||||||
|  |         val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) | ||||||
|  |         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) | ||||||
|  |         } | ||||||
|  |  | ||||||
|         val windowController = WindowCompat.getInsetsController( |         val windowController = WindowCompat.getInsetsController( | ||||||
|             activity.window, |             activity.window, | ||||||
|             activity.window.decorView |             activity.window.decorView | ||||||
| @@ -60,4 +72,12 @@ object ThemeHelper { | |||||||
|             Color.green(color), Color.blue(color) |             Color.green(color), Color.blue(color) | ||||||
|         ) |         ) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     fun setCorrectTheme(activity: AppCompatActivity) { | ||||||
|  |         val currentTheme = (activity as ThemeProvider).themeId | ||||||
|  |         setTheme(activity) | ||||||
|  |         if (currentTheme != (activity as ThemeProvider).themeId) { | ||||||
|  |             activity.recreate() | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -183,4 +183,20 @@ | |||||||
|         <item>@string/gamepad_screenshot</item> |         <item>@string/gamepad_screenshot</item> | ||||||
|     </string-array> |     </string-array> | ||||||
|  |  | ||||||
|  |     <string-array name="themeEntries"> | ||||||
|  |         <item>@string/theme_default</item> | ||||||
|  |     </string-array> | ||||||
|  |     <integer-array name="themeValues"> | ||||||
|  |         <item>0</item> | ||||||
|  |     </integer-array> | ||||||
|  |  | ||||||
|  |     <string-array name="themeEntriesA12"> | ||||||
|  |         <item>@string/theme_default</item> | ||||||
|  |         <item>@string/theme_material_you</item> | ||||||
|  |     </string-array> | ||||||
|  |     <integer-array name="themeValuesA12"> | ||||||
|  |         <item>0</item> | ||||||
|  |         <item>1</item> | ||||||
|  |     </integer-array> | ||||||
|  |  | ||||||
| </resources> | </resources> | ||||||
|   | |||||||
| @@ -103,6 +103,7 @@ | |||||||
|     <string name="preferences_system">System</string> |     <string name="preferences_system">System</string> | ||||||
|     <string name="preferences_graphics">Graphics</string> |     <string name="preferences_graphics">Graphics</string> | ||||||
|     <string name="preferences_audio">Audio</string> |     <string name="preferences_audio">Audio</string> | ||||||
|  |     <string name="preferences_theme">Theme and Color</string> | ||||||
|  |  | ||||||
|     <!-- ROM loading errors --> |     <!-- ROM loading errors --> | ||||||
|     <string name="loader_error_encrypted">Your ROM is encrypted</string> |     <string name="loader_error_encrypted">Your ROM is encrypted</string> | ||||||
| @@ -229,4 +230,9 @@ | |||||||
|     <string name="preparing_shaders">Preparing shaders</string> |     <string name="preparing_shaders">Preparing shaders</string> | ||||||
|     <string name="building_shaders">Building shaders</string> |     <string name="building_shaders">Building shaders</string> | ||||||
|  |  | ||||||
|  |     <!-- Theme options --> | ||||||
|  |     <string name="change_app_theme">Change App Theme</string> | ||||||
|  |     <string name="theme_default">Default</string> | ||||||
|  |     <string name="theme_material_you">Material You</string> | ||||||
|  |  | ||||||
| </resources> | </resources> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user