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.
master
Charles Lombardo 2023-08-25 21:27:13 +07:00
parent fd5c7b21dd
commit 45280a0342
9 changed files with 319 additions and 198 deletions

@ -4,58 +4,54 @@
package org.yuzu.yuzu_emu.features.settings.ui package org.yuzu.yuzu_emu.features.settings.ui
import android.content.Context import android.content.Context
import android.content.DialogInterface
import android.icu.util.Calendar import android.icu.util.Calendar
import android.icu.util.TimeZone import android.icu.util.TimeZone
import android.text.format.DateFormat import android.text.format.DateFormat
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.findNavController import androidx.navigation.findNavController
import androidx.recyclerview.widget.AsyncDifferConfig import androidx.recyclerview.widget.AsyncDifferConfig
import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.ListAdapter
import com.google.android.material.datepicker.MaterialDatePicker 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.MaterialTimePicker
import com.google.android.material.timepicker.TimeFormat import com.google.android.material.timepicker.TimeFormat
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.SettingsNavigationDirections 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.ListItemSettingBinding
import org.yuzu.yuzu_emu.databinding.ListItemSettingSwitchBinding import org.yuzu.yuzu_emu.databinding.ListItemSettingSwitchBinding
import org.yuzu.yuzu_emu.databinding.ListItemSettingsHeaderBinding 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.model.view.*
import org.yuzu.yuzu_emu.features.settings.ui.viewholder.* import org.yuzu.yuzu_emu.features.settings.ui.viewholder.*
import org.yuzu.yuzu_emu.fragments.SettingsDialogFragment
import org.yuzu.yuzu_emu.model.SettingsViewModel import org.yuzu.yuzu_emu.model.SettingsViewModel
class SettingsAdapter( class SettingsAdapter(
private val fragment: Fragment, private val fragment: Fragment,
private val context: Context private val context: Context
) : ListAdapter<SettingsItem, SettingViewHolder>(AsyncDifferConfig.Builder(DiffCallback()).build()), ) : ListAdapter<SettingsItem, SettingViewHolder>(
DialogInterface.OnClickListener { AsyncDifferConfig.Builder(DiffCallback()).build()
private var clickedItem: SettingsItem? = null ) {
private var clickedPosition: Int
private var dialog: AlertDialog? = null
private var sliderProgress = 0
private var textSliderValue: TextView? = null
private val settingsViewModel: SettingsViewModel private val settingsViewModel: SettingsViewModel
get() = ViewModelProvider(fragment.requireActivity())[SettingsViewModel::class.java] get() = ViewModelProvider(fragment.requireActivity())[SettingsViewModel::class.java]
private var defaultCancelListener =
DialogInterface.OnClickListener { _: DialogInterface?, _: Int -> closeDialog() }
init { 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 { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SettingViewHolder {
@ -112,36 +108,25 @@ class SettingsAdapter(
settingsViewModel.shouldSave = true 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) { fun onSingleChoiceClick(item: SingleChoiceSetting, position: Int) {
clickedPosition = position SettingsDialogFragment.newInstance(
onSingleChoiceClick(item) settingsViewModel,
} item,
SettingsItem.TYPE_SINGLE_CHOICE,
private fun onStringSingleChoiceClick(item: StringSingleChoiceSetting) { position
clickedItem = item ).show(fragment.childFragmentManager, SettingsDialogFragment.TAG)
dialog = MaterialAlertDialogBuilder(context)
.setTitle(item.nameId)
.setSingleChoiceItems(item.choices, item.selectValueIndex, this)
.show()
} }
fun onStringSingleChoiceClick(item: StringSingleChoiceSetting, position: Int) { fun onStringSingleChoiceClick(item: StringSingleChoiceSetting, position: Int) {
clickedPosition = position SettingsDialogFragment.newInstance(
onStringSingleChoiceClick(item) settingsViewModel,
item,
SettingsItem.TYPE_STRING_SINGLE_CHOICE,
position
).show(fragment.childFragmentManager, SettingsDialogFragment.TAG)
} }
fun onDateTimeClick(item: DateTimeSetting, position: Int) { fun onDateTimeClick(item: DateTimeSetting, position: Int) {
clickedItem = item
clickedPosition = position
val storedTime = item.value * 1000 val storedTime = item.value * 1000
// Helper to extract hour and minute from epoch time // Helper to extract hour and minute from epoch time
@ -177,10 +162,9 @@ class SettingsAdapter(
epochTime += timePicker.minute.toLong() * 60 epochTime += timePicker.minute.toLong() * 60
if (item.value != epochTime) { if (item.value != epochTime) {
settingsViewModel.shouldSave = true settingsViewModel.shouldSave = true
notifyItemChanged(clickedPosition) notifyItemChanged(position)
item.value = epochTime item.value = epochTime
} }
clickedItem = null
} }
datePicker.show( datePicker.show(
fragment.childFragmentManager, fragment.childFragmentManager,
@ -189,40 +173,12 @@ class SettingsAdapter(
} }
fun onSliderClick(item: SliderSetting, position: Int) { fun onSliderClick(item: SliderSetting, position: Int) {
clickedItem = item SettingsDialogFragment.newInstance(
clickedPosition = position settingsViewModel,
sliderProgress = item.selectedValue as Int item,
SettingsItem.TYPE_SLIDER,
val inflater = LayoutInflater.from(context) position
val sliderBinding = DialogSliderBinding.inflate(inflater) ).show(fragment.childFragmentManager, SettingsDialogFragment.TAG)
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()
} }
fun onSubmenuClick(item: SubmenuSetting) { fun onSubmenuClick(item: SubmenuSetting) {
@ -230,112 +186,17 @@ class SettingsAdapter(
fragment.view?.findNavController()?.navigate(action) fragment.view?.findNavController()?.navigate(action)
} }
override fun onClick(dialog: DialogInterface, which: Int) { fun onLongClick(item: SettingsItem, position: Int): Boolean {
when (clickedItem) { SettingsDialogFragment.newInstance(
is SingleChoiceSetting -> { settingsViewModel,
val scSetting = clickedItem as SingleChoiceSetting item,
val value = getValueForSingleChoiceSelection(scSetting, which) SettingsDialogFragment.TYPE_RESET_SETTING,
if (scSetting.selectedValue != value) { position
settingsViewModel.shouldSave = true ).show(fragment.childFragmentManager, SettingsDialogFragment.TAG)
}
// 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()
return true 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<SettingsItem>() { private class DiffCallback : DiffUtil.ItemCallback<SettingsItem>() {
override fun areItemsTheSame(oldItem: SettingsItem, newItem: SettingsItem): Boolean { override fun areItemsTheSame(oldItem: SettingsItem, newItem: SettingsItem): Boolean {
return oldItem.setting.key == newItem.setting.key return oldItem.setting.key == newItem.setting.key

@ -123,11 +123,6 @@ class SettingsFragment : Fragment() {
settingsViewModel.setIsUsingSearch(false) settingsViewModel.setIsUsingSearch(false)
} }
override fun onDetach() {
super.onDetach()
settingsAdapter?.closeDialog()
}
private fun setInsets() { private fun setInsets() {
ViewCompat.setOnApplyWindowInsetsListener( ViewCompat.setOnApplyWindowInsetsListener(
binding.root binding.root

@ -46,7 +46,7 @@ class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA
override fun onLongClick(clicked: View): Boolean { override fun onLongClick(clicked: View): Boolean {
if (setting.isEditable) { if (setting.isEditable) {
return adapter.onLongClick(setting.setting, bindingAdapterPosition) return adapter.onLongClick(setting, bindingAdapterPosition)
} }
return false return false
} }

@ -66,7 +66,7 @@ class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: Setti
override fun onLongClick(clicked: View): Boolean { override fun onLongClick(clicked: View): Boolean {
if (setting.isEditable) { if (setting.isEditable) {
return adapter.onLongClick(setting.setting, bindingAdapterPosition) return adapter.onLongClick(setting, bindingAdapterPosition)
} }
return false return false
} }

@ -41,7 +41,7 @@ class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAda
override fun onLongClick(clicked: View): Boolean { override fun onLongClick(clicked: View): Boolean {
if (setting.isEditable) { if (setting.isEditable) {
return adapter.onLongClick(setting.setting, bindingAdapterPosition) return adapter.onLongClick(setting, bindingAdapterPosition)
} }
return false return false
} }

@ -43,7 +43,7 @@ class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter
override fun onLongClick(clicked: View): Boolean { override fun onLongClick(clicked: View): Boolean {
if (setting.isEditable) { if (setting.isEditable) {
return adapter.onLongClick(setting.setting, bindingAdapterPosition) return adapter.onLongClick(setting, bindingAdapterPosition)
} }
return false return false
} }

@ -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
}
}
}

@ -91,11 +91,6 @@ class SettingsSearchFragment : Fragment() {
setInsets() setInsets()
} }
override fun onDetach() {
super.onDetach()
settingsAdapter?.closeDialog()
}
override fun onSaveInstanceState(outState: Bundle) { override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState) super.onSaveInstanceState(outState)
outState.putString(SEARCH_TEXT, binding.searchText.text.toString()) outState.putString(SEARCH_TEXT, binding.searchText.text.toString())

@ -5,13 +5,19 @@ package org.yuzu.yuzu_emu.model
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel 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 game: Game? = null
var shouldSave = false var shouldSave = false
var clickedItem: SettingsItem? = null
private val _toolbarTitle = MutableLiveData("") private val _toolbarTitle = MutableLiveData("")
val toolbarTitle: LiveData<String> get() = _toolbarTitle val toolbarTitle: LiveData<String> get() = _toolbarTitle
@ -30,6 +36,12 @@ class SettingsViewModel : ViewModel() {
private val _isUsingSearch = MutableLiveData(false) private val _isUsingSearch = MutableLiveData(false)
val isUsingSearch: LiveData<Boolean> get() = _isUsingSearch val isUsingSearch: LiveData<Boolean> 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) { fun setToolbarTitle(value: String) {
_toolbarTitle.value = value _toolbarTitle.value = value
} }
@ -54,8 +66,31 @@ class SettingsViewModel : ViewModel() {
_isUsingSearch.value = value _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() { fun clear() {
game = null game = null
shouldSave = false shouldSave = false
} }
companion object {
const val KEY_SLIDER_TEXT_VALUE = "SliderTextValue"
const val KEY_SLIDER_PROGRESS = "SliderProgress"
const val KEY_ADAPTER_ITEM_CHANGED = "AdapterItemChanged"
}
} }