From bd92ba217572fc148ad1437422a912cd13c74f43 Mon Sep 17 00:00:00 2001 From: OxygenCobalt Date: Mon, 20 Jun 2022 11:09:43 -0600 Subject: [PATCH] settings: improve preference management Rework the preference classes to reduce the horrible bloat of the recursivelyHandlePreference function. This was mostly implementing new methods into IntListPreference and adding a new preference to represent the weird, "generic" dialogs that are used at points. While some preferences still need to be tweaked in recursivelyHandlePreference, it is nowhere near as bad as it was prior. --- CHANGELOG.md | 2 + .../org/oxycblt/auxio/home/HomeViewModel.kt | 9 +- .../playback/system/MediaSessionComponent.kt | 8 +- .../auxio/playback/system/PlaybackService.kt | 32 +++-- .../org/oxycblt/auxio/settings/Settings.kt | 50 +++---- .../auxio/settings/SettingsListFragment.kt | 132 +++++++----------- .../auxio/settings/ui/IntListPreference.kt | 40 +++++- .../settings/ui/WrappedDialogPreference.kt | 35 +++++ ...centDialog.kt => AccentCustomizeDialog.kt} | 3 +- .../oxycblt/auxio/widgets/WidgetComponent.kt | 8 +- app/src/main/res/values/attrs.xml | 2 + app/src/main/res/values/settings.xml | 6 + app/src/main/res/xml/prefs_main.xml | 10 +- 13 files changed, 204 insertions(+), 133 deletions(-) create mode 100644 app/src/main/java/org/oxycblt/auxio/settings/ui/WrappedDialogPreference.kt rename app/src/main/java/org/oxycblt/auxio/ui/accent/{AccentDialog.kt => AccentCustomizeDialog.kt} (96%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5911649e4..1000ca237 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ - Fixed broken tablet layouts - Fixed seam that would appear on some album covers - Fixed visual issue with the queue opening animation +- Fixed crash if settings was navigated away before playback state +finished saving #### Dev/Meta - Migrated preferences from shared object to utility diff --git a/app/src/main/java/org/oxycblt/auxio/home/HomeViewModel.kt b/app/src/main/java/org/oxycblt/auxio/home/HomeViewModel.kt index b62e285d1..6d839d81d 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/HomeViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/HomeViewModel.kt @@ -21,6 +21,7 @@ import android.app.Application import androidx.lifecycle.AndroidViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow +import org.oxycblt.auxio.R import org.oxycblt.auxio.home.tabs.Tab import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Artist @@ -145,9 +146,11 @@ class HomeViewModel(application: Application) : } } - override fun onLibrarySettingsChanged() { - tabs = visibleTabs - _shouldRecreateTabs.value = true + override fun onSettingChanged(key: String) { + if (key == application.getString(R.string.set_lib_tabs)) { + tabs = visibleTabs + _shouldRecreateTabs.value = true + } } override fun onCleared() { diff --git a/app/src/main/java/org/oxycblt/auxio/playback/system/MediaSessionComponent.kt b/app/src/main/java/org/oxycblt/auxio/playback/system/MediaSessionComponent.kt index e0752ffb8..ac86b2c2b 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/system/MediaSessionComponent.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/system/MediaSessionComponent.kt @@ -26,6 +26,7 @@ import android.support.v4.media.session.MediaSessionCompat import android.support.v4.media.session.PlaybackStateCompat import androidx.media.session.MediaButtonReceiver import com.google.android.exoplayer2.Player +import org.oxycblt.auxio.R import org.oxycblt.auxio.image.BitmapProvider import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.Song @@ -163,8 +164,11 @@ class MediaSessionComponent(private val context: Context, private val player: Pl // --- SETTINGSMANAGER CALLBACKS --- - override fun onCoverSettingsChanged() { - updateMediaMetadata(playbackManager.song) + override fun onSettingChanged(key: String) { + if (key == context.getString(R.string.set_key_show_covers) || + key == context.getString(R.string.set_key_show_covers)) { + updateMediaMetadata(playbackManager.song) + } } // --- EXOPLAYER CALLBACKS --- diff --git a/app/src/main/java/org/oxycblt/auxio/playback/system/PlaybackService.kt b/app/src/main/java/org/oxycblt/auxio/playback/system/PlaybackService.kt index ac4b61a95..0b4c729a9 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/system/PlaybackService.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/system/PlaybackService.kt @@ -46,6 +46,7 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.launch import org.oxycblt.auxio.BuildConfig import org.oxycblt.auxio.IntegerTable +import org.oxycblt.auxio.R import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.playback.replaygain.ReplayGainAudioProcessor import org.oxycblt.auxio.playback.state.PlaybackStateDatabase @@ -289,21 +290,22 @@ class PlaybackService : // --- SETTINGSMANAGER OVERRIDES --- - override fun onReplayGainSettingsChanged() { - onTracksInfoChanged(player.currentTracksInfo) - } - - override fun onCoverSettingsChanged() { - playbackManager.song?.let { song -> - notificationComponent.updateMetadata(song, playbackManager.parent) - } - } - - override fun onNotifSettingsChanged() { - if (settings.useAltNotifAction) { - onShuffledChanged(playbackManager.isShuffled) - } else { - onRepeatChanged(playbackManager.repeatMode) + override fun onSettingChanged(key: String) { + when (key) { + getString(R.string.set_replay_gain), + getString(R.string.set_pre_amp_with), + getString(R.string.set_pre_amp_without) -> onTracksInfoChanged(player.currentTracksInfo) + getString(R.string.set_show_covers), + getString(R.string.set_quality_covers) -> + playbackManager.song?.let { song -> + notificationComponent.updateMetadata(song, playbackManager.parent) + } + getString(R.string.set_key_alt_notif_action) -> + if (settings.useAltNotifAction) { + onShuffledChanged(playbackManager.isShuffled) + } else { + onRepeatChanged(playbackManager.repeatMode) + } } } diff --git a/app/src/main/java/org/oxycblt/auxio/settings/Settings.kt b/app/src/main/java/org/oxycblt/auxio/settings/Settings.kt index 59d258602..53643a2f8 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/Settings.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/Settings.kt @@ -42,6 +42,12 @@ import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.requireAttached import org.oxycblt.auxio.util.unlikelyToBeNull +/** + * Shortcut delegate in order to receive a [Settings] that will be created/destroyed + * in each lifecycle. + * + * TODO: Replace with generalized method + */ fun Fragment.settings(): ReadOnlyProperty = object : ReadOnlyProperty, DefaultLifecycleObserver { private var settings: Settings? = null @@ -71,10 +77,20 @@ fun Fragment.settings(): ReadOnlyProperty = } override fun onDestroy(owner: LifecycleOwner) { + settings?.release() settings = null } } +/** + * Auxio's settings. + * + * This object wraps [SharedPreferences] in a type-safe manner, allowing access to all of the + * major settings that Auxio uses. Mutability is determined by use, as some values are written + * by PreferenceManager and others are written by Auxio's code. + * + * @author OxygenCobalt + */ class Settings(private val context: Context, private val callback: Callback? = null) : SharedPreferences.OnSharedPreferenceChangeListener { private val inner = PreferenceManager.getDefaultSharedPreferences(context.applicationContext) @@ -90,18 +106,16 @@ class Settings(private val context: Context, private val callback: Callback? = n } override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) { - val callback = unlikelyToBeNull(callback) - when (key) { - context.getString(R.string.set_key_alt_notif_action) -> - callback.onNotifSettingsChanged() - context.getString(R.string.set_key_show_covers), - context.getString(R.string.set_key_quality_covers) -> callback.onCoverSettingsChanged() - context.getString(R.string.set_key_lib_tabs) -> callback.onLibrarySettingsChanged() - context.getString(R.string.set_key_replay_gain), - context.getString(R.string.set_key_pre_amp_with), - context.getString(R.string.set_key_pre_amp_without) -> - callback.onReplayGainSettingsChanged() - } + unlikelyToBeNull(callback).onSettingChanged(key) + } + + /** + * An interface for receiving some preference updates. Use/Extend this instead of + * [SharedPreferences.OnSharedPreferenceChangeListener] if possible, as it doesn't require a + * context. + */ + interface Callback { + fun onSettingChanged(key: String) } // --- VALUES --- @@ -354,16 +368,4 @@ class Settings(private val context: Context, private val callback: Callback? = n apply() } } - - /** - * An interface for receiving some preference updates. Use/Extend this instead of - * [SharedPreferences.OnSharedPreferenceChangeListener] if possible, as it doesn't require a - * context. - */ - interface Callback { - fun onLibrarySettingsChanged() {} - fun onNotifSettingsChanged() {} - fun onCoverSettingsChanged() {} - fun onReplayGainSettingsChanged() {} - } } diff --git a/app/src/main/java/org/oxycblt/auxio/settings/SettingsListFragment.kt b/app/src/main/java/org/oxycblt/auxio/settings/SettingsListFragment.kt index 1e31e4f6d..815cb7009 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/SettingsListFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/SettingsListFragment.kt @@ -33,15 +33,16 @@ import org.oxycblt.auxio.home.tabs.TabCustomizeDialog import org.oxycblt.auxio.music.dirs.MusicDirsDialog import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.playback.replaygain.PreAmpCustomizeDialog -import org.oxycblt.auxio.playback.replaygain.ReplayGainMode import org.oxycblt.auxio.settings.ui.IntListPreference import org.oxycblt.auxio.settings.ui.IntListPreferenceDialog -import org.oxycblt.auxio.ui.accent.AccentDialog +import org.oxycblt.auxio.settings.ui.WrappedDialogPreference +import org.oxycblt.auxio.ui.accent.AccentCustomizeDialog import org.oxycblt.auxio.util.androidActivityViewModels import org.oxycblt.auxio.util.getSystemBarInsetsCompat import org.oxycblt.auxio.util.hardRestart import org.oxycblt.auxio.util.isNight import org.oxycblt.auxio.util.logD +import org.oxycblt.auxio.util.logEOrThrow import org.oxycblt.auxio.util.showToast /** @@ -82,24 +83,55 @@ class SettingsListFragment : PreferenceFragmentCompat() { @Suppress("Deprecation") override fun onDisplayPreferenceDialog(preference: Preference) { - if (preference is IntListPreference) { - // Creating our own preference dialog is hilariously difficult. For one, we need - // to override this random method within the class in order to launch the dialog in - // the first (because apparently you can't just implement some interface that - // automatically provides this behavior), then we also need to use a deprecated method - // to adequately supply a "target fragment" (otherwise we will crash since the dialog - // requires one), and then we need to actually show the dialog, making sure we use - // the parent FragmentManager as again, it will crash if we don't. - // - // Fragments were a mistake. - val dialog = IntListPreferenceDialog.from(preference) - dialog.setTargetFragment(this, 0) - dialog.show(parentFragmentManager, IntListPreferenceDialog.TAG) - } else { - super.onDisplayPreferenceDialog(preference) + when (preference) { + is IntListPreference -> { + // Creating our own preference dialog is hilariously difficult. For one, we need + // to override this random method within the class in order to launch the dialog in + // the first (because apparently you can't just implement some interface that + // automatically provides this behavior), then we also need to use a deprecated + // method to adequately supply a "target fragment" (otherwise we will crash since + // the dialog requires one), and then we need to actually show the dialog, making + // sure we use the parent FragmentManager as again, it will crash if we don't. + // + // Fragments were a mistake. + val dialog = IntListPreferenceDialog.from(preference) + dialog.setTargetFragment(this, 0) + dialog.show(parentFragmentManager, IntListPreferenceDialog.TAG) + } + is WrappedDialogPreference -> + when (preference.key) { + getString(R.string.set_key_accent) -> + AccentCustomizeDialog() + .show(childFragmentManager, AccentCustomizeDialog.TAG) + getString(R.string.set_key_lib_tabs) -> + TabCustomizeDialog().show(childFragmentManager, TabCustomizeDialog.TAG) + getString(R.string.set_key_pre_amp) -> + PreAmpCustomizeDialog() + .show(childFragmentManager, PreAmpCustomizeDialog.TAG) + getString(R.string.set_key_music_dirs) -> + MusicDirsDialog().show(childFragmentManager, MusicDirsDialog.TAG) + else -> logEOrThrow("Unexpected dialog key ${preference.key}") + } + else -> super.onDisplayPreferenceDialog(preference) } } + override fun onPreferenceTreeClick(preference: Preference): Boolean { + when (preference.key) { + getString(R.string.set_key_save_state) -> { + playbackModel.savePlaybackState(requireContext()) { + context?.showToast(R.string.lbl_state_saved) + } + } + getString(R.string.set_key_reindex) -> { + playbackModel.savePlaybackState(requireContext()) { context?.hardRestart() } + } + else -> return super.onPreferenceTreeClick(preference) + } + + return true + } + /** Recursively handle a preference, doing any specific actions on it. */ private fun recursivelyHandlePreference(preference: Preference) { if (!preference.isVisible) return @@ -113,28 +145,18 @@ class SettingsListFragment : PreferenceFragmentCompat() { preference.apply { when (key) { getString(R.string.set_key_theme) -> { - setIcon(AppCompatDelegate.getDefaultNightMode().toThemeIcon()) - onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, value -> AppCompatDelegate.setDefaultNightMode(value as Int) - setIcon(AppCompatDelegate.getDefaultNightMode().toThemeIcon()) true } } getString(R.string.set_key_accent) -> { - onPreferenceClickListener = - Preference.OnPreferenceClickListener { - AccentDialog().show(childFragmentManager, AccentDialog.TAG) - true - } - - // TODO: Replace with preference impl summary = context.getString(settings.accent.name) } getString(R.string.set_key_black_theme) -> { - onPreferenceClickListener = - Preference.OnPreferenceClickListener { + onPreferenceChangeListener = + Preference.OnPreferenceChangeListener { _, _ -> if (requireContext().isNight) { requireActivity().recreate() } @@ -142,13 +164,6 @@ class SettingsListFragment : PreferenceFragmentCompat() { true } } - getString(R.string.set_key_lib_tabs) -> { - onPreferenceClickListener = - Preference.OnPreferenceClickListener { - TabCustomizeDialog().show(childFragmentManager, TabCustomizeDialog.TAG) - true - } - } getString(R.string.set_key_show_covers), getString(R.string.set_key_quality_covers) -> { onPreferenceChangeListener = @@ -157,51 +172,6 @@ class SettingsListFragment : PreferenceFragmentCompat() { true } } - getString(R.string.set_key_replay_gain) -> { - notifyDependencyChange(settings.replayGainMode == ReplayGainMode.OFF) - onPreferenceChangeListener = - Preference.OnPreferenceChangeListener { _, value -> - notifyDependencyChange( - ReplayGainMode.fromIntCode(value as Int) == ReplayGainMode.OFF) - true - } - } - getString(R.string.set_key_pre_amp) -> { - onPreferenceClickListener = - Preference.OnPreferenceClickListener { - PreAmpCustomizeDialog() - .show(childFragmentManager, PreAmpCustomizeDialog.TAG) - true - } - } - getString(R.string.set_key_save_state) -> { - onPreferenceClickListener = - Preference.OnPreferenceClickListener { - // FIXME: Callback can still occur on non-attached fragment - playbackModel.savePlaybackState(requireContext()) { - requireContext().showToast(R.string.lbl_state_saved) - } - - true - } - } - getString(R.string.set_key_reindex) -> { - onPreferenceClickListener = - Preference.OnPreferenceClickListener { - playbackModel.savePlaybackState(requireContext()) { - requireContext().hardRestart() - } - - true - } - } - getString(R.string.set_key_music_dirs) -> { - onPreferenceClickListener = - Preference.OnPreferenceClickListener { - MusicDirsDialog().show(childFragmentManager, MusicDirsDialog.TAG) - true - } - } } } } diff --git a/app/src/main/java/org/oxycblt/auxio/settings/ui/IntListPreference.kt b/app/src/main/java/org/oxycblt/auxio/settings/ui/IntListPreference.kt index d96461ad4..85c54ff7c 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/ui/IntListPreference.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/ui/IntListPreference.kt @@ -20,11 +20,16 @@ package org.oxycblt.auxio.settings.ui import android.content.Context import android.content.res.TypedArray import android.util.AttributeSet +import android.widget.ImageView +import androidx.core.content.res.getResourceIdOrThrow +import androidx.core.content.res.getTextArrayOrThrow import androidx.preference.DialogPreference import androidx.preference.Preference +import androidx.preference.PreferenceViewHolder import java.lang.reflect.Field import org.oxycblt.auxio.R import org.oxycblt.auxio.util.lazyReflectedField +import org.oxycblt.auxio.util.logD class IntListPreference @JvmOverloads @@ -36,22 +41,39 @@ constructor( ) : DialogPreference(context, attrs, defStyleAttr, defStyleRes) { val entries: Array val values: IntArray + private var offValue: Int? = -1 + private var icons: TypedArray? = null private var currentValue: Int? = null // Reflect into Preference to get the (normally inaccessible) default value. private val defValue: Int get() = PREFERENCE_DEFAULT_VALUE_FIELD.get(this) as Int + override fun onDependencyChanged(dependency: Preference, disableDependent: Boolean) { + super.onDependencyChanged(dependency, disableDependent) + logD("dependency changed: $dependency") + } + init { val prefAttrs = context.obtainStyledAttributes( attrs, R.styleable.IntListPreference, defStyleAttr, defStyleRes) - entries = prefAttrs.getTextArray(R.styleable.IntListPreference_entries) + entries = prefAttrs.getTextArrayOrThrow(R.styleable.IntListPreference_entries) values = context.resources.getIntArray( - prefAttrs.getResourceId(R.styleable.IntListPreference_entryValues, -1)) + prefAttrs.getResourceIdOrThrow(R.styleable.IntListPreference_entryValues)) + + val offValueId = prefAttrs.getResourceId(R.styleable.IntListPreference_offValue, -1) + if (offValueId > -1) { + offValue = context.resources.getInteger(offValueId) + } + + val iconsId = prefAttrs.getResourceId(R.styleable.IntListPreference_entryIcons, -1) + if (iconsId > -1) { + icons = context.resources.obtainTypedArray(iconsId) + } prefAttrs.recycle() @@ -71,6 +93,19 @@ constructor( } } + override fun shouldDisableDependents(): Boolean = currentValue == offValue + + override fun onBindViewHolder(holder: PreferenceViewHolder) { + super.onBindViewHolder(holder) + val index = getValueIndex() + if (index > -1) { + val resourceId = icons?.getResourceId(index, -1) ?: -1 + if (resourceId > -1) { + (holder.findViewById(android.R.id.icon) as ImageView).setImageResource(resourceId) + } + } + } + fun getValueIndex(): Int { val curValue = currentValue @@ -91,6 +126,7 @@ constructor( currentValue = value callChangeListener(value) + notifyDependencyChange(shouldDisableDependents()) persistInt(value) notifyChanged() } diff --git a/app/src/main/java/org/oxycblt/auxio/settings/ui/WrappedDialogPreference.kt b/app/src/main/java/org/oxycblt/auxio/settings/ui/WrappedDialogPreference.kt new file mode 100644 index 000000000..627a0fa2a --- /dev/null +++ b/app/src/main/java/org/oxycblt/auxio/settings/ui/WrappedDialogPreference.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2022 Auxio Project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.oxycblt.auxio.settings.ui + +import android.content.Context +import android.util.AttributeSet +import androidx.preference.DialogPreference + +/** + * Wraps [DialogPreference] as to make it type-distinct from other preferences while also + * making it possible to use in a PreferenceScreen. + */ +class WrappedDialogPreference +@JvmOverloads +constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = androidx.preference.R.attr.dialogPreferenceStyle, + defStyleRes: Int = 0 +) : DialogPreference(context, attrs, defStyleAttr, defStyleRes) diff --git a/app/src/main/java/org/oxycblt/auxio/ui/accent/AccentDialog.kt b/app/src/main/java/org/oxycblt/auxio/ui/accent/AccentCustomizeDialog.kt similarity index 96% rename from app/src/main/java/org/oxycblt/auxio/ui/accent/AccentDialog.kt rename to app/src/main/java/org/oxycblt/auxio/ui/accent/AccentCustomizeDialog.kt index 2802153cb..ed1447646 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/accent/AccentDialog.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/accent/AccentCustomizeDialog.kt @@ -33,7 +33,8 @@ import org.oxycblt.auxio.util.unlikelyToBeNull * Dialog responsible for showing the list of accents to select. * @author OxygenCobalt */ -class AccentDialog : ViewBindingDialogFragment(), AccentAdapter.Listener { +class AccentCustomizeDialog : + ViewBindingDialogFragment(), AccentAdapter.Listener { private var accentAdapter = AccentAdapter(this) private val settings: Settings by settings() diff --git a/app/src/main/java/org/oxycblt/auxio/widgets/WidgetComponent.kt b/app/src/main/java/org/oxycblt/auxio/widgets/WidgetComponent.kt index 54048527b..699e28e87 100644 --- a/app/src/main/java/org/oxycblt/auxio/widgets/WidgetComponent.kt +++ b/app/src/main/java/org/oxycblt/auxio/widgets/WidgetComponent.kt @@ -23,6 +23,7 @@ import android.os.Build import coil.request.ImageRequest import coil.size.Size import coil.transform.RoundedCornersTransformation +import org.oxycblt.auxio.R import org.oxycblt.auxio.image.BitmapProvider import org.oxycblt.auxio.image.SquareFrameTransform import org.oxycblt.auxio.music.MusicParent @@ -140,7 +141,12 @@ class WidgetComponent(private val context: Context) : override fun onPlayingChanged(isPlaying: Boolean) = update() override fun onShuffledChanged(isShuffled: Boolean) = update() override fun onRepeatChanged(repeatMode: RepeatMode) = update() - override fun onCoverSettingsChanged() = update() + override fun onSettingChanged(key: String) { + if (key == context.getString(R.string.set_key_show_covers) || + key == context.getString(R.string.set_key_quality_covers)) { + update() + } + } /* * An immutable condensed variant of the current playback state, used so that PlaybackStateManager diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index 33611e92d..750140147 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -8,5 +8,7 @@ + + \ No newline at end of file diff --git a/app/src/main/res/values/settings.xml b/app/src/main/res/values/settings.xml index 542db3ec1..66698961f 100644 --- a/app/src/main/res/values/settings.xml +++ b/app/src/main/res/values/settings.xml @@ -44,6 +44,12 @@ @string/set_theme_night + + @drawable/ic_auto + @drawable/ic_light + @drawable/ic_dark + + @integer/theme_auto @integer/theme_light diff --git a/app/src/main/res/xml/prefs_main.xml b/app/src/main/res/xml/prefs_main.xml index 7477e03d3..f236c40f1 100644 --- a/app/src/main/res/xml/prefs_main.xml +++ b/app/src/main/res/xml/prefs_main.xml @@ -12,9 +12,10 @@ app:iconSpaceReserved="false" app:isPreferenceVisible="@bool/enable_theme_settings" app:key="@string/set_key_theme" + app:entryIcons="@array/icons_theme" app:title="@string/set_theme" /> - @@ -33,7 +34,7 @@ app:layout="@layout/item_header" app:title="@string/set_display"> - - -