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.
This commit is contained in:
parent
fd5c7b21dd
commit
45280a0342
|
@ -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<SettingsItem, SettingViewHolder>(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<SettingsItem, SettingViewHolder>(
|
||||
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<SettingsItem>() {
|
||||
override fun areItemsTheSame(oldItem: SettingsItem, newItem: SettingsItem): Boolean {
|
||||
return oldItem.setting.key == newItem.setting.key
|
||||
|
|
|
@ -123,11 +123,6 @@ class SettingsFragment : Fragment() {
|
|||
settingsViewModel.setIsUsingSearch(false)
|
||||
}
|
||||
|
||||
override fun onDetach() {
|
||||
super.onDetach()
|
||||
settingsAdapter?.closeDialog()
|
||||
}
|
||||
|
||||
private fun setInsets() {
|
||||
ViewCompat.setOnApplyWindowInsetsListener(
|
||||
binding.root
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
||||
override fun onDetach() {
|
||||
super.onDetach()
|
||||
settingsAdapter?.closeDialog()
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
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.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<String> get() = _toolbarTitle
|
||||
|
||||
|
@ -30,6 +36,12 @@ class SettingsViewModel : ViewModel() {
|
|||
private val _isUsingSearch = MutableLiveData(false)
|
||||
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) {
|
||||
_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"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue