Standardize settings entirely

Update the structure of the settings system to do several things:
- Finally use int preferences everywhere instead of the mix of strings & ints from before
- Create a new preference named `IntListPreference` that enables the use of integers in list preferences
- Actually centralize array values and default values into a single integers xml
- Isolate all the new migration code into a single file
- Refreshed the int tables used by data objects [DB version has been updated, will not update when other changes]

The only preference not migrated is doAtEnd since that is being planned to be retired in a future LoopMode update.
This commit is contained in:
OxygenCobalt 2021-04-03 10:53:16 -06:00
parent 355b3885e3
commit 0305eb0beb
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
29 changed files with 575 additions and 280 deletions

View file

@ -9,8 +9,8 @@ android {
defaultConfig {
applicationId "org.oxycblt.auxio"
versionName "1.3.3"
versionCode 5
versionName "1.4.0"
versionCode 6
minSdkVersion 21
targetSdkVersion 30
@ -65,7 +65,7 @@ dependencies {
// General
implementation "androidx.core:core-ktx:1.3.2"
implementation "androidx.activity:activity-ktx:1.2.2"
implementation "androidx.fragment:fragment-ktx:1.3.1"
implementation "androidx.fragment:fragment-ktx:1.3.2"
// UI
implementation "androidx.recyclerview:recyclerview:1.1.0"
@ -73,7 +73,7 @@ dependencies {
implementation "androidx.dynamicanimation:dynamicanimation:1.0.0"
// Lifecycle
def lifecycle_version = "2.3.0"
def lifecycle_version = "2.3.1"
implementation "androidx.lifecycle:lifecycle-common:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"

View file

@ -3,8 +3,6 @@ package org.oxycblt.auxio.database
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import android.os.Looper
import org.oxycblt.auxio.logE
import java.lang.Exception
/**
* Shortcut for querying all items in a database and running [block] with the cursor returned.

View file

@ -228,7 +228,7 @@ class PlaybackStateDatabase(context: Context) :
companion object {
const val DB_NAME = "auxio_state_database.db"
const val DB_VERSION = 3
const val DB_VERSION = 4
const val TABLE_NAME_STATE = "playback_state_table"
const val TABLE_NAME_QUEUE = "queue_table"

View file

@ -5,7 +5,7 @@ import android.net.Uri
// --- MUSIC MODELS ---
// TODO: Implement some kind of hash system, removing the need to redundant names but alsow without the volitility of id
// They need to be completely unique, however, and from whatever information I have about them.
// They need to be completely unique, however, and from whatever information I have about them on creation
/**
* The base data object for all music.

View file

@ -31,9 +31,9 @@ enum class LoopMode {
}
companion object {
private const val CONST_NONE = 0xA050
private const val CONST_ONCE = 0xA051
private const val CONST_INFINITE = 0xA052
const val CONST_NONE = 0xA100
const val CONST_ONCE = 0xA101
const val CONST_INFINITE = 0xA102
/**
* Convert an int [constant] into a LoopMode

View file

@ -28,10 +28,10 @@ enum class PlaybackMode {
}
companion object {
private const val CONST_IN_ARTIST = 0xA040
private const val CONST_IN_GENRE = 0xA041
private const val CONST_IN_ALBUM = 0xA042
private const val CONST_ALL_SONGS = 0xA043
const val CONST_IN_GENRE = 0xA103
const val CONST_IN_ARTIST = 0xA104
const val CONST_IN_ALBUM = 0xA105
const val CONST_ALL_SONGS = 0xA106
/**
* Get a [PlaybackMode] for an int [constant]

View file

@ -810,6 +810,10 @@ class PlaybackStateManager private constructor() {
companion object {
private const val REWIND_THRESHOLD = 3000L
const val AT_END_LOOP_PAUSE = 0
const val AT_END_LOOP = 1
const val AT_END_STOP = 2
@Volatile
private var INSTANCE: PlaybackStateManager? = null

View file

@ -170,7 +170,7 @@ class PlaybackNotification private constructor(
companion object {
const val CHANNEL_ID = "CHANNEL_AUXIO_PLAYBACK"
const val NOTIFICATION_ID = 0xA0A0
const val REQUEST_CODE = 0xA0C0
const val REQUEST_CODE = 0xA0AA
// Build type is added to the codes so that dual release/debug installations dont conflict
// with each other.

View file

@ -28,7 +28,23 @@ enum class DisplayMode(@DrawableRes val iconRes: Int) {
}
}
fun toInt(): Int {
return when (this) {
SHOW_ALL -> CONST_SHOW_ALL
SHOW_GENRES -> CONST_SHOW_GENRES
SHOW_ARTISTS -> CONST_SHOW_ARTISTS
SHOW_ALBUMS -> CONST_SHOW_ALBUMS
SHOW_SONGS -> CONST_SHOW_SONGS
}
}
companion object {
const val CONST_SHOW_ALL = 0xA107
const val CONST_SHOW_GENRES = 0xA108
const val CONST_SHOW_ARTISTS = 0xA109
const val CONST_SHOW_ALBUMS = 0xA10A
const val CONST_SHOW_SONGS = 0xA10B
/**
* A valueOf wrapper that will return a default value if given a null/invalid string.
*/
@ -55,5 +71,21 @@ enum class DisplayMode(@DrawableRes val iconRes: Int) {
else -> SHOW_ALL
}
}
/**
* Get an enum for an int constant
* @return The [DisplayMode] if the constant is valid, null otherwise.
*/
fun fromInt(value: Int): DisplayMode? {
return when (value) {
CONST_SHOW_ALL -> SHOW_ALL
CONST_SHOW_GENRES -> SHOW_GENRES
CONST_SHOW_ARTISTS -> SHOW_ARTISTS
CONST_SHOW_ALBUMS -> SHOW_ALBUMS
CONST_SHOW_SONGS -> SHOW_SONGS
else -> null
}
}
}
}

View file

@ -174,13 +174,11 @@ enum class SortMode(@DrawableRes val iconRes: Int) {
}
companion object {
private const val CONST_NONE = 0xA060
private const val CONST_ALPHA_UP = 0xA061
private const val CONST_ALPHA_DOWN = 0xA062
private const val CONST_NUMERIC_UP = 0xA063
private const val CONST_NUMERIC_DOWN = 0xA065
const val CONST_SORT_DEFAULT = CONST_ALPHA_DOWN
const val CONST_NONE = 0xA10C
const val CONST_ALPHA_UP = 0xA10D
const val CONST_ALPHA_DOWN = 0xA10E
const val CONST_NUMERIC_UP = 0xA10F
const val CONST_NUMERIC_DOWN = 0xA110
/**
* Get an enum for an int constant

View file

@ -14,23 +14,6 @@ import org.oxycblt.auxio.music.Header
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.ui.inflater
/*
* A table of all ViewHolder codes. Please add to these so that all viewholder codes are unique.
* SongViewHolder -> 0xA000
* AlbumViewHolder -> 0xA001
* ArtistViewHolder -> 0xA002
* GenreViewHolder -> 0xA003
* HeaderViewHolder -> 0xA004
* QueueSongViewHolder -> 0xA005
* UserQueueHeaderViewHolder -> 0xA006
* AlbumHeaderViewHolder -> 0xA007
* AlbumSongViewHolder -> 0xA008
* ArtistHeaderViewHolder -> 0xA009
* ArtistAlbumViewHolder -> 0xA00A
* GenreHeaderViewHolder -> 0xA00B
* GenreSongViewHolder -> 0xA00C
*/
/**
* The Shared ViewHolder for a [Song]. Instantiation should be done with [from].
*/

View file

@ -4,21 +4,6 @@ import androidx.annotation.DrawableRes
import androidx.appcompat.app.AppCompatDelegate
import org.oxycblt.auxio.R
/**
* Convert a string representing a theme entry name to an actual theme int that can be used.
* This is only done because PreferenceFragment does not like int arrays for some...reason.
* @return The proper theme int for this value.
*/
fun String.toThemeInt(): Int {
return when (this) {
SettingsManager.EntryValues.THEME_AUTO -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
SettingsManager.EntryValues.THEME_LIGHT -> AppCompatDelegate.MODE_NIGHT_NO
SettingsManager.EntryValues.THEME_DARK -> AppCompatDelegate.MODE_NIGHT_YES
else -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
}
}
/**
* Convert an theme integer into an icon that can be used.
* @return An icon for this theme.

View file

@ -0,0 +1,175 @@
package org.oxycblt.auxio.settings
import android.content.SharedPreferences
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.content.edit
import org.oxycblt.auxio.playback.state.PlaybackMode
import org.oxycblt.auxio.recycler.DisplayMode
import org.oxycblt.auxio.ui.ACCENTS
import org.oxycblt.auxio.ui.Accent
// A couple of utils for migrating from old settings values to the new the new
// formats used in 1.3.2 & 1.4.0
fun handleThemeCompat(prefs: SharedPreferences): Int {
if (prefs.contains(OldKeys.KEY_THEME)) {
// Before the creation of IntListPreference, I used strings to represent the themes.
// I no longer need to do this.
val newValue = when (prefs.getString(OldKeys.KEY_THEME, EntryValues.THEME_AUTO)) {
EntryValues.THEME_AUTO -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
EntryValues.THEME_LIGHT -> AppCompatDelegate.MODE_NIGHT_NO
EntryValues.THEME_DARK -> AppCompatDelegate.MODE_NIGHT_YES
else -> error("Invalid theme")
}
prefs.edit {
putInt(SettingsManager.KEY_THEME, newValue)
remove(OldKeys.KEY_THEME)
apply()
}
return newValue
}
return prefs.getInt(SettingsManager.KEY_THEME, AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
}
fun handleAccentCompat(prefs: SharedPreferences): Accent {
if (prefs.contains(OldKeys.KEY_ACCENT)) {
var accent = prefs.getInt(OldKeys.KEY_ACCENT, 5)
// Correct any accents over yellow to their correct positions
if (accent > 12) {
accent--
}
// Correct neutral accents to the closest accent [Grey]
if (accent == 18) {
accent = 16
}
// If there are still any issues with indices, just correct them so a crash doesnt occur.
if (accent > ACCENTS.lastIndex) {
accent = ACCENTS.lastIndex
}
prefs.edit {
putInt(SettingsManager.KEY_ACCENT, accent)
remove(OldKeys.KEY_ACCENT)
apply()
}
return ACCENTS[accent]
}
return ACCENTS[prefs.getInt(SettingsManager.KEY_ACCENT, 5)]
}
fun handleLibDisplayCompat(prefs: SharedPreferences): DisplayMode {
if (prefs.contains(OldKeys.KEY_LIB_MODE)) {
val mode = handleStringDisplayMode(
prefs.getString(OldKeys.KEY_LIB_MODE, EntryValues.SHOW_ARTISTS),
) ?: DisplayMode.SHOW_ARTISTS
prefs.edit {
putInt(SettingsManager.KEY_LIB_DISPLAY_MODE, mode.toInt())
remove(OldKeys.KEY_LIB_MODE)
apply()
}
return mode
}
return DisplayMode.fromInt(
prefs.getInt(SettingsManager.KEY_LIB_DISPLAY_MODE, DisplayMode.CONST_SHOW_ARTISTS)
) ?: DisplayMode.SHOW_ARTISTS
}
fun handleSongPlayModeCompat(prefs: SharedPreferences): PlaybackMode {
if (prefs.contains(OldKeys.KEY_SONG_PLAYBACK_MODE)) {
val mode = when (prefs.getString(OldKeys.KEY_SONG_PLAYBACK_MODE, EntryValues.ALL_SONGS)) {
EntryValues.IN_GENRE -> PlaybackMode.IN_GENRE
EntryValues.IN_ARTIST -> PlaybackMode.IN_ARTIST
EntryValues.IN_ALBUM -> PlaybackMode.IN_ALBUM
EntryValues.ALL_SONGS -> PlaybackMode.ALL_SONGS
else -> PlaybackMode.ALL_SONGS
}
prefs.edit {
putInt(SettingsManager.KEY_SONG_PLAYBACK_MODE, mode.toInt())
remove(OldKeys.KEY_SONG_PLAYBACK_MODE)
apply()
}
return mode
}
return PlaybackMode.fromInt(
prefs.getInt(SettingsManager.KEY_SONG_PLAYBACK_MODE, PlaybackMode.CONST_ALL_SONGS)
) ?: PlaybackMode.ALL_SONGS
}
fun handleSearchModeCompat(prefs: SharedPreferences): DisplayMode {
if (prefs.contains(OldKeys.KEY_SEARCH_FILTER)) {
val mode = handleStringDisplayMode(
prefs.getString(OldKeys.KEY_SEARCH_FILTER, EntryValues.SHOW_ALL)
) ?: DisplayMode.SHOW_ALL
prefs.edit {
putInt(SettingsManager.KEY_SEARCH_FILTER_MODE, mode.toInt())
remove(OldKeys.KEY_SEARCH_FILTER)
apply()
}
return mode
}
return DisplayMode.fromInt(
prefs.getInt(SettingsManager.KEY_SEARCH_FILTER_MODE, DisplayMode.CONST_SHOW_ALL)
) ?: DisplayMode.SHOW_ARTISTS
}
private fun handleStringDisplayMode(string: String?): DisplayMode? {
return when (string) {
EntryValues.SHOW_GENRES -> DisplayMode.SHOW_GENRES
EntryValues.SHOW_ARTISTS -> DisplayMode.SHOW_ARTISTS
EntryValues.SHOW_ALBUMS -> DisplayMode.SHOW_ALBUMS
EntryValues.SHOW_SONGS -> DisplayMode.SHOW_SONGS
EntryValues.SHOW_ALL -> DisplayMode.SHOW_ALL
else -> null
}
}
/**
* Cache of the old keys used in Auxio.
*/
private object OldKeys {
const val KEY_ACCENT = "KEY_ACCENT"
const val KEY_THEME = "KEY_THEME"
const val KEY_LIB_MODE = "KEY_LIBRARY_DISPLAY_MODE"
const val KEY_SONG_PLAYBACK_MODE = "KEY_SONG_PLAY_MODE"
const val KEY_SEARCH_FILTER = "KEY_SEARCH"
}
/**
* Static cache of old string values used in Auxio
*/
private object EntryValues {
const val THEME_AUTO = "AUTO"
const val THEME_LIGHT = "LIGHT"
const val THEME_DARK = "DARK"
const val SHOW_GENRES = "SHOW_GENRES"
const val SHOW_ARTISTS = "SHOW_ARTISTS"
const val SHOW_ALBUMS = "SHOW_ALBUMS"
const val SHOW_SONGS = "SHOW_SONGS"
const val SHOW_ALL = "SHOW_ALL"
const val IN_GENRE = "IN_GENRE"
const val IN_ARTIST = "IN_ARTIST"
const val IN_ALBUM = "IN_ALBUM"
const val ALL_SONGS = "ALL_SONGS"
}

View file

@ -15,12 +15,13 @@ import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.recycler.DisplayMode
import org.oxycblt.auxio.settings.accent.AccentDialog
import org.oxycblt.auxio.settings.blacklist.BlacklistDialog
import org.oxycblt.auxio.settings.ui.IntListPrefDialog
import org.oxycblt.auxio.settings.ui.IntListPreference
import org.oxycblt.auxio.ui.Accent
import org.oxycblt.auxio.ui.createToast
/**
* The actual fragment containing the settings menu. Inherits [PreferenceFragmentCompat].
* TODO: Roll your own ListPreference that supports int prefs [and is a bottom sheet]
* @author OxygenCobalt
*/
@Suppress("UNUSED")
@ -44,6 +45,13 @@ class SettingsListFragment : PreferenceFragmentCompat() {
setPreferencesFromResource(R.xml.prefs_main, rootKey)
}
override fun onDisplayPreferenceDialog(preference: Preference?) {
if (preference is IntListPreference) {
IntListPrefDialog(preference).show(childFragmentManager, IntListPrefDialog.TAG)
} else {
super.onDisplayPreferenceDialog(preference)
}
}
/**
* Recursively call [handlePreference] on a preference.
*/
@ -64,44 +72,35 @@ class SettingsListFragment : PreferenceFragmentCompat() {
private fun handlePreference(pref: Preference) {
pref.apply {
when (key) {
SettingsManager.Keys.KEY_THEME -> {
SettingsManager.KEY_THEME -> {
setIcon(AppCompatDelegate.getDefaultNightMode().toThemeIcon())
onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, value ->
AppCompatDelegate.setDefaultNightMode((value as String).toThemeInt())
AppCompatDelegate.setDefaultNightMode(value as Int)
setIcon(AppCompatDelegate.getDefaultNightMode().toThemeIcon())
true
}
}
SettingsManager.Keys.KEY_ACCENT -> {
SettingsManager.KEY_ACCENT -> {
onPreferenceClickListener = Preference.OnPreferenceClickListener {
AccentDialog().show(childFragmentManager, TAG_ACCENT_DIALOG)
AccentDialog().show(childFragmentManager, AccentDialog.TAG)
true
}
summary = Accent.get().getDetailedSummary(context)
}
SettingsManager.Keys.KEY_EDGE_TO_EDGE -> {
onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, _ ->
requireActivity().recreate()
true
}
}
SettingsManager.Keys.KEY_LIBRARY_DISPLAY_MODE -> {
SettingsManager.KEY_LIB_DISPLAY_MODE -> {
setIcon(settingsManager.libraryDisplayMode.iconRes)
onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, value ->
setIcon(DisplayMode.valueOfOrFallback(value as String).iconRes)
setIcon(DisplayMode.fromInt(value as Int)!!.iconRes)
true
}
}
SettingsManager.Keys.KEY_SHOW_COVERS -> {
SettingsManager.KEY_SHOW_COVERS -> {
onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, _ ->
Coil.imageLoader(requireContext()).apply {
bitmapPool.clear()
@ -114,7 +113,7 @@ class SettingsListFragment : PreferenceFragmentCompat() {
}
}
SettingsManager.Keys.KEY_QUALITY_COVERS -> {
SettingsManager.KEY_QUALITY_COVERS -> {
onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, _ ->
// Clear out any cached images, before recreating the activity
Coil.imageLoader(requireContext()).apply {
@ -128,7 +127,7 @@ class SettingsListFragment : PreferenceFragmentCompat() {
}
}
SettingsManager.Keys.KEY_SAVE_STATE -> {
SettingsManager.KEY_SAVE_STATE -> {
onPreferenceClickListener = Preference.OnPreferenceClickListener {
playbackModel.savePlaybackState(requireContext()) {
getString(R.string.label_state_saved).createToast(requireContext())
@ -137,17 +136,13 @@ class SettingsListFragment : PreferenceFragmentCompat() {
}
}
SettingsManager.Keys.KEY_BLACKLIST -> {
SettingsManager.KEY_BLACKLIST -> {
onPreferenceClickListener = Preference.OnPreferenceClickListener {
BlacklistDialog().show(childFragmentManager, TAG_ACCENT_DIALOG)
BlacklistDialog().show(childFragmentManager, BlacklistDialog.TAG)
true
}
}
}
}
}
companion object {
const val TAG_ACCENT_DIALOG = "ACCENT_DIALOG"
}
}

View file

@ -2,8 +2,8 @@ package org.oxycblt.auxio.settings
import android.content.Context
import android.content.SharedPreferences
import androidx.core.content.edit
import androidx.preference.PreferenceManager
import org.oxycblt.auxio.logD
import org.oxycblt.auxio.playback.state.PlaybackMode
import org.oxycblt.auxio.recycler.DisplayMode
import org.oxycblt.auxio.recycler.SortMode
@ -16,9 +16,16 @@ import org.oxycblt.auxio.ui.Accent
*/
class SettingsManager private constructor(context: Context) :
SharedPreferences.OnSharedPreferenceChangeListener {
private val sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context)
init {
// If needed, we need to touch the song mode pref so that it migrates before something
// else is written by the Preference.
if (!sharedPrefs.contains(KEY_SONG_PLAYBACK_MODE)) {
handleSongPlayModeCompat(sharedPrefs)
}
sharedPrefs.registerOnSharedPreferenceChangeListener(this)
}
@ -26,125 +33,93 @@ class SettingsManager private constructor(context: Context) :
/** The current theme */
val theme: Int
get() = sharedPrefs.getString(Keys.KEY_THEME, EntryValues.THEME_AUTO)!!.toThemeInt()
get() = handleThemeCompat(sharedPrefs)
/** The current accent. */
var accent: Accent
get() {
@Suppress("DEPRECATION")
if (sharedPrefs.contains(Keys.KEY_ACCENT_OLD)) {
logD("Migrating from old accent to new accent.")
val newAccent = handleAccentCompat(
sharedPrefs.getInt(Keys.KEY_ACCENT_OLD, 5)
)
// When converted, write them to the new accent pref and delete the old one.
sharedPrefs.edit()
.putInt(Keys.KEY_ACCENT, newAccent)
.remove(Keys.KEY_ACCENT_OLD)
.apply()
}
return ACCENTS[sharedPrefs.getInt(Keys.KEY_ACCENT, 5)]
}
get() = handleAccentCompat(sharedPrefs)
set(value) {
val accentIndex = ACCENTS.indexOf(value)
check(accentIndex != -1) { "Invalid accent" }
sharedPrefs.edit()
.putInt(Keys.KEY_ACCENT, accentIndex)
.apply()
sharedPrefs.edit {
putInt(KEY_ACCENT, accentIndex)
apply()
}
}
/** Whether to colorize the notification */
val colorizeNotif: Boolean
get() = sharedPrefs.getBoolean(Keys.KEY_COLORIZE_NOTIFICATION, true)
get() = sharedPrefs.getBoolean(KEY_COLORIZE_NOTIFICATION, true)
/**
* Whether to display the LoopMode or the shuffle status on the notification.
* False if loop, true if shuffle.
*/
val useAltNotifAction: Boolean
get() = sharedPrefs.getBoolean(Keys.KEY_USE_ALT_NOTIFICATION_ACTION, false)
get() = sharedPrefs.getBoolean(KEY_USE_ALT_NOTIFICATION_ACTION, false)
/** What to display on the library. */
val libraryDisplayMode: DisplayMode
get() = DisplayMode.valueOfOrFallback(
sharedPrefs.getString(
Keys.KEY_LIBRARY_DISPLAY_MODE,
DisplayMode.SHOW_ARTISTS.toString()
)
)
get() = handleLibDisplayCompat(sharedPrefs)
/**
* Whether to even loading embedded covers
* TODO: Make the UI result of this better?
*/
val showCovers: Boolean
get() = sharedPrefs.getBoolean(Keys.KEY_SHOW_COVERS, true)
get() = sharedPrefs.getBoolean(KEY_SHOW_COVERS, true)
/** Whether to ignore MediaStore covers */
val useQualityCovers: Boolean
get() = sharedPrefs.getBoolean(Keys.KEY_QUALITY_COVERS, false)
get() = sharedPrefs.getBoolean(KEY_QUALITY_COVERS, false)
/** Whether to do Audio focus. */
val doAudioFocus: Boolean
get() = sharedPrefs.getBoolean(Keys.KEY_AUDIO_FOCUS, true)
get() = sharedPrefs.getBoolean(KEY_AUDIO_FOCUS, true)
/** Whether to resume/stop playback when a headset is connected/disconnected. */
val doPlugMgt: Boolean
get() = sharedPrefs.getBoolean(Keys.KEY_PLUG_MANAGEMENT, true)
get() = sharedPrefs.getBoolean(KEY_PLUG_MANAGEMENT, true)
/** What queue to create when a song is selected (ex. From All Songs or Search) */
val songPlaybackMode: PlaybackMode
get() = PlaybackMode.valueOfOrFallback(
sharedPrefs.getString(
Keys.KEY_SONG_PLAYBACK_MODE,
PlaybackMode.ALL_SONGS.toString()
)
)
get() = handleSongPlayModeCompat(sharedPrefs)
/** What to do at the end of a playlist. */
val doAtEnd: String
get() = sharedPrefs.getString(Keys.KEY_AT_END, EntryValues.AT_END_LOOP_PAUSE)
get() = sharedPrefs.getString(KEY_AT_END, EntryValues.AT_END_LOOP_PAUSE)
?: EntryValues.AT_END_LOOP_PAUSE
/** Whether shuffle should stay on when a new song is selected. */
val keepShuffle: Boolean
get() = sharedPrefs.getBoolean(Keys.KEY_KEEP_SHUFFLE, true)
get() = sharedPrefs.getBoolean(KEY_KEEP_SHUFFLE, true)
/** Whether to rewind when the back button is pressed. */
val rewindWithPrev: Boolean
get() = sharedPrefs.getBoolean(Keys.KEY_PREV_REWIND, true)
get() = sharedPrefs.getBoolean(KEY_PREV_REWIND, true)
/** The current [SortMode] of the library. */
var librarySortMode: SortMode
get() = SortMode.fromInt(
sharedPrefs.getInt(
Keys.KEY_LIBRARY_SORT_MODE, SortMode.CONST_SORT_DEFAULT
)
sharedPrefs.getInt(KEY_LIBRARY_SORT_MODE, SortMode.CONST_ALPHA_DOWN)
) ?: SortMode.ALPHA_DOWN
set(value) {
sharedPrefs.edit()
.putInt(Keys.KEY_LIBRARY_SORT_MODE, value.toInt())
.apply()
sharedPrefs.edit {
putInt(KEY_LIBRARY_SORT_MODE, value.toInt())
apply()
}
}
/** The current filter mode of the search tab */
var searchFilterMode: DisplayMode
get() = DisplayMode.valueOfOrFallback(
sharedPrefs.getString(
Keys.KEY_SEARCH_FILTER_MODE, DisplayMode.SHOW_ALL.toString()
),
fallback = DisplayMode.SHOW_ALL
)
get() = handleSearchModeCompat(sharedPrefs)
set(value) {
sharedPrefs.edit()
.putString(Keys.KEY_SEARCH_FILTER_MODE, value.toString())
.apply()
sharedPrefs.edit {
putInt(KEY_SEARCH_FILTER_MODE, value.toInt())
apply()
}
}
// --- CALLBACKS ---
@ -163,89 +138,31 @@ class SettingsManager private constructor(context: Context) :
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
when (key) {
Keys.KEY_COLORIZE_NOTIFICATION -> callbacks.forEach {
KEY_COLORIZE_NOTIFICATION -> callbacks.forEach {
it.onColorizeNotifUpdate(colorizeNotif)
}
Keys.KEY_USE_ALT_NOTIFICATION_ACTION -> callbacks.forEach {
KEY_USE_ALT_NOTIFICATION_ACTION -> callbacks.forEach {
it.onNotifActionUpdate(useAltNotifAction)
}
Keys.KEY_LIBRARY_DISPLAY_MODE -> callbacks.forEach {
KEY_LIB_DISPLAY_MODE -> callbacks.forEach {
it.onLibDisplayModeUpdate(libraryDisplayMode)
}
Keys.KEY_SHOW_COVERS -> callbacks.forEach {
KEY_SHOW_COVERS -> callbacks.forEach {
it.onShowCoverUpdate(showCovers)
}
Keys.KEY_QUALITY_COVERS -> callbacks.forEach {
KEY_QUALITY_COVERS -> callbacks.forEach {
it.onQualityCoverUpdate(useQualityCovers)
}
}
}
/**
* Convert the old accent format of <1.3.1 to the accent format of 1.3.2-Onwards,
* where many accents were changed or removed.
*/
private fun handleAccentCompat(oldAccent: Int): Int {
var newAccent = oldAccent
// Correct any accents over yellow to their correct positions
if (oldAccent > 12) {
newAccent--
}
// Correct neutral accents to the closest accent [Grey]
if (newAccent == 18) {
newAccent = 16
}
// If there are still any issues with indices, just correct them so a crash doesnt occur.
if (newAccent > ACCENTS.lastIndex) {
newAccent = ACCENTS.lastIndex
}
return newAccent
}
/**
* SharedPreferences keys.
*/
object Keys {
const val KEY_THEME = "KEY_THEME"
const val KEY_ACCENT = "KEY_ACCENT2"
const val KEY_EDGE_TO_EDGE = "KEY_EDGE"
const val KEY_LIBRARY_DISPLAY_MODE = "KEY_LIBRARY_DISPLAY_MODE"
const val KEY_SHOW_COVERS = "KEY_SHOW_COVERS"
const val KEY_QUALITY_COVERS = "KEY_QUALITY_COVERS"
const val KEY_COLORIZE_NOTIFICATION = "KEY_COLOR_NOTIF"
const val KEY_USE_ALT_NOTIFICATION_ACTION = "KEY_ALT_NOTIF_ACTION"
const val KEY_AUDIO_FOCUS = "KEY_AUDIO_FOCUS"
const val KEY_PLUG_MANAGEMENT = "KEY_PLUG_MGT"
const val KEY_SONG_PLAYBACK_MODE = "KEY_SONG_PLAY_MODE"
const val KEY_AT_END = "KEY_AT_END"
const val KEY_KEEP_SHUFFLE = "KEY_KEEP_SHUFFLE"
const val KEY_PREV_REWIND = "KEY_PREV_REWIND"
const val KEY_LIBRARY_SORT_MODE = "KEY_LIBRARY_SORT_MODE"
const val KEY_SEARCH_FILTER_MODE = "KEY_SEARCH"
const val KEY_SAVE_STATE = "KEY_SAVE_STATE"
const val KEY_BLACKLIST = "KEY_BLACKLIST"
@Deprecated("Use the new KEY_ACCENT instead.")
const val KEY_ACCENT_OLD = "KEY_ACCENT"
}
/**
* Values for some settings entries that arent important enough to recieve an enum.
*/
object EntryValues {
const val THEME_AUTO = "AUTO"
const val THEME_LIGHT = "LIGHT"
const val THEME_DARK = "DARK"
/** Pause and loop at the end. Similar to Spotify. */
const val AT_END_LOOP_PAUSE = "LOOP_PAUSE"
@ -270,6 +187,29 @@ class SettingsManager private constructor(context: Context) :
}
companion object {
const val KEY_THEME = "KEY_THEME2"
const val KEY_ACCENT = "KEY_ACCENT2"
const val KEY_LIB_DISPLAY_MODE = "KEY_LIB_MODE"
const val KEY_SHOW_COVERS = "KEY_SHOW_COVERS"
const val KEY_QUALITY_COVERS = "KEY_QUALITY_COVERS"
const val KEY_COLORIZE_NOTIFICATION = "KEY_COLOR_NOTIF"
const val KEY_USE_ALT_NOTIFICATION_ACTION = "KEY_ALT_NOTIF_ACTION"
const val KEY_AUDIO_FOCUS = "KEY_AUDIO_FOCUS"
const val KEY_PLUG_MANAGEMENT = "KEY_PLUG_MGT"
const val KEY_SONG_PLAYBACK_MODE = "KEY_SONG_PLAY_MODE2"
const val KEY_AT_END = "KEY_AT_END"
const val KEY_KEEP_SHUFFLE = "KEY_KEEP_SHUFFLE"
const val KEY_PREV_REWIND = "KEY_PREV_REWIND"
const val KEY_SAVE_STATE = "KEY_SAVE_STATE"
const val KEY_BLACKLIST = "KEY_BLACKLIST"
const val KEY_LIBRARY_SORT_MODE = "KEY_LIBRARY_SORT_MODE"
const val KEY_SEARCH_FILTER_MODE = "KEY_SEARCH_FILTER"
@Volatile
private var INSTANCE: SettingsManager? = null

View file

@ -80,6 +80,7 @@ class AccentDialog : LifecycleDialog() {
}
companion object {
const val TAG = "TAG_ACCENT_DIALOG"
const val KEY_PENDING_ACCENT = "AXKEY_PEND_ACCENT"
}
}

View file

@ -156,4 +156,8 @@ class BlacklistDialog : LifecycleDialog() {
private fun getRootPath(): String {
return Environment.getExternalStorageDirectory().absolutePath
}
companion object {
const val TAG = "TAG_BLACKLIST_DIALOG"
}
}

View file

@ -0,0 +1,21 @@
package org.oxycblt.auxio.settings.ui
import androidx.appcompat.app.AlertDialog
class IntListPrefDialog(private val pref: IntListPreference) : LifecycleDialog() {
override fun onConfigDialog(builder: AlertDialog.Builder) {
builder.setTitle(pref.title)
builder.setSingleChoiceItems(pref.entries, pref.getValueIndex()) { _, index ->
pref.setValue(pref.values[index])
dismiss()
}
builder.setNegativeButton(android.R.string.cancel, null)
}
companion object {
const val TAG = "TAG_INT_PREF_DIALOG"
}
}

View file

@ -0,0 +1,85 @@
package org.oxycblt.auxio.settings.ui
import android.content.Context
import android.content.res.TypedArray
import android.util.AttributeSet
import androidx.preference.DialogPreference
import org.oxycblt.auxio.R
import androidx.preference.R as prefR
class IntListPreference @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = prefR.attr.dialogPreferenceStyle,
defStyleRes: Int = 0
) : DialogPreference(context, attrs, defStyleAttr, defStyleRes) {
val entries: Array<CharSequence>
val values: IntArray
var currentValue: Int? = null
private set
private val default: Int
init {
val prefAttrs = context.obtainStyledAttributes(
attrs, R.styleable.IntListPreference, defStyleAttr, defStyleRes
)
entries = prefAttrs.getTextArray(R.styleable.IntListPreference_entries)
values = context.resources.getIntArray(
prefAttrs.getResourceId(R.styleable.IntListPreference_entryValues, -1)
)
default = prefAttrs.getInt(prefR.styleable.Preference_defaultValue, Int.MIN_VALUE)
prefAttrs.recycle()
summaryProvider = IntListSummaryProvider()
}
override fun onGetDefaultValue(a: TypedArray, index: Int) = a.getInt(index, -1)
override fun onSetInitialValue(defaultValue: Any?) {
super.onSetInitialValue(defaultValue)
if (defaultValue != null) {
// If were given a default value, we need to assign it.
setValue(defaultValue as Int)
} else {
currentValue = getPersistedInt(default)
}
}
fun getValueIndex(): Int {
val curValue = currentValue
if (curValue != null) {
return values.indexOf(curValue)
}
return -1
}
fun setValue(value: Int) {
if (value != currentValue) {
currentValue = value
callChangeListener(value)
persistInt(value)
notifyChanged()
}
}
private inner class IntListSummaryProvider : SummaryProvider<IntListPreference> {
override fun provideSummary(preference: IntListPreference?): CharSequence {
val index = getValueIndex()
if (index != -1) {
return entries[index]
}
return context.getString(prefR.string.not_set)
}
}
}

View file

@ -47,7 +47,7 @@ data class Accent(@ColorRes val color: Int, @StyleRes val theme: Int, @StringRes
/**
* Get a [ColorStateList] of the accent
*/
fun getStateList(context: Context): ColorStateList = color.toStateList(context)
fun getStateList(context: Context) = color.toStateList(context)
/**
* Get the name (in bold) and the hex value of a accent.

View file

@ -62,7 +62,6 @@
<string name="setting_theme_day">Hell</string>
<string name="setting_theme_night">Dunkel</string>
<string name="setting_accent">Akzentfarbe</string>
<string name="setting_accent_unknown">Unbekannte Akzentfarbe</string>
<string name="setting_display">Anzeige</string>
<string name="setting_lib_display">Musikbibliothekitems</string>
@ -97,7 +96,7 @@
<string name="setting_content_save">Wiedergabezustand abspeichern</string>
<string name="setting_content_save_desc">Der aktuell Wiedergabezustand jetzt abspeichern</string>
<string name="setting_content_blacklist">Ausgeschlossene Ordner</string>
<string name="setting_content_blacklist_desc">Die Inhalte der ausgeschlossene Ordner sind versteckt von deinen Musikbibliothek</string>
<string name="setting_content_blacklist_desc">Die Inhalte der ausgeschlossene Ordner sind versteckt von deiner Musikbibliothek</string>
<!-- Error Namespace | Error Labels -->
<string name="error_no_music">Keine Musik gefunden</string>

View file

@ -6,11 +6,11 @@
<item>@string/setting_theme_night</item>
</string-array>
<string-array name="values_theme" translatable="false">
<item>AUTO</item>
<item>LIGHT</item>
<item>DARK</item>
</string-array>
<integer-array name="values_theme">
<item>@integer/theme_auto</item>
<item>@integer/theme_light</item>
<item>@integer/theme_dark</item>
</integer-array>
<string-array name="entries_lib_display">
<item>@string/label_genres</item>
@ -18,11 +18,11 @@
<item>@string/label_albums</item>
</string-array>
<string-array name="values_lib_display" translatable="false">
<item>SHOW_GENRES</item>
<item>SHOW_ARTISTS</item>
<item>SHOW_ALBUMS</item>
</string-array>
<integer-array name="values_lib_display">
<item>@integer/display_genre</item>
<item>@integer/display_artist</item>
<item>@integer/display_album</item>
</integer-array>
<array name="entries_song_playback_mode">
<item>@string/label_play_all_songs</item>
@ -31,11 +31,11 @@
<item>@string/label_play_genre</item>
</array>
<string-array name="values_song_playback_mode" translatable="false">
<item>ALL_SONGS</item>
<item>IN_ARTIST</item>
<item>IN_ALBUM</item>
<item>IN_GENRE</item>
<string-array name="values_song_playback_mode">
<item>@integer/play_mode_songs</item>
<item>@integer/play_mode_artist</item>
<item>@integer/play_mode_album</item>
<item>@integer/play_mode_genre</item>
</string-array>
<string-array name="entries_at_end">
@ -44,7 +44,7 @@
<item>@string/setting_behavior_end_stop</item>
</string-array>
<string-array name="values_at_end" translatable="false">
<string-array name="values_at_end">
<item>LOOP_PAUSE</item>
<item>LOOP</item>
<item>STOP</item>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="theme_auto">-1</integer>
<integer name="theme_light">1</integer>
<integer name="theme_dark">2</integer>
<integer name="display_genre">0xA108</integer>
<integer name="display_artist">0xA109</integer>
<integer name="display_album">0xA10A</integer>
<integer name="play_mode_genre">0xA103</integer>
<integer name="play_mode_artist">0xA104</integer>
<integer name="play_mode_album">0xA105</integer>
<integer name="play_mode_songs">0xA106</integer>
</resources>

View file

@ -63,7 +63,6 @@
<string name="setting_theme_day">Light</string>
<string name="setting_theme_night">Dark</string>
<string name="setting_accent">Accent</string>
<string name="setting_accent_unknown">Unknown Accent</string>
<string name="setting_display">Display</string>
<string name="setting_lib_display">Library Items</string>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="IntListPreference">
<attr name="entries" format="reference" />
<attr name="entryValues" format="reference" />
</declare-styleable>
</resources>

View file

@ -179,7 +179,7 @@
<item name="android:layout_height">wrap_content</item>
<item name="android:clickable">true</item>
<item name="android:focusable">true</item>
<item name="android:theme">@style/Theme.MaterialComponents</item>
<item name="android:theme">@style/Theme.MaterialComponents.DayNight</item>
<item name="rippleColor">@color/selection_color</item>
<item name="fontFamily">@font/inter_semibold</item>
<item name="textAllCaps">false</item>

View file

@ -1,148 +1,150 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<PreferenceCategory
android:layout="@layout/item_header"
android:title="@string/setting_ui">
<ListPreference
android:entries="@array/entires_theme"
android:entryValues="@array/values_theme"
android:icon="@drawable/ic_day"
android:title="@string/setting_theme"
app:defaultValue="AUTO"
app:key="KEY_THEME"
app:useSimpleSummaryProvider="true" />
app:layout="@layout/item_header"
app:title="@string/setting_ui">
<org.oxycblt.auxio.settings.ui.IntListPreference
app:defaultValue="@integer/theme_auto"
app:entries="@array/entires_theme"
app:entryValues="@array/values_theme"
app:iconSpaceReserved="false"
app:key="KEY_THEME2"
app:icon="@drawable/ic_day"
app:title="@string/setting_theme" />
<Preference
android:icon="@drawable/ic_accent"
android:title="@string/setting_accent"
app:allowDividerBelow="false"
app:icon="@drawable/ic_accent"
app:key="KEY_ACCENT2"
app:summary="@string/setting_accent_unknown" />
app:summary="@string/color_label_blue"
app:title="@string/setting_accent" />
</PreferenceCategory>
<PreferenceCategory
android:layout="@layout/item_header"
android:title="@string/setting_display">
app:layout="@layout/item_header"
app:title="@string/setting_display">
<ListPreference
android:icon="@drawable/ic_artist"
android:title="@string/setting_lib_display"
app:defaultValue="SHOW_ARTISTS"
<org.oxycblt.auxio.settings.ui.IntListPreference
app:defaultValue="@integer/display_artist"
app:entries="@array/entries_lib_display"
app:entryValues="@array/values_lib_display"
app:key="KEY_LIBRARY_DISPLAY_MODE"
app:icon="@drawable/ic_artist"
app:key="KEY_LIB_MODE"
app:title="@string/setting_lib_display"
app:useSimpleSummaryProvider="true" />
<SwitchPreferenceCompat
android:title="@string/setting_show_covers"
app:defaultValue="true"
app:iconSpaceReserved="false"
app:key="KEY_SHOW_COVERS"
app:summary="@string/setting_show_covers_desc" />
app:summary="@string/setting_show_covers_desc"
app:title="@string/setting_show_covers" />
<SwitchPreferenceCompat
android:title="@string/setting_quality_covers"
app:defaultValue="false"
app:dependency="KEY_SHOW_COVERS"
app:iconSpaceReserved="false"
app:key="KEY_QUALITY_COVERS"
app:summary="@string/setting_quality_covers_desc" />
app:summary="@string/setting_quality_covers_desc"
app:title="@string/setting_quality_covers" />
<SwitchPreferenceCompat
android:title="@string/setting_color_notif"
app:defaultValue="true"
app:dependency="KEY_SHOW_COVERS"
app:iconSpaceReserved="false"
app:key="KEY_COLOR_NOTIF"
app:summary="@string/setting_color_desc" />
app:summary="@string/setting_color_desc"
app:title="@string/setting_color_notif" />
<SwitchPreferenceCompat
android:title="@string/setting_use_alt_action"
app:allowDividerBelow="false"
app:defaultValue="false"
app:iconSpaceReserved="false"
app:key="KEY_ALT_NOTIF_ACTION"
app:summaryOff="@string/setting_use_alt_loop"
app:summaryOn="@string/setting_use_alt_shuffle" />
app:summaryOn="@string/setting_use_alt_shuffle"
app:title="@string/setting_use_alt_action" />
</PreferenceCategory>
<PreferenceCategory
android:layout="@layout/item_header"
android:title="@string/setting_audio">
app:layout="@layout/item_header"
app:title="@string/setting_audio">
<SwitchPreferenceCompat
android:title="@string/setting_audio_focus"
app:defaultValue="true"
app:iconSpaceReserved="false"
app:key="KEY_AUDIO_FOCUS"
app:summary="@string/setting_audio_focus_desc" />
app:summary="@string/setting_audio_focus_desc"
app:title="@string/setting_audio_focus" />
<SwitchPreferenceCompat
android:title="@string/setting_audio_plug_mgt"
app:allowDividerBelow="false"
app:defaultValue="true"
app:iconSpaceReserved="false"
app:key="KEY_PLUG_MGT"
app:summary="@string/setting_audio_plug_mgt_desc" />
app:summary="@string/setting_audio_plug_mgt_desc"
app:title="@string/setting_audio_plug_mgt" />
</PreferenceCategory>
<PreferenceCategory
android:layout="@layout/item_header"
android:title="@string/setting_behavior">
app:layout="@layout/item_header"
app:title="@string/setting_behavior">
<ListPreference
android:title="@string/setting_behavior_song_playback_mode"
app:defaultValue="ALL_SONGS"
<org.oxycblt.auxio.settings.ui.IntListPreference
app:defaultValue="@integer/play_mode_songs"
app:entries="@array/entries_song_playback_mode"
app:entryValues="@array/values_song_playback_mode"
app:iconSpaceReserved="false"
app:key="KEY_SONG_PLAY_MODE"
app:key="KEY_SONG_PLAY_MODE2"
app:title="@string/setting_behavior_song_playback_mode"
app:useSimpleSummaryProvider="true" />
<ListPreference
android:title="@string/setting_behavior_at_end"
app:defaultValue="LOOP_PAUSE"
app:entries="@array/entries_at_end"
app:entryValues="@array/values_at_end"
app:iconSpaceReserved="false"
app:key="KEY_AT_END"
app:title="@string/setting_behavior_at_end"
app:useSimpleSummaryProvider="true" />
<SwitchPreferenceCompat
android:title="@string/setting_behavior_keep_shuffle"
app:defaultValue="true"
app:iconSpaceReserved="false"
app:key="KEY_KEEP_SHUFFLE"
app:summary="@string/setting_behavior_keep_shuffle_desc" />
app:summary="@string/setting_behavior_keep_shuffle_desc"
app:title="@string/setting_behavior_keep_shuffle" />
<SwitchPreference
android:title="@string/setting_behavior_rewind_prev"
app:allowDividerBelow="false"
app:defaultValue="true"
app:iconSpaceReserved="false"
app:key="KEY_PREV_REWIND"
app:summary="@string/setting_behavior_rewind_prev_desc" />
app:summary="@string/setting_behavior_rewind_prev_desc"
app:title="@string/setting_behavior_rewind_prev" />
</PreferenceCategory>
<PreferenceCategory
android:layout="@layout/item_header"
android:title="@string/setting_content">
app:layout="@layout/item_header"
app:title="@string/setting_content">
<Preference
android:title="@string/setting_content_save"
app:iconSpaceReserved="false"
app:key="KEY_SAVE_STATE"
app:summary="@string/setting_content_save_desc" />
app:summary="@string/setting_content_save_desc"
app:title="@string/setting_content_save" />
<Preference
android:title="@string/setting_content_blacklist"
app:iconSpaceReserved="false"
app:key="KEY_BLACKLIST"
app:summary="@string/setting_content_blacklist_desc" />
app:summary="@string/setting_content_blacklist_desc"
app:title="@string/setting_content_blacklist" />
</PreferenceCategory>
</PreferenceScreen>

View file

@ -1,6 +1,6 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = "1.4.31"
ext.kotlin_version = "1.4.32"
ext.navigation_version = "2.3.4"
repositories {

View file

@ -29,6 +29,57 @@ When creating a ViewHolder for a `RecyclerView`, one should use `BaseViewHolder`
Data is often bound using Binding Adapters, which are XML attributes assigned in layout files that can automatically display data, usually written as `app:bindingAdapterName="@{data}"`. Its recommended to use these instead of duplicating code manually.
#### Integers
Integer representations of data/ui elements are used heavily in Auxio.
To prevent any strange bugs, all integer representations must be unique. A table of all current integers used are shown below:
```
0xA0XX | UI Integer Space [Required by android]
0xA000 | SongViewHolder
0xA001 | AlbumViewHolder
0xA002 | ArtistViewHolder
0xA003 | GenreViewHolder
0xA004 | HeaderViewHolder
0xA005 | QueueSongViewHolder
0xA006 | UserQueueHeaderViewHolder
0xA007 | AlbumHeaderViewHolder
0xA008 | AlbumSongViewHolder
0xA009 | ArtistHeaderViewHolder
0xA00A | ArtistAlbumViewHolder
0xA00B | GenreHeaderViewHolder
0xA00C | GenreSongViewHolder
0xA0A0 | Auxio notification code
0xA0C0 | Auxio request code
0xA1XX | Data Integer Space [Stored for IO efficency]
0xA100 | LoopMode.NONE
0xA101 | LoopMode.ONCE
0xA102 | LoopMode.INFINITE
0xA103 | PlaybackMode.IN_GENRE
0xA104 | PlaybackMode.IN_ARTIST
0xA105 | PlaybackMode.IN_ALBUM
0xA106 | PlaybackMode.ALL_SONGS
0xA107 | DisplayMode.SHOW_ALL
0xA108 | DisplayMode.SHOW_GENRES
0xA109 | DisplayMode.SHOW_ARTISTS
0xA10A | DisplayMode.SHOW_ALBUMS
0xA10B | DisplayMode.SHOW_SONGS
0xA10C | SortMode.NONE
0xA10D | SortMode.ALPHA_UP
0xA10E | SortMode.ALPHA_DOWN
0xA10F | SortMode.NUMERIC_UP
0xA110 | SortMode.NUMERIC_DOWN
```
#### Package structure overview
Auxio's package structure is mostly based around the features, and then any sub-features or components involved with that. There are some shared packages however. A diagram of the package structure is shown below:
@ -51,7 +102,8 @@ org.oxycblt.auxio # Main UI's and logging utilities
├──.search # Search UI
├──.settings # Settings UI and systems
│ ├──.blacklist # Excluded Directories UI/Systems
│ └──.ui # Contains UI's related to the settings view, such as the about screen
│ ├──.accent # Accent UI + Systems
│ └──.ui # Settings-Related UIs
├──.songs # Songs UI
└──.ui # Shared user interface utilities
```
@ -120,7 +172,7 @@ Shared RecyclerView utilities, often for adapters and ViewHolders. Important one
#### `.settings`
The settings system is primarily based off of `SettingsManager`, a wrapper around `SharedPreferences`. This allows settings to be read/written in a much simpler/safer manner and without a context being needed. The Settings UI is largely contained in `SettingsListFragment`, while the `.ui` sub-package contains UIs related to the settings UI, such as the About Dialog.
The settings system is primarily based off of `SettingsManager`, a wrapper around `SharedPreferences`. This allows settings to be read/written in a much simpler/safer manner and without a context being needed. The Settings UI is largely contained in `SettingsListFragment`, while the sub-packages contain sub-uis related to the `SettingsListFragment`, such as the custom list preference `IntListPreference` and the about dialog.
#### `.search`