Use MaterialAlertDialogBuilder in PreferenceDialogFragments

`PreferenceDialogFragment`s have been extended to use `MaterialAlertDialogBuilder`, which results in Material Design 3 dialogs. `DialogFragment` creation logic has been moved to `SettingsActivity` to reduce code duplication.
This commit is contained in:
lynxnb 2023-03-07 23:35:35 +01:00 committed by Niccolò Betto
parent a4a5bedeea
commit d3d22670f9
7 changed files with 243 additions and 45 deletions

View File

@ -199,7 +199,7 @@ open class IntegerListPreference @JvmOverloads constructor(
}
}
class IntegerListPreferenceDialogFragmentCompat : PreferenceDialogFragmentCompat() {
open class IntegerListPreferenceDialogFragmentCompat : PreferenceDialogFragmentCompat() {
var clickedDialogEntryIndex = 0
private var entries : Array<CharSequence>? = null
private var entryValues : IntArray? = null
@ -259,9 +259,9 @@ open class IntegerListPreference @JvmOverloads constructor(
}
companion object {
private const val SAVE_STATE_INDEX = "ListPreferenceDialogFragment.index"
private const val SAVE_STATE_ENTRIES = "ListPreferenceDialogFragment.entries"
private const val SAVE_STATE_ENTRY_VALUES = "ListPreferenceDialogFragment.entryValues"
private const val SAVE_STATE_INDEX = "IntegerListPreferenceDialogFragment.index"
private const val SAVE_STATE_ENTRIES = "IntegerListPreferenceDialogFragment.entries"
private const val SAVE_STATE_ENTRY_VALUES = "IntegerListPreferenceDialogFragment.entryValues"
fun newInstance(key : String?) : IntegerListPreferenceDialogFragmentCompat {
val fragment = IntegerListPreferenceDialogFragmentCompat()

View File

@ -0,0 +1,64 @@
/*
* SPDX-License-Identifier: MPL-2.0
* Copyright © 2023 Skyline Team and Contributors (https://github.com/skyline-emu/)
*/
@file:SuppressLint("RestrictedApi")
package emu.skyline.preference.dialog
import android.annotation.SuppressLint
import android.app.Dialog
import android.os.Build
import android.os.Bundle
import android.view.WindowInsets
import androidx.preference.EditTextPreferenceDialogFragmentCompat
import com.google.android.material.dialog.MaterialAlertDialogBuilder
/**
* An [EditTextPreferenceDialogFragmentCompat] that uses [MaterialAlertDialogBuilder]
*/
class EditTextPreferenceMaterialDialogFragmentCompat : EditTextPreferenceDialogFragmentCompat() {
override fun onCreateDialog(savedInstanceState : Bundle?) : Dialog {
val builder = MaterialAlertDialogBuilder(requireContext())
.setTitle(preference.dialogTitle)
.setIcon(preference.dialogIcon)
.setPositiveButton(preference.positiveButtonText, this)
.setNegativeButton(preference.negativeButtonText, this)
val contentView = onCreateDialogView(requireContext())
if (contentView != null) {
onBindDialogView(contentView)
builder.setView(contentView)
} else {
builder.setMessage(preference.dialogMessage)
}
onPrepareDialogBuilder(builder)
// Create the dialog
val dialog : Dialog = builder.create()
if (needInputMethod()) {
requestInputMethod(dialog)
}
return dialog
}
private fun requestInputMethod(dialog : Dialog) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
dialog.window?.decorView?.windowInsetsController?.show(WindowInsets.Type.ime())
else
scheduleShowSoftInput()
}
companion object {
fun newInstance(key : String?) : EditTextPreferenceMaterialDialogFragmentCompat {
val fragment = EditTextPreferenceMaterialDialogFragmentCompat()
val bundle = Bundle(1)
bundle.putString(ARG_KEY, key)
fragment.arguments = bundle
return fragment
}
}
}

View File

@ -0,0 +1,64 @@
/*
* SPDX-License-Identifier: MPL-2.0
* Copyright © 2023 Skyline Team and Contributors (https://github.com/skyline-emu/)
*/
@file:SuppressLint("RestrictedApi")
package emu.skyline.preference.dialog
import android.annotation.SuppressLint
import android.app.Dialog
import android.os.Build
import android.os.Bundle
import android.view.WindowInsets
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import emu.skyline.preference.IntegerListPreference
/**
* An [IntegerListPreference.IntegerListPreferenceDialogFragmentCompat] that uses [MaterialAlertDialogBuilder]
*/
class IntegerListPreferenceMaterialDialogFragmentCompat : IntegerListPreference.IntegerListPreferenceDialogFragmentCompat() {
override fun onCreateDialog(savedInstanceState : Bundle?) : Dialog {
val builder = MaterialAlertDialogBuilder(requireContext())
.setTitle(preference.dialogTitle)
.setIcon(preference.dialogIcon)
.setPositiveButton(preference.positiveButtonText, this)
.setNegativeButton(preference.negativeButtonText, this)
val contentView = onCreateDialogView(requireContext())
if (contentView != null) {
onBindDialogView(contentView)
builder.setView(contentView)
} else {
builder.setMessage(preference.dialogMessage)
}
onPrepareDialogBuilder(builder)
// Create the dialog
val dialog : Dialog = builder.create()
if (needInputMethod()) {
requestInputMethod(dialog)
}
return dialog
}
private fun requestInputMethod(dialog : Dialog) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
dialog.window?.decorView?.windowInsetsController?.show(WindowInsets.Type.ime())
else
scheduleShowSoftInput()
}
companion object {
fun newInstance(key : String?) : IntegerListPreferenceMaterialDialogFragmentCompat {
val fragment = IntegerListPreferenceMaterialDialogFragmentCompat()
val bundle = Bundle(1)
bundle.putString(ARG_KEY, key)
fragment.arguments = bundle
return fragment
}
}
}

View File

@ -0,0 +1,64 @@
/*
* SPDX-License-Identifier: MPL-2.0
* Copyright © 2023 Skyline Team and Contributors (https://github.com/skyline-emu/)
*/
@file:SuppressLint("RestrictedApi")
package emu.skyline.preference.dialog
import android.annotation.SuppressLint
import android.app.Dialog
import android.os.Build
import android.os.Bundle
import android.view.WindowInsets
import androidx.preference.ListPreferenceDialogFragmentCompat
import com.google.android.material.dialog.MaterialAlertDialogBuilder
/**
* A [ListPreferenceDialogFragmentCompat] that uses [MaterialAlertDialogBuilder]
*/
class ListPreferenceMaterialDialogFragmentCompat : ListPreferenceDialogFragmentCompat() {
override fun onCreateDialog(savedInstanceState : Bundle?) : Dialog {
val builder = MaterialAlertDialogBuilder(requireContext())
.setTitle(preference.dialogTitle)
.setIcon(preference.dialogIcon)
.setPositiveButton(preference.positiveButtonText, this)
.setNegativeButton(preference.negativeButtonText, this)
val contentView = onCreateDialogView(requireContext())
if (contentView != null) {
onBindDialogView(contentView)
builder.setView(contentView)
} else {
builder.setMessage(preference.dialogMessage)
}
onPrepareDialogBuilder(builder)
// Create the dialog
val dialog : Dialog = builder.create()
if (needInputMethod()) {
requestInputMethod(dialog)
}
return dialog
}
private fun requestInputMethod(dialog : Dialog) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
dialog.window?.decorView?.windowInsetsController?.show(WindowInsets.Type.ime())
else
scheduleShowSoftInput()
}
companion object {
fun newInstance(key : String?) : ListPreferenceMaterialDialogFragmentCompat {
val fragment = ListPreferenceMaterialDialogFragmentCompat()
val bundle = Bundle(1)
bundle.putString(ARG_KEY, key)
fragment.arguments = bundle
return fragment
}
}
}

View File

@ -14,7 +14,6 @@ import emu.skyline.R
import emu.skyline.data.AppItem
import emu.skyline.data.AppItemTag
import emu.skyline.preference.GpuDriverPreference
import emu.skyline.preference.IntegerListPreference
import emu.skyline.utils.GpuDriverHelper
import emu.skyline.utils.WindowInsetsHelper
import emu.skyline.utils.serializable
@ -23,10 +22,6 @@ import emu.skyline.utils.serializable
* This fragment is used to display custom game preferences
*/
class GameSettingsFragment : PreferenceFragmentCompat() {
companion object {
private const val DIALOG_FRAGMENT_TAG = "androidx.preference.PreferenceFragment.DIALOG"
}
private val item by lazy { requireArguments().serializable<AppItem>(AppItemTag)!! }
override fun onViewCreated(view : View, savedInstanceState : Bundle?) {
@ -87,19 +82,4 @@ class GameSettingsFragment : PreferenceFragmentCompat() {
if (BuildConfig.BUILD_TYPE == "release")
findPreference<PreferenceCategory>("category_debug")?.isVisible = false
}
override fun onDisplayPreferenceDialog(preference : Preference) {
if (preference is IntegerListPreference) {
// Check if dialog is already showing
if (parentFragmentManager.findFragmentByTag(DIALOG_FRAGMENT_TAG) != null)
return
val dialogFragment = IntegerListPreference.IntegerListPreferenceDialogFragmentCompat.newInstance(preference.getKey())
@Suppress("DEPRECATION")
dialogFragment.setTargetFragment(this, 0) // androidx.preference.PreferenceDialogFragmentCompat depends on the target fragment being set correctly even though it's deprecated
dialogFragment.show(parentFragmentManager, DIALOG_FRAGMENT_TAG)
} else {
super.onDisplayPreferenceDialog(preference)
}
}
}

View File

@ -13,7 +13,6 @@ import androidx.preference.PreferenceFragmentCompat
import androidx.preference.TwoStatePreference
import emu.skyline.BuildConfig
import emu.skyline.R
import emu.skyline.preference.IntegerListPreference
import emu.skyline.utils.GpuDriverHelper
import emu.skyline.utils.WindowInsetsHelper
@ -21,10 +20,6 @@ import emu.skyline.utils.WindowInsetsHelper
* This fragment is used to display the global preferences
*/
class GlobalSettingsFragment : PreferenceFragmentCompat() {
companion object {
private const val DIALOG_FRAGMENT_TAG = "androidx.preference.PreferenceFragment.DIALOG"
}
override fun onViewCreated(view : View, savedInstanceState : Bundle?) {
super.onViewCreated(view, savedInstanceState)
val recyclerView = view.findViewById<View>(R.id.recycler_view)
@ -66,19 +61,4 @@ class GlobalSettingsFragment : PreferenceFragmentCompat() {
})
}
}
override fun onDisplayPreferenceDialog(preference : Preference) {
if (preference is IntegerListPreference) {
// Check if dialog is already showing
if (parentFragmentManager.findFragmentByTag(DIALOG_FRAGMENT_TAG) != null)
return
val dialogFragment = IntegerListPreference.IntegerListPreferenceDialogFragmentCompat.newInstance(preference.getKey())
@Suppress("DEPRECATION")
dialogFragment.setTargetFragment(this, 0) // androidx.preference.PreferenceDialogFragmentCompat depends on the target fragment being set correctly even though it's deprecated
dialogFragment.show(parentFragmentManager, DIALOG_FRAGMENT_TAG)
} else {
super.onDisplayPreferenceDialog(preference)
}
}
}

View File

@ -14,14 +14,23 @@ import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.WindowCompat
import androidx.preference.EditTextPreference
import androidx.preference.ListPreference
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import com.google.android.material.internal.ToolbarUtils
import emu.skyline.R
import emu.skyline.data.AppItemTag
import emu.skyline.databinding.SettingsActivityBinding
import emu.skyline.preference.IntegerListPreference
import emu.skyline.preference.dialog.EditTextPreferenceMaterialDialogFragmentCompat
import emu.skyline.preference.dialog.IntegerListPreferenceMaterialDialogFragmentCompat
import emu.skyline.preference.dialog.ListPreferenceMaterialDialogFragmentCompat
import emu.skyline.utils.WindowInsetsHelper
class SettingsActivity : AppCompatActivity() {
private const val PREFERENCE_DIALOG_FRAGMENT_TAG = "androidx.preference.PreferenceFragment.DIALOG"
class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPreferenceDisplayDialogCallback {
val binding by lazy { SettingsActivityBinding.inflate(layoutInflater) }
/**
@ -118,4 +127,41 @@ class SettingsActivity : AppCompatActivity() {
setResult(RESULT_OK)
super.finish()
}
override fun onPreferenceDisplayDialog(caller : PreferenceFragmentCompat, pref : Preference) : Boolean {
when (pref) {
is IntegerListPreference -> {
// Check if dialog is already showing
if (supportFragmentManager.findFragmentByTag(PREFERENCE_DIALOG_FRAGMENT_TAG) != null)
return true
val dialogFragment = IntegerListPreferenceMaterialDialogFragmentCompat.newInstance(pref.getKey())
@Suppress("DEPRECATION")
dialogFragment.setTargetFragment(caller, 0) // androidx.preference.PreferenceDialogFragmentCompat depends on the target fragment being set correctly even though it's deprecated
dialogFragment.show(supportFragmentManager, PREFERENCE_DIALOG_FRAGMENT_TAG)
return true
}
is EditTextPreference -> {
if (supportFragmentManager.findFragmentByTag(PREFERENCE_DIALOG_FRAGMENT_TAG) != null)
return true
val dialogFragment = EditTextPreferenceMaterialDialogFragmentCompat.newInstance(pref.getKey())
@Suppress("DEPRECATION")
dialogFragment.setTargetFragment(caller, 0)
dialogFragment.show(supportFragmentManager, PREFERENCE_DIALOG_FRAGMENT_TAG)
return true
}
is ListPreference -> {
if (supportFragmentManager.findFragmentByTag(PREFERENCE_DIALOG_FRAGMENT_TAG) != null)
return true
val dialogFragment = ListPreferenceMaterialDialogFragmentCompat.newInstance(pref.getKey())
@Suppress("DEPRECATION")
dialogFragment.setTargetFragment(caller, 0)
dialogFragment.show(supportFragmentManager, PREFERENCE_DIALOG_FRAGMENT_TAG)
return true
}
else -> return false
}
}
}