|
@@ -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()),
|
|
|
|
|
- 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
|
|
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
|
|
|
|
|
- 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) {
|
|
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) {
|
|
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
|
|
|
|
|
- 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) {
|
|
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) {
|
|
|
|
|
- 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
|
|
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
|