android: Add theme picker
This commit is contained in:
		@@ -107,6 +107,7 @@ class Settings {
 | 
			
		||||
        const val SECTION_RENDERER = "Renderer"
 | 
			
		||||
        const val SECTION_AUDIO = "Audio"
 | 
			
		||||
        const val SECTION_CPU = "Cpu"
 | 
			
		||||
        const val SECTION_THEME = "Theme"
 | 
			
		||||
 | 
			
		||||
        const val PREF_OVERLAY_INIT = "OverlayInit"
 | 
			
		||||
        const val PREF_CONTROL_SCALE = "controlScale"
 | 
			
		||||
@@ -134,6 +135,7 @@ class Settings {
 | 
			
		||||
        const val PREF_MENU_SETTINGS_SHOW_OVERLAY = "EmulationMenuSettings_ShowOverlay"
 | 
			
		||||
 | 
			
		||||
        const val PREF_FIRST_APP_LAUNCH = "FirstApplicationLaunch"
 | 
			
		||||
        const val PREF_THEME = "Theme"
 | 
			
		||||
 | 
			
		||||
        private val configFileSectionsMap: MutableMap<String, List<String>> = HashMap()
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,11 +3,15 @@
 | 
			
		||||
 | 
			
		||||
package org.yuzu.yuzu_emu.features.settings.ui
 | 
			
		||||
 | 
			
		||||
import android.content.SharedPreferences
 | 
			
		||||
import android.os.Build
 | 
			
		||||
import android.text.TextUtils
 | 
			
		||||
import androidx.appcompat.app.AppCompatActivity
 | 
			
		||||
import androidx.preference.PreferenceManager
 | 
			
		||||
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.BooleanSetting
 | 
			
		||||
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.view.*
 | 
			
		||||
@@ -21,12 +25,15 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
 | 
			
		||||
    private val settingsActivity get() = fragmentView.activityView as AppCompatActivity
 | 
			
		||||
    private val settings get() = fragmentView.activityView!!.settings
 | 
			
		||||
 | 
			
		||||
    private lateinit var preferences: SharedPreferences
 | 
			
		||||
 | 
			
		||||
    fun onCreate(menuTag: String, gameId: String) {
 | 
			
		||||
        this.gameId = gameId
 | 
			
		||||
        this.menuTag = menuTag
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun onViewCreated() {
 | 
			
		||||
        preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
 | 
			
		||||
        loadSettingsList()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -55,6 +62,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
 | 
			
		||||
            Settings.SECTION_SYSTEM -> addSystemSettings(sl)
 | 
			
		||||
            Settings.SECTION_RENDERER -> addGraphicsSettings(sl)
 | 
			
		||||
            Settings.SECTION_AUDIO -> addAudioSettings(sl)
 | 
			
		||||
            Settings.SECTION_THEME -> addThemeSettings(sl)
 | 
			
		||||
            else -> {
 | 
			
		||||
                fragmentView.showToastMessage("Unimplemented menu", false)
 | 
			
		||||
                return
 | 
			
		||||
@@ -99,6 +107,14 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
 | 
			
		||||
                    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 java.io.IOException
 | 
			
		||||
 | 
			
		||||
class MainActivity : AppCompatActivity() {
 | 
			
		||||
class MainActivity : AppCompatActivity(), ThemeProvider {
 | 
			
		||||
    private lateinit var binding: ActivityMainBinding
 | 
			
		||||
 | 
			
		||||
    private val homeViewModel: HomeViewModel by viewModels()
 | 
			
		||||
    private val gamesViewModel: GamesViewModel by viewModels()
 | 
			
		||||
 | 
			
		||||
    override var themeId: Int = 0
 | 
			
		||||
 | 
			
		||||
    override fun onCreate(savedInstanceState: Bundle?) {
 | 
			
		||||
        val splashScreen = installSplashScreen()
 | 
			
		||||
        splashScreen.setKeepOnScreenCondition { !DirectoryInitialization.areDirectoriesReady }
 | 
			
		||||
@@ -166,6 +168,11 @@ class MainActivity : AppCompatActivity() {
 | 
			
		||||
        }.start()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onResume() {
 | 
			
		||||
        ThemeHelper.setCorrectTheme(this)
 | 
			
		||||
        super.onResume()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onDestroy() {
 | 
			
		||||
        EmulationActivity.tryDismissRunningNotification(this)
 | 
			
		||||
        super.onDestroy()
 | 
			
		||||
@@ -180,6 +187,11 @@ class MainActivity : AppCompatActivity() {
 | 
			
		||||
            windowInsets
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    override fun setTheme(resId: Int) {
 | 
			
		||||
        super.setTheme(resId)
 | 
			
		||||
        themeId = resId
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun hasExtension(path: String, extension: String): Boolean {
 | 
			
		||||
        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.core.content.ContextCompat
 | 
			
		||||
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.YuzuApplication
 | 
			
		||||
import org.yuzu.yuzu_emu.features.settings.model.Settings
 | 
			
		||||
import org.yuzu.yuzu_emu.ui.main.ThemeProvider
 | 
			
		||||
import kotlin.math.roundToInt
 | 
			
		||||
 | 
			
		||||
object ThemeHelper {
 | 
			
		||||
    const val SYSTEM_BAR_ALPHA = 0.9f
 | 
			
		||||
 | 
			
		||||
    private const val DEFAULT = 0
 | 
			
		||||
    private const val MATERIAL_YOU = 1
 | 
			
		||||
 | 
			
		||||
    @JvmStatic
 | 
			
		||||
    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(
 | 
			
		||||
            activity.window,
 | 
			
		||||
            activity.window.decorView
 | 
			
		||||
@@ -60,4 +72,12 @@ object ThemeHelper {
 | 
			
		||||
            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>
 | 
			
		||||
    </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>
 | 
			
		||||
 
 | 
			
		||||
@@ -103,6 +103,7 @@
 | 
			
		||||
    <string name="preferences_system">System</string>
 | 
			
		||||
    <string name="preferences_graphics">Graphics</string>
 | 
			
		||||
    <string name="preferences_audio">Audio</string>
 | 
			
		||||
    <string name="preferences_theme">Theme and Color</string>
 | 
			
		||||
 | 
			
		||||
    <!-- ROM loading errors -->
 | 
			
		||||
    <string name="loader_error_encrypted">Your ROM is encrypted</string>
 | 
			
		||||
@@ -229,4 +230,9 @@
 | 
			
		||||
    <string name="preparing_shaders">Preparing 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>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user