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.
This commit is contained in:
OxygenCobalt 2022-06-20 11:09:43 -06:00
parent 532a30325a
commit bd92ba2175
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
13 changed files with 204 additions and 133 deletions

View file

@ -9,6 +9,8 @@
- Fixed broken tablet layouts - Fixed broken tablet layouts
- Fixed seam that would appear on some album covers - Fixed seam that would appear on some album covers
- Fixed visual issue with the queue opening animation - Fixed visual issue with the queue opening animation
- Fixed crash if settings was navigated away before playback state
finished saving
#### Dev/Meta #### Dev/Meta
- Migrated preferences from shared object to utility - Migrated preferences from shared object to utility

View file

@ -21,6 +21,7 @@ import android.app.Application
import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.AndroidViewModel
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import org.oxycblt.auxio.R
import org.oxycblt.auxio.home.tabs.Tab import org.oxycblt.auxio.home.tabs.Tab
import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Artist
@ -145,10 +146,12 @@ class HomeViewModel(application: Application) :
} }
} }
override fun onLibrarySettingsChanged() { override fun onSettingChanged(key: String) {
if (key == application.getString(R.string.set_lib_tabs)) {
tabs = visibleTabs tabs = visibleTabs
_shouldRecreateTabs.value = true _shouldRecreateTabs.value = true
} }
}
override fun onCleared() { override fun onCleared() {
super.onCleared() super.onCleared()

View file

@ -26,6 +26,7 @@ import android.support.v4.media.session.MediaSessionCompat
import android.support.v4.media.session.PlaybackStateCompat import android.support.v4.media.session.PlaybackStateCompat
import androidx.media.session.MediaButtonReceiver import androidx.media.session.MediaButtonReceiver
import com.google.android.exoplayer2.Player import com.google.android.exoplayer2.Player
import org.oxycblt.auxio.R
import org.oxycblt.auxio.image.BitmapProvider import org.oxycblt.auxio.image.BitmapProvider
import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.MusicParent
import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.Song
@ -163,9 +164,12 @@ class MediaSessionComponent(private val context: Context, private val player: Pl
// --- SETTINGSMANAGER CALLBACKS --- // --- SETTINGSMANAGER CALLBACKS ---
override fun onCoverSettingsChanged() { 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) updateMediaMetadata(playbackManager.song)
} }
}
// --- EXOPLAYER CALLBACKS --- // --- EXOPLAYER CALLBACKS ---

View file

@ -46,6 +46,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.oxycblt.auxio.BuildConfig import org.oxycblt.auxio.BuildConfig
import org.oxycblt.auxio.IntegerTable import org.oxycblt.auxio.IntegerTable
import org.oxycblt.auxio.R
import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.replaygain.ReplayGainAudioProcessor import org.oxycblt.auxio.playback.replaygain.ReplayGainAudioProcessor
import org.oxycblt.auxio.playback.state.PlaybackStateDatabase import org.oxycblt.auxio.playback.state.PlaybackStateDatabase
@ -289,23 +290,24 @@ class PlaybackService :
// --- SETTINGSMANAGER OVERRIDES --- // --- SETTINGSMANAGER OVERRIDES ---
override fun onReplayGainSettingsChanged() { override fun onSettingChanged(key: String) {
onTracksInfoChanged(player.currentTracksInfo) when (key) {
} getString(R.string.set_replay_gain),
getString(R.string.set_pre_amp_with),
override fun onCoverSettingsChanged() { 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 -> playbackManager.song?.let { song ->
notificationComponent.updateMetadata(song, playbackManager.parent) notificationComponent.updateMetadata(song, playbackManager.parent)
} }
} getString(R.string.set_key_alt_notif_action) ->
override fun onNotifSettingsChanged() {
if (settings.useAltNotifAction) { if (settings.useAltNotifAction) {
onShuffledChanged(playbackManager.isShuffled) onShuffledChanged(playbackManager.isShuffled)
} else { } else {
onRepeatChanged(playbackManager.repeatMode) onRepeatChanged(playbackManager.repeatMode)
} }
} }
}
// --- NOTIFICATION CALLBACKS --- // --- NOTIFICATION CALLBACKS ---

View file

