mirror of
https://github.com/Michatec/Radio.git
synced 2026-04-01 16:06:27 +02:00
feat(ui): implement theme selection dialog with TV support
This commit is contained in:
@@ -84,6 +84,7 @@ object Keys {
|
||||
const val DIALOG_REMOVE_STATION: Int = 2
|
||||
const val DIALOG_UPDATE_STATION_IMAGES: Int = 4
|
||||
const val DIALOG_RESTORE_COLLECTION: Int = 5
|
||||
const val DIALOG_THEME_SELECTION: Int = 6
|
||||
|
||||
// dialog results
|
||||
const val DIALOG_EMPTY_PAYLOAD_STRING: String = ""
|
||||
|
||||
@@ -5,6 +5,7 @@ import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
@@ -16,8 +17,10 @@ import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.net.toUri
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.preference.*
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.michatec.radio.dialogs.ErrorDialog
|
||||
import com.michatec.radio.dialogs.ThemeSelectionDialog
|
||||
import com.michatec.radio.dialogs.YesNoDialog
|
||||
import com.michatec.radio.helpers.*
|
||||
import com.michatec.radio.helpers.AppThemeHelper.getColor
|
||||
@@ -31,7 +34,7 @@ import java.util.*
|
||||
/*
|
||||
* SettingsFragment class
|
||||
*/
|
||||
class SettingsFragment : PreferenceFragmentCompat(), YesNoDialog.YesNoDialogListener {
|
||||
class SettingsFragment : PreferenceFragmentCompat(), YesNoDialog.YesNoDialogListener, ThemeSelectionDialog.ThemeSelectionDialogListener {
|
||||
|
||||
|
||||
/* Define log tag */
|
||||
@@ -55,35 +58,24 @@ class SettingsFragment : PreferenceFragmentCompat(), YesNoDialog.YesNoDialogList
|
||||
val screen = preferenceManager.createPreferenceScreen(context)
|
||||
|
||||
// set up "App Theme" preference
|
||||
val preferenceThemeSelection = ListPreference(activity as Context)
|
||||
val preferenceThemeSelection = Preference(activity as Context)
|
||||
preferenceThemeSelection.title = getString(R.string.pref_theme_selection_title)
|
||||
preferenceThemeSelection.setIcon(R.drawable.ic_brush_24dp)
|
||||
preferenceThemeSelection.key = Keys.PREF_THEME_SELECTION
|
||||
preferenceThemeSelection.summary = "${getString(R.string.pref_theme_selection_summary)} ${
|
||||
AppThemeHelper.getCurrentTheme(activity as Context)
|
||||
}"
|
||||
preferenceThemeSelection.entries = arrayOf(
|
||||
getString(R.string.pref_theme_selection_mode_device_default),
|
||||
getString(R.string.pref_theme_selection_mode_light),
|
||||
getString(R.string.pref_theme_selection_mode_dark)
|
||||
)
|
||||
preferenceThemeSelection.entryValues = arrayOf(
|
||||
Keys.STATE_THEME_FOLLOW_SYSTEM,
|
||||
Keys.STATE_THEME_LIGHT_MODE,
|
||||
Keys.STATE_THEME_DARK_MODE
|
||||
)
|
||||
preferenceThemeSelection.setDefaultValue(Keys.STATE_THEME_FOLLOW_SYSTEM)
|
||||
preferenceThemeSelection.setOnPreferenceChangeListener { preference, newValue ->
|
||||
if (preference is ListPreference) {
|
||||
val index: Int = preference.entryValues.indexOf(newValue)
|
||||
preferenceThemeSelection.summary =
|
||||
"${getString(R.string.pref_theme_selection_summary)} ${preference.entries[index]}"
|
||||
|
||||
AppThemeHelper.setTheme(newValue as String)
|
||||
return@setOnPreferenceChangeListener true
|
||||
preferenceThemeSelection.setOnPreferenceClickListener {
|
||||
// check if device is a TV
|
||||
val isTv = requireContext().packageManager.hasSystemFeature(android.content.pm.PackageManager.FEATURE_LEANBACK)
|
||||
if (isTv) {
|
||||
// show TV-specific theme selection dialog
|
||||
ThemeSelectionDialog(this).show(activity as Context)
|
||||
} else {
|
||||
return@setOnPreferenceChangeListener false
|
||||
// show standard theme selection dialog for non-TV devices
|
||||
showThemeSelectionDialog()
|
||||
}
|
||||
return@setOnPreferenceClickListener true
|
||||
}
|
||||
|
||||
// set up "Update Station Images" preference
|
||||
@@ -306,6 +298,57 @@ class SettingsFragment : PreferenceFragmentCompat(), YesNoDialog.YesNoDialogList
|
||||
}
|
||||
|
||||
|
||||
/* Shows theme selection dialog for non-TV devices */
|
||||
private fun showThemeSelectionDialog() {
|
||||
val themes = arrayOf(
|
||||
getString(R.string.pref_theme_selection_mode_device_default),
|
||||
getString(R.string.pref_theme_selection_mode_light),
|
||||
getString(R.string.pref_theme_selection_mode_dark)
|
||||
)
|
||||
val themeValues = arrayOf(
|
||||
Keys.STATE_THEME_FOLLOW_SYSTEM,
|
||||
Keys.STATE_THEME_LIGHT_MODE,
|
||||
Keys.STATE_THEME_DARK_MODE
|
||||
)
|
||||
val currentTheme = AppThemeHelper.getCurrentTheme(activity as Context)
|
||||
val currentIndex = themes.indexOf(currentTheme)
|
||||
|
||||
val builder = MaterialAlertDialogBuilder(activity as Context)
|
||||
builder.setTitle(getString(R.string.pref_theme_selection_title))
|
||||
builder.setSingleChoiceItems(themes, currentIndex) { dialog, which ->
|
||||
val selectedTheme = themeValues[which]
|
||||
AppThemeHelper.setTheme(selectedTheme)
|
||||
// update summary
|
||||
val preferenceThemeSelection = findPreference<Preference>(Keys.PREF_THEME_SELECTION)
|
||||
preferenceThemeSelection?.summary = "${getString(R.string.pref_theme_selection_summary)} ${themes[which]}"
|
||||
dialog.dismiss()
|
||||
}
|
||||
builder.setNegativeButton(R.string.dialog_generic_button_cancel, null)
|
||||
builder.show()
|
||||
}
|
||||
|
||||
|
||||
/* Overrides onThemeSelectionDialog from ThemeSelectionDialogListener */
|
||||
override fun onThemeSelectionDialog(dialogResult: Boolean, selectedTheme: String) {
|
||||
if (dialogResult) {
|
||||
// update summary
|
||||
val themes = arrayOf(
|
||||
getString(R.string.pref_theme_selection_mode_device_default),
|
||||
getString(R.string.pref_theme_selection_mode_light),
|
||||
getString(R.string.pref_theme_selection_mode_dark)
|
||||
)
|
||||
val themeValues = arrayOf(
|
||||
Keys.STATE_THEME_FOLLOW_SYSTEM,
|
||||
Keys.STATE_THEME_LIGHT_MODE,
|
||||
Keys.STATE_THEME_DARK_MODE
|
||||
)
|
||||
val index = themeValues.indexOf(selectedTheme)
|
||||
val preferenceThemeSelection = findPreference<Preference>(Keys.PREF_THEME_SELECTION)
|
||||
preferenceThemeSelection?.summary = "${getString(R.string.pref_theme_selection_summary)} ${themes[index]}"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Overrides onYesNoDialog from YesNoDialogListener */
|
||||
override fun onYesNoDialog(
|
||||
type: Int,
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
package com.michatec.radio.dialogs
|
||||
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.widget.RadioButton
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.michatec.radio.Keys
|
||||
import com.michatec.radio.R
|
||||
import com.michatec.radio.helpers.AppThemeHelper
|
||||
|
||||
|
||||
/*
|
||||
* ThemeSelectionDialog class
|
||||
*/
|
||||
class ThemeSelectionDialog(private var themeSelectionDialogListener: ThemeSelectionDialogListener) {
|
||||
|
||||
/* Interface used to communicate back to activity */
|
||||
interface ThemeSelectionDialogListener {
|
||||
fun onThemeSelectionDialog(dialogResult: Boolean, selectedTheme: String) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Main class variables */
|
||||
private lateinit var dialog: AlertDialog
|
||||
|
||||
|
||||
/* Construct and show dialog */
|
||||
fun show(context: Context) {
|
||||
// prepare dialog builder
|
||||
val builder = MaterialAlertDialogBuilder(context)
|
||||
|
||||
// inflate custom layout
|
||||
val inflater = LayoutInflater.from(context)
|
||||
val view = inflater.inflate(R.layout.dialog_theme_selection, null)
|
||||
|
||||
// find radio buttons
|
||||
val radioGroup = view.findViewById<android.widget.RadioGroup>(R.id.theme_radio_group)
|
||||
val radioFollowSystem = view.findViewById<RadioButton>(R.id.radio_theme_follow_system)
|
||||
val radioLight = view.findViewById<RadioButton>(R.id.radio_theme_light)
|
||||
val radioDark = view.findViewById<RadioButton>(R.id.radio_theme_dark)
|
||||
|
||||
// set current selection
|
||||
val currentTheme = AppThemeHelper.getCurrentTheme(context)
|
||||
when (currentTheme) {
|
||||
context.getString(R.string.pref_theme_selection_mode_device_default) -> {
|
||||
radioFollowSystem.isChecked = true
|
||||
}
|
||||
context.getString(R.string.pref_theme_selection_mode_light) -> {
|
||||
radioLight.isChecked = true
|
||||
}
|
||||
context.getString(R.string.pref_theme_selection_mode_dark) -> {
|
||||
radioDark.isChecked = true
|
||||
}
|
||||
}
|
||||
|
||||
// set up radio group listener
|
||||
radioGroup.setOnCheckedChangeListener { _, checkedId ->
|
||||
val selectedTheme = when (checkedId) {
|
||||
R.id.radio_theme_follow_system -> Keys.STATE_THEME_FOLLOW_SYSTEM
|
||||
R.id.radio_theme_light -> Keys.STATE_THEME_LIGHT_MODE
|
||||
R.id.radio_theme_dark -> Keys.STATE_THEME_DARK_MODE
|
||||
else -> Keys.STATE_THEME_FOLLOW_SYSTEM
|
||||
}
|
||||
// apply theme immediately
|
||||
AppThemeHelper.setTheme(selectedTheme)
|
||||
}
|
||||
|
||||
// set custom view
|
||||
builder.setView(view)
|
||||
|
||||
// add OK button
|
||||
builder.setPositiveButton(R.string.dialog_generic_button_ok) { _, _ ->
|
||||
// get selected theme
|
||||
val selectedTheme = when (radioGroup.checkedRadioButtonId) {
|
||||
R.id.radio_theme_follow_system -> Keys.STATE_THEME_FOLLOW_SYSTEM
|
||||
R.id.radio_theme_light -> Keys.STATE_THEME_LIGHT_MODE
|
||||
R.id.radio_theme_dark -> Keys.STATE_THEME_DARK_MODE
|
||||
else -> Keys.STATE_THEME_FOLLOW_SYSTEM
|
||||
}
|
||||
// notify listener
|
||||
themeSelectionDialogListener.onThemeSelectionDialog(true, selectedTheme)
|
||||
}
|
||||
|
||||
// add cancel button
|
||||
builder.setNegativeButton(R.string.dialog_generic_button_cancel) { _, _ ->
|
||||
// notify listener
|
||||
themeSelectionDialogListener.onThemeSelectionDialog(false, Keys.STATE_THEME_FOLLOW_SYSTEM)
|
||||
}
|
||||
|
||||
// handle outside-click as cancel
|
||||
builder.setOnCancelListener {
|
||||
themeSelectionDialogListener.onThemeSelectionDialog(false, Keys.STATE_THEME_FOLLOW_SYSTEM)
|
||||
}
|
||||
|
||||
// display dialog
|
||||
dialog = builder.create()
|
||||
dialog.show()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="24dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dialog_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/pref_theme_selection_title"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
android:paddingBottom="16dp" />
|
||||
|
||||
<RadioGroup
|
||||
android:id="@+id/theme_radio_group"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/radio_theme_follow_system"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/pref_theme_selection_mode_device_default"
|
||||
android:textSize="20sp"
|
||||
android:padding="12dp"
|
||||
android:button="@null"
|
||||
android:drawableStart="?android:attr/listChoiceIndicatorSingle"
|
||||
android:drawablePadding="16dp"
|
||||
android:focusable="true"
|
||||
android:clickable="true" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/radio_theme_light"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/pref_theme_selection_mode_light"
|
||||
android:textSize="20sp"
|
||||
android:padding="12dp"
|
||||
android:button="@null"
|
||||
android:drawableStart="?android:attr/listChoiceIndicatorSingle"
|
||||
android:drawablePadding="16dp"
|
||||
android:focusable="true"
|
||||
android:clickable="true" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/radio_theme_dark"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/pref_theme_selection_mode_dark"
|
||||
android:textSize="20sp"
|
||||
android:padding="12dp"
|
||||
android:button="@null"
|
||||
android:drawableStart="?android:attr/listChoiceIndicatorSingle"
|
||||
android:drawablePadding="16dp"
|
||||
android:focusable="true"
|
||||
android:clickable="true" />
|
||||
|
||||
</RadioGroup>
|
||||
|
||||
</LinearLayout>
|
||||
Reference in New Issue
Block a user