diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/LobbyBrowser.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/LobbyBrowser.kt index 6d5c6ef23f..2d54bb5f54 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/LobbyBrowser.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/LobbyBrowser.kt @@ -31,6 +31,7 @@ import org.yuzu.yuzu_emu.databinding.DialogLobbyBrowserBinding import org.yuzu.yuzu_emu.databinding.ItemLobbyRoomBinding import org.yuzu.yuzu_emu.features.settings.model.StringSetting import org.yuzu.yuzu_emu.network.NetPlayManager +import org.yuzu.yuzu_emu.utils.BackgroundHelper import java.util.Locale class LobbyBrowser(context: Context) : BottomSheetDialog(context) { @@ -47,6 +48,7 @@ class LobbyBrowser(context: Context) : BottomSheetDialog(context) { binding = DialogLobbyBrowserBinding.inflate(layoutInflater) setContentView(binding.root) + BackgroundHelper.applyBackground(binding.backgroundLogo, context) binding.emptyRefreshButton.setOnClickListener { binding.progressBar.visibility = View.VISIBLE 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 0f89533d8e..d15f03652c 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 @@ -105,6 +105,14 @@ object Settings { const val PREF_BLACK_BACKGROUNDS = "BlackBackgrounds" const val PREF_STATIC_THEME_COLOR = "StaticThemeColor" + // App background preference keys + const val PREF_HOME_BACKGROUND_STYLE = "HomeBackgroundStyle" + const val HOME_BACKGROUND_STYLE_NONE = 0 + const val HOME_BACKGROUND_STYLE_EDEN = 1 + const val HOME_BACKGROUND_STYLE_DEFAULT = HOME_BACKGROUND_STYLE_NONE + const val PREF_HOME_BACKGROUND_ALPHA = "HomeBackgroundAlpha" + const val HOME_BACKGROUND_ALPHA_DEFAULT = 40 + enum class EmulationOrientation(val int: Int) { Unspecified(0), SensorLandscape(5), diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragment.kt index 667141725d..00dc7883f8 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragment.kt @@ -33,6 +33,7 @@ import org.yuzu.yuzu_emu.features.input.NativeInput import org.yuzu.yuzu_emu.features.settings.model.Settings import org.yuzu.yuzu_emu.features.settings.model.view.PathSetting import org.yuzu.yuzu_emu.fragments.MessageDialogFragment +import org.yuzu.yuzu_emu.utils.BackgroundHelper import org.yuzu.yuzu_emu.utils.PathUtil import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins import org.yuzu.yuzu_emu.utils.* @@ -178,9 +179,17 @@ class SettingsFragment : Fragment() { } presenter.onViewCreated() + applyBackgroundPreference() + setInsets() } -private fun getPlayerIndex(): Int = + + override fun onResume() { + super.onResume() + applyBackgroundPreference() + } + + private fun getPlayerIndex(): Int = when (args.menuTag) { Settings.MenuTag.SECTION_INPUT_PLAYER_ONE -> 0 Settings.MenuTag.SECTION_INPUT_PLAYER_TWO -> 1 @@ -232,6 +241,10 @@ private fun getPlayerIndex(): Int = } } + private fun applyBackgroundPreference() { + BackgroundHelper.applyBackground(binding.backgroundLogo, requireContext()) + } + private fun hasAllFilesPermission(): Boolean { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { Environment.isExternalStorageManager() 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 ff25584c92..607682be5b 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 @@ -29,6 +29,7 @@ import org.yuzu.yuzu_emu.features.settings.model.view.* import org.yuzu.yuzu_emu.utils.InputHandler import org.yuzu.yuzu_emu.utils.NativeConfig import org.yuzu.yuzu_emu.utils.DirectoryInitialization +import org.yuzu.yuzu_emu.utils.BackgroundHelper import androidx.fragment.app.FragmentActivity import org.yuzu.yuzu_emu.fragments.MessageDialogFragment @@ -1071,6 +1072,26 @@ class SettingsFragmentPresenter( add(HeaderSetting(R.string.theme_and_color)) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + add( + SingleChoiceSetting( + theme, + titleId = R.string.change_app_theme, + choicesId = R.array.themeEntriesA12, + valuesId = R.array.themeValuesA12 + ) + ) + } else { + add( + SingleChoiceSetting( + theme, + titleId = R.string.change_app_theme, + choicesId = R.array.themeEntries, + valuesId = R.array.themeValues + ) + ) + } + val themeMode: AbstractIntSetting = object : AbstractIntSetting { override fun getInt(needsGlobal: Boolean): Int = IntSetting.THEME_MODE.getInt() override fun setInt(value: Int) { @@ -1101,26 +1122,6 @@ class SettingsFragmentPresenter( ) ) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - add( - SingleChoiceSetting( - theme, - titleId = R.string.change_app_theme, - choicesId = R.array.themeEntriesA12, - valuesId = R.array.themeValuesA12 - ) - ) - } else { - add( - SingleChoiceSetting( - theme, - titleId = R.string.change_app_theme, - choicesId = R.array.themeEntries, - valuesId = R.array.themeValues - ) - ) - } - val staticThemeColor: AbstractIntSetting = object : AbstractIntSetting { override fun getInt(needsGlobal: Boolean): Int = IntSetting.STATIC_THEME_COLOR.getInt(needsGlobal) @@ -1187,6 +1188,79 @@ class SettingsFragmentPresenter( ) ) + val backgroundStyleSetting: AbstractIntSetting = object : AbstractIntSetting { + override fun getInt(needsGlobal: Boolean): Int = + BackgroundHelper.getBackgroundStyle(context) + + override fun setInt(value: Int) { + BackgroundHelper.setBackgroundStyle(context, value) + settingsViewModel.setShouldRecreate(true) + } + + override val key: String = Settings.PREF_HOME_BACKGROUND_STYLE + override val isRuntimeModifiable: Boolean = true + override val pairedSettingKey: String = "" + override val isSwitchable: Boolean = false + override var global: Boolean = true + override val isSaveable: Boolean = true + override val defaultValue: Int = Settings.HOME_BACKGROUND_STYLE_DEFAULT + + override fun getValueAsString(needsGlobal: Boolean): String = + getInt(needsGlobal).toString() + + override fun reset() { + setInt(defaultValue) + } + } + + add( + SingleChoiceSetting( + backgroundStyleSetting, + titleId = R.string.home_background, + descriptionId = R.string.home_background_description, + choicesId = R.array.homeBackgroundEntries, + valuesId = R.array.homeBackgroundValues + ) + ) + + val backgroundAlphaSetting: AbstractIntSetting = object : AbstractIntSetting { + override fun getInt(needsGlobal: Boolean): Int = + (BackgroundHelper.getBackgroundAlpha(context) * 100).toInt() + + override fun setInt(value: Int) { + BackgroundHelper.setBackgroundAlpha(context, value) + settingsViewModel.setShouldRecreate(true) + } + + override val key: String = Settings.PREF_HOME_BACKGROUND_ALPHA + override val isRuntimeModifiable: Boolean = true + override val pairedSettingKey: String = "" + override val isSwitchable: Boolean = false + override var global: Boolean = true + override val isSaveable: Boolean = true + override val defaultValue: Int = Settings.HOME_BACKGROUND_ALPHA_DEFAULT + + override fun getValueAsString(needsGlobal: Boolean): String = + getInt(needsGlobal).toString() + + override fun reset() { + setInt(defaultValue) + } + } + + if (BackgroundHelper.getBackgroundStyle(context) != Settings.HOME_BACKGROUND_STYLE_NONE) { + add( + SliderSetting( + backgroundAlphaSetting, + titleId = R.string.home_background_opacity, + descriptionId = R.string.home_background_opacity_description, + min = 0, + max = 100, + units = "%" + ) + ) + } + add(HeaderSetting(R.string.buttons)) add(BooleanSetting.ENABLE_FOLDER_BUTTON.key) add(BooleanSetting.ENABLE_QLAUNCH_BUTTON.key) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt index 7fec413b66..984e3ed1a0 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt @@ -25,6 +25,7 @@ import org.yuzu.yuzu_emu.BuildConfig import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.databinding.FragmentAboutBinding import org.yuzu.yuzu_emu.model.HomeViewModel +import org.yuzu.yuzu_emu.utils.BackgroundHelper import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins import org.yuzu.yuzu_emu.NativeLibrary @@ -53,6 +54,8 @@ class AboutFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) homeViewModel.setStatusBarShadeVisibility(visible = false) + applyBackgroundPreference() + binding.toolbarAbout.setNavigationOnClickListener { binding.root.findNavController().popBackStack() } @@ -105,6 +108,11 @@ class AboutFragment : Fragment() { setInsets() } + override fun onResume() { + super.onResume() + applyBackgroundPreference() + } + private fun openLink(link: String) { val intent = Intent(Intent.ACTION_VIEW, Uri.parse(link)) startActivity(intent) @@ -127,4 +135,8 @@ class AboutFragment : Fragment() { windowInsets } + + private fun applyBackgroundPreference() { + BackgroundHelper.applyBackground(binding.backgroundLogo, requireContext()) + } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AddonsFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AddonsFragment.kt index 96b7a8cce2..aec5f7e079 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AddonsFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AddonsFragment.kt @@ -25,6 +25,7 @@ import org.yuzu.yuzu_emu.databinding.FragmentAddonsBinding import org.yuzu.yuzu_emu.model.AddonViewModel import org.yuzu.yuzu_emu.model.HomeViewModel import org.yuzu.yuzu_emu.utils.AddonUtil +import org.yuzu.yuzu_emu.utils.BackgroundHelper import org.yuzu.yuzu_emu.utils.FileUtil.copyFilesTo import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins import org.yuzu.yuzu_emu.utils.collect @@ -59,6 +60,7 @@ class AddonsFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) homeViewModel.setStatusBarShadeVisibility(false) + applyBackgroundPreference() binding.toolbarAddons.setNavigationOnClickListener { binding.root.findNavController().popBackStack() @@ -122,6 +124,7 @@ class AddonsFragment : Fragment() { override fun onResume() { super.onResume() addonViewModel.onAddonsViewStarted(args.game) + applyBackgroundPreference() } override fun onDestroy() { @@ -202,4 +205,8 @@ class AddonsFragment : Fragment() { windowInsets } + + private fun applyBackgroundPreference() { + BackgroundHelper.applyBackground(binding.backgroundLogo, requireContext()) + } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AppletLauncherFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AppletLauncherFragment.kt index 3ab171a8d4..4b55ed1ede 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AppletLauncherFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AppletLauncherFragment.kt @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later package org.yuzu.yuzu_emu.fragments @@ -21,6 +21,7 @@ import org.yuzu.yuzu_emu.databinding.FragmentAppletLauncherBinding import org.yuzu.yuzu_emu.model.Applet import org.yuzu.yuzu_emu.model.AppletInfo import org.yuzu.yuzu_emu.model.HomeViewModel +import org.yuzu.yuzu_emu.utils.BackgroundHelper import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins class AppletLauncherFragment : Fragment() { @@ -48,6 +49,7 @@ class AppletLauncherFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) homeViewModel.setStatusBarShadeVisibility(visible = false) + applyBackgroundPreference() binding.toolbarApplets.setNavigationOnClickListener { binding.root.findNavController().popBackStack() @@ -91,6 +93,11 @@ class AppletLauncherFragment : Fragment() { setInsets() } + override fun onResume() { + super.onResume() + applyBackgroundPreference() + } + private fun setInsets() = ViewCompat.setOnApplyWindowInsetsListener( binding.root @@ -108,4 +115,8 @@ class AppletLauncherFragment : Fragment() { windowInsets } + + private fun applyBackgroundPreference() { + BackgroundHelper.applyBackground(binding.backgroundLogo, requireContext()) + } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverFetcherFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverFetcherFragment.kt index e2b652dc60..37998a03d0 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverFetcherFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverFetcherFragment.kt @@ -30,6 +30,7 @@ import org.yuzu.yuzu_emu.databinding.FragmentDriverFetcherBinding import org.yuzu.yuzu_emu.features.fetcher.DriverGroupAdapter import org.yuzu.yuzu_emu.model.DriverViewModel import org.yuzu.yuzu_emu.model.HomeViewModel +import org.yuzu.yuzu_emu.utils.BackgroundHelper import org.yuzu.yuzu_emu.utils.GpuDriverHelper import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins import java.io.IOException @@ -141,6 +142,8 @@ class DriverFetcherFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) homeViewModel.setStatusBarShadeVisibility(visible = false) + applyBackgroundPreference() + binding.toolbarDrivers.setNavigationOnClickListener { binding.root.findNavController().popBackStack() } @@ -154,6 +157,11 @@ class DriverFetcherFragment : Fragment() { fetchDrivers() } + override fun onResume() { + super.onResume() + applyBackgroundPreference() + } + private fun fetchDrivers() { binding.loadingIndicator.isVisible = true @@ -242,6 +250,10 @@ class DriverFetcherFragment : Fragment() { windowInsets } + private fun applyBackgroundPreference() { + BackgroundHelper.applyBackground(binding.backgroundLogo, requireContext()) + } + data class Artifact(val url: URL, val name: String) data class Release( diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt index 23334f05eb..1d514ba9d4 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later package org.yuzu.yuzu_emu.fragments @@ -33,6 +33,7 @@ import org.yuzu.yuzu_emu.model.HomeViewModel import org.yuzu.yuzu_emu.utils.FileUtil import org.yuzu.yuzu_emu.utils.GpuDriverHelper import org.yuzu.yuzu_emu.utils.NativeConfig +import org.yuzu.yuzu_emu.utils.BackgroundHelper import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins import org.yuzu.yuzu_emu.utils.collect import java.io.File @@ -66,6 +67,7 @@ class DriverManagerFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) homeViewModel.setStatusBarShadeVisibility(visible = false) + applyBackgroundPreference() driverViewModel.onOpenDriverManager(args.game) if (NativeConfig.isPerGameConfigLoaded()) { @@ -138,6 +140,11 @@ class DriverManagerFragment : Fragment() { driverViewModel.onCloseDriverManager(args.game) } + override fun onResume() { + super.onResume() + applyBackgroundPreference() + } + private fun setInsets() = ViewCompat.setOnApplyWindowInsetsListener( binding.root @@ -256,4 +263,8 @@ class DriverManagerFragment : Fragment() { .setCancelable(false) .show() } + + private fun applyBackgroundPreference() { + BackgroundHelper.applyBackground(binding.backgroundLogo, requireContext()) + } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/FreedrenoSettingsFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/FreedrenoSettingsFragment.kt index 2eb77690ca..0bf7200fd9 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/FreedrenoSettingsFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/FreedrenoSettingsFragment.kt @@ -20,6 +20,7 @@ import org.yuzu.yuzu_emu.adapters.FreedrenoPresetAdapter import org.yuzu.yuzu_emu.adapters.FreedrenoVariableAdapter import org.yuzu.yuzu_emu.databinding.FragmentFreedrenoSettingsBinding import org.yuzu.yuzu_emu.model.Game +import org.yuzu.yuzu_emu.utils.BackgroundHelper import org.yuzu.yuzu_emu.utils.NativeFreedrenoConfig import org.yuzu.yuzu_emu.utils.FreedrenoPresets import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins @@ -68,6 +69,7 @@ class FreedrenoSettingsFragment : Fragment() { setupAdapters() loadCurrentSettings() setupButtonListeners() + applyBackgroundPreference() setupWindowInsets() } @@ -193,7 +195,17 @@ class FreedrenoSettingsFragment : Fragment() { insets } } -private fun showSnackbar(message: String) { + + override fun onResume() { + super.onResume() + applyBackgroundPreference() + } + + private fun applyBackgroundPreference() { + BackgroundHelper.applyBackground(binding.backgroundLogo, requireContext()) + } + + private fun showSnackbar(message: String) { Snackbar.make(binding.root, message, Snackbar.LENGTH_SHORT).show() } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GameFoldersFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GameFoldersFragment.kt index 9c43d2c6e1..b459c82719 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GameFoldersFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GameFoldersFragment.kt @@ -26,6 +26,7 @@ import org.yuzu.yuzu_emu.model.GameDir import org.yuzu.yuzu_emu.model.GamesViewModel import org.yuzu.yuzu_emu.model.HomeViewModel import org.yuzu.yuzu_emu.ui.main.MainActivity +import org.yuzu.yuzu_emu.utils.BackgroundHelper import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins import org.yuzu.yuzu_emu.utils.collect @@ -57,6 +58,7 @@ class GameFoldersFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) homeViewModel.setStatusBarShadeVisibility(visible = false) + applyBackgroundPreference() binding.toolbarFolders.setNavigationOnClickListener { binding.root.findNavController().popBackStack() @@ -100,6 +102,11 @@ class GameFoldersFragment : Fragment() { setInsets() } + override fun onResume() { + super.onResume() + applyBackgroundPreference() + } + override fun onStop() { super.onStop() gamesViewModel.onCloseGameFoldersFragment() @@ -133,4 +140,8 @@ class GameFoldersFragment : Fragment() { windowInsets } + + private fun applyBackgroundPreference() { + BackgroundHelper.applyBackground(binding.backgroundLogo, requireContext()) + } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GameInfoFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GameInfoFragment.kt index 7863e40ff5..4c1f641a20 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GameInfoFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GameInfoFragment.kt @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later package org.yuzu.yuzu_emu.fragments @@ -26,6 +26,7 @@ import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.databinding.FragmentGameInfoBinding import org.yuzu.yuzu_emu.model.GameVerificationResult import org.yuzu.yuzu_emu.model.HomeViewModel +import org.yuzu.yuzu_emu.utils.BackgroundHelper import org.yuzu.yuzu_emu.utils.GameMetadata import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins @@ -60,6 +61,7 @@ class GameInfoFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) homeViewModel.setStatusBarShadeVisibility(false) + applyBackgroundPreference() binding.apply { toolbarInfo.title = args.game.title @@ -143,6 +145,11 @@ class GameInfoFragment : Fragment() { setInsets() } + override fun onResume() { + super.onResume() + applyBackgroundPreference() + } + private fun copyToClipboard(label: String, body: String) { val clipBoard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager @@ -175,4 +182,8 @@ class GameInfoFragment : Fragment() { windowInsets } + + private fun applyBackgroundPreference() { + BackgroundHelper.applyBackground(binding.backgroundLogo, requireContext()) + } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GamePropertiesFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GamePropertiesFragment.kt index 9e55297846..6bf40607b5 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GamePropertiesFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GamePropertiesFragment.kt @@ -48,6 +48,7 @@ import org.yuzu.yuzu_emu.utils.FileUtil import org.yuzu.yuzu_emu.utils.GameIconUtils import org.yuzu.yuzu_emu.utils.GpuDriverHelper import org.yuzu.yuzu_emu.utils.MemoryUtil +import org.yuzu.yuzu_emu.utils.BackgroundHelper import org.yuzu.yuzu_emu.utils.ViewUtils.marquee import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins import org.yuzu.yuzu_emu.utils.collect @@ -83,6 +84,7 @@ class GamePropertiesFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) homeViewModel.setStatusBarShadeVisibility(true) + applyBackgroundPreference() binding.buttonBack.setOnClickListener { view.findNavController().popBackStack() @@ -487,6 +489,7 @@ class GamePropertiesFragment : Fragment() { override fun onResume() { super.onResume() + applyBackgroundPreference() driverViewModel.updateDriverNameForGame(args.game) getPlayTime() reloadList() @@ -711,4 +714,8 @@ class GamePropertiesFragment : Fragment() { ).show() } } + + private fun applyBackgroundPreference() { + BackgroundHelper.applyBackground(binding.backgroundLogo, requireContext()) + } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt index 6f4bf858ea..3717fcbb04 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt @@ -40,6 +40,7 @@ import org.yuzu.yuzu_emu.model.DriverViewModel import org.yuzu.yuzu_emu.model.HomeSetting import org.yuzu.yuzu_emu.model.HomeViewModel import org.yuzu.yuzu_emu.ui.main.MainActivity +import org.yuzu.yuzu_emu.utils.BackgroundHelper import org.yuzu.yuzu_emu.utils.FileUtil import org.yuzu.yuzu_emu.utils.GpuDriverHelper import org.yuzu.yuzu_emu.utils.Log @@ -76,6 +77,7 @@ class HomeSettingsFragment : Fragment() { findNavController().popBackStack() } binding.toolbarHomeSettings.title = getString(R.string.preferences_settings) + applyBackgroundPreference() val optionsList: MutableList = mutableListOf().apply { add( @@ -315,6 +317,7 @@ class HomeSettingsFragment : Fragment() { override fun onResume() { super.onResume() driverViewModel.updateDriverNameForGame(null) + applyBackgroundPreference() } override fun onDestroyView() { @@ -500,4 +503,8 @@ class HomeSettingsFragment : Fragment() { windowInsets } + + private fun applyBackgroundPreference() { + BackgroundHelper.applyBackground(binding.logoImage, requireContext()) + } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallableFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallableFragment.kt index 1b94d5f1a6..c605552f3e 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallableFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallableFragment.kt @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later package org.yuzu.yuzu_emu.fragments @@ -32,6 +32,7 @@ import org.yuzu.yuzu_emu.ui.main.MainActivity import org.yuzu.yuzu_emu.utils.DirectoryInitialization import org.yuzu.yuzu_emu.utils.FileUtil import org.yuzu.yuzu_emu.utils.NativeConfig +import org.yuzu.yuzu_emu.utils.BackgroundHelper import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins import org.yuzu.yuzu_emu.utils.collect import java.io.BufferedOutputStream @@ -68,6 +69,7 @@ class InstallableFragment : Fragment() { val mainActivity = requireActivity() as MainActivity homeViewModel.setStatusBarShadeVisibility(visible = false) + applyBackgroundPreference() binding.toolbarInstallables.setNavigationOnClickListener { binding.root.findNavController().popBackStack() @@ -162,6 +164,11 @@ class InstallableFragment : Fragment() { setInsets() } + override fun onResume() { + super.onResume() + applyBackgroundPreference() + } + private fun setInsets() = ViewCompat.setOnApplyWindowInsetsListener( binding.root @@ -325,4 +332,8 @@ class InstallableFragment : Fragment() { } }.show(parentFragmentManager, ProgressDialogFragment.TAG) } + + private fun applyBackgroundPreference() { + BackgroundHelper.applyBackground(binding.backgroundLogo, requireContext()) + } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ProfileManagerFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ProfileManagerFragment.kt index 6ee34105e7..dcc2299169 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ProfileManagerFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ProfileManagerFragment.kt @@ -21,6 +21,7 @@ import org.yuzu.yuzu_emu.adapters.ProfileAdapter import org.yuzu.yuzu_emu.databinding.FragmentProfileManagerBinding import org.yuzu.yuzu_emu.model.HomeViewModel import org.yuzu.yuzu_emu.model.UserProfile +import org.yuzu.yuzu_emu.utils.BackgroundHelper import org.yuzu.yuzu_emu.utils.NativeConfig class ProfileManagerFragment : Fragment() { @@ -49,6 +50,7 @@ class ProfileManagerFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) homeViewModel.setStatusBarShadeVisibility(visible = false) + applyBackgroundPreference() binding.toolbarProfiles.setNavigationOnClickListener { findNavController().popBackStack() @@ -75,6 +77,7 @@ class ProfileManagerFragment : Fragment() { override fun onResume() { super.onResume() loadProfiles() + applyBackgroundPreference() } private fun setupRecyclerView() { @@ -187,4 +190,8 @@ class ProfileManagerFragment : Fragment() { NativeConfig.saveGlobalConfig() _binding = null } + + private fun applyBackgroundPreference() { + BackgroundHelper.applyBackground(binding.backgroundLogo, requireContext()) + } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt index 6931a1f9d5..5eccb23038 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt @@ -40,6 +40,7 @@ import org.yuzu.yuzu_emu.model.Game import org.yuzu.yuzu_emu.model.GamesViewModel import org.yuzu.yuzu_emu.model.HomeViewModel import org.yuzu.yuzu_emu.ui.main.MainActivity +import org.yuzu.yuzu_emu.utils.BackgroundHelper import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible import org.yuzu.yuzu_emu.utils.collect import info.debatty.java.stringsimilarity.Jaccard @@ -106,6 +107,7 @@ class GamesFragment : Fragment() { super.onViewCreated(view, savedInstanceState) homeViewModel.setStatusBarShadeVisibility(true) mainActivity = requireActivity() as MainActivity + applyBackgroundPreference() if (savedInstanceState != null) { binding.searchText.setText(savedInstanceState.getString(SEARCH_TEXT)) @@ -252,6 +254,7 @@ class GamesFragment : Fragment() { override fun onResume() { super.onResume() + applyBackgroundPreference() if (getCurrentViewType() == GameAdapter.VIEW_TYPE_CAROUSEL) { (binding.gridGames as? CarouselRecyclerView)?.setupCarousel(true) (binding.gridGames as? CarouselRecyclerView)?.restoreScrollState(gamesViewModel.lastScrollPosition) @@ -497,6 +500,10 @@ class GamesFragment : Fragment() { binding.addDirectory.visibility = if (showFolder) View.VISIBLE else View.GONE } + private fun applyBackgroundPreference() { + BackgroundHelper.applyBackground(binding.backgroundLogo, requireContext()) + } + private fun setInsets() = ViewCompat.setOnApplyWindowInsetsListener( binding.root diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/BackgroundHelper.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/BackgroundHelper.kt new file mode 100644 index 0000000000..b15f3ec296 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/BackgroundHelper.kt @@ -0,0 +1,64 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +package org.yuzu.yuzu_emu.utils + +import android.content.Context +import android.view.View +import androidx.core.content.edit +import androidx.preference.PreferenceManager +import org.yuzu.yuzu_emu.R +import org.yuzu.yuzu_emu.features.settings.model.Settings + +object BackgroundHelper { + fun getBackgroundStyle(context: Context): Int { + return PreferenceManager.getDefaultSharedPreferences(context).getInt( + Settings.PREF_HOME_BACKGROUND_STYLE, + Settings.HOME_BACKGROUND_STYLE_DEFAULT + ) + } + + fun setBackgroundStyle(context: Context, style: Int) { + PreferenceManager.getDefaultSharedPreferences(context).edit { + putInt(Settings.PREF_HOME_BACKGROUND_STYLE, style) + } + } + + fun getBackgroundAlpha(context: Context): Float { + val alphaPercent = PreferenceManager.getDefaultSharedPreferences(context).getInt( + Settings.PREF_HOME_BACKGROUND_ALPHA, + Settings.HOME_BACKGROUND_ALPHA_DEFAULT + ).coerceIn(0, 100) + return alphaPercent / 100f + } + + fun setBackgroundAlpha(context: Context, alphaPercent: Int) { + PreferenceManager.getDefaultSharedPreferences(context).edit { + putInt(Settings.PREF_HOME_BACKGROUND_ALPHA, alphaPercent.coerceIn(0, 100)) + } + } + + fun applyBackground(view: View, context: Context) { + val isEnabled = getBackgroundStyle(context) != Settings.HOME_BACKGROUND_STYLE_NONE + val visibilityStrength = getBackgroundAlpha(context) + + val parent = view.parent as? View + val scrim = parent?.findViewById(R.id.background_scrim) + + view.visibility = if (isEnabled) View.VISIBLE else View.GONE + + if (!isEnabled) { + scrim?.visibility = View.GONE + return + } + + if (scrim != null) { + // Keep background image opaque; control perceived intensity through a cheap flat-color scrim. + view.alpha = 1f + scrim.visibility = View.VISIBLE + scrim.alpha = (1f - visibilityStrength).coerceIn(0f, 1f) + } else { + view.alpha = visibilityStrength + } + } +} diff --git a/src/android/app/src/main/res/drawable-nodpi/eden_background.webp b/src/android/app/src/main/res/drawable-nodpi/eden_background.webp new file mode 100644 index 0000000000..2af59a8dc4 Binary files /dev/null and b/src/android/app/src/main/res/drawable-nodpi/eden_background.webp differ diff --git a/src/android/app/src/main/res/layout-land/dialog_lobby_browser.xml b/src/android/app/src/main/res/layout-land/dialog_lobby_browser.xml index 88d06d4873..5c26dc66b3 100644 --- a/src/android/app/src/main/res/layout-land/dialog_lobby_browser.xml +++ b/src/android/app/src/main/res/layout-land/dialog_lobby_browser.xml @@ -6,6 +6,17 @@ android:layout_height="match_parent" android:background="?attr/colorSurface"> + + + + + + - \ No newline at end of file + diff --git a/src/android/app/src/main/res/layout-w600dp/fragment_about.xml b/src/android/app/src/main/res/layout-w600dp/fragment_about.xml index ae2b3e3637..8d282e9166 100644 --- a/src/android/app/src/main/res/layout-w600dp/fragment_about.xml +++ b/src/android/app/src/main/res/layout-w600dp/fragment_about.xml @@ -8,6 +8,17 @@ android:background="?attr/colorSurface" > + + + + + + + + - \ No newline at end of file + diff --git a/src/android/app/src/main/res/layout/fragment_about.xml b/src/android/app/src/main/res/layout/fragment_about.xml index da823bcc25..361b86ac0c 100644 --- a/src/android/app/src/main/res/layout/fragment_about.xml +++ b/src/android/app/src/main/res/layout/fragment_about.xml @@ -8,6 +8,17 @@ android:background="?attr/colorSurface" > + + + + + + + + + + + + diff --git a/src/android/app/src/main/res/layout/fragment_freedreno_settings.xml b/src/android/app/src/main/res/layout/fragment_freedreno_settings.xml index ac8121c120..4c6c8546ab 100644 --- a/src/android/app/src/main/res/layout/fragment_freedreno_settings.xml +++ b/src/android/app/src/main/res/layout/fragment_freedreno_settings.xml @@ -6,6 +6,16 @@ android:layout_height="match_parent" android:background="?attr/colorSurface"> + + + + + + + + + + - \ No newline at end of file + diff --git a/src/android/app/src/main/res/layout/fragment_home_settings.xml b/src/android/app/src/main/res/layout/fragment_home_settings.xml index a52ae09477..88a1ae7137 100644 --- a/src/android/app/src/main/res/layout/fragment_home_settings.xml +++ b/src/android/app/src/main/res/layout/fragment_home_settings.xml @@ -6,6 +6,20 @@ android:layout_height="match_parent" android:background="?attr/colorSurface"> + + + + + + + + 2 + + @string/background_none + @string/background_eden_default + + + 0 + 1 + + @string/app_language_system @string/app_language_english diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 7d094effcb..0ea2de66e8 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -1160,6 +1160,12 @@ Material You App Settings Theme And Color + Home background + Show a decorative background across app screens. + Background opacity + Adjust the background visibility strength. + None + Eden (default) Change theme mode