From 45280a03420d4cdc2fb491b21d409f4101997bab Mon Sep 17 00:00:00 2001 From: Charles Lombardo Date: Fri, 25 Aug 2023 21:27:13 -0400 Subject: [PATCH] android: Proper state restoration on settings dialogs All dialog code (except for the Date/Time ones) has been extracted out into a generic settings dialog fragment that handles everything through a viewmodel. State for each dialog will now be retained and dialogs will stay shown through configuration changes. I won't be changing the current state of the date and time dialog fragments until Google decides to make their classes non-final or if/when we migrate to Jetpack Compose. --- .../features/settings/ui/SettingsAdapter.kt | 227 ++++------------- .../features/settings/ui/SettingsFragment.kt | 5 - .../ui/viewholder/DateTimeViewHolder.kt | 2 +- .../ui/viewholder/SingleChoiceViewHolder.kt | 2 +- .../ui/viewholder/SliderViewHolder.kt | 2 +- .../ui/viewholder/SwitchSettingViewHolder.kt | 2 +- .../fragments/SettingsDialogFragment.kt | 235 ++++++++++++++++++ .../fragments/SettingsSearchFragment.kt | 5 - .../yuzu/yuzu_emu/model/SettingsViewModel.kt | 37 ++- 9 files changed, 319 insertions(+), 198 deletions(-) create mode 100644 src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SettingsDialogFragment.kt 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 f5eba1222..a7a029fc1 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 @@ -4,58 +4,54 @@ package org.yuzu.yuzu_emu.features.settings.ui import android.content.Context -import android.content.DialogInterface import android.icu.util.Calendar import android.icu.util.TimeZone import android.text.format.DateFormat import android.view.LayoutInflater import android.view.ViewGroup -import android.widget.TextView -import androidx.appcompat.app.AlertDialog import androidx.fragment.app.Fragment +import androidx.lifecycle.Lifecycle import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle import androidx.navigation.findNavController import androidx.recyclerview.widget.AsyncDifferConfig import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import com.google.android.material.datepicker.MaterialDatePicker -import com.google.android.material.dialog.MaterialAlertDialogBuilder -import com.google.android.material.slider.Slider import com.google.android.material.timepicker.MaterialTimePicker import com.google.android.material.timepicker.TimeFormat +import kotlinx.coroutines.launch import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.SettingsNavigationDirections -import org.yuzu.yuzu_emu.databinding.DialogSliderBinding import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding import org.yuzu.yuzu_emu.databinding.ListItemSettingSwitchBinding import org.yuzu.yuzu_emu.databinding.ListItemSettingsHeaderBinding -import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting -import org.yuzu.yuzu_emu.features.settings.model.ByteSetting -import org.yuzu.yuzu_emu.features.settings.model.FloatSetting -import org.yuzu.yuzu_emu.features.settings.model.ShortSetting import org.yuzu.yuzu_emu.features.settings.model.view.* import org.yuzu.yuzu_emu.features.settings.ui.viewholder.* +import org.yuzu.yuzu_emu.fragments.SettingsDialogFragment import org.yuzu.yuzu_emu.model.SettingsViewModel class SettingsAdapter( private val fragment: Fragment, private val context: Context -) : ListAdapter(AsyncDifferConfig.Builder(DiffCallback()).build()), - DialogInterface.OnClickListener { - private var clickedItem: SettingsItem? = null - private var clickedPosition: Int - private var dialog: AlertDialog? = null - private var sliderProgress = 0 - private var textSliderValue: TextView? = null - +) : ListAdapter( + AsyncDifferConfig.Builder(DiffCallback()).build() +) { private val settingsViewModel: SettingsViewModel get() = ViewModelProvider(fragment.requireActivity())[SettingsViewModel::class.java] - private var defaultCancelListener = - DialogInterface.OnClickListener { _: DialogInterface?, _: Int -> closeDialog() } - init { - clickedPosition = -1 + fragment.viewLifecycleOwner.lifecycleScope.launch { + fragment.repeatOnLifecycle(Lifecycle.State.STARTED) { + settingsViewModel.adapterItemChanged.collect { + if (it != -1) { + notifyItemChanged(it) + settingsViewModel.setAdapterItemChanged(-1) + } + } + } + } } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SettingViewHolder { @@ -112,36 +108,25 @@ class SettingsAdapter( settingsViewModel.shouldSave = true } - private fun onSingleChoiceClick(item: SingleChoiceSetting) { - clickedItem = item - val value = getSelectionForSingleChoiceValue(item) - dialog = MaterialAlertDialogBuilder(context) - .setTitle(item.nameId) - .setSingleChoiceItems(item.choicesId, value, this) - .show() - } - fun onSingleChoiceClick(item: SingleChoiceSetting, position: Int) { - clickedPosition = position - onSingleChoiceClick(item) - } - - private fun onStringSingleChoiceClick(item: StringSingleChoiceSetting) { - clickedItem = item - dialog = MaterialAlertDialogBuilder(context) - .setTitle(item.nameId) - .setSingleChoiceItems(item.choices, item.selectValueIndex, this) - .show() + SettingsDialogFragment.newInstance( + settingsViewModel, + item, + SettingsItem.TYPE_SINGLE_CHOICE, + position + ).show(fragment.childFragmentManager, SettingsDialogFragment.TAG) } fun onStringSingleChoiceClick(item: StringSingleChoiceSetting, position: Int) { - clickedPosition = position - onStringSingleChoiceClick(item) + SettingsDialogFragment.newInstance( + settingsViewModel, + item, + SettingsItem.TYPE_STRING_SINGLE_CHOICE, + position + ).show(fragment.childFragmentManager, SettingsDialogFragment.TAG) } fun onDateTimeClick(item: DateTimeSetting, position: Int) { - clickedItem = item - clickedPosition = position val storedTime = item.value * 1000 // Helper to extract hour and minute from epoch time @@ -177,10 +162,9 @@ class SettingsAdapter( epochTime += timePicker.minute.toLong() * 60 if (item.value != epochTime) { settingsViewModel.shouldSave = true - notifyItemChanged(clickedPosition) + notifyItemChanged(position) item.value = epochTime } - clickedItem = null } datePicker.show( fragment.childFragmentManager, @@ -189,40 +173,12 @@ class SettingsAdapter( } fun onSliderClick(item: SliderSetting, position: Int) { - clickedItem = item - clickedPosition = position - sliderProgress = item.selectedValue as Int - - val inflater = LayoutInflater.from(context) - val sliderBinding = DialogSliderBinding.inflate(inflater) - - textSliderValue = sliderBinding.textValue - textSliderValue!!.text = String.format( - context.getString(R.string.value_with_units), - sliderProgress.toString(), - item.units - ) - - sliderBinding.slider.apply { - valueFrom = item.min.toFloat() - valueTo = item.max.toFloat() - value = sliderProgress.toFloat() - addOnChangeListener { _: Slider, value: Float, _: Boolean -> - sliderProgress = value.toInt() - textSliderValue!!.text = String.format( - context.getString(R.string.value_with_units), - sliderProgress.toString(), - item.units - ) - } - } - - dialog = MaterialAlertDialogBuilder(context) - .setTitle(item.nameId) - .setView(sliderBinding.root) - .setPositiveButton(android.R.string.ok, this) - .setNegativeButton(android.R.string.cancel, defaultCancelListener) - .show() + SettingsDialogFragment.newInstance( + settingsViewModel, + item, + SettingsItem.TYPE_SLIDER, + position + ).show(fragment.childFragmentManager, SettingsDialogFragment.TAG) } fun onSubmenuClick(item: SubmenuSetting) { @@ -230,112 +186,17 @@ class SettingsAdapter( fragment.view?.findNavController()?.navigate(action) } - override fun onClick(dialog: DialogInterface, which: Int) { - when (clickedItem) { - is SingleChoiceSetting -> { - val scSetting = clickedItem as SingleChoiceSetting - val value = getValueForSingleChoiceSelection(scSetting, which) - if (scSetting.selectedValue != value) { - settingsViewModel.shouldSave = true - } - - // Get the backing Setting, which may be null (if for example it was missing from the file) - scSetting.selectedValue = value - closeDialog() - } - - is StringSingleChoiceSetting -> { - val scSetting = clickedItem as StringSingleChoiceSetting - val value = scSetting.getValueAt(which) - if (scSetting.selectedValue != value) settingsViewModel.shouldSave = true - scSetting.selectedValue = value!! - closeDialog() - } - - is SliderSetting -> { - val sliderSetting = clickedItem as SliderSetting - if (sliderSetting.selectedValue != sliderProgress) { - settingsViewModel.shouldSave = true - } - when (sliderSetting.setting) { - is ByteSetting -> { - val value = sliderProgress.toByte() - sliderSetting.selectedValue = value.toInt() - } - - is ShortSetting -> { - val value = sliderProgress.toShort() - sliderSetting.selectedValue = value.toInt() - } - - is FloatSetting -> { - val value = sliderProgress.toFloat() - sliderSetting.selectedValue = value.toInt() - } - - else -> { - sliderSetting.selectedValue = sliderProgress - } - } - closeDialog() - } - } - clickedItem = null - sliderProgress = -1 - } - - fun onLongClick(setting: AbstractSetting, position: Int): Boolean { - MaterialAlertDialogBuilder(context) - .setMessage(R.string.reset_setting_confirmation) - .setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int -> - setting.reset() - notifyItemChanged(position) - settingsViewModel.shouldSave = true - } - .setNegativeButton(android.R.string.cancel, null) - .show() + fun onLongClick(item: SettingsItem, position: Int): Boolean { + SettingsDialogFragment.newInstance( + settingsViewModel, + item, + SettingsDialogFragment.TYPE_RESET_SETTING, + position + ).show(fragment.childFragmentManager, SettingsDialogFragment.TAG) return true } - fun closeDialog() { - if (dialog != null) { - if (clickedPosition != -1) { - notifyItemChanged(clickedPosition) - clickedPosition = -1 - } - dialog!!.dismiss() - dialog = null - } - } - - private fun getValueForSingleChoiceSelection(item: SingleChoiceSetting, which: Int): Int { - val valuesId = item.valuesId - return if (valuesId > 0) { - val valuesArray = context.resources.getIntArray(valuesId) - valuesArray[which] - } else { - which - } - } - - private fun getSelectionForSingleChoiceValue(item: SingleChoiceSetting): Int { - val value = item.selectedValue - val valuesId = item.valuesId - if (valuesId > 0) { - val valuesArray = context.resources.getIntArray(valuesId) - for (index in valuesArray.indices) { - val current = valuesArray[index] - if (current == value) { - return index - } - } - } else { - return value - } - return -1 - } - private class DiffCallback : DiffUtil.ItemCallback() { override fun areItemsTheSame(oldItem: SettingsItem, newItem: SettingsItem): Boolean { return oldItem.setting.key == newItem.setting.key 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 0ea587a88..bc319714c 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 @@ -123,11 +123,6 @@ class SettingsFragment : Fragment() { settingsViewModel.setIsUsingSearch(false) } - override fun onDetach() { - super.onDetach() - settingsAdapter?.closeDialog() - } - private fun setInsets() { ViewCompat.setOnApplyWindowInsetsListener( binding.root diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt index 68c0b24d6..525f013f8 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt @@ -46,7 +46,7 @@ class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA override fun onLongClick(clicked: View): Boolean { if (setting.isEditable) { - return adapter.onLongClick(setting.setting, bindingAdapterPosition) + return adapter.onLongClick(setting, bindingAdapterPosition) } return false } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.kt index a582c425b..80d1b22c1 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.kt @@ -66,7 +66,7 @@ class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: Setti override fun onLongClick(clicked: View): Boolean { if (setting.isEditable) { - return adapter.onLongClick(setting.setting, bindingAdapterPosition) + return adapter.onLongClick(setting, bindingAdapterPosition) } return false } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SliderViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SliderViewHolder.kt index d94a46262..b83c90100 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SliderViewHolder.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SliderViewHolder.kt @@ -41,7 +41,7 @@ class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAda override fun onLongClick(clicked: View): Boolean { if (setting.isEditable) { - return adapter.onLongClick(setting.setting, bindingAdapterPosition) + return adapter.onLongClick(setting, bindingAdapterPosition) } return false } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt index 0a37d3624..57fdeaa20 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt @@ -43,7 +43,7 @@ class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter override fun onLongClick(clicked: View): Boolean { if (setting.isEditable) { - return adapter.onLongClick(setting.setting, bindingAdapterPosition) + return adapter.onLongClick(setting, bindingAdapterPosition) } return false } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SettingsDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SettingsDialogFragment.kt new file mode 100644 index 000000000..d18ec6974 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SettingsDialogFragment.kt @@ -0,0 +1,235 @@ +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.yuzu.yuzu_emu.fragments + +import android.app.Dialog +import android.content.DialogInterface +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.DialogFragment +import androidx.fragment.app.activityViewModels +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.google.android.material.slider.Slider +import kotlinx.coroutines.launch +import org.yuzu.yuzu_emu.R +import org.yuzu.yuzu_emu.databinding.DialogSliderBinding +import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem +import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting +import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting +import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting +import org.yuzu.yuzu_emu.model.SettingsViewModel + +class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener { + private var type = 0 + private var position = 0 + + private var defaultCancelListener = + DialogInterface.OnClickListener { _: DialogInterface?, _: Int -> closeDialog() } + + private val settingsViewModel: SettingsViewModel by activityViewModels() + + private lateinit var sliderBinding: DialogSliderBinding + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + type = requireArguments().getInt(TYPE) + position = requireArguments().getInt(POSITION) + + if (settingsViewModel.clickedItem == null) dismiss() + } + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + return when (type) { + TYPE_RESET_SETTING -> { + MaterialAlertDialogBuilder(requireContext()) + .setMessage(R.string.reset_setting_confirmation) + .setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int -> + settingsViewModel.clickedItem!!.setting.reset() + settingsViewModel.setAdapterItemChanged(position) + settingsViewModel.shouldSave = true + } + .setNegativeButton(android.R.string.cancel, null) + .create() + } + + SettingsItem.TYPE_SINGLE_CHOICE -> { + val item = settingsViewModel.clickedItem as SingleChoiceSetting + val value = getSelectionForSingleChoiceValue(item) + MaterialAlertDialogBuilder(requireContext()) + .setTitle(item.nameId) + .setSingleChoiceItems(item.choicesId, value, this) + .create() + } + + SettingsItem.TYPE_SLIDER -> { + sliderBinding = DialogSliderBinding.inflate(layoutInflater) + val item = settingsViewModel.clickedItem as SliderSetting + + settingsViewModel.setSliderTextValue(item.selectedValue.toFloat(), item.units) + sliderBinding.slider.apply { + valueFrom = item.min.toFloat() + valueTo = item.max.toFloat() + value = settingsViewModel.sliderProgress.value.toFloat() + addOnChangeListener { _: Slider, value: Float, _: Boolean -> + settingsViewModel.setSliderTextValue(value, item.units) + } + } + + MaterialAlertDialogBuilder(requireContext()) + .setTitle(item.nameId) + .setView(sliderBinding.root) + .setPositiveButton(android.R.string.ok, this) + .setNegativeButton(android.R.string.cancel, defaultCancelListener) + .create() + } + + SettingsItem.TYPE_STRING_SINGLE_CHOICE -> { + val item = settingsViewModel.clickedItem as StringSingleChoiceSetting + MaterialAlertDialogBuilder(requireContext()) + .setTitle(item.nameId) + .setSingleChoiceItems(item.choices, item.selectValueIndex, this) + .create() + } + + else -> super.onCreateDialog(savedInstanceState) + } + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + return when (type) { + SettingsItem.TYPE_SLIDER -> sliderBinding.root + else -> super.onCreateView(inflater, container, savedInstanceState) + } + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + when (type) { + SettingsItem.TYPE_SLIDER -> { + viewLifecycleOwner.lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.CREATED) { + settingsViewModel.sliderTextValue.collect { + sliderBinding.textValue.text = it + } + } + repeatOnLifecycle(Lifecycle.State.CREATED) { + settingsViewModel.sliderProgress.collect { + sliderBinding.slider.value = it.toFloat() + } + } + } + } + } + } + + override fun onClick(dialog: DialogInterface, which: Int) { + when (settingsViewModel.clickedItem) { + is SingleChoiceSetting -> { + val scSetting = settingsViewModel.clickedItem as SingleChoiceSetting + val value = getValueForSingleChoiceSelection(scSetting, which) + if (scSetting.selectedValue != value) { + settingsViewModel.shouldSave = true + } + scSetting.selectedValue = value + } + + is StringSingleChoiceSetting -> { + val scSetting = settingsViewModel.clickedItem as StringSingleChoiceSetting + val value = scSetting.getValueAt(which) + if (scSetting.selectedValue != value) settingsViewModel.shouldSave = true + scSetting.selectedValue = value + } + + is SliderSetting -> { + val sliderSetting = settingsViewModel.clickedItem as SliderSetting + if (sliderSetting.selectedValue != settingsViewModel.sliderProgress.value) { + settingsViewModel.shouldSave = true + } + sliderSetting.selectedValue = settingsViewModel.sliderProgress.value + } + } + closeDialog() + } + + private fun closeDialog() { + settingsViewModel.setAdapterItemChanged(position) + settingsViewModel.clickedItem = null + settingsViewModel.setSliderProgress(-1f) + dismiss() + } + + private fun getValueForSingleChoiceSelection(item: SingleChoiceSetting, which: Int): Int { + val valuesId = item.valuesId + return if (valuesId > 0) { + val valuesArray = requireContext().resources.getIntArray(valuesId) + valuesArray[which] + } else { + which + } + } + + private fun getSelectionForSingleChoiceValue(item: SingleChoiceSetting): Int { + val value = item.selectedValue + val valuesId = item.valuesId + if (valuesId > 0) { + val valuesArray = requireContext().resources.getIntArray(valuesId) + for (index in valuesArray.indices) { + val current = valuesArray[index] + if (current == value) { + return index + } + } + } else { + return value + } + return -1 + } + + companion object { + const val TAG = "SettingsDialogFragment" + + const val TYPE_RESET_SETTING = -1 + + const val TITLE = "Title" + const val TYPE = "Type" + const val POSITION = "Position" + + fun newInstance( + settingsViewModel: SettingsViewModel, + clickedItem: SettingsItem, + type: Int, + position: Int + ): SettingsDialogFragment { + when (type) { + SettingsItem.TYPE_HEADER, + SettingsItem.TYPE_SWITCH, + SettingsItem.TYPE_SUBMENU, + SettingsItem.TYPE_DATETIME_SETTING, + SettingsItem.TYPE_RUNNABLE -> + throw IllegalArgumentException("[SettingsDialogFragment] Incompatible type!") + + SettingsItem.TYPE_SLIDER -> settingsViewModel.setSliderProgress( + (clickedItem as SliderSetting).selectedValue.toFloat() + ) + } + settingsViewModel.clickedItem = clickedItem + + val args = Bundle() + args.putInt(TYPE, type) + args.putInt(POSITION, position) + val fragment = SettingsDialogFragment() + fragment.arguments = args + return fragment + } + } +} diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SettingsSearchFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SettingsSearchFragment.kt index 4f93db4ad..55b6a0367 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SettingsSearchFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SettingsSearchFragment.kt @@ -91,11 +91,6 @@ class SettingsSearchFragment : Fragment() { setInsets() } - override fun onDetach() { - super.onDetach() - settingsAdapter?.closeDialog() - } - override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putString(SEARCH_TEXT, binding.searchText.text.toString()) 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 index a0cb7225f..d16d15fa6 100644 --- 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 @@ -5,13 +5,19 @@ package org.yuzu.yuzu_emu.model import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel +import org.yuzu.yuzu_emu.R +import org.yuzu.yuzu_emu.YuzuApplication +import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem -class SettingsViewModel : ViewModel() { +class SettingsViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() { var game: Game? = null var shouldSave = false + var clickedItem: SettingsItem? = null + private val _toolbarTitle = MutableLiveData("") val toolbarTitle: LiveData get() = _toolbarTitle @@ -30,6 +36,12 @@ class SettingsViewModel : ViewModel() { private val _isUsingSearch = MutableLiveData(false) val isUsingSearch: LiveData get() = _isUsingSearch + val sliderProgress = savedStateHandle.getStateFlow(KEY_SLIDER_PROGRESS, -1) + + val sliderTextValue = savedStateHandle.getStateFlow(KEY_SLIDER_TEXT_VALUE, "") + + val adapterItemChanged = savedStateHandle.getStateFlow(KEY_ADAPTER_ITEM_CHANGED, -1) + fun setToolbarTitle(value: String) { _toolbarTitle.value = value } @@ -54,8 +66,31 @@ class SettingsViewModel : ViewModel() { _isUsingSearch.value = value } + fun setSliderTextValue(value: Float, units: String) { + savedStateHandle[KEY_SLIDER_PROGRESS] = value + savedStateHandle[KEY_SLIDER_TEXT_VALUE] = String.format( + YuzuApplication.appContext.getString(R.string.value_with_units), + value.toInt().toString(), + units + ) + } + + fun setSliderProgress(value: Float) { + savedStateHandle[KEY_SLIDER_PROGRESS] = value + } + + fun setAdapterItemChanged(value: Int) { + savedStateHandle[KEY_ADAPTER_ITEM_CHANGED] = value + } + fun clear() { game = null shouldSave = false } + + companion object { + const val KEY_SLIDER_TEXT_VALUE = "SliderTextValue" + const val KEY_SLIDER_PROGRESS = "SliderProgress" + const val KEY_ADAPTER_ITEM_CHANGED = "AdapterItemChanged" + } }