summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/YuzuApplication.kt2
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt4
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt176
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivityPresenter.kt81
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivityView.kt38
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt47
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragment.kt112
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt68
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentView.kt42
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt11
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt19
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/model/SettingsViewModel.kt47
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt14
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt10
-rw-r--r--src/android/app/src/main/res/anim-ldrtl/anim_pop_settings_fragment_out.xml16
-rw-r--r--src/android/app/src/main/res/anim-ldrtl/anim_settings_fragment_in.xml16
-rw-r--r--src/android/app/src/main/res/anim/anim_pop_settings_fragment_out.xml16
-rw-r--r--src/android/app/src/main/res/anim/anim_settings_fragment_in.xml16
-rw-r--r--src/android/app/src/main/res/anim/anim_settings_fragment_out.xml10
-rw-r--r--src/android/app/src/main/res/animator/menu_slide_in_from_start.xml20
-rw-r--r--src/android/app/src/main/res/animator/menu_slide_out_to_start.xml21
-rw-r--r--src/android/app/src/main/res/layout/activity_settings.xml52
-rw-r--r--src/android/app/src/main/res/layout/fragment_settings.xml39
-rw-r--r--src/android/app/src/main/res/menu/menu_settings.xml2
-rw-r--r--src/android/app/src/main/res/navigation/emulation_navigation.xml17
-rw-r--r--src/android/app/src/main/res/navigation/home_navigation.xml17
-rw-r--r--src/android/app/src/main/res/navigation/settings_navigation.xml24
-rw-r--r--src/android/app/src/main/res/values/strings.xml1
28 files changed, 371 insertions, 567 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/YuzuApplication.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/YuzuApplication.kt
index 04ab6a220..9561748cb 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/YuzuApplication.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/YuzuApplication.kt
@@ -46,7 +46,7 @@ class YuzuApplication : Application() {
46 super.onCreate() 46 super.onCreate()
47 application = this 47 application = this
48 documentsTree = DocumentsTree() 48 documentsTree = DocumentsTree()
49 DirectoryInitialization.start(applicationContext) 49 DirectoryInitialization.start()
50 GpuDriverHelper.initializeDriverParameters(applicationContext) 50 GpuDriverHelper.initializeDriverParameters(applicationContext)
51 NativeLibrary.logDeviceInfo() 51 NativeLibrary.logDeviceInfo()
52 52
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt
index 6f52a7a8d..dbd602a1d 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt
@@ -85,9 +85,7 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
85 85
86 val navHostFragment = 86 val navHostFragment =
87 supportFragmentManager.findFragmentById(R.id.fragment_container) as NavHostFragment 87 supportFragmentManager.findFragmentById(R.id.fragment_container) as NavHostFragment
88 val navController = navHostFragment.navController 88 navHostFragment.navController.setGraph(R.navigation.emulation_navigation, intent.extras)
89 navController
90 .setGraph(R.navigation.emulation_navigation, intent.extras)
91 89
92 isActivityRecreated = savedInstanceState != null 90 isActivityRecreated = savedInstanceState != null
93 91
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt
index 733a53c8c..7fd83f5f7 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt
@@ -3,10 +3,7 @@
3 3
4package org.yuzu.yuzu_emu.features.settings.ui 4package org.yuzu.yuzu_emu.features.settings.ui
5 5
6import android.content.Context
7import android.content.Intent
8import android.os.Bundle 6import android.os.Bundle
9import android.view.Menu
10import android.view.View 7import android.view.View
11import android.view.ViewGroup.MarginLayoutParams 8import android.view.ViewGroup.MarginLayoutParams
12import android.widget.Toast 9import android.widget.Toast
@@ -16,20 +13,26 @@ import androidx.appcompat.app.AppCompatActivity
16import androidx.core.view.ViewCompat 13import androidx.core.view.ViewCompat
17import androidx.core.view.WindowCompat 14import androidx.core.view.WindowCompat
18import androidx.core.view.WindowInsetsCompat 15import androidx.core.view.WindowInsetsCompat
19import androidx.core.view.updatePadding 16import androidx.navigation.fragment.NavHostFragment
17import androidx.navigation.navArgs
20import com.google.android.material.color.MaterialColors 18import com.google.android.material.color.MaterialColors
19import org.yuzu.yuzu_emu.NativeLibrary
21import java.io.IOException 20import java.io.IOException
22import org.yuzu.yuzu_emu.R 21import org.yuzu.yuzu_emu.R
23import org.yuzu.yuzu_emu.databinding.ActivitySettingsBinding 22import org.yuzu.yuzu_emu.databinding.ActivitySettingsBinding
24import org.yuzu.yuzu_emu.features.settings.model.Settings 23import org.yuzu.yuzu_emu.features.settings.model.Settings
25import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile 24import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
25import org.yuzu.yuzu_emu.fragments.ResetSettingsDialogFragment
26import org.yuzu.yuzu_emu.model.SettingsViewModel
26import org.yuzu.yuzu_emu.utils.* 27import org.yuzu.yuzu_emu.utils.*
27 28
28class SettingsActivity : AppCompatActivity(), SettingsActivityView { 29class SettingsActivity : AppCompatActivity() {
29 private val presenter = SettingsActivityPresenter(this)
30
31 private lateinit var binding: ActivitySettingsBinding 30 private lateinit var binding: ActivitySettingsBinding
32 31
32 private val args by navArgs<SettingsActivityArgs>()
33
34 private val settingsViewModel: SettingsViewModel by viewModels()
35
33 override fun onCreate(savedInstanceState: Bundle?) { 36 override fun onCreate(savedInstanceState: Bundle?) {
34 ThemeHelper.setTheme(this) 37 ThemeHelper.setTheme(this)
35 38
@@ -38,16 +41,17 @@ class SettingsActivity : AppCompatActivity(), SettingsActivityView {
38 binding = ActivitySettingsBinding.inflate(layoutInflater) 41 binding = ActivitySettingsBinding.inflate(layoutInflater)
39 setContentView(binding.root) 42 setContentView(binding.root)
40 43
41 WindowCompat.setDecorFitsSystemWindows(window, false) 44 settingsViewModel.game = args.game
42 45
43 val launcher = intent 46 val navHostFragment =
44 val gameID = launcher.getStringExtra(ARG_GAME_ID) 47 supportFragmentManager.findFragmentById(R.id.fragment_container) as NavHostFragment
45 val menuTag = launcher.getStringExtra(ARG_MENU_TAG) 48 navHostFragment.navController.setGraph(R.navigation.settings_navigation, intent.extras)
46 presenter.onCreate(savedInstanceState, menuTag!!, gameID!!)
47 49
48 // Show "Back" button in the action bar for navigation 50 WindowCompat.setDecorFitsSystemWindows(window, false)
49 setSupportActionBar(binding.toolbarSettings) 51
50 supportActionBar!!.setDisplayHomeAsUpEnabled(true) 52 if (savedInstanceState != null) {
53 settingsViewModel.shouldSave = savedInstanceState.getBoolean(KEY_SHOULD_SAVE)
54 }
51 55
52 if (InsetsHelper.getSystemGestureType(applicationContext) != 56 if (InsetsHelper.getSystemGestureType(applicationContext) !=
53 InsetsHelper.GESTURE_NAVIGATION 57 InsetsHelper.GESTURE_NAVIGATION
@@ -63,6 +67,28 @@ class SettingsActivity : AppCompatActivity(), SettingsActivityView {
63 ) 67 )
64 } 68 }
65 69
70 settingsViewModel.shouldRecreate.observe(this) {
71 if (it) {
72 settingsViewModel.setShouldRecreate(false)
73 recreate()
74 }
75 }
76 settingsViewModel.shouldNavigateBack.observe(this) {
77 if (it) {
78 settingsViewModel.setShouldNavigateBack(false)
79 navigateBack()
80 }
81 }
82 settingsViewModel.shouldShowResetSettingsDialog.observe(this) {
83 if (it) {
84 settingsViewModel.setShouldShowResetSettingsDialog(false)
85 ResetSettingsDialogFragment().show(
86 supportFragmentManager,
87 ResetSettingsDialogFragment.TAG
88 )
89 }
90 }
91
66 onBackPressedDispatcher.addCallback( 92 onBackPressedDispatcher.addCallback(
67 this, 93 this,
68 object : OnBackPressedCallback(true) { 94 object : OnBackPressedCallback(true) {
@@ -73,34 +99,28 @@ class SettingsActivity : AppCompatActivity(), SettingsActivityView {
73 setInsets() 99 setInsets()
74 } 100 }
75 101
76 override fun onSupportNavigateUp(): Boolean { 102 fun navigateBack() {
77 navigateBack() 103 val navHostFragment =
78 return true 104 supportFragmentManager.findFragmentById(R.id.fragment_container) as NavHostFragment
79 } 105 if (navHostFragment.childFragmentManager.backStackEntryCount > 0) {
80 106 navHostFragment.navController.popBackStack()
81 private fun navigateBack() {
82 if (supportFragmentManager.backStackEntryCount > 0) {
83 supportFragmentManager.popBackStack()
84 } else { 107 } else {
85 finish() 108 finish()
86 } 109 }
87 } 110 }
88 111
89 override fun onCreateOptionsMenu(menu: Menu): Boolean {
90 val inflater = menuInflater
91 inflater.inflate(R.menu.menu_settings, menu)
92 return true
93 }
94
95 override fun onSaveInstanceState(outState: Bundle) { 112 override fun onSaveInstanceState(outState: Bundle) {
96 // Critical: If super method is not called, rotations will be busted. 113 // Critical: If super method is not called, rotations will be busted.
97 super.onSaveInstanceState(outState) 114 super.onSaveInstanceState(outState)
98 presenter.saveState(outState) 115 outState.putBoolean(KEY_SHOULD_SAVE, settingsViewModel.shouldSave)
99 } 116 }
100 117
101 override fun onStart() { 118 override fun onStart() {
102 super.onStart() 119 super.onStart()
103 presenter.onStart() 120 // TODO: Load custom settings contextually
121 if (!DirectoryInitialization.areDirectoriesReady) {
122 DirectoryInitialization.start()
123 }
104 } 124 }
105 125
106 /** 126 /**
@@ -110,65 +130,21 @@ class SettingsActivity : AppCompatActivity(), SettingsActivityView {
110 */ 130 */
111 override fun onStop() { 131 override fun onStop() {
112 super.onStop() 132 super.onStop()
113 presenter.onStop(isFinishing) 133 if (isFinishing && settingsViewModel.shouldSave) {
114 } 134 Log.debug("[SettingsActivity] Settings activity stopping. Saving settings to INI...")
115 135 Settings.saveSettings()
116 override fun showSettingsFragment(menuTag: String, addToStack: Boolean, gameId: String) { 136 NativeLibrary.reloadSettings()
117 if (!addToStack && settingsFragment != null) {
118 return
119 }
120
121 val transaction = supportFragmentManager.beginTransaction()
122 if (addToStack) {
123 if (areSystemAnimationsEnabled()) {
124 transaction.setCustomAnimations(
125 R.anim.anim_settings_fragment_in,
126 R.anim.anim_settings_fragment_out,
127 0,
128 R.anim.anim_pop_settings_fragment_out
129 )
130 }
131 transaction.addToBackStack(null)
132 } 137 }
133 transaction.replace(
134 R.id.frame_content,
135 SettingsFragment.newInstance(menuTag, gameId),
136 FRAGMENT_TAG
137 )
138 transaction.commit()
139 }
140
141 private fun areSystemAnimationsEnabled(): Boolean {
142 val duration = android.provider.Settings.Global.getFloat(
143 contentResolver,
144 android.provider.Settings.Global.ANIMATOR_DURATION_SCALE,
145 1f
146 )
147 val transition = android.provider.Settings.Global.getFloat(
148 contentResolver,
149 android.provider.Settings.Global.TRANSITION_ANIMATION_SCALE,
150 1f
151 )
152 return duration != 0f && transition != 0f
153 } 138 }
154 139
155 override fun onSettingsFileLoaded() { 140 override fun onDestroy() {
156 val fragment: SettingsFragmentView? = settingsFragment 141 settingsViewModel.clear()
157 fragment?.loadSettingsList() 142 super.onDestroy()
158 }
159
160 override fun onSettingsFileNotFound() {
161 val fragment: SettingsFragmentView? = settingsFragment
162 fragment?.loadSettingsList()
163 }
164
165 override fun onSettingChanged() {
166 presenter.onSettingChanged()
167 } 143 }
168 144
169 fun onSettingsReset() { 145 fun onSettingsReset() {
170 // Prevents saving to a non-existent settings file 146 // Prevents saving to a non-existent settings file
171 presenter.onSettingsReset() 147 settingsViewModel.shouldSave = false
172 148
173 // Delete settings file because the user may have changed values that do not exist in the UI 149 // Delete settings file because the user may have changed values that do not exist in the UI
174 val settingsFile = SettingsFile.getSettingsFile(SettingsFile.FILE_NAME_CONFIG) 150 val settingsFile = SettingsFile.getSettingsFile(SettingsFile.FILE_NAME_CONFIG)
@@ -185,47 +161,21 @@ class SettingsActivity : AppCompatActivity(), SettingsActivityView {
185 finish() 161 finish()
186 } 162 }
187 163
188 fun setToolbarTitle(title: String) {
189 binding.toolbarSettingsLayout.title = title
190 }
191
192 private val settingsFragment: SettingsFragment?
193 get() = supportFragmentManager.findFragmentByTag(FRAGMENT_TAG) as SettingsFragment?
194
195 private fun setInsets() { 164 private fun setInsets() {
196 ViewCompat.setOnApplyWindowInsetsListener( 165 ViewCompat.setOnApplyWindowInsetsListener(
197 binding.frameContent 166 binding.navigationBarShade
198 ) { view: View, windowInsets: WindowInsetsCompat -> 167 ) { view: View, windowInsets: WindowInsetsCompat ->
199 val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) 168 val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
200 val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout())
201 view.updatePadding(
202 left = barInsets.left + cutoutInsets.left,
203 right = barInsets.right + cutoutInsets.right
204 )
205 169
206 val mlpAppBar = binding.appbarSettings.layoutParams as MarginLayoutParams 170 val mlpShade = view.layoutParams as MarginLayoutParams
207 mlpAppBar.leftMargin = barInsets.left + cutoutInsets.left
208 mlpAppBar.rightMargin = barInsets.right + cutoutInsets.right
209 binding.appbarSettings.layoutParams = mlpAppBar
210
211 val mlpShade = binding.navigationBarShade.layoutParams as MarginLayoutParams
212 mlpShade.height = barInsets.bottom 171 mlpShade.height = barInsets.bottom
213 binding.navigationBarShade.layoutParams = mlpShade 172 view.layoutParams = mlpShade
214 173
215 windowInsets 174 windowInsets
216 } 175 }
217 } 176 }
218 177
219 companion object { 178 companion object {
220 private const val ARG_MENU_TAG = "menu_tag" 179 private const val KEY_SHOULD_SAVE = "should_save"
221 private const val ARG_GAME_ID = "game_id"
222 private const val FRAGMENT_TAG = "settings"
223
224 fun launch(context: Context, menuTag: String?, gameId: String?) {
225 val settings = Intent(context, SettingsActivity::class.java)
226 settings.putExtra(ARG_MENU_TAG, menuTag)
227 settings.putExtra(ARG_GAME_ID, gameId)
228 context.startActivity(settings)
229 }
230 } 180 }
231} 181}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivityPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivityPresenter.kt
deleted file mode 100644
index fdbad32bf..000000000
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivityPresenter.kt
+++ /dev/null
@@ -1,81 +0,0 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4package org.yuzu.yuzu_emu.features.settings.ui
5
6import android.content.Context
7import android.os.Bundle
8import java.io.File
9import org.yuzu.yuzu_emu.NativeLibrary
10import org.yuzu.yuzu_emu.features.settings.model.Settings
11import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
12import org.yuzu.yuzu_emu.utils.DirectoryInitialization
13import org.yuzu.yuzu_emu.utils.Log
14
15class SettingsActivityPresenter(private val activityView: SettingsActivityView) {
16 private var shouldSave = false
17 private lateinit var menuTag: String
18 private lateinit var gameId: String
19
20 fun onCreate(savedInstanceState: Bundle?, menuTag: String, gameId: String) {
21 this.menuTag = menuTag
22 this.gameId = gameId
23 if (savedInstanceState != null) {
24 shouldSave = savedInstanceState.getBoolean(KEY_SHOULD_SAVE)
25 }
26 }
27
28 fun onStart() {
29 prepareDirectoriesIfNeeded()
30 }
31
32 private fun loadSettingsUI() {
33 // TODO: Load custom settings contextually
34 activityView.showSettingsFragment(menuTag, false, gameId)
35 activityView.onSettingsFileLoaded()
36 }
37
38 private fun prepareDirectoriesIfNeeded() {
39 val configFile =
40 File(
41 "${DirectoryInitialization.userDirectory}/config/" +
42 "${SettingsFile.FILE_NAME_CONFIG}.ini"
43 )
44 if (!configFile.exists()) {
45 Log.error(
46 "${DirectoryInitialization.userDirectory}/config/" +
47 "${SettingsFile.FILE_NAME_CONFIG}.ini"
48 )
49 Log.error("yuzu config file could not be found!")
50 }
51
52 if (!DirectoryInitialization.areDirectoriesReady) {
53 DirectoryInitialization.start(activityView as Context)
54 }
55 loadSettingsUI()
56 }
57
58 fun onStop(finishing: Boolean) {
59 if (finishing && shouldSave) {
60 Log.debug("[SettingsActivity] Settings activity stopping. Saving settings to INI...")
61 Settings.saveSettings()
62 NativeLibrary.reloadSettings()
63 }
64 }
65
66 fun onSettingChanged() {
67 shouldSave = true
68 }
69
70 fun onSettingsReset() {
71 shouldSave = false
72 }
73
74 fun saveState(outState: Bundle) {
75 outState.putBoolean(KEY_SHOULD_SAVE, shouldSave)
76 }
77
78 companion object {
79 private const val KEY_SHOULD_SAVE = "should_save"
80 }
81}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivityView.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivityView.kt
deleted file mode 100644
index 07a58b4ea..000000000
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivityView.kt
+++ /dev/null
@@ -1,38 +0,0 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4package org.yuzu.yuzu_emu.features.settings.ui
5
6/**
7 * Abstraction for the Activity that manages SettingsFragments.
8 */
9interface SettingsActivityView {
10 /**
11 * Show a new SettingsFragment.
12 *
13 * @param menuTag Identifier for the settings group that should be displayed.
14 * @param addToStack Whether or not this fragment should replace a previous one.
15 */
16 fun showSettingsFragment(menuTag: String, addToStack: Boolean, gameId: String)
17
18 /**
19 * Called when a load operation completes.
20 */
21 fun onSettingsFileLoaded()
22
23 /**
24 * Called when a load operation fails.
25 */
26 fun onSettingsFileNotFound()
27
28 /**
29 * End the activity.
30 */
31 fun finish()
32
33 /**
34 * Called by a containing Fragment to tell the Activity that a setting was changed;
35 * unless this has been called, the Activity will not save to disk.
36 */
37 fun onSettingChanged()
38}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt
index 27eaaa576..9883c2ec7 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt
@@ -12,7 +12,8 @@ import android.view.LayoutInflater
12import android.view.ViewGroup 12import android.view.ViewGroup
13import android.widget.TextView 13import android.widget.TextView
14import androidx.appcompat.app.AlertDialog 14import androidx.appcompat.app.AlertDialog
15import androidx.appcompat.app.AppCompatActivity 15import androidx.lifecycle.ViewModelProvider
16import androidx.navigation.findNavController
16import androidx.recyclerview.widget.RecyclerView 17import androidx.recyclerview.widget.RecyclerView
17import com.google.android.material.datepicker.MaterialDatePicker 18import com.google.android.material.datepicker.MaterialDatePicker
18import com.google.android.material.dialog.MaterialAlertDialogBuilder 19import com.google.android.material.dialog.MaterialAlertDialogBuilder
@@ -20,6 +21,7 @@ import com.google.android.material.slider.Slider
20import com.google.android.material.timepicker.MaterialTimePicker 21import com.google.android.material.timepicker.MaterialTimePicker
21import com.google.android.material.timepicker.TimeFormat 22import com.google.android.material.timepicker.TimeFormat
22import org.yuzu.yuzu_emu.R 23import org.yuzu.yuzu_emu.R
24import org.yuzu.yuzu_emu.SettingsNavigationDirections
23import org.yuzu.yuzu_emu.databinding.DialogSliderBinding 25import org.yuzu.yuzu_emu.databinding.DialogSliderBinding
24import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding 26import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
25import org.yuzu.yuzu_emu.databinding.ListItemSettingSwitchBinding 27import org.yuzu.yuzu_emu.databinding.ListItemSettingSwitchBinding
@@ -30,18 +32,22 @@ import org.yuzu.yuzu_emu.features.settings.model.FloatSetting
30import org.yuzu.yuzu_emu.features.settings.model.ShortSetting 32import org.yuzu.yuzu_emu.features.settings.model.ShortSetting
31import org.yuzu.yuzu_emu.features.settings.model.view.* 33import org.yuzu.yuzu_emu.features.settings.model.view.*
32import org.yuzu.yuzu_emu.features.settings.ui.viewholder.* 34import org.yuzu.yuzu_emu.features.settings.ui.viewholder.*
35import org.yuzu.yuzu_emu.model.SettingsViewModel
33 36
34class SettingsAdapter( 37class SettingsAdapter(
35 private val fragmentView: SettingsFragmentView, 38 private val fragment: SettingsFragment,
36 private val context: Context 39 private val context: Context
37) : RecyclerView.Adapter<SettingViewHolder?>(), DialogInterface.OnClickListener { 40) : RecyclerView.Adapter<SettingViewHolder?>(), DialogInterface.OnClickListener {
38 private var settings: ArrayList<SettingsItem>? = null 41 private var settings = ArrayList<SettingsItem>()
39 private var clickedItem: SettingsItem? = null 42 private var clickedItem: SettingsItem? = null
40 private var clickedPosition: Int 43 private var clickedPosition: Int
41 private var dialog: AlertDialog? = null 44 private var dialog: AlertDialog? = null
42 private var sliderProgress = 0 45 private var sliderProgress = 0
43 private var textSliderValue: TextView? = null 46 private var textSliderValue: TextView? = null
44 47
48 private val settingsViewModel: SettingsViewModel
49 get() = ViewModelProvider(fragment.requireActivity())[SettingsViewModel::class.java]
50
45 private var defaultCancelListener = 51 private var defaultCancelListener =
46 DialogInterface.OnClickListener { _: DialogInterface?, _: Int -> closeDialog() } 52 DialogInterface.OnClickListener { _: DialogInterface?, _: Int -> closeDialog() }
47 53
@@ -91,30 +97,22 @@ class SettingsAdapter(
91 holder.bind(getItem(position)) 97 holder.bind(getItem(position))
92 } 98 }
93 99
94 private fun getItem(position: Int): SettingsItem { 100 private fun getItem(position: Int): SettingsItem = settings[position]
95 return settings!![position]
96 }
97 101
98 override fun getItemCount(): Int { 102 override fun getItemCount(): Int = settings.size
99 return if (settings != null) {
100 settings!!.size
101 } else {
102 0
103 }
104 }
105 103
106 override fun getItemViewType(position: Int): Int { 104 override fun getItemViewType(position: Int): Int {
107 return getItem(position).type 105 return getItem(position).type
108 } 106 }
109 107
110 fun setSettingsList(settings: ArrayList<SettingsItem>?) { 108 fun setSettingsList(settings: ArrayList<SettingsItem>) {
111 this.settings = settings 109 this.settings = settings
112 notifyDataSetChanged() 110 notifyDataSetChanged()
113 } 111 }
114 112
115 fun onBooleanClick(item: SwitchSetting, position: Int, checked: Boolean) { 113 fun onBooleanClick(item: SwitchSetting, position: Int, checked: Boolean) {
116 item.checked = checked 114 item.checked = checked
117 fragmentView.onSettingChanged() 115 settingsViewModel.shouldSave = true
118 } 116 }
119 117
120 private fun onSingleChoiceClick(item: SingleChoiceSetting) { 118 private fun onSingleChoiceClick(item: SingleChoiceSetting) {
@@ -155,7 +153,7 @@ class SettingsAdapter(
155 calendar.timeZone = TimeZone.getTimeZone("UTC") 153 calendar.timeZone = TimeZone.getTimeZone("UTC")
156 154
157 var timeFormat: Int = TimeFormat.CLOCK_12H 155 var timeFormat: Int = TimeFormat.CLOCK_12H
158 if (DateFormat.is24HourFormat(fragmentView.activityView as AppCompatActivity)) { 156 if (DateFormat.is24HourFormat(context)) {
159 timeFormat = TimeFormat.CLOCK_24H 157 timeFormat = TimeFormat.CLOCK_24H
160 } 158 }
161 159
@@ -172,7 +170,7 @@ class SettingsAdapter(
172 170
173 datePicker.addOnPositiveButtonClickListener { 171 datePicker.addOnPositiveButtonClickListener {
174 timePicker.show( 172 timePicker.show(
175 (fragmentView.activityView as AppCompatActivity).supportFragmentManager, 173 fragment.childFragmentManager,
176 "TimePicker" 174 "TimePicker"
177 ) 175 )
178 } 176 }
@@ -181,14 +179,14 @@ class SettingsAdapter(
181 epochTime += timePicker.hour.toLong() * 60 * 60 179 epochTime += timePicker.hour.toLong() * 60 * 60
182 epochTime += timePicker.minute.toLong() * 60 180 epochTime += timePicker.minute.toLong() * 60
183 if (item.value != epochTime) { 181 if (item.value != epochTime) {
184 fragmentView.onSettingChanged() 182 settingsViewModel.shouldSave = true
185 notifyItemChanged(clickedPosition) 183 notifyItemChanged(clickedPosition)
186 item.value = epochTime 184 item.value = epochTime
187 } 185 }
188 clickedItem = null 186 clickedItem = null
189 } 187 }
190 datePicker.show( 188 datePicker.show(
191 (fragmentView.activityView as AppCompatActivity).supportFragmentManager, 189 fragment.childFragmentManager,
192 "DatePicker" 190 "DatePicker"
193 ) 191 )
194 } 192 }
@@ -231,7 +229,8 @@ class SettingsAdapter(
231 } 229 }
232 230
233 fun onSubmenuClick(item: SubmenuSetting) { 231 fun onSubmenuClick(item: SubmenuSetting) {
234 fragmentView.loadSubMenu(item.menuKey) 232 val action = SettingsNavigationDirections.actionGlobalSettingsFragment(item.menuKey, null)
233 fragment.view?.findNavController()?.navigate(action)
235 } 234 }
236 235
237 override fun onClick(dialog: DialogInterface, which: Int) { 236 override fun onClick(dialog: DialogInterface, which: Int) {
@@ -240,7 +239,7 @@ class SettingsAdapter(
240 val scSetting = clickedItem as SingleChoiceSetting 239 val scSetting = clickedItem as SingleChoiceSetting
241 val value = getValueForSingleChoiceSelection(scSetting, which) 240 val value = getValueForSingleChoiceSelection(scSetting, which)
242 if (scSetting.selectedValue != value) { 241 if (scSetting.selectedValue != value) {
243 fragmentView.onSettingChanged() 242 settingsViewModel.shouldSave = true
244 } 243 }
245 244
246 // Get the backing Setting, which may be null (if for example it was missing from the file) 245 // Get the backing Setting, which may be null (if for example it was missing from the file)
@@ -251,7 +250,7 @@ class SettingsAdapter(
251 is StringSingleChoiceSetting -> { 250 is StringSingleChoiceSetting -> {
252 val scSetting = clickedItem as StringSingleChoiceSetting 251 val scSetting = clickedItem as StringSingleChoiceSetting
253 val value = scSetting.getValueAt(which) 252 val value = scSetting.getValueAt(which)
254 if (scSetting.selectedValue != value) fragmentView.onSettingChanged() 253 if (scSetting.selectedValue != value) settingsViewModel.shouldSave = true
255 scSetting.selectedValue = value!! 254 scSetting.selectedValue = value!!
256 closeDialog() 255 closeDialog()
257 } 256 }
@@ -259,7 +258,7 @@ class SettingsAdapter(
259 is SliderSetting -> { 258 is SliderSetting -> {
260 val sliderSetting = clickedItem as SliderSetting 259 val sliderSetting = clickedItem as SliderSetting
261 if (sliderSetting.selectedValue != sliderProgress) { 260 if (sliderSetting.selectedValue != sliderProgress) {
262 fragmentView.onSettingChanged() 261 settingsViewModel.shouldSave = true
263 } 262 }
264 when (sliderSetting.setting) { 263 when (sliderSetting.setting) {
265 is ByteSetting -> { 264 is ByteSetting -> {
@@ -294,7 +293,7 @@ class SettingsAdapter(
294 .setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int -> 293 .setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int ->
295 setting.reset() 294 setting.reset()
296 notifyItemChanged(position) 295 notifyItemChanged(position)
297 fragmentView.onSettingChanged() 296 settingsViewModel.shouldSave = true
298 } 297 }
299 .setNegativeButton(android.R.string.cancel, null) 298 .setNegativeButton(android.R.string.cancel, null)
300 .show() 299 .show()
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 dc1bf6eb1..de6aebd9d 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
@@ -3,39 +3,41 @@
3 3
4package org.yuzu.yuzu_emu.features.settings.ui 4package org.yuzu.yuzu_emu.features.settings.ui
5 5
6import android.content.Context
7import android.os.Bundle 6import android.os.Bundle
8import android.view.LayoutInflater 7import android.view.LayoutInflater
9import android.view.View 8import android.view.View
10import android.view.ViewGroup 9import android.view.ViewGroup
10import android.view.ViewGroup.MarginLayoutParams
11import androidx.core.view.ViewCompat 11import androidx.core.view.ViewCompat
12import androidx.core.view.WindowInsetsCompat 12import androidx.core.view.WindowInsetsCompat
13import androidx.core.view.updatePadding 13import androidx.core.view.updatePadding
14import androidx.fragment.app.Fragment 14import androidx.fragment.app.Fragment
15import androidx.fragment.app.activityViewModels
16import androidx.navigation.fragment.navArgs
15import androidx.recyclerview.widget.LinearLayoutManager 17import androidx.recyclerview.widget.LinearLayoutManager
16import com.google.android.material.divider.MaterialDividerItemDecoration 18import com.google.android.material.divider.MaterialDividerItemDecoration
19import com.google.android.material.transition.MaterialSharedAxis
20import org.yuzu.yuzu_emu.R
17import org.yuzu.yuzu_emu.databinding.FragmentSettingsBinding 21import org.yuzu.yuzu_emu.databinding.FragmentSettingsBinding
18import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem 22import org.yuzu.yuzu_emu.model.SettingsViewModel
19 23
20class SettingsFragment : Fragment(), SettingsFragmentView { 24class SettingsFragment : Fragment() {
21 override var activityView: SettingsActivityView? = null 25 private lateinit var presenter: SettingsFragmentPresenter
22
23 private val fragmentPresenter = SettingsFragmentPresenter(this)
24 private var settingsAdapter: SettingsAdapter? = null 26 private var settingsAdapter: SettingsAdapter? = null
25 27
26 private var _binding: FragmentSettingsBinding? = null 28 private var _binding: FragmentSettingsBinding? = null
27 private val binding get() = _binding!! 29 private val binding get() = _binding!!
28 30
29 override fun onAttach(context: Context) { 31 private val args by navArgs<SettingsFragmentArgs>()
30 super.onAttach(context) 32
31 activityView = requireActivity() as SettingsActivityView 33 private val settingsViewModel: SettingsViewModel by activityViewModels()
32 }
33 34
34 override fun onCreate(savedInstanceState: Bundle?) { 35 override fun onCreate(savedInstanceState: Bundle?) {
35 super.onCreate(savedInstanceState) 36 super.onCreate(savedInstanceState)
36 val menuTag = requireArguments().getString(ARGUMENT_MENU_TAG) 37 enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
37 val gameId = requireArguments().getString(ARGUMENT_GAME_ID) 38 returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
38 fragmentPresenter.onCreate(menuTag!!, gameId!!) 39 reenterTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
40 exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
39 } 41 }
40 42
41 override fun onCreateView( 43 override fun onCreateView(
@@ -48,7 +50,14 @@ class SettingsFragment : Fragment(), SettingsFragmentView {
48 } 50 }
49 51
50 override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 52 override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
51 settingsAdapter = SettingsAdapter(this, requireActivity()) 53 settingsAdapter = SettingsAdapter(this, requireContext())
54 presenter = SettingsFragmentPresenter(
55 settingsViewModel,
56 settingsAdapter!!,
57 args.menuTag,
58 args.game?.gameId ?: ""
59 )
60
52 val dividerDecoration = MaterialDividerItemDecoration( 61 val dividerDecoration = MaterialDividerItemDecoration(
53 requireContext(), 62 requireContext(),
54 LinearLayoutManager.VERTICAL 63 LinearLayoutManager.VERTICAL
@@ -56,63 +65,52 @@ class SettingsFragment : Fragment(), SettingsFragmentView {
56 dividerDecoration.isLastItemDecorated = false 65 dividerDecoration.isLastItemDecorated = false
57 binding.listSettings.apply { 66 binding.listSettings.apply {
58 adapter = settingsAdapter 67 adapter = settingsAdapter
59 layoutManager = LinearLayoutManager(activity) 68 layoutManager = LinearLayoutManager(requireContext())
60 addItemDecoration(dividerDecoration) 69 addItemDecoration(dividerDecoration)
61 } 70 }
62 fragmentPresenter.onViewCreated()
63 71
64 setInsets() 72 binding.toolbarSettings.setNavigationOnClickListener {
65 } 73 settingsViewModel.setShouldNavigateBack(true)
66
67 override fun onDetach() {
68 super.onDetach()
69 activityView = null
70 if (settingsAdapter != null) {
71 settingsAdapter!!.closeDialog()
72 } 74 }
73 }
74 75
75 override fun showSettingsList(settingsList: ArrayList<SettingsItem>) { 76 settingsViewModel.toolbarTitle.observe(viewLifecycleOwner) {
76 settingsAdapter!!.setSettingsList(settingsList) 77 if (it.isNotEmpty()) binding.toolbarSettingsLayout.title = it
77 } 78 }
78 79
79 override fun loadSettingsList() { 80 presenter.onViewCreated()
80 fragmentPresenter.loadSettingsList()
81 }
82 81
83 override fun loadSubMenu(menuKey: String) { 82 setInsets()
84 activityView!!.showSettingsFragment(
85 menuKey,
86 true,
87 requireArguments().getString(ARGUMENT_GAME_ID)!!
88 )
89 } 83 }
90 84
91 override fun onSettingChanged() { 85 override fun onDetach() {
92 activityView!!.onSettingChanged() 86 super.onDetach()
87 settingsAdapter?.closeDialog()
93 } 88 }
94 89
95 private fun setInsets() { 90 private fun setInsets() {
96 ViewCompat.setOnApplyWindowInsetsListener( 91 ViewCompat.setOnApplyWindowInsetsListener(
97 binding.listSettings 92 binding.root
98 ) { view: View, windowInsets: WindowInsetsCompat -> 93 ) { _: View, windowInsets: WindowInsetsCompat ->
99 val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) 94 val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
100 view.updatePadding(bottom = insets.bottom) 95 val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout())
96
97 val leftInsets = barInsets.left + cutoutInsets.left
98 val rightInsets = barInsets.right + cutoutInsets.right
99
100 val sideMargin = resources.getDimensionPixelSize(R.dimen.spacing_medlarge)
101 val mlpSettingsList = binding.listSettings.layoutParams as MarginLayoutParams
102 mlpSettingsList.leftMargin = sideMargin + leftInsets
103 mlpSettingsList.rightMargin = sideMargin + rightInsets
104 binding.listSettings.layoutParams = mlpSettingsList
105 binding.listSettings.updatePadding(
106 bottom = barInsets.bottom
107 )
108
109 val mlpAppBar = binding.appbarSettings.layoutParams as MarginLayoutParams
110 mlpAppBar.leftMargin = leftInsets
111 mlpAppBar.rightMargin = rightInsets
112 binding.appbarSettings.layoutParams = mlpAppBar
101 windowInsets 113 windowInsets
102 } 114 }
103 } 115 }
104
105 companion object {
106 private const val ARGUMENT_MENU_TAG = "menu_tag"
107 private const val ARGUMENT_GAME_ID = "game_id"
108
109 fun newInstance(menuTag: String?, gameId: String?): Fragment {
110 val fragment = SettingsFragment()
111 val arguments = Bundle()
112 arguments.putString(ARGUMENT_MENU_TAG, menuTag)
113 arguments.putString(ARGUMENT_GAME_ID, gameId)
114 fragment.arguments = arguments
115 return fragment
116 }
117 }
118} 116}
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 dddbf65bb..ba45c317d 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,6 +3,7 @@
3 3
4package org.yuzu.yuzu_emu.features.settings.ui 4package org.yuzu.yuzu_emu.features.settings.ui
5 5
6import android.content.Context
6import android.content.SharedPreferences 7import android.content.SharedPreferences
7import android.os.Build 8import android.os.Build
8import android.text.TextUtils 9import android.text.TextUtils
@@ -20,36 +21,36 @@ import org.yuzu.yuzu_emu.features.settings.model.Settings
20import org.yuzu.yuzu_emu.features.settings.model.ShortSetting 21import org.yuzu.yuzu_emu.features.settings.model.ShortSetting
21import org.yuzu.yuzu_emu.features.settings.model.view.* 22import org.yuzu.yuzu_emu.features.settings.model.view.*
22import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile 23import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
23import org.yuzu.yuzu_emu.fragments.ResetSettingsDialogFragment 24import org.yuzu.yuzu_emu.model.SettingsViewModel
24import org.yuzu.yuzu_emu.utils.ThemeHelper
25 25
26class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) { 26class SettingsFragmentPresenter(
27 private var menuTag: String? = null 27 private val settingsViewModel: SettingsViewModel,
28 private lateinit var gameId: String 28 private val adapter: SettingsAdapter,
29 private var settingsList: ArrayList<SettingsItem>? = null 29 private var menuTag: String,
30 private var gameId: String
31) {
32 private var settingsList = ArrayList<SettingsItem>()
30 33
31 private val settingsActivity get() = fragmentView.activityView as SettingsActivity 34 private val preferences: SharedPreferences
35 get() = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
32 36
33 private lateinit var preferences: SharedPreferences 37 private val context: Context get() = YuzuApplication.appContext
34
35 fun onCreate(menuTag: String, gameId: String) {
36 this.gameId = gameId
37 this.menuTag = menuTag
38 }
39 38
40 fun onViewCreated() { 39 fun onViewCreated() {
41 preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
42 loadSettingsList() 40 loadSettingsList()
43 } 41 }
44 42
45 fun loadSettingsList() { 43 private fun loadSettingsList() {
46 if (!TextUtils.isEmpty(gameId)) { 44 if (!TextUtils.isEmpty(gameId)) {
47 settingsActivity.setToolbarTitle("Game Settings: $gameId") 45 settingsViewModel.setToolbarTitle(
46 context.getString(
47 R.string.advanced_settings_game,
48 gameId
49 )
50 )
48 } 51 }
52
49 val sl = ArrayList<SettingsItem>() 53 val sl = ArrayList<SettingsItem>()
50 if (menuTag == null) {
51 return
52 }
53 when (menuTag) { 54 when (menuTag) {
54 SettingsFile.FILE_NAME_CONFIG -> addConfigSettings(sl) 55 SettingsFile.FILE_NAME_CONFIG -> addConfigSettings(sl)
55 Settings.SECTION_GENERAL -> addGeneralSettings(sl) 56 Settings.SECTION_GENERAL -> addGeneralSettings(sl)
@@ -69,11 +70,11 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
69 } 70 }
70 } 71 }
71 settingsList = sl 72 settingsList = sl
72 fragmentView.showSettingsList(settingsList!!) 73 adapter.setSettingsList(settingsList)
73 } 74 }
74 75
75 private fun addConfigSettings(sl: ArrayList<SettingsItem>) { 76 private fun addConfigSettings(sl: ArrayList<SettingsItem>) {
76 settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.advanced_settings)) 77 settingsViewModel.setToolbarTitle(context.getString(R.string.advanced_settings))
77 sl.apply { 78 sl.apply {
78 add(SubmenuSetting(R.string.preferences_general, 0, Settings.SECTION_GENERAL)) 79 add(SubmenuSetting(R.string.preferences_general, 0, Settings.SECTION_GENERAL))
79 add(SubmenuSetting(R.string.preferences_system, 0, Settings.SECTION_SYSTEM)) 80 add(SubmenuSetting(R.string.preferences_system, 0, Settings.SECTION_SYSTEM))
@@ -82,17 +83,14 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
82 add(SubmenuSetting(R.string.preferences_debug, 0, Settings.SECTION_DEBUG)) 83 add(SubmenuSetting(R.string.preferences_debug, 0, Settings.SECTION_DEBUG))
83 add( 84 add(
84 RunnableSetting(R.string.reset_to_default, 0, false) { 85 RunnableSetting(R.string.reset_to_default, 0, false) {
85 ResetSettingsDialogFragment().show( 86 settingsViewModel.setShouldShowResetSettingsDialog(true)
86 settingsActivity.supportFragmentManager,
87 ResetSettingsDialogFragment.TAG
88 )
89 } 87 }
90 ) 88 )
91 } 89 }
92 } 90 }
93 91
94 private fun addGeneralSettings(sl: ArrayList<SettingsItem>) { 92 private fun addGeneralSettings(sl: ArrayList<SettingsItem>) {
95 settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.preferences_general)) 93 settingsViewModel.setToolbarTitle(context.getString(R.string.preferences_general))
96 sl.apply { 94 sl.apply {
97 add( 95 add(
98 SwitchSetting( 96 SwitchSetting(
@@ -131,7 +129,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
131 } 129 }
132 130
133 private fun addSystemSettings(sl: ArrayList<SettingsItem>) { 131 private fun addSystemSettings(sl: ArrayList<SettingsItem>) {
134 settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.preferences_system)) 132 settingsViewModel.setToolbarTitle(context.getString(R.string.preferences_system))
135 sl.apply { 133 sl.apply {
136 add( 134 add(
137 SwitchSetting( 135 SwitchSetting(
@@ -170,7 +168,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
170 } 168 }
171 169
172 private fun addGraphicsSettings(sl: ArrayList<SettingsItem>) { 170 private fun addGraphicsSettings(sl: ArrayList<SettingsItem>) {
173 settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.preferences_graphics)) 171 settingsViewModel.setToolbarTitle(context.getString(R.string.preferences_graphics))
174 sl.apply { 172 sl.apply {
175 add( 173 add(
176 SingleChoiceSetting( 174 SingleChoiceSetting(
@@ -267,7 +265,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
267 } 265 }
268 266
269 private fun addAudioSettings(sl: ArrayList<SettingsItem>) { 267 private fun addAudioSettings(sl: ArrayList<SettingsItem>) {
270 settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.preferences_audio)) 268 settingsViewModel.setToolbarTitle(context.getString(R.string.preferences_audio))
271 sl.apply { 269 sl.apply {
272 add( 270 add(
273 SingleChoiceSetting( 271 SingleChoiceSetting(
@@ -292,7 +290,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
292 } 290 }
293 291
294 private fun addThemeSettings(sl: ArrayList<SettingsItem>) { 292 private fun addThemeSettings(sl: ArrayList<SettingsItem>) {
295 settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.preferences_theme)) 293 settingsViewModel.setToolbarTitle(context.getString(R.string.preferences_theme))
296 sl.apply { 294 sl.apply {
297 val theme: AbstractIntSetting = object : AbstractIntSetting { 295 val theme: AbstractIntSetting = object : AbstractIntSetting {
298 override val int: Int 296 override val int: Int
@@ -302,7 +300,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
302 preferences.edit() 300 preferences.edit()
303 .putInt(Settings.PREF_THEME, value) 301 .putInt(Settings.PREF_THEME, value)
304 .apply() 302 .apply()
305 settingsActivity.recreate() 303 settingsViewModel.setShouldRecreate(true)
306 } 304 }
307 305
308 override val key: String? = null 306 override val key: String? = null
@@ -346,7 +344,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
346 preferences.edit() 344 preferences.edit()
347 .putInt(Settings.PREF_THEME_MODE, value) 345 .putInt(Settings.PREF_THEME_MODE, value)
348 .apply() 346 .apply()
349 ThemeHelper.setThemeMode(settingsActivity) 347 settingsViewModel.setShouldRecreate(true)
350 } 348 }
351 349
352 override val key: String? = null 350 override val key: String? = null
@@ -357,6 +355,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
357 preferences.edit() 355 preferences.edit()
358 .putInt(Settings.PREF_BLACK_BACKGROUNDS, defaultValue) 356 .putInt(Settings.PREF_BLACK_BACKGROUNDS, defaultValue)
359 .apply() 357 .apply()
358 settingsViewModel.setShouldRecreate(true)
360 } 359 }
361 } 360 }
362 361
@@ -378,7 +377,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
378 preferences.edit() 377 preferences.edit()
379 .putBoolean(Settings.PREF_BLACK_BACKGROUNDS, value) 378 .putBoolean(Settings.PREF_BLACK_BACKGROUNDS, value)
380 .apply() 379 .apply()
381 settingsActivity.recreate() 380 settingsViewModel.setShouldRecreate(true)
382 } 381 }
383 382
384 override val key: String? = null 383 override val key: String? = null
@@ -389,6 +388,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
389 preferences.edit() 388 preferences.edit()
390 .putBoolean(Settings.PREF_BLACK_BACKGROUNDS, defaultValue) 389 .putBoolean(Settings.PREF_BLACK_BACKGROUNDS, defaultValue)
391 .apply() 390 .apply()
391 settingsViewModel.setShouldRecreate(true)
392 } 392 }
393 } 393 }
394 394
@@ -403,7 +403,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
403 } 403 }
404 404
405 private fun addDebugSettings(sl: ArrayList<SettingsItem>) { 405 private fun addDebugSettings(sl: ArrayList<SettingsItem>) {
406 settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.preferences_debug)) 406 settingsViewModel.setToolbarTitle(context.getString(R.string.preferences_debug))
407 sl.apply { 407 sl.apply {
408 add(HeaderSetting(R.string.gpu)) 408 add(HeaderSetting(R.string.gpu))
409 add( 409 add(
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentView.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentView.kt
deleted file mode 100644
index a4d7a80aa..000000000
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentView.kt
+++ /dev/null
@@ -1,42 +0,0 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4package org.yuzu.yuzu_emu.features.settings.ui
5
6import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
7
8/**
9 * Abstraction for a screen showing a list of settings. Instances of
10 * this type of view will each display a layer of the setting hierarchy.
11 */
12interface SettingsFragmentView {
13 /**
14 * Pass an ArrayList to the View so that it can be displayed on screen.
15 *
16 * @param settingsList The result of converting the HashMap to an ArrayList
17 */
18 fun showSettingsList(settingsList: ArrayList<SettingsItem>)
19
20 /**
21 * Instructs the Fragment to load the settings screen.
22 */
23 fun loadSettingsList()
24
25 /**
26 * @return The Fragment's containing activity.
27 */
28 val activityView: SettingsActivityView?
29
30 /**
31 * Tell the Fragment to tell the containing Activity to show a new
32 * Fragment containing a submenu of settings.
33 *
34 * @param menuKey Identifier for the settings group that should be shown.
35 */
36 fun loadSubMenu(menuKey: String)
37
38 /**
39 * Have the fragment tell the containing Activity that a setting was modified.
40 */
41 fun onSettingChanged()
42}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
index 09e93a017..70df3af80 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
@@ -28,6 +28,7 @@ import androidx.fragment.app.Fragment
28import androidx.lifecycle.Lifecycle 28import androidx.lifecycle.Lifecycle
29import androidx.lifecycle.lifecycleScope 29import androidx.lifecycle.lifecycleScope
30import androidx.lifecycle.repeatOnLifecycle 30import androidx.lifecycle.repeatOnLifecycle
31import androidx.navigation.findNavController
31import androidx.navigation.fragment.navArgs 32import androidx.navigation.fragment.navArgs
32import androidx.preference.PreferenceManager 33import androidx.preference.PreferenceManager
33import androidx.window.layout.FoldingFeature 34import androidx.window.layout.FoldingFeature
@@ -37,6 +38,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
37import com.google.android.material.slider.Slider 38import com.google.android.material.slider.Slider
38import kotlinx.coroutines.Dispatchers 39import kotlinx.coroutines.Dispatchers
39import kotlinx.coroutines.launch 40import kotlinx.coroutines.launch
41import org.yuzu.yuzu_emu.HomeNavigationDirections
40import org.yuzu.yuzu_emu.NativeLibrary 42import org.yuzu.yuzu_emu.NativeLibrary
41import org.yuzu.yuzu_emu.R 43import org.yuzu.yuzu_emu.R
42import org.yuzu.yuzu_emu.YuzuApplication 44import org.yuzu.yuzu_emu.YuzuApplication
@@ -45,7 +47,6 @@ import org.yuzu.yuzu_emu.databinding.DialogOverlayAdjustBinding
45import org.yuzu.yuzu_emu.databinding.FragmentEmulationBinding 47import org.yuzu.yuzu_emu.databinding.FragmentEmulationBinding
46import org.yuzu.yuzu_emu.features.settings.model.IntSetting 48import org.yuzu.yuzu_emu.features.settings.model.IntSetting
47import org.yuzu.yuzu_emu.features.settings.model.Settings 49import org.yuzu.yuzu_emu.features.settings.model.Settings
48import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity
49import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile 50import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
50import org.yuzu.yuzu_emu.overlay.InputOverlay 51import org.yuzu.yuzu_emu.overlay.InputOverlay
51import org.yuzu.yuzu_emu.utils.* 52import org.yuzu.yuzu_emu.utils.*
@@ -139,7 +140,11 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
139 } 140 }
140 141
141 R.id.menu_settings -> { 142 R.id.menu_settings -> {
142 SettingsActivity.launch(requireContext(), SettingsFile.FILE_NAME_CONFIG, "") 143 val action = HomeNavigationDirections.actionGlobalSettingsActivity(
144 null,
145 SettingsFile.FILE_NAME_CONFIG
146 )
147 binding.root.findNavController().navigate(action)
143 true 148 true
144 } 149 }
145 150
@@ -211,7 +216,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
211 override fun onResume() { 216 override fun onResume() {
212 super.onResume() 217 super.onResume()
213 if (!DirectoryInitialization.areDirectoriesReady) { 218 if (!DirectoryInitialization.areDirectoriesReady) {
214 DirectoryInitialization.start(requireContext()) 219 DirectoryInitialization.start()
215 } 220 }
216 221
217 updateScreenLayout() 222 updateScreenLayout()
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 d5e793491..cbbe14d22 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
@@ -25,17 +25,18 @@ import androidx.core.view.updatePadding
25import androidx.documentfile.provider.DocumentFile 25import androidx.documentfile.provider.DocumentFile
26import androidx.fragment.app.Fragment 26import androidx.fragment.app.Fragment
27import androidx.fragment.app.activityViewModels 27import androidx.fragment.app.activityViewModels
28import androidx.navigation.findNavController
28import androidx.navigation.fragment.findNavController 29import androidx.navigation.fragment.findNavController
29import androidx.recyclerview.widget.LinearLayoutManager 30import androidx.recyclerview.widget.LinearLayoutManager
30import com.google.android.material.dialog.MaterialAlertDialogBuilder 31import com.google.android.material.dialog.MaterialAlertDialogBuilder
31import com.google.android.material.transition.MaterialSharedAxis 32import com.google.android.material.transition.MaterialSharedAxis
32import org.yuzu.yuzu_emu.BuildConfig 33import org.yuzu.yuzu_emu.BuildConfig
34import org.yuzu.yuzu_emu.HomeNavigationDirections
33import org.yuzu.yuzu_emu.R 35import org.yuzu.yuzu_emu.R
34import org.yuzu.yuzu_emu.adapters.HomeSettingAdapter 36import org.yuzu.yuzu_emu.adapters.HomeSettingAdapter
35import org.yuzu.yuzu_emu.databinding.FragmentHomeSettingsBinding 37import org.yuzu.yuzu_emu.databinding.FragmentHomeSettingsBinding
36import org.yuzu.yuzu_emu.features.DocumentProvider 38import org.yuzu.yuzu_emu.features.DocumentProvider
37import org.yuzu.yuzu_emu.features.settings.model.Settings 39import org.yuzu.yuzu_emu.features.settings.model.Settings
38import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity
39import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile 40import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
40import org.yuzu.yuzu_emu.model.HomeSetting 41import org.yuzu.yuzu_emu.model.HomeSetting
41import org.yuzu.yuzu_emu.model.HomeViewModel 42import org.yuzu.yuzu_emu.model.HomeViewModel
@@ -74,7 +75,13 @@ class HomeSettingsFragment : Fragment() {
74 R.string.advanced_settings, 75 R.string.advanced_settings,
75 R.string.settings_description, 76 R.string.settings_description,
76 R.drawable.ic_settings, 77 R.drawable.ic_settings,
77 { SettingsActivity.launch(requireContext(), SettingsFile.FILE_NAME_CONFIG, "") } 78 {
79 val action = HomeNavigationDirections.actionGlobalSettingsActivity(
80 null,
81 SettingsFile.FILE_NAME_CONFIG
82 )
83 binding.root.findNavController().navigate(action)
84 }
78 ) 85 )
79 ) 86 )
80 add( 87 add(
@@ -90,7 +97,13 @@ class HomeSettingsFragment : Fragment() {
90 R.string.preferences_theme, 97 R.string.preferences_theme,
91 R.string.theme_and_color_description, 98 R.string.theme_and_color_description,
92 R.drawable.ic_palette, 99 R.drawable.ic_palette,
93 { SettingsActivity.launch(requireContext(), Settings.SECTION_THEME, "") } 100 {
101 val action = HomeNavigationDirections.actionGlobalSettingsActivity(
102 null,
103 Settings.SECTION_THEME
104 )
105 binding.root.findNavController().navigate(action)
106 }
94 ) 107 )
95 ) 108 )
96 add( 109 add(
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/SettingsViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/SettingsViewModel.kt
new file mode 100644
index 000000000..1763341e2
--- /dev/null
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/SettingsViewModel.kt
@@ -0,0 +1,47 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4package org.yuzu.yuzu_emu.model
5
6import androidx.lifecycle.LiveData
7import androidx.lifecycle.MutableLiveData
8import androidx.lifecycle.ViewModel
9
10class SettingsViewModel : ViewModel() {
11 var game: Game? = null
12
13 var shouldSave = false
14
15 private val _toolbarTitle = MutableLiveData("")
16 val toolbarTitle: LiveData<String> get() = _toolbarTitle
17
18 private val _shouldRecreate = MutableLiveData(false)
19 val shouldRecreate: LiveData<Boolean> get() = _shouldRecreate
20
21 private val _shouldNavigateBack = MutableLiveData(false)
22 val shouldNavigateBack: LiveData<Boolean> get() = _shouldNavigateBack
23
24 private val _shouldShowResetSettingsDialog = MutableLiveData(false)
25 val shouldShowResetSettingsDialog: LiveData<Boolean> get() = _shouldShowResetSettingsDialog
26
27 fun setToolbarTitle(value: String) {
28 _toolbarTitle.value = value
29 }
30
31 fun setShouldRecreate(value: Boolean) {
32 _shouldRecreate.value = value
33 }
34
35 fun setShouldNavigateBack(value: Boolean) {
36 _shouldNavigateBack.value = value
37 }
38
39 fun setShouldShowResetSettingsDialog(value: Boolean) {
40 _shouldShowResetSettingsDialog.value = value
41 }
42
43 fun clear() {
44 game = null
45 shouldSave = false
46 }
47}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
index d8dbf1f45..7735452e5 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
@@ -33,13 +33,13 @@ import java.io.IOException
33import kotlinx.coroutines.Dispatchers 33import kotlinx.coroutines.Dispatchers
34import kotlinx.coroutines.launch 34import kotlinx.coroutines.launch
35import kotlinx.coroutines.withContext 35import kotlinx.coroutines.withContext
36import org.yuzu.yuzu_emu.HomeNavigationDirections
36import org.yuzu.yuzu_emu.NativeLibrary 37import org.yuzu.yuzu_emu.NativeLibrary
37import org.yuzu.yuzu_emu.R 38import org.yuzu.yuzu_emu.R
38import org.yuzu.yuzu_emu.activities.EmulationActivity 39import org.yuzu.yuzu_emu.activities.EmulationActivity
39import org.yuzu.yuzu_emu.databinding.ActivityMainBinding 40import org.yuzu.yuzu_emu.databinding.ActivityMainBinding
40import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding 41import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding
41import org.yuzu.yuzu_emu.features.settings.model.Settings 42import org.yuzu.yuzu_emu.features.settings.model.Settings
42import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity
43import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile 43import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
44import org.yuzu.yuzu_emu.fragments.IndeterminateProgressDialogFragment 44import org.yuzu.yuzu_emu.fragments.IndeterminateProgressDialogFragment
45import org.yuzu.yuzu_emu.fragments.LongMessageDialogFragment 45import org.yuzu.yuzu_emu.fragments.LongMessageDialogFragment
@@ -105,11 +105,13 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
105 when (it.itemId) { 105 when (it.itemId) {
106 R.id.gamesFragment -> gamesViewModel.setShouldScrollToTop(true) 106 R.id.gamesFragment -> gamesViewModel.setShouldScrollToTop(true)
107 R.id.searchFragment -> gamesViewModel.setSearchFocused(true) 107 R.id.searchFragment -> gamesViewModel.setSearchFocused(true)
108 R.id.homeSettingsFragment -> SettingsActivity.launch( 108 R.id.homeSettingsFragment -> {
109 this, 109 val action = HomeNavigationDirections.actionGlobalSettingsActivity(
110 SettingsFile.FILE_NAME_CONFIG, 110 null,
111 "" 111 SettingsFile.FILE_NAME_CONFIG
112 ) 112 )
113 navHostFragment.navController.navigate(action)
114 }
113 } 115 }
114 } 116 }
115 117
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 2ee63697e..3c9f6bad0 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,18 +3,18 @@
3 3
4package org.yuzu.yuzu_emu.utils 4package org.yuzu.yuzu_emu.utils
5 5
6import android.content.Context
7import java.io.IOException 6import java.io.IOException
8import org.yuzu.yuzu_emu.NativeLibrary 7import org.yuzu.yuzu_emu.NativeLibrary
8import org.yuzu.yuzu_emu.YuzuApplication
9 9
10object DirectoryInitialization { 10object DirectoryInitialization {
11 private var userPath: String? = null 11 private var userPath: String? = null
12 12
13 var areDirectoriesReady: Boolean = false 13 var areDirectoriesReady: Boolean = false
14 14
15 fun start(context: Context) { 15 fun start() {
16 if (!areDirectoriesReady) { 16 if (!areDirectoriesReady) {
17 initializeInternalStorage(context) 17 initializeInternalStorage()
18 NativeLibrary.initializeEmulation() 18 NativeLibrary.initializeEmulation()
19 areDirectoriesReady = true 19 areDirectoriesReady = true
20 } 20 }
@@ -26,9 +26,9 @@ object DirectoryInitialization {
26 return userPath 26 return userPath
27 } 27 }
28 28
29 private fun initializeInternalStorage(context: Context) { 29 private fun initializeInternalStorage() {
30 try { 30 try {
31 userPath = context.getExternalFilesDir(null)!!.canonicalPath 31 userPath = YuzuApplication.appContext.getExternalFilesDir(null)!!.canonicalPath
32 NativeLibrary.setAppDirectory(userPath!!) 32 NativeLibrary.setAppDirectory(userPath!!)
33 } catch (e: IOException) { 33 } catch (e: IOException) {
34 e.printStackTrace() 34 e.printStackTrace()
diff --git a/src/android/app/src/main/res/anim-ldrtl/anim_pop_settings_fragment_out.xml b/src/android/app/src/main/res/anim-ldrtl/anim_pop_settings_fragment_out.xml
deleted file mode 100644
index 9f49c133a..000000000
--- a/src/android/app/src/main/res/anim-ldrtl/anim_pop_settings_fragment_out.xml
+++ /dev/null
@@ -1,16 +0,0 @@
1<?xml version="1.0" encoding="utf-8"?>
2<set xmlns:android="http://schemas.android.com/apk/res/android">
3
4 <alpha
5 android:duration="125"
6 android:interpolator="@android:anim/decelerate_interpolator"
7 android:fromAlpha="1"
8 android:toAlpha="0" />
9
10 <translate
11 android:duration="125"
12 android:interpolator="@android:anim/decelerate_interpolator"
13 android:fromXDelta="0"
14 android:toXDelta="-75" />
15
16</set>
diff --git a/src/android/app/src/main/res/anim-ldrtl/anim_settings_fragment_in.xml b/src/android/app/src/main/res/anim-ldrtl/anim_settings_fragment_in.xml
deleted file mode 100644
index 82fd719db..000000000
--- a/src/android/app/src/main/res/anim-ldrtl/anim_settings_fragment_in.xml
+++ /dev/null
@@ -1,16 +0,0 @@
1<?xml version="1.0" encoding="utf-8"?>
2<set xmlns:android="http://schemas.android.com/apk/res/android">
3
4 <alpha
5 android:duration="@android:integer/config_shortAnimTime"
6 android:interpolator="@android:anim/decelerate_interpolator"
7 android:fromAlpha="0"
8 android:toAlpha="1" />
9
10 <translate
11 android:duration="@android:integer/config_shortAnimTime"
12 android:interpolator="@android:anim/decelerate_interpolator"
13 android:fromXDelta="-200"
14 android:toXDelta="0" />
15
16</set>
diff --git a/src/android/app/src/main/res/anim/anim_pop_settings_fragment_out.xml b/src/android/app/src/main/res/anim/anim_pop_settings_fragment_out.xml
deleted file mode 100644
index 5892128f1..000000000
--- a/src/android/app/src/main/res/anim/anim_pop_settings_fragment_out.xml
+++ /dev/null
@@ -1,16 +0,0 @@
1<?xml version="1.0" encoding="utf-8"?>
2<set xmlns:android="http://schemas.android.com/apk/res/android">
3
4 <alpha
5 android:duration="125"
6 android:interpolator="@android:anim/decelerate_interpolator"
7 android:fromAlpha="1"
8 android:toAlpha="0" />
9
10 <translate
11 android:duration="125"
12 android:interpolator="@android:anim/decelerate_interpolator"
13 android:fromXDelta="0"
14 android:toXDelta="75" />
15
16</set>
diff --git a/src/android/app/src/main/res/anim/anim_settings_fragment_in.xml b/src/android/app/src/main/res/anim/anim_settings_fragment_in.xml
deleted file mode 100644
index 98e0cf8bd..000000000
--- a/src/android/app/src/main/res/anim/anim_settings_fragment_in.xml
+++ /dev/null
@@ -1,16 +0,0 @@
1<?xml version="1.0" encoding="utf-8"?>
2<set xmlns:android="http://schemas.android.com/apk/res/android">
3
4 <alpha
5 android:duration="@android:integer/config_shortAnimTime"
6 android:interpolator="@android:anim/decelerate_interpolator"
7 android:fromAlpha="0"
8 android:toAlpha="1" />
9
10 <translate
11 android:duration="@android:integer/config_shortAnimTime"
12 android:interpolator="@android:anim/decelerate_interpolator"
13 android:fromXDelta="200"
14 android:toXDelta="0" />
15
16</set>
diff --git a/src/android/app/src/main/res/anim/anim_settings_fragment_out.xml b/src/android/app/src/main/res/anim/anim_settings_fragment_out.xml
deleted file mode 100644
index 77a40a4d1..000000000
--- a/src/android/app/src/main/res/anim/anim_settings_fragment_out.xml
+++ /dev/null
@@ -1,10 +0,0 @@
1<?xml version="1.0" encoding="utf-8"?>
2<set xmlns:android="http://schemas.android.com/apk/res/android">
3
4 <alpha
5 android:duration="@android:integer/config_shortAnimTime"
6 android:interpolator="@android:anim/decelerate_interpolator"
7 android:fromAlpha="1"
8 android:toAlpha="0" />
9
10</set>
diff --git a/src/android/app/src/main/res/animator/menu_slide_in_from_start.xml b/src/android/app/src/main/res/animator/menu_slide_in_from_start.xml
deleted file mode 100644
index 4612aee13..000000000
--- a/src/android/app/src/main/res/animator/menu_slide_in_from_start.xml
+++ /dev/null
@@ -1,20 +0,0 @@
1<?xml version="1.0" encoding="utf-8"?>
2<set xmlns:android="http://schemas.android.com/apk/res/android">
3
4 <objectAnimator
5 android:propertyName="translationX"
6 android:valueType="floatType"
7 android:valueFrom="-1280dp"
8 android:valueTo="0"
9 android:interpolator="@android:interpolator/decelerate_quad"
10 android:duration="300"/>
11
12 <objectAnimator
13 android:propertyName="alpha"
14 android:valueType="floatType"
15 android:valueFrom="0"
16 android:valueTo="1"
17 android:interpolator="@android:interpolator/accelerate_quad"
18 android:duration="300"/>
19
20</set> \ No newline at end of file
diff --git a/src/android/app/src/main/res/animator/menu_slide_out_to_start.xml b/src/android/app/src/main/res/animator/menu_slide_out_to_start.xml
deleted file mode 100644
index c00478946..000000000
--- a/src/android/app/src/main/res/animator/menu_slide_out_to_start.xml
+++ /dev/null
@@ -1,21 +0,0 @@
1<?xml version="1.0" encoding="utf-8"?>
2<set xmlns:android="http://schemas.android.com/apk/res/android">
3
4 <!-- This animation is used ONLY when a submenu is replaced. -->
5 <objectAnimator
6 android:propertyName="translationX"
7 android:valueType="floatType"
8 android:valueFrom="0"
9 android:valueTo="-1280dp"
10 android:interpolator="@android:interpolator/decelerate_quad"
11 android:duration="200"/>
12
13 <objectAnimator
14 android:propertyName="alpha"
15 android:valueType="floatType"
16 android:valueFrom="1"
17 android:valueTo="0"
18 android:interpolator="@android:interpolator/decelerate_quad"
19 android:duration="200"/>
20
21</set> \ No newline at end of file
diff --git a/src/android/app/src/main/res/layout/activity_settings.xml b/src/android/app/src/main/res/layout/activity_settings.xml
index 14ae83b04..8a026a30a 100644
--- a/src/android/app/src/main/res/layout/activity_settings.xml
+++ b/src/android/app/src/main/res/layout/activity_settings.xml
@@ -1,42 +1,24 @@
1<?xml version="1.0" encoding="utf-8"?> 1<?xml version="1.0" encoding="utf-8"?>
2<androidx.coordinatorlayout.widget.CoordinatorLayout 2<androidx.constraintlayout.widget.ConstraintLayout
3 android:id="@+id/coordinator_main"
4 xmlns:android="http://schemas.android.com/apk/res/android" 3 xmlns:android="http://schemas.android.com/apk/res/android"
5 xmlns:app="http://schemas.android.com/apk/res-auto" 4 xmlns:app="http://schemas.android.com/apk/res-auto"
5 xmlns:tools="http://schemas.android.com/tools"
6 android:id="@+id/constraint_settings"
6 android:layout_width="match_parent" 7 android:layout_width="match_parent"
7 android:layout_height="match_parent" 8 android:layout_height="match_parent"
8 android:background="?attr/colorSurface"> 9 android:background="?attr/colorSurface">
9 10
10 <com.google.android.material.appbar.AppBarLayout 11 <androidx.fragment.app.FragmentContainerView
11 android:id="@+id/appbar_settings" 12 android:id="@+id/fragment_container"
12 android:layout_width="match_parent" 13 android:name="androidx.navigation.fragment.NavHostFragment"
13 android:layout_height="wrap_content" 14 android:layout_width="0dp"
14 android:fitsSystemWindows="true" 15 android:layout_height="0dp"
15 app:elevation="0dp"> 16 app:defaultNavHost="true"
16 17 app:layout_constraintBottom_toBottomOf="parent"
17 <com.google.android.material.appbar.CollapsingToolbarLayout 18 app:layout_constraintLeft_toLeftOf="parent"
18 style="?attr/collapsingToolbarLayoutMediumStyle" 19 app:layout_constraintRight_toRightOf="parent"
19 android:id="@+id/toolbar_settings_layout" 20 app:layout_constraintTop_toTopOf="parent"
20 android:layout_width="match_parent" 21 tools:layout="@layout/fragment_settings" />
21 android:layout_height="?attr/collapsingToolbarLayoutMediumSize"
22 app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
23
24 <com.google.android.material.appbar.MaterialToolbar
25 android:id="@+id/toolbar_settings"
26 android:layout_width="match_parent"
27 android:layout_height="?attr/actionBarSize"
28 app:layout_collapseMode="pin" />
29
30 </com.google.android.material.appbar.CollapsingToolbarLayout>
31
32 </com.google.android.material.appbar.AppBarLayout>
33
34 <FrameLayout
35 android:id="@+id/frame_content"
36 android:layout_width="match_parent"
37 android:layout_height="match_parent"
38 android:layout_marginHorizontal="12dp"
39 app:layout_behavior="@string/appbar_scrolling_view_behavior" />
40 22
41 <View 23 <View
42 android:id="@+id/navigation_bar_shade" 24 android:id="@+id/navigation_bar_shade"
@@ -45,6 +27,8 @@
45 android:background="@android:color/transparent" 27 android:background="@android:color/transparent"
46 android:clickable="false" 28 android:clickable="false"
47 android:focusable="false" 29 android:focusable="false"
48 android:layout_gravity="bottom|center_horizontal" /> 30 app:layout_constraintBottom_toBottomOf="parent"
31 app:layout_constraintEnd_toEndOf="parent"
32 app:layout_constraintStart_toStartOf="parent" />
49 33
50</androidx.coordinatorlayout.widget.CoordinatorLayout> 34</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/src/android/app/src/main/res/layout/fragment_settings.xml b/src/android/app/src/main/res/layout/fragment_settings.xml
index 167720347..ebedbf1ec 100644
--- a/src/android/app/src/main/res/layout/fragment_settings.xml
+++ b/src/android/app/src/main/res/layout/fragment_settings.xml
@@ -1,14 +1,41 @@
1<?xml version="1.0" encoding="utf-8"?> 1<?xml version="1.0" encoding="utf-8"?>
2<FrameLayout 2<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 xmlns:android="http://schemas.android.com/apk/res/android" 3 xmlns:app="http://schemas.android.com/apk/res-auto"
4 android:id="@+id/coordinator_main"
4 android:layout_width="match_parent" 5 android:layout_width="match_parent"
5 android:layout_height="match_parent"> 6 android:layout_height="match_parent"
7 android:background="?attr/colorSurface">
8
9 <com.google.android.material.appbar.AppBarLayout
10 android:id="@+id/appbar_settings"
11 android:layout_width="match_parent"
12 android:layout_height="wrap_content"
13 android:fitsSystemWindows="true"
14 app:elevation="0dp">
15
16 <com.google.android.material.appbar.CollapsingToolbarLayout
17 android:id="@+id/toolbar_settings_layout"
18 style="?attr/collapsingToolbarLayoutMediumStyle"
19 android:layout_width="match_parent"
20 android:layout_height="?attr/collapsingToolbarLayoutMediumSize"
21 app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
22
23 <com.google.android.material.appbar.MaterialToolbar
24 android:id="@+id/toolbar_settings"
25 android:layout_width="match_parent"
26 android:layout_height="?attr/actionBarSize"
27 app:layout_collapseMode="pin"
28 app:navigationIcon="@drawable/ic_back" />
29
30 </com.google.android.material.appbar.CollapsingToolbarLayout>
31
32 </com.google.android.material.appbar.AppBarLayout>
6 33
7 <androidx.recyclerview.widget.RecyclerView 34 <androidx.recyclerview.widget.RecyclerView
8 android:id="@+id/list_settings" 35 android:id="@+id/list_settings"
9 android:layout_width="match_parent" 36 android:layout_width="match_parent"
10 android:layout_height="match_parent" 37 android:layout_height="match_parent"
11 android:background="?attr/colorSurface" 38 android:clipToPadding="false"
12 android:clipToPadding="false" /> 39 app:layout_behavior="@string/appbar_scrolling_view_behavior" />
13 40
14</FrameLayout> 41</androidx.coordinatorlayout.widget.CoordinatorLayout>
diff --git a/src/android/app/src/main/res/menu/menu_settings.xml b/src/android/app/src/main/res/menu/menu_settings.xml
deleted file mode 100644
index 1fe7aa6d4..000000000
--- a/src/android/app/src/main/res/menu/menu_settings.xml
+++ /dev/null
@@ -1,2 +0,0 @@
1<?xml version="1.0" encoding="utf-8"?>
2<menu /> \ No newline at end of file
diff --git a/src/android/app/src/main/res/navigation/emulation_navigation.xml b/src/android/app/src/main/res/navigation/emulation_navigation.xml
index 8208f4c2c..2a3c23d55 100644
--- a/src/android/app/src/main/res/navigation/emulation_navigation.xml
+++ b/src/android/app/src/main/res/navigation/emulation_navigation.xml
@@ -15,4 +15,21 @@
15 app:argType="org.yuzu.yuzu_emu.model.Game" /> 15 app:argType="org.yuzu.yuzu_emu.model.Game" />
16 </fragment> 16 </fragment>
17 17
18 <activity
19 android:id="@+id/settingsActivity"
20 android:name="org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity"
21 android:label="SettingsActivity">
22 <argument
23 android:name="game"
24 app:argType="org.yuzu.yuzu_emu.model.Game"
25 app:nullable="true" />
26 <argument
27 android:name="menuTag"
28 app:argType="string" />
29 </activity>
30
31 <action
32 android:id="@+id/action_global_settingsActivity"
33 app:destination="@id/settingsActivity" />
34
18</navigation> 35</navigation>
diff --git a/src/android/app/src/main/res/navigation/home_navigation.xml b/src/android/app/src/main/res/navigation/home_navigation.xml
index fcebba726..fb8e14448 100644
--- a/src/android/app/src/main/res/navigation/home_navigation.xml
+++ b/src/android/app/src/main/res/navigation/home_navigation.xml
@@ -70,4 +70,21 @@
70 app:destination="@id/emulationActivity" 70 app:destination="@id/emulationActivity"
71 app:launchSingleTop="true" /> 71 app:launchSingleTop="true" />
72 72
73 <activity
74 android:id="@+id/settingsActivity"
75 android:name="org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity"
76 android:label="SettingsActivity">
77 <argument
78 android:name="game"
79 app:argType="org.yuzu.yuzu_emu.model.Game"
80 app:nullable="true" />
81 <argument
82 android:name="menuTag"
83 app:argType="string" />
84 </activity>
85
86 <action
87 android:id="@+id/action_global_settingsActivity"
88 app:destination="@id/settingsActivity" />
89
73</navigation> 90</navigation>
diff --git a/src/android/app/src/main/res/navigation/settings_navigation.xml b/src/android/app/src/main/res/navigation/settings_navigation.xml
new file mode 100644
index 000000000..b36200c65
--- /dev/null
+++ b/src/android/app/src/main/res/navigation/settings_navigation.xml
@@ -0,0 +1,24 @@
1<?xml version="1.0" encoding="utf-8"?>
2<navigation xmlns:android="http://schemas.android.com/apk/res/android"
3 xmlns:app="http://schemas.android.com/apk/res-auto"
4 android:id="@+id/settings_navigation"
5 app:startDestination="@id/settingsFragment">
6
7 <fragment
8 android:id="@+id/settingsFragment"
9 android:name="org.yuzu.yuzu_emu.features.settings.ui.SettingsFragment"
10 android:label="SettingsFragment">
11 <argument
12 android:name="menuTag"
13 app:argType="string" />
14 <argument
15 android:name="game"
16 app:argType="org.yuzu.yuzu_emu.model.Game"
17 app:nullable="true" />
18 </fragment>
19
20 <action
21 android:id="@+id/action_global_settingsFragment"
22 app:destination="@id/settingsFragment" />
23
24</navigation>
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml
index df76563fc..6b782780a 100644
--- a/src/android/app/src/main/res/values/strings.xml
+++ b/src/android/app/src/main/res/values/strings.xml
@@ -74,6 +74,7 @@
74 <string name="install_gpu_driver">Install GPU driver</string> 74 <string name="install_gpu_driver">Install GPU driver</string>
75 <string name="install_gpu_driver_description">Install alternative drivers for potentially better performance or accuracy</string> 75 <string name="install_gpu_driver_description">Install alternative drivers for potentially better performance or accuracy</string>
76 <string name="advanced_settings">Advanced settings</string> 76 <string name="advanced_settings">Advanced settings</string>
77 <string name="advanced_settings_game">Advanced settings: %1$s</string>
77 <string name="settings_description">Configure emulator settings</string> 78 <string name="settings_description">Configure emulator settings</string>
78 <string name="search_recently_played">Recently played</string> 79 <string name="search_recently_played">Recently played</string>
79 <string name="search_recently_added">Recently added</string> 80 <string name="search_recently_added">Recently added</string>