From a5f59858bdc1ee7f702bf8a307e56c393d33c082 Mon Sep 17 00:00:00 2001 From: OxygenCobalt Date: Sat, 28 Nov 2020 20:25:41 -0700 Subject: [PATCH] Add accent customization Add the ability to customize the accent. --- app/build.gradle | 2 + app/proguard-rules.pro | 4 +- .../java/org/oxycblt/auxio/MainActivity.kt | 10 ++- .../auxio/settings/SettingListFragment.kt | 90 ++++++++++++++++++- .../oxycblt/auxio/settings/SettingsManager.kt | 51 ++++++++--- .../auxio/settings/adapters/AccentAdapter.kt | 54 +++++++++++ .../java/org/oxycblt/auxio/ui/ThemeUtils.kt | 10 ++- app/src/main/res/drawable/ic_accent.xml | 10 +++ app/src/main/res/drawable/ic_check.xml | 11 +++ app/src/main/res/drawable/ui_circle.xml | 9 ++ app/src/main/res/layout/item_accent.xml | 24 +++++ app/src/main/res/values/arrays.xml | 1 + app/src/main/res/values/strings.xml | 1 + app/src/main/res/values/styles.xml | 7 ++ app/src/main/res/xml/prefs_main.xml | 7 ++ 15 files changed, 272 insertions(+), 19 deletions(-) create mode 100644 app/src/main/java/org/oxycblt/auxio/settings/adapters/AccentAdapter.kt create mode 100644 app/src/main/res/drawable/ic_accent.xml create mode 100644 app/src/main/res/drawable/ic_check.xml create mode 100644 app/src/main/res/drawable/ui_circle.xml create mode 100644 app/src/main/res/layout/item_accent.xml diff --git a/app/build.gradle b/app/build.gradle index 496b40ba8..1ec5af13a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -94,6 +94,8 @@ dependencies { // Fast-Scroll implementation 'com.reddit:indicator-fast-scroll:1.3.0' + implementation 'com.afollestad.material-dialogs:core:3.3.0' + // --- DEV --- // Lint diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index f5fb65b3f..b19c33a72 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -20,4 +20,6 @@ # hide the original source file name. #-renamesourcefileattribute SourceFile --dontobfuscate \ No newline at end of file +-dontobfuscate + +-keep class org.oxycblt.auxio.settings.SettingListFragment \ No newline at end of file diff --git a/app/src/main/java/org/oxycblt/auxio/MainActivity.kt b/app/src/main/java/org/oxycblt/auxio/MainActivity.kt index 0d335d7db..5488523ce 100644 --- a/app/src/main/java/org/oxycblt/auxio/MainActivity.kt +++ b/app/src/main/java/org/oxycblt/auxio/MainActivity.kt @@ -22,6 +22,8 @@ class MainActivity : AppCompatActivity(R.layout.activity_main), SettingsManager. settingsManager.getTheme() ) + accent = settingsManager.getAccent() + // Apply the theme setTheme(accent.second) @@ -50,7 +52,11 @@ class MainActivity : AppCompatActivity(R.layout.activity_main), SettingsManager. SettingsManager.getInstance().removeCallback(this) } - override fun onThemeUpdate(value: Int) { - AppCompatDelegate.setDefaultNightMode(value) + override fun onThemeUpdate(newTheme: Int) { + AppCompatDelegate.setDefaultNightMode(newTheme) + } + + override fun onAccentUpdate(newAccent: Pair) { + recreate() } } 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 8cc29119b..a9984a5e0 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/SettingListFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/SettingListFragment.kt @@ -1,11 +1,99 @@ package org.oxycblt.auxio.settings import android.os.Bundle +import android.util.Log +import android.view.View +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.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 + +class SettingListFragment : PreferenceFragmentCompat(), SettingsManager.Callback { + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + findPreference(SettingsManager.Keys.KEY_ACCENT)?.apply { + onPreferenceClickListener = Preference.OnPreferenceClickListener { + showAccentDialog() + true + } + + summary = getAccentItemSummary(requireActivity(), accent) + } + + Log.d(this::class.simpleName, "Fragment created.") + } -class SettingListFragment : PreferenceFragmentCompat() { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { 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) + + // Roll my own RecyclerView since [To no surprise whatsoever] Material Dialogs + // has a bug where ugly dividers will show with the RecyclerView even if you disable them. + // This is why I hate using third party libraries. + val recycler = RecyclerView(requireContext()).apply { + adapter = AccentAdapter { + if (it.first != accent.first) { + SettingsManager.getInstance().setAccent(it) + } + + this@show.dismiss() + } + + post { + // Combine the width of the recyclerview with the width of an item in order + // to center the currently selected accent. + val childWidth = getChildAt(0).width / 2 + + (layoutManager as LinearLayoutManager) + .scrollToPositionWithOffset( + ACCENTS.indexOf(accent), + (width / 2) - childWidth + ) + } + + layoutManager = LinearLayoutManager( + requireContext() + ).also { it.orientation = LinearLayoutManager.HORIZONTAL } + } + + customView(view = recycler) + + view.invalidateDividers(showTop = false, showBottom = false) + + negativeButton(android.R.string.cancel) + + 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 20b01baa4..a781a0c0d 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/SettingsManager.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/SettingsManager.kt @@ -5,6 +5,7 @@ import android.content.SharedPreferences import androidx.appcompat.app.AppCompatDelegate import androidx.preference.PreferenceManager import org.oxycblt.auxio.recycler.SortMode +import org.oxycblt.auxio.ui.ACCENTS /** * Wrapper around the [SharedPreferences] class that writes & reads values without a context. @@ -30,6 +31,39 @@ class SettingsManager private constructor(context: Context) : SharedPreferences. callbacks.remove(callback) } + fun getTheme(): Int { + // Turn the string from SharedPreferences into an actual theme value that can + // be used, as apparently the preference system provided by androidx doesn't like integers + // for some...reason. + return when (sharedPrefs.getString(Keys.KEY_THEME, Theme.THEME_AUTO)) { + Theme.THEME_AUTO -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM + Theme.THEME_LIGHT -> AppCompatDelegate.MODE_NIGHT_NO + Theme.THEME_DARK -> AppCompatDelegate.MODE_NIGHT_YES + + else -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM + } + } + + fun getAccent(): Pair { + val accentIndex = sharedPrefs.getInt(Keys.KEY_ACCENT, 5) + + return ACCENTS[accentIndex] + } + + fun setAccent(accent: Pair) { + val accentIndex = ACCENTS.indexOf(accent) + + check(accentIndex != -1) { "Invalid accent" } + + sharedPrefs.edit() + .putInt(Keys.KEY_ACCENT, accentIndex) + .apply() + + callbacks.forEach { + it.onAccentUpdate(getAccent()) + } + } + fun setLibrarySortMode(sortMode: SortMode) { sharedPrefs.edit() .putInt(Keys.KEY_LIBRARY_SORT_MODE, sortMode.toConstant()) @@ -45,18 +79,7 @@ class SettingsManager private constructor(context: Context) : SharedPreferences. ) ?: SortMode.ALPHA_DOWN } - fun getTheme(): Int { - // Turn the string from SharedPreferences into an actual theme value that can - // be used, as apparently the preference system provided by androidx doesn't like integers - // for some...reason. - return when (sharedPrefs.getString(Keys.KEY_THEME, Theme.THEME_AUTO)) { - Theme.THEME_AUTO -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM - Theme.THEME_LIGHT -> AppCompatDelegate.MODE_NIGHT_NO - Theme.THEME_DARK -> AppCompatDelegate.MODE_NIGHT_YES - - else -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM - } - } + // --- OVERRIDES --- override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { when (key) { @@ -100,6 +123,7 @@ class SettingsManager private constructor(context: Context) : SharedPreferences. object Keys { const val KEY_LIBRARY_SORT_MODE = "KEY_LIBRARY_SORT_MODE" const val KEY_THEME = "KEY_THEME" + const val KEY_ACCENT = "KEY_ACCENT" } private object Theme { @@ -113,6 +137,7 @@ class SettingsManager private constructor(context: Context) : SharedPreferences. * [SharedPreferences.OnSharedPreferenceChangeListener]. */ interface Callback { - fun onThemeUpdate(value: Int) {} + fun onThemeUpdate(newTheme: Int) {} + fun onAccentUpdate(newAccent: Pair) {} } } diff --git a/app/src/main/java/org/oxycblt/auxio/settings/adapters/AccentAdapter.kt b/app/src/main/java/org/oxycblt/auxio/settings/adapters/AccentAdapter.kt new file mode 100644 index 000000000..3314ed8ca --- /dev/null +++ b/app/src/main/java/org/oxycblt/auxio/settings/adapters/AccentAdapter.kt @@ -0,0 +1,54 @@ +package org.oxycblt.auxio.settings.adapters + +import android.content.res.ColorStateList +import android.util.Log +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import org.oxycblt.auxio.R +import org.oxycblt.auxio.databinding.ItemAccentBinding +import org.oxycblt.auxio.ui.ACCENTS +import org.oxycblt.auxio.ui.accent +import org.oxycblt.auxio.ui.toColor + +class AccentAdapter( + private val doOnAccentConfirm: (accent: Pair) -> Unit +) : RecyclerView.Adapter() { + override fun getItemCount(): Int = ACCENTS.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder(ItemAccentBinding.inflate(LayoutInflater.from(parent.context))) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + holder.bind(ACCENTS[position]) + } + + inner class ViewHolder( + private val binding: ItemAccentBinding + ) : RecyclerView.ViewHolder(binding.root) { + + fun bind(accentData: Pair) { + binding.accent.setOnClickListener { + Log.d(this::class.simpleName, accentData.toString()) + doOnAccentConfirm(accentData) + } + + binding.accent.apply { + imageTintList = if (accentData.first != accent.first) { + ColorStateList.valueOf( + android.R.color.transparent.toColor(context) + ) + } else { + ColorStateList.valueOf( + R.color.background.toColor(context) + ) + } + + backgroundTintList = ColorStateList.valueOf( + accentData.first.toColor(context) + ) + } + } + } +} 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 5913436de..210f02445 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/ThemeUtils.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/ThemeUtils.kt @@ -8,11 +8,12 @@ import androidx.annotation.ColorRes import androidx.core.content.ContextCompat import androidx.core.graphics.ColorUtils import org.oxycblt.auxio.R +import java.util.Locale // Functions for managing colors/accents/whatever. // Pairs of the base accent and its theme -private val ACCENTS = listOf( +val ACCENTS = listOf( Pair(R.color.red, R.style.Theme_Red), // 0 Pair(R.color.pink, R.style.Theme_Pink), // 1 Pair(R.color.purple, R.style.Theme_Purple), // 2 @@ -34,7 +35,7 @@ private val ACCENTS = listOf( Pair(R.color.blue_grey, R.style.Theme_BlueGrey) // 18 ) -val accent = ACCENTS[5] +lateinit var accent: Pair /** * Gets the transparent form of a color. @@ -96,3 +97,8 @@ fun resolveAttr(context: Context, @AttrRes attr: Int): Int { return color.toColor(context) } + +fun getAccentItemSummary(context: Context, newAccent: Pair): String { + return context.resources.getResourceEntryName(newAccent.first) + .replace("_", " ").capitalize(Locale.getDefault()) +} diff --git a/app/src/main/res/drawable/ic_accent.xml b/app/src/main/res/drawable/ic_accent.xml new file mode 100644 index 000000000..54fa8c5c4 --- /dev/null +++ b/app/src/main/res/drawable/ic_accent.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_check.xml b/app/src/main/res/drawable/ic_check.xml new file mode 100644 index 000000000..54c0432e0 --- /dev/null +++ b/app/src/main/res/drawable/ic_check.xml @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ui_circle.xml b/app/src/main/res/drawable/ui_circle.xml new file mode 100644 index 000000000..fc9a783a4 --- /dev/null +++ b/app/src/main/res/drawable/ui_circle.xml @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_accent.xml b/app/src/main/res/layout/item_accent.xml new file mode 100644 index 000000000..ebe46d7a5 --- /dev/null +++ b/app/src/main/res/layout/item_accent.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 6e9bd2bcd..1b6a1db54 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -5,6 +5,7 @@ @string/label_settings_theme_light @string/label_settings_theme_dark + AUTO LIGHT diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 61ee9e70f..8107649d1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -34,6 +34,7 @@ Light Dark Choose theme + Accent State saved diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index c9eb164f3..2199f72ec 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -13,6 +13,12 @@ @color/control_color @style/Theme.CustomDialog @style/FastScrollTheme + + @android:color/transparent + @color/background + 0dp + @color/control_color + @font/inter_black @@ -56,6 +62,7 @@ @style/TextAppearance.Dialog.Title @color/control_color @color/control_color + 0dp