diff --git a/app/src/main/java/org/oxycblt/auxio/MainActivity.kt b/app/src/main/java/org/oxycblt/auxio/MainActivity.kt index 5488523ce..cdeac30b2 100644 --- a/app/src/main/java/org/oxycblt/auxio/MainActivity.kt +++ b/app/src/main/java/org/oxycblt/auxio/MainActivity.kt @@ -14,7 +14,7 @@ import org.oxycblt.auxio.ui.accent // lead to nothing being displayed [Possibly Un-fixable] // TODO: Landscape UI layouts // FIXME: Compat issue with Versions 5 that leads to progress bar looking off -class MainActivity : AppCompatActivity(R.layout.activity_main), SettingsManager.Callback { +class MainActivity : AppCompatActivity(R.layout.activity_main) { override fun onCreateView(name: String, context: Context, attrs: AttributeSet): View? { val settingsManager = SettingsManager.init(applicationContext) @@ -38,25 +38,11 @@ class MainActivity : AppCompatActivity(R.layout.activity_main), SettingsManager. } } - override fun onResume() { - super.onResume() - - // Perform callback additions/removals in onPause/onResume so that they are always - // ran when the activity is recreated. - SettingsManager.getInstance().addCallback(this) - } - - override fun onPause() { - super.onPause() - - SettingsManager.getInstance().removeCallback(this) - } - - override fun onThemeUpdate(newTheme: Int) { + fun doThemeRecreate(newTheme: Int) { AppCompatDelegate.setDefaultNightMode(newTheme) } - override fun onAccentUpdate(newAccent: Pair) { + fun doAccentRecreate() { recreate() } } diff --git a/app/src/main/java/org/oxycblt/auxio/playback/state/LoopMode.kt b/app/src/main/java/org/oxycblt/auxio/playback/state/LoopMode.kt index 03204af70..ad427db45 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/state/LoopMode.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/state/LoopMode.kt @@ -11,7 +11,7 @@ enum class LoopMode { } } - fun toConstant(): Int { + fun toInt(): Int { return when (this) { NONE -> CONSTANT_NONE ONCE -> CONSTANT_ONCE @@ -24,7 +24,7 @@ enum class LoopMode { const val CONSTANT_ONCE = 0xA051 const val CONSTANT_INFINITE = 0xA052 - fun fromConstant(constant: Int): LoopMode? { + fun fromInt(constant: Int): LoopMode? { return when (constant) { CONSTANT_NONE -> NONE CONSTANT_ONCE -> ONCE diff --git a/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackMode.kt b/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackMode.kt index 4ad5a8145..235e8d396 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackMode.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackMode.kt @@ -7,7 +7,7 @@ package org.oxycblt.auxio.playback.state enum class PlaybackMode { IN_ARTIST, IN_GENRE, IN_ALBUM, ALL_SONGS; - fun toConstant(): Int { + fun toInt(): Int { return when (this) { IN_ARTIST -> CONSTANT_IN_ARTIST IN_GENRE -> CONSTANT_IN_GENRE @@ -22,7 +22,7 @@ enum class PlaybackMode { const val CONSTANT_IN_ALBUM = 0xA042 const val CONSTANT_ALL_SONGS = 0xA043 - fun fromConstant(constant: Int): PlaybackMode? { + fun fromInt(constant: Int): PlaybackMode? { return when (constant) { CONSTANT_IN_ARTIST -> IN_ARTIST CONSTANT_IN_ALBUM -> IN_ALBUM diff --git a/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt b/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt index 6137de9d9..dc8750294 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt @@ -511,8 +511,8 @@ class PlaybackStateManager private constructor() { private fun packToPlaybackState(): PlaybackState { val songId = mSong?.id ?: -1L val parentId = mParent?.id ?: -1L - val intMode = mMode.toConstant() - val intLoopMode = mLoopMode.toConstant() + val intMode = mMode.toInt() + val intLoopMode = mLoopMode.toInt() return PlaybackState( songId = songId, @@ -552,8 +552,8 @@ class PlaybackStateManager private constructor() { mSong = musicStore.songs.find { it.id == playbackState.songId } mPosition = playbackState.position mParent = musicStore.parents.find { it.id == playbackState.parentId } - mMode = PlaybackMode.fromConstant(playbackState.mode) ?: PlaybackMode.ALL_SONGS - mLoopMode = LoopMode.fromConstant(playbackState.loopMode) ?: LoopMode.NONE + mMode = PlaybackMode.fromInt(playbackState.mode) ?: PlaybackMode.ALL_SONGS + mLoopMode = LoopMode.fromInt(playbackState.loopMode) ?: LoopMode.NONE mIsShuffling = playbackState.isShuffling mShuffleSeed = playbackState.shuffleSeed mIsInUserQueue = playbackState.inUserQueue diff --git a/app/src/main/java/org/oxycblt/auxio/recycler/SortMode.kt b/app/src/main/java/org/oxycblt/auxio/recycler/SortMode.kt index 3a0cf92d9..19f94f6ff 100644 --- a/app/src/main/java/org/oxycblt/auxio/recycler/SortMode.kt +++ b/app/src/main/java/org/oxycblt/auxio/recycler/SortMode.kt @@ -95,7 +95,7 @@ enum class SortMode(val iconRes: Int) { } } - fun toConstant(): Int { + fun toInt(): Int { return when (this) { NONE -> CONSTANT_NONE ALPHA_UP -> CONSTANT_ALPHA_UP @@ -112,8 +112,8 @@ enum class SortMode(val iconRes: Int) { const val CONSTANT_NUMERIC_UP = 0xA063 const val CONSTANT_NUMERIC_DOWN = 0xA065 - fun fromConstant(constant: Int): SortMode? { - return when (constant) { + fun fromInt(value: Int): SortMode? { + return when (value) { CONSTANT_NONE -> NONE CONSTANT_ALPHA_UP -> ALPHA_UP CONSTANT_ALPHA_DOWN -> ALPHA_DOWN diff --git a/app/src/main/java/org/oxycblt/auxio/settings/SettingListFragment.kt b/app/src/main/java/org/oxycblt/auxio/settings/SettingListFragment.kt index a9984a5e0..4623547bf 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/SettingListFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/SettingListFragment.kt @@ -3,30 +3,74 @@ package org.oxycblt.auxio.settings import android.os.Bundle import android.util.Log import android.view.View +import androidx.appcompat.app.AppCompatDelegate +import androidx.fragment.app.activityViewModels import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.afollestad.materialdialogs.MaterialDialog import com.afollestad.materialdialogs.customview.customView +import org.oxycblt.auxio.MainActivity import org.oxycblt.auxio.R import org.oxycblt.auxio.settings.adapters.AccentAdapter import org.oxycblt.auxio.ui.ACCENTS import org.oxycblt.auxio.ui.accent -import org.oxycblt.auxio.ui.getAccentItemSummary +import org.oxycblt.auxio.ui.getDetailedAccentSummary -class SettingListFragment : PreferenceFragmentCompat(), SettingsManager.Callback { +class SettingListFragment : PreferenceFragmentCompat() { + private val settingsModel: SettingsViewModel by activityViewModels() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - findPreference(SettingsManager.Keys.KEY_ACCENT)?.apply { + val themePref = findPreference(SettingsManager.Keys.KEY_THEME)?.apply { + setIcon( + when (AppCompatDelegate.getDefaultNightMode()) { + AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM -> R.drawable.ic_auto + AppCompatDelegate.MODE_NIGHT_NO -> R.drawable.ic_day + AppCompatDelegate.MODE_NIGHT_YES -> R.drawable.ic_night + + else -> R.drawable.ic_auto + } + ) + } + + val accentPref = findPreference(SettingsManager.Keys.KEY_ACCENT)?.apply { onPreferenceClickListener = Preference.OnPreferenceClickListener { showAccentDialog() true } - summary = getAccentItemSummary(requireActivity(), accent) + summary = getDetailedAccentSummary(requireActivity(), accent) + } + + settingsModel.theme.observe(viewLifecycleOwner) { + if (it != null) { + themePref?.setIcon( + when (it) { + AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM -> R.drawable.ic_auto + AppCompatDelegate.MODE_NIGHT_NO -> R.drawable.ic_day + AppCompatDelegate.MODE_NIGHT_YES -> R.drawable.ic_night + + else -> R.drawable.ic_auto + } + ) + + (requireActivity() as MainActivity).doThemeRecreate(it) + + settingsModel.doneWithThemeUpdate() + } + } + + settingsModel.accent.observe(viewLifecycleOwner) { + if (it != null) { + accentPref?.summary = getDetailedAccentSummary(requireActivity(), it) + + (requireActivity() as MainActivity).doAccentRecreate() + + settingsModel.doneWithAccentUpdate() + } } Log.d(this::class.simpleName, "Fragment created.") @@ -36,18 +80,6 @@ class SettingListFragment : PreferenceFragmentCompat(), SettingsManager.Callback setPreferencesFromResource(R.xml.prefs_main, rootKey) } - override fun onResume() { - super.onResume() - - SettingsManager.getInstance().addCallback(this) - } - - override fun onPause() { - super.onPause() - - SettingsManager.getInstance().removeCallback(this) - } - private fun showAccentDialog() { MaterialDialog(requireActivity()).show { title(R.string.label_settings_accent) @@ -90,10 +122,4 @@ class SettingListFragment : PreferenceFragmentCompat(), SettingsManager.Callback show() } } - - override fun onAccentUpdate(newAccent: Pair) { - findPreference(getString(R.string.label_settings_accent))?.apply { - summary = getAccentItemSummary(requireActivity(), accent) - } - } } diff --git a/app/src/main/java/org/oxycblt/auxio/settings/SettingsManager.kt b/app/src/main/java/org/oxycblt/auxio/settings/SettingsManager.kt index a781a0c0d..ca726cd46 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/SettingsManager.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/SettingsManager.kt @@ -66,12 +66,12 @@ class SettingsManager private constructor(context: Context) : SharedPreferences. fun setLibrarySortMode(sortMode: SortMode) { sharedPrefs.edit() - .putInt(Keys.KEY_LIBRARY_SORT_MODE, sortMode.toConstant()) + .putInt(Keys.KEY_LIBRARY_SORT_MODE, sortMode.toInt()) .apply() } fun getLibrarySortMode(): SortMode { - return SortMode.fromConstant( + return SortMode.fromInt( sharedPrefs.getInt( Keys.KEY_LIBRARY_SORT_MODE, SortMode.CONSTANT_ALPHA_DOWN diff --git a/app/src/main/java/org/oxycblt/auxio/settings/SettingsViewModel.kt b/app/src/main/java/org/oxycblt/auxio/settings/SettingsViewModel.kt new file mode 100644 index 000000000..dc8567a8a --- /dev/null +++ b/app/src/main/java/org/oxycblt/auxio/settings/SettingsViewModel.kt @@ -0,0 +1,45 @@ +package org.oxycblt.auxio.settings + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel + +class SettingsViewModel : ViewModel(), SettingsManager.Callback { + private val mTheme = MutableLiveData() + val theme: LiveData get() = mTheme + + private val mAccent = MutableLiveData?>() + val accent: LiveData?> get() = mAccent + + private val settingsManager = SettingsManager.getInstance() + + init { + settingsManager.addCallback(this) + } + + fun doneWithThemeUpdate() { + mTheme.value = null + } + + fun doneWithAccentUpdate() { + mAccent.value = null + } + + override fun onThemeUpdate(newTheme: Int) { + super.onThemeUpdate(newTheme) + + mTheme.value = newTheme + } + + override fun onAccentUpdate(newAccent: Pair) { + super.onAccentUpdate(newAccent) + + mAccent.value = newAccent + } + + override fun onCleared() { + super.onCleared() + + settingsManager.removeCallback(this) + } +} diff --git a/app/src/main/java/org/oxycblt/auxio/ui/InterfaceUtils.kt b/app/src/main/java/org/oxycblt/auxio/ui/InterfaceUtils.kt index 70461d02a..ee4766f8f 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/InterfaceUtils.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/InterfaceUtils.kt @@ -3,6 +3,7 @@ package org.oxycblt.auxio.ui import android.content.Context import android.content.res.ColorStateList import android.text.SpannableString +import android.text.Spanned import android.text.style.ForegroundColorSpan import android.view.MenuItem import android.widget.ImageButton @@ -10,6 +11,7 @@ import android.widget.Toast import androidx.annotation.ColorInt import androidx.annotation.MenuRes import androidx.appcompat.widget.PopupMenu +import androidx.core.text.HtmlCompat import org.oxycblt.auxio.R import org.oxycblt.auxio.detail.DetailViewModel import org.oxycblt.auxio.music.Album @@ -54,6 +56,16 @@ fun String.createToast(context: Context) { Toast.makeText(context.applicationContext, this, Toast.LENGTH_SHORT).show() } +/** + * "Render" a [Spanned] using [HtmlCompat]. + * @return A [Spanned] that actually works. + */ +fun Spanned.render(): Spanned { + return HtmlCompat.fromHtml( + this.toString(), HtmlCompat.FROM_HTML_OPTION_USE_CSS_COLORS + ) +} + /** * Show actions for a song item, such as the ones found in [org.oxycblt.auxio.songs.SongsFragment] */ diff --git a/app/src/main/java/org/oxycblt/auxio/ui/ThemeUtils.kt b/app/src/main/java/org/oxycblt/auxio/ui/ThemeUtils.kt index 210f02445..2c341ff9c 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/ThemeUtils.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/ThemeUtils.kt @@ -1,12 +1,14 @@ package org.oxycblt.auxio.ui import android.content.Context +import android.text.Spanned import android.util.TypedValue import androidx.annotation.AttrRes import androidx.annotation.ColorInt import androidx.annotation.ColorRes import androidx.core.content.ContextCompat import androidx.core.graphics.ColorUtils +import androidx.core.text.toSpanned import org.oxycblt.auxio.R import java.util.Locale @@ -102,3 +104,13 @@ fun getAccentItemSummary(context: Context, newAccent: Pair): String { return context.resources.getResourceEntryName(newAccent.first) .replace("_", " ").capitalize(Locale.getDefault()) } + +fun getDetailedAccentSummary(context: Context, newAccent: Pair): Spanned { + val name = getAccentItemSummary(context, newAccent) + val hex = context.getString(accent.first).toUpperCase(Locale.getDefault()) + + return context.getString( + R.string.format_accent_summary, + name, hex + ).toSpanned().render() +} diff --git a/app/src/main/res/drawable/ic_auto.xml b/app/src/main/res/drawable/ic_auto.xml new file mode 100644 index 000000000..e80ee38d9 --- /dev/null +++ b/app/src/main/res/drawable/ic_auto.xml @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_night.xml b/app/src/main/res/drawable/ic_night.xml new file mode 100644 index 000000000..99a7fd8e2 --- /dev/null +++ b/app/src/main/res/drawable/ic_night.xml @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8107649d1..928a29590 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -30,7 +30,7 @@ Settings Appearance Theme - Auto + Automatic Light Dark Choose theme @@ -77,6 +77,7 @@ %1$s / %2$s / %3$s %1$s, %2$s Next From: %s + <b>%1s</b>: %2s %s Song diff --git a/app/src/main/res/xml/prefs_main.xml b/app/src/main/res/xml/prefs_main.xml index e6e7583dd..ae3519406 100644 --- a/app/src/main/res/xml/prefs_main.xml +++ b/app/src/main/res/xml/prefs_main.xml @@ -10,6 +10,7 @@ android:icon="@drawable/ic_day" android:entries="@array/theme_entries" android:entryValues="@array/theme_values" + app:defaultValue="AUTO" app:useSimpleSummaryProvider="true" />