@ -42,6 +42,12 @@ import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.requireAttached import org.oxycblt.auxio.util.requireAttached
import org.oxycblt.auxio.util.unlikelyToBeNull 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<Fragment, Settings> = fun Fragment.settings(): ReadOnlyProperty<Fragment, Settings> =
object : ReadOnlyProperty<Fragment, Settings>, DefaultLifecycleObserver { object : ReadOnlyProperty<Fragment, Settings>, DefaultLifecycleObserver {
private var settings: Settings? = null private var settings: Settings? = null
@ -71,10 +77,20 @@ fun Fragment.settings(): ReadOnlyProperty<Fragment, Settings> =
} }
override fun onDestroy(owner: LifecycleOwner) { override fun onDestroy(owner: LifecycleOwner) {
settings?.release()
settings = null 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) : class Settings(private val context: Context, private val callback: Callback? = null) :
SharedPreferences.OnSharedPreferenceChangeListener { SharedPreferences.OnSharedPreferenceChangeListener {
private val inner = PreferenceManager.getDefaultSharedPreferences(context.applicationContext) 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) { override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
val callback = unlikelyToBeNull(callback) unlikelyToBeNull(callback).onSettingChanged(key)
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()
} }
/**
* 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 --- // --- VALUES ---
@ -354,16 +368,4 @@ class Settings(private val context: Context, private val callback: Callback? = n
apply() 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() {}
}
} }

View file

@ -33,15 +33,16 @@ import org.oxycblt.auxio.home.tabs.TabCustomizeDialog
import org.oxycblt.auxio.music.dirs.MusicDirsDialog import org.oxycblt.auxio.music.dirs.MusicDirsDialog
import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.playback.replaygain.PreAmpCustomizeDialog 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.IntListPreference
import org.oxycblt.auxio.settings.ui.IntListPreferenceDialog 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.androidActivityViewModels
import org.oxycblt.auxio.util.getSystemBarInsetsCompat import org.oxycblt.auxio.util.getSystemBarInsetsCompat
import org.oxycblt.auxio.util.hardRestart import org.oxycblt.auxio.util.hardRestart
import org.oxycblt.auxio.util.isNight import org.oxycblt.auxio.util.isNight
import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.logEOrThrow
import org.oxycblt.auxio.util.showToast import org.oxycblt.auxio.util.showToast
/** /**
@ -82,22 +83,53 @@ class SettingsListFragment : PreferenceFragmentCompat() {
@Suppress("Deprecation") @Suppress("Deprecation")
override fun onDisplayPreferenceDialog(preference: Preference) { override fun onDisplayPreferenceDialog(preference: Preference) {
if (preference is IntListPreference) { when (preference) {
is IntListPreference -> {
// Creating our own preference dialog is hilariously difficult. For one, we need // 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 // 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 // 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 // automatically provides this behavior), then we also need to use a deprecated
// to adequately supply a "target fragment" (otherwise we will crash since the dialog // method to adequately supply a "target fragment" (otherwise we will crash since
// requires one), and then we need to actually show the dialog, making sure we use // the dialog requires one), and then we need to actually show the dialog, making
// the parent FragmentManager as again, it will crash if we don't. // sure we use the parent FragmentManager as again, it will crash if we don't.
// //
// Fragments were a mistake. // Fragments were a mistake.
val dialog = IntListPreferenceDialog.from(preference) val dialog = IntListPreferenceDialog.from(preference)
dialog.setTargetFragment(this, 0) dialog.setTargetFragment(this, 0)
dialog.show(parentFragmentManager, IntListPreferenceDialog.TAG) dialog.show(parentFragmentManager, IntListPreferenceDialog.TAG)
} else {
super.onDisplayPreferenceDialog(preference)
} }
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. */ /** Recursively handle a preference, doing any specific actions on it. */
@ -113,28 +145,18 @@ class SettingsListFragment : PreferenceFragmentCompat() {
preference.apply { preference.apply {
when (key) { when (key) {
getString(R.string.set_key_theme) -> { getString(R.string.set_key_theme) -> {
setIcon(AppCompatDelegate.getDefaultNightMode().toThemeIcon())
onPreferenceChangeListener = onPreferenceChangeListener =
Preference.OnPreferenceChangeListener { _, value -> Preference.OnPreferenceChangeListener { _, value ->
AppCompatDelegate.setDefaultNightMode(value as Int) AppCompatDelegate.setDefaultNightMode(value as Int)
setIcon(AppCompatDelegate.getDefaultNightMode().toThemeIcon())
true true
} }
} }
getString(R.string.set_key_accent) -> { 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) summary = context.getString(settings.accent.name)
} }
getString(R.string.set_key_black_theme) -> { getString(R.string.set_key_black_theme) -> {
onPreferenceClickListener = onPreferenceChangeListener =
Preference.OnPreferenceClickListener { Preference.OnPreferenceChangeListener { _, _ ->
if (requireContext().isNight) { if (requireContext().isNight) {
requireActivity().recreate() requireActivity().recreate()
} }
@ -142,13 +164,6 @@ class SettingsListFragment : PreferenceFragmentCompat() {
true 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_show_covers),
getString(R.string.set_key_quality_covers) -> { getString(R.string.set_key_quality_covers) -> {
onPreferenceChangeListener = onPreferenceChangeListener =
@ -157,51 +172,6 @@ class SettingsListFragment : PreferenceFragmentCompat() {
true 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
}
}
} }
} }
} }

View file

@ -20,11 +20,16 @@ package org.oxycblt.auxio.settings.ui
import android.content.Context import android.content.Context
import android.content.res.TypedArray import android.content.res.TypedArray
import android.util.AttributeSet 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.DialogPreference
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceViewHolder
import java.lang.reflect.Field import java.lang.reflect.Field
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.util.lazyReflectedField import org.oxycblt.auxio.util.lazyReflectedField
import org.oxycblt.auxio.util.logD
class IntListPreference class IntListPreference
@JvmOverloads @JvmOverloads
@ -36,22 +41,39 @@ constructor(
) : DialogPreference(context, attrs, defStyleAttr, defStyleRes) { ) : DialogPreference(context, attrs, defStyleAttr, defStyleRes) {
val entries: Array<CharSequence> val entries: Array<CharSequence>
val values: IntArray val values: IntArray
private var offValue: Int? = -1
private var icons: TypedArray? = null
private var currentValue: Int? = null private var currentValue: Int? = null
// Reflect into Preference to get the (normally inaccessible) default value. // Reflect into Preference to get the (normally inaccessible) default value.
private val defValue: Int private val defValue: Int
get() = PREFERENCE_DEFAULT_VALUE_FIELD.get(this) as 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 { init {
val prefAttrs = val prefAttrs =
context.obtainStyledAttributes( context.obtainStyledAttributes(
attrs, R.styleable.IntListPreference, defStyleAttr, defStyleRes) attrs, R.styleable.IntListPreference, defStyleAttr, defStyleRes)
entries = prefAttrs.getTextArray(R.styleable.IntListPreference_entries) entries = prefAttrs.getTextArrayOrThrow(R.styleable.IntListPreference_entries)
values = values =
context.resources.getIntArray( 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() 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 { fun getValueIndex(): Int {
val curValue = currentValue val curValue = currentValue
@ -91,6 +126,7 @@ constructor(
currentValue = value currentValue = value
callChangeListener(value) callChangeListener(value)
notifyDependencyChange(shouldDisableDependents())
persistInt(value) persistInt(value)
notifyChanged() notifyChanged()
} }

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
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)

View file

@ -33,7 +33,8 @@ import org.oxycblt.auxio.util.unlikelyToBeNull
* Dialog responsible for showing the list of accents to select. * Dialog responsible for showing the list of accents to select.
* @author OxygenCobalt * @author OxygenCobalt
*/ */
class AccentDialog : ViewBindingDialogFragment<DialogAccentBinding>(), AccentAdapter.Listener { class AccentCustomizeDialog :
ViewBindingDialogFragment<DialogAccentBinding>(), AccentAdapter.Listener {
private var accentAdapter = AccentAdapter(this) private var accentAdapter = AccentAdapter(this)
private val settings: Settings by settings() private val settings: Settings by settings()

View file

@ -23,6 +23,7 @@ import android.os.Build
import coil.request.ImageRequest import coil.request.ImageRequest
import coil.size.Size import coil.size.Size
import coil.transform.RoundedCornersTransformation import coil.transform.RoundedCornersTransformation
import org.oxycblt.auxio.R
import org.oxycblt.auxio.image.BitmapProvider import org.oxycblt.auxio.image.BitmapProvider
import org.oxycblt.auxio.image.SquareFrameTransform import org.oxycblt.auxio.image.SquareFrameTransform
import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.MusicParent
@ -140,7 +141,12 @@ class WidgetComponent(private val context: Context) :
override fun onPlayingChanged(isPlaying: Boolean) = update() override fun onPlayingChanged(isPlaying: Boolean) = update()
override fun onShuffledChanged(isShuffled: Boolean) = update() override fun onShuffledChanged(isShuffled: Boolean) = update()
override fun onRepeatChanged(repeatMode: RepeatMode) = 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 * An immutable condensed variant of the current playback state, used so that PlaybackStateManager

View file

@ -8,5 +8,7 @@
<declare-styleable name="IntListPreference"> <declare-styleable name="IntListPreference">
<attr name="entries" format="reference" /> <attr name="entries" format="reference" />
<attr name="entryValues" format="reference" /> <attr name="entryValues" format="reference" />
<attr name="entryIcons" format="reference" />
<attr name="offValue" format="reference" />
</declare-styleable> </declare-styleable>
</resources> </resources>

View file

@ -44,6 +44,12 @@
<item>@string/set_theme_night</item> <item>@string/set_theme_night</item>
</string-array> </string-array>
<array name="icons_theme">
<item>@drawable/ic_auto</item>
<item>@drawable/ic_light</item>
<item>@drawable/ic_dark</item>
</array>
<integer-array name="values_theme"> <integer-array name="values_theme">
<item>@integer/theme_auto</item> <item>@integer/theme_auto</item>
<item>@integer/theme_light</item> <item>@integer/theme_light</item>

View file

@ -12,9 +12,10 @@
app:iconSpaceReserved="false" app:iconSpaceReserved="false"
app:isPreferenceVisible="@bool/enable_theme_settings" app:isPreferenceVisible="@bool/enable_theme_settings"
app:key="@string/set_key_theme" app:key="@string/set_key_theme"
app:entryIcons="@array/icons_theme"
app:title="@string/set_theme" /> app:title="@string/set_theme" />
<Preference <org.oxycblt.auxio.settings.ui.WrappedDialogPreference
app:icon="@drawable/ic_accent" app:icon="@drawable/ic_accent"
app:key="@string/set_key_accent" app:key="@string/set_key_accent"
app:title="@string/set_accent" /> app:title="@string/set_accent" />
@ -33,7 +34,7 @@
app:layout="@layout/item_header" app:layout="@layout/item_header"
app:title="@string/set_display"> app:title="@string/set_display">
<Preference <org.oxycblt.auxio.settings.ui.WrappedDialogPreference
app:iconSpaceReserved="false" app:iconSpaceReserved="false"
app:key="@string/set_key_lib_tabs" app:key="@string/set_key_lib_tabs"
app:summary="@string/set_lib_tabs_desc" app:summary="@string/set_lib_tabs_desc"
@ -89,10 +90,11 @@
app:entries="@array/entries_replay_gain" app:entries="@array/entries_replay_gain"
app:entryValues="@array/values_replay_gain" app:entryValues="@array/values_replay_gain"
app:iconSpaceReserved="false" app:iconSpaceReserved="false"
app:offValue="@integer/replay_gain_off"
app:key="@string/set_key_replay_gain" app:key="@string/set_key_replay_gain"
app:title="@string/set_replay_gain" /> app:title="@string/set_replay_gain" />
<Preference <org.oxycblt.auxio.settings.ui.WrappedDialogPreference
app:allowDividerBelow="false" app:allowDividerBelow="false"
app:dependency="@string/set_key_replay_gain" app:dependency="@string/set_key_replay_gain"
app:iconSpaceReserved="false" app:iconSpaceReserved="false"
@ -156,7 +158,7 @@
app:summary="@string/set_reindex_desc" app:summary="@string/set_reindex_desc"
app:title="@string/set_reindex" /> app:title="@string/set_reindex" />
<Preference <org.oxycblt.auxio.settings.ui.WrappedDialogPreference
app:iconSpaceReserved="false" app:iconSpaceReserved="false"
app:key="@string/set_key_music_dirs" app:key="@string/set_key_music_dirs"
app:summary="@string/set_dirs_desc" app:summary="@string/set_dirs_desc"