Completely refactor accents

Completely refactor the accent system to be much more understandable.
This commit is contained in:
OxygenCobalt 2021-01-18 09:28:31 -07:00
parent 2889e6fdfd
commit c4bc86cb05
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
15 changed files with 181 additions and 184 deletions

View file

@ -11,7 +11,7 @@ import androidx.databinding.DataBindingUtil
import org.oxycblt.auxio.databinding.ActivityMainBinding
import org.oxycblt.auxio.playback.PlaybackService
import org.oxycblt.auxio.settings.SettingsManager
import org.oxycblt.auxio.ui.accent
import org.oxycblt.auxio.ui.Accent
import org.oxycblt.auxio.ui.isEdgeOn
/**
@ -30,10 +30,10 @@ class MainActivity : AppCompatActivity() {
AppCompatDelegate.setDefaultNightMode(settingsManager.theme)
accent = settingsManager.accent
val accent = Accent.set(settingsManager.accent)
// Apply the theme
setTheme(accent.second)
setTheme(accent.theme)
if (isEdgeOn()) {
doEdgeToEdgeSetup(binding)

View file

@ -6,6 +6,7 @@ import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.core.graphics.ColorUtils
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.navigation.NavController
@ -17,8 +18,7 @@ import org.oxycblt.auxio.detail.DetailViewModel
import org.oxycblt.auxio.music.MusicStore
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.ui.accent
import org.oxycblt.auxio.ui.getTransparentAccent
import org.oxycblt.auxio.ui.Accent
import org.oxycblt.auxio.ui.isLandscape
import org.oxycblt.auxio.ui.toColor
@ -45,10 +45,8 @@ class MainFragment : Fragment() {
return null
}
val colorActive = accent.first.toColor(requireContext())
val colorInactive = getTransparentAccent(
requireContext(), accent.first, 150
)
val colorActive = Accent.get().color.toColor(requireContext())
val colorInactive = ColorUtils.setAlphaComponent(colorActive, 150)
// Set up the tints for the navigation icons + text
val navTints = ColorStateList(

View file

@ -16,7 +16,7 @@ import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.recycler.DiffCallback
import org.oxycblt.auxio.recycler.viewholders.BaseViewHolder
import org.oxycblt.auxio.recycler.viewholders.Highlightable
import org.oxycblt.auxio.ui.accent
import org.oxycblt.auxio.ui.Accent
import org.oxycblt.auxio.ui.applyAccents
import org.oxycblt.auxio.ui.disable
import org.oxycblt.auxio.ui.setTextColorResource
@ -138,8 +138,10 @@ class AlbumDetailAdapter(
override fun setHighlighted(isHighlighted: Boolean) {
if (isHighlighted) {
binding.songName.setTextColorResource(accent.first)
binding.songTrack.setTextColorResource(accent.first)
val accent = Accent.get()
binding.songName.setTextColorResource(accent.color)
binding.songTrack.setTextColorResource(accent.color)
} else {
binding.songName.setTextColor(normalTextColor)
binding.songTrack.setTextColor(inactiveTextColor)

View file

@ -16,7 +16,7 @@ import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.recycler.DiffCallback
import org.oxycblt.auxio.recycler.viewholders.BaseViewHolder
import org.oxycblt.auxio.recycler.viewholders.Highlightable
import org.oxycblt.auxio.ui.accent
import org.oxycblt.auxio.ui.Accent
import org.oxycblt.auxio.ui.applyAccents
import org.oxycblt.auxio.ui.disable
import org.oxycblt.auxio.ui.setTextColorResource
@ -137,7 +137,7 @@ class ArtistDetailAdapter(
override fun setHighlighted(isHighlighted: Boolean) {
if (isHighlighted) {
binding.albumName.setTextColorResource(accent.first)
binding.albumName.setTextColorResource(Accent.get().color)
} else {
binding.albumName.setTextColor(normalTextColor)
}

View file

@ -16,7 +16,7 @@ import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.recycler.DiffCallback
import org.oxycblt.auxio.recycler.viewholders.BaseViewHolder
import org.oxycblt.auxio.recycler.viewholders.Highlightable
import org.oxycblt.auxio.ui.accent
import org.oxycblt.auxio.ui.Accent
import org.oxycblt.auxio.ui.applyAccents
import org.oxycblt.auxio.ui.disable
import org.oxycblt.auxio.ui.setTextColorResource
@ -138,7 +138,7 @@ class GenreDetailAdapter(
override fun setHighlighted(isHighlighted: Boolean) {
if (isHighlighted) {
binding.songName.setTextColorResource(accent.first)
binding.songName.setTextColorResource(Accent.get().color)
} else {
binding.songName.setTextColor(normalTextColor)
}

View file

@ -17,7 +17,7 @@ import org.oxycblt.auxio.databinding.FragmentPlaybackBinding
import org.oxycblt.auxio.detail.DetailViewModel
import org.oxycblt.auxio.logD
import org.oxycblt.auxio.playback.state.LoopMode
import org.oxycblt.auxio.ui.accent
import org.oxycblt.auxio.ui.Accent
import org.oxycblt.auxio.ui.memberBinding
import org.oxycblt.auxio.ui.toColor
@ -36,7 +36,7 @@ class PlaybackFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
// Colors
private val accentColor: ColorStateList by lazy {
ColorStateList.valueOf(accent.first.toColor(requireContext()))
Accent.get().getStateList(requireContext())
}
private val controlColor: ColorStateList by lazy {

View file

@ -22,7 +22,7 @@ import androidx.dynamicanimation.animation.SpringForce
import com.reddit.indicatorfastscroll.FastScrollItemIndicator
import com.reddit.indicatorfastscroll.FastScrollerView
import org.oxycblt.auxio.R
import org.oxycblt.auxio.ui.accent
import org.oxycblt.auxio.ui.Accent
import org.oxycblt.auxio.ui.toColor
/**
@ -40,7 +40,7 @@ class NoLeakThumbView @JvmOverloads constructor(
) : ConstraintLayout(context, attrs, defStyleAttr),
FastScrollerView.ItemIndicatorSelectedCallback {
private val thumbColor = ColorStateList.valueOf(accent.first.toColor(context))
private val thumbColor = Accent.get().getStateList(context)
private val iconColor = R.color.background.toColor(context)
private val textAppearanceRes = R.style.TextAppearance_ThumbIndicator
private val textColor = R.color.background.toColor(context)

View file

@ -5,7 +5,6 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.graphics.toColor
import androidx.core.widget.addTextChangedListener
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
@ -23,8 +22,8 @@ import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Header
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.ui.Accent
import org.oxycblt.auxio.ui.ActionMenu
import org.oxycblt.auxio.ui.accent
import org.oxycblt.auxio.ui.fixAnimationInfoMemoryLeak
import org.oxycblt.auxio.ui.getLandscapeSpans
import org.oxycblt.auxio.ui.isLandscape
@ -51,7 +50,7 @@ class SearchFragment : Fragment() {
// Apply the accents manually. Not going through the mess of converting my app's
// styling to Material given all the second-and-third-order effects it has.
val accent = accent.first.toColor(requireContext())
val accent = Accent.get().color.toColor(requireContext())
val searchAdapter = SearchAdapter(::onItemSelection) { view, data ->
ActionMenu(requireCompatActivity(), view, data, ActionMenu.FLAG_NONE)

View file

@ -20,9 +20,8 @@ import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.recycler.DisplayMode
import org.oxycblt.auxio.settings.ui.AccentAdapter
import org.oxycblt.auxio.ui.ACCENTS
import org.oxycblt.auxio.ui.accent
import org.oxycblt.auxio.ui.Accent
import org.oxycblt.auxio.ui.createToast
import org.oxycblt.auxio.ui.getDetailedAccentSummary
/**
* The actual fragment containing the settings menu. Inherits [PreferenceFragmentCompat].
@ -84,7 +83,7 @@ class SettingsListFragment : PreferenceFragmentCompat() {
true
}
summary = getDetailedAccentSummary(requireActivity(), accent)
summary = Accent.get().getDetailedSummary(context)
}
SettingsManager.Keys.KEY_EDGE_TO_EDGE -> {
@ -153,7 +152,7 @@ class SettingsListFragment : PreferenceFragmentCompat() {
// This is why I hate using third party libraries.
val recycler = RecyclerView(requireContext()).apply {
adapter = AccentAdapter {
if (it.first != accent.first) {
if (it != Accent.get()) {
SettingsManager.getInstance().accent = it
requireActivity().recreate()
@ -169,7 +168,7 @@ class SettingsListFragment : PreferenceFragmentCompat() {
(layoutManager as LinearLayoutManager)
.scrollToPositionWithOffset(
ACCENTS.indexOf(accent),
ACCENTS.indexOf(Accent.get()),
(width / 2) - childWidth
)
}

View file

@ -7,6 +7,7 @@ import org.oxycblt.auxio.playback.state.PlaybackMode
import org.oxycblt.auxio.recycler.DisplayMode
import org.oxycblt.auxio.recycler.SortMode
import org.oxycblt.auxio.ui.ACCENTS
import org.oxycblt.auxio.ui.Accent
/**
* Wrapper around the [SharedPreferences] class that writes & reads values without a context.
@ -31,12 +32,10 @@ class SettingsManager private constructor(context: Context) :
/**
* The current accent.
*/
var accent: Pair<Int, Int>
var accent: Accent
get() {
val accentIndex = sharedPrefs.getInt(Keys.KEY_ACCENT, 5)
// Accent is stored as an index [to be efficient], so retrieve it when done.
return ACCENTS[accentIndex]
return ACCENTS[sharedPrefs.getInt(Keys.KEY_ACCENT, 5)]
}
set(value) {
val accentIndex = ACCENTS.indexOf(value)
@ -200,14 +199,14 @@ class SettingsManager private constructor(context: Context) :
companion object {
@Volatile
private lateinit var INSTANCE: SettingsManager
private var INSTANCE: SettingsManager? = null
/**
* Init the single instance of [SettingsManager]. Done so that every object
* can have access to it regardless of if it has a context.
*/
fun init(context: Context): SettingsManager {
if (!::INSTANCE.isInitialized) {
if (INSTANCE == null) {
synchronized(this) {
INSTANCE = SettingsManager(context)
}
@ -220,10 +219,13 @@ class SettingsManager private constructor(context: Context) :
* Get the single instance of [SettingsManager].
*/
fun getInstance(): SettingsManager {
check(::INSTANCE.isInitialized) {
"SettingsManager must be initialized with init() before getting its instance."
val instance = INSTANCE
if (instance != null) {
return instance
}
return INSTANCE
error("SettingsManager must be initialized with init() before getting its instance.")
}
}

View file

@ -7,8 +7,7 @@ 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.getAccentItemSummary
import org.oxycblt.auxio.ui.Accent
import org.oxycblt.auxio.ui.toColor
/**
@ -17,7 +16,7 @@ import org.oxycblt.auxio.ui.toColor
* @param doOnAccentConfirm What to do when an accent is confirmed.
*/
class AccentAdapter(
private val doOnAccentConfirm: (accent: Pair<Int, Int>) -> Unit
private val doOnAccentConfirm: (accent: Accent) -> Unit
) : RecyclerView.Adapter<AccentAdapter.ViewHolder>() {
override fun getItemCount(): Int = ACCENTS.size
@ -33,31 +32,25 @@ class AccentAdapter(
private val binding: ItemAccentBinding
) : RecyclerView.ViewHolder(binding.root) {
fun bind(accentData: Pair<Int, Int>) {
fun bind(accent: Accent) {
binding.accent.apply {
contentDescription = getAccentItemSummary(context, accentData)
contentDescription = accent.getDetailedSummary(context)
setOnClickListener {
doOnAccentConfirm(accentData)
doOnAccentConfirm(accent)
}
imageTintList = if (accentData.first == accent.first) {
imageTintList = if (accent == Accent.get()) {
isEnabled = false
ColorStateList.valueOf(
R.color.background.toColor(context)
)
ColorStateList.valueOf(R.color.background.toColor(context))
} else {
isEnabled = true
ColorStateList.valueOf(
android.R.color.transparent.toColor(context)
)
ColorStateList.valueOf(android.R.color.transparent.toColor(context))
}
backgroundTintList = ColorStateList.valueOf(
accentData.first.toColor(context)
)
backgroundTintList = accent.getStateList(context)
}
}
}

View file

@ -1,6 +1,5 @@
package org.oxycblt.auxio.songs
import android.content.res.ColorStateList
import android.os.Build
import android.os.Bundle
import android.util.TypedValue
@ -18,12 +17,11 @@ import org.oxycblt.auxio.databinding.FragmentSongsBinding
import org.oxycblt.auxio.logD
import org.oxycblt.auxio.music.MusicStore
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.ui.Accent
import org.oxycblt.auxio.ui.ActionMenu
import org.oxycblt.auxio.ui.accent
import org.oxycblt.auxio.ui.getLandscapeSpans
import org.oxycblt.auxio.ui.isLandscape
import org.oxycblt.auxio.ui.requireCompatActivity
import org.oxycblt.auxio.ui.toColor
import kotlin.math.ceil
/**
@ -109,7 +107,7 @@ class SongsFragment : Fragment() {
// API 22 and below don't support the state color, so just use the accent.
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
textColor = ColorStateList.valueOf(accent.first.toColor(requireContext()))
textColor = Accent.get().getStateList(requireContext())
}
setupWithRecyclerView(

View file

@ -0,0 +1,111 @@
package org.oxycblt.auxio.ui
import android.annotation.SuppressLint
import android.content.Context
import android.content.res.ColorStateList
import android.text.Spanned
import androidx.annotation.ColorRes
import androidx.annotation.StringRes
import androidx.annotation.StyleRes
import androidx.core.text.toSpanned
import org.oxycblt.auxio.R
import org.oxycblt.auxio.settings.SettingsManager
import java.util.Locale
/**
* A list of all possible accents.
* TODO: Add custom accents
*/
val ACCENTS = arrayOf(
Accent(R.color.red, R.style.Theme_Red, R.string.color_label_red),
Accent(R.color.pink, R.style.Theme_Pink, R.string.color_label_pink),
Accent(R.color.purple, R.style.Theme_Purple, R.string.color_label_purple),
Accent(R.color.deep_purple, R.style.Theme_DeepPurple, R.string.color_label_deep_purple),
Accent(R.color.indigo, R.style.Theme_Indigo, R.string.color_label_indigo),
Accent(R.color.blue, R.style.Theme_Blue, R.string.color_label_blue),
Accent(R.color.light_blue, R.style.Theme_LightBlue, R.string.color_label_light_blue),
Accent(R.color.cyan, R.style.Theme_Cyan, R.string.color_label_cyan),
Accent(R.color.teal, R.style.Theme_Teal, R.string.color_label_teal),
Accent(R.color.green, R.style.Theme_Green, R.string.color_label_green),
Accent(R.color.light_green, R.style.Theme_LightGreen, R.string.color_label_light_green),
Accent(R.color.lime, R.style.Theme_Lime, R.string.color_label_lime),
Accent(R.color.yellow, R.style.Theme_Yellow, R.string.color_label_yellow),
Accent(R.color.amber, R.style.Theme_Amber, R.string.color_label_amber),
Accent(R.color.orange, R.style.Theme_Orange, R.string.color_label_orange),
Accent(R.color.deep_orange, R.style.Theme_DeepOrange, R.string.color_label_deep_orange),
Accent(R.color.brown, R.style.Theme_Brown, R.string.color_label_brown),
Accent(R.color.grey, R.style.Theme_Gray, R.string.color_label_grey),
Accent(R.color.blue_grey, R.style.Theme_BlueGrey, R.string.color_label_blue_grey),
Accent(R.color.control_color, R.style.Theme_Neutral, R.string.color_label_neutral)
)
/**
* The data object for an accent.
* @property color The color resource for this accent
* @property theme The theme resource for this accent
* @property name The name of this accent
*/
data class Accent(
@ColorRes val color: Int,
@StyleRes val theme: Int,
@StringRes val name: Int
) {
/**
* Get a [ColorStateList] of the accent
*/
fun getStateList(context: Context): ColorStateList {
return ColorStateList.valueOf(color.toColor(context))
}
/**
* Get the name (in bold) and the hex value of a accent.
* @param context [Context] required
* @return A rendered span with the name in bold + the hex value of the accent.
*/
@SuppressLint("ResourceType")
fun getDetailedSummary(context: Context): Spanned {
val name = context.getString(name)
val hex = context.getString(color).toUpperCase(Locale.getDefault())
return context.getString(
R.string.format_accent_summary,
name, hex
).toSpanned().render()
}
companion object {
@Volatile
private var current: Accent? = null
/**
* Get the current accent, will default to whatever is stored in [SettingsManager]
* if there isnt one.
* @return The current accent
*/
fun get(): Accent {
val cur = current
if (cur != null) {
return cur
}
synchronized(this) {
val newCur = SettingsManager.getInstance().accent
current = newCur
return newCur
}
}
/**
* Set the current accent.
* @return The new accent
*/
fun set(accent: Accent): Accent {
synchronized(this) {
current = accent
}
return accent
}
}
}

View file

@ -14,9 +14,11 @@ import android.view.WindowManager
import android.widget.ImageButton
import android.widget.TextView
import android.widget.Toast
import androidx.annotation.ColorInt
import androidx.annotation.ColorRes
import androidx.annotation.PluralsRes
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.text.HtmlCompat
import androidx.fragment.app.Fragment
import com.google.android.material.button.MaterialButton
@ -51,7 +53,7 @@ fun TextView.setTextColorResource(@ColorRes color: Int) {
* Required because you cant determine a style of a view before API 29
*/
fun MaterialButton.applyAccents(highlighted: Boolean) {
val accent = accent.first.toColor(context)
val accent = Accent.get().color.toColor(context)
if (highlighted) {
backgroundTintList = ColorStateList.valueOf(accent)
@ -103,6 +105,23 @@ fun Spanned.render(): Spanned {
)
}
/**
* Resolve a color.
* @param context [Context] required
* @return The resolved color, black if the resolving process failed.
*/
@ColorInt
fun Int.toColor(context: Context): Int {
return try {
ContextCompat.getColor(context, this)
} catch (e: Resources.NotFoundException) {
logE("Attempted color load failed.")
// Default to the emergency color [Black] if the loading fails.
ContextCompat.getColor(context, android.R.color.black)
}
}
// --- CONFIGURATION ---
/**
@ -177,8 +196,9 @@ private fun isSystemBarOnBottom(activity: Activity): Boolean {
// --- HACKY NIGHTMARES ---
/**
* Use R E F L E C T I O N to fix a memory leak where mAnimationInfo will keep a reference to
* Use ***R E F L E C T I O N*** to fix a memory leak where mAnimationInfo will keep a reference to
* its focused view.
*
* I can't believe I have to do this.
*/
fun Fragment.fixAnimationInfoMemoryLeak() {

View file

@ -1,125 +0,0 @@
package org.oxycblt.auxio.ui
import android.content.Context
import android.content.res.Resources
import android.text.Spanned
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 org.oxycblt.auxio.logE
import java.util.Locale
// Functions for managing colors/accents.
/**
* An array of the base accents and their respective themes.
*/
val ACCENTS = arrayOf(
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
Pair(R.color.deep_purple, R.style.Theme_DeepPurple), // 3
Pair(R.color.indigo, R.style.Theme_Indigo), // 4
Pair(R.color.blue, R.style.Theme_Blue), // 5 - Default!
Pair(R.color.light_blue, R.style.Theme_LightBlue), // 6
Pair(R.color.cyan, R.style.Theme_Cyan), // 7
Pair(R.color.teal, R.style.Theme_Teal), // 8
Pair(R.color.green, R.style.Theme_Green), // 9
Pair(R.color.light_green, R.style.Theme_LightGreen), // 10
Pair(R.color.lime, R.style.Theme_Lime), // 11
Pair(R.color.yellow, R.style.Theme_Yellow), // 12
Pair(R.color.amber, R.style.Theme_Amber), // 13
Pair(R.color.orange, R.style.Theme_Orange), // 14
Pair(R.color.deep_orange, R.style.Theme_DeepOrange), // 15
Pair(R.color.brown, R.style.Theme_Brown), // 16
Pair(R.color.grey, R.style.Theme_Gray), // 17
Pair(R.color.blue_grey, R.style.Theme_BlueGrey), // 18
Pair(R.color.control_color, R.style.Theme_Neutral)
)
/**
* An array of strings for each accent, use these instead of [Resources.getResourceName] so that
* the accent names are translated.
*/
private val ACCENT_NAMES = arrayOf(
R.string.color_label_red, R.string.color_label_pink,
R.string.color_label_purple, R.string.color_label_deep_purple,
R.string.color_label_indigo, R.string.color_label_blue,
R.string.color_label_light_blue, R.string.color_label_cyan,
R.string.color_label_teal, R.string.color_label_green,
R.string.color_label_light_green, R.string.color_label_lime,
R.string.color_label_yellow, R.string.color_label_amber,
R.string.color_label_orange, R.string.color_label_deep_orange,
R.string.color_label_brown, R.string.color_label_grey,
R.string.color_label_blue_grey, R.string.color_label_neutral
)
/**
* The programmatically accessible accent, reflects the currently set accent.
*/
lateinit var accent: Pair<Int, Int>
/**
* Gets the transparent form of a color.
* @param context [Context] required to create the color
* @param color The RESOURCE ID for the color
* @param alpha The new alpha that wants to be applied
* @return The new, resolved transparent color
*/
@ColorInt
fun getTransparentAccent(context: Context, @ColorRes color: Int, alpha: Int): Int {
return ColorUtils.setAlphaComponent(
color.toColor(context),
alpha
)
}
/**
* Resolve a color.
* @param context [Context] required
* @return The resolved color, black if the resolving process failed.
*/
@ColorInt
fun Int.toColor(context: Context): Int {
return try {
ContextCompat.getColor(context, this)
} catch (e: Resources.NotFoundException) {
logE("Attempted color load failed.")
// Default to the emergency color [Black] if the loading fails.
ContextCompat.getColor(context, android.R.color.black)
}
}
/**
* Get the name of an accent.
* @param context [Context] required
* @param newAccent The accent the name should be given for.
* @return The accent name according to the strings for this specific locale.
*/
fun getAccentItemSummary(context: Context, newAccent: Pair<Int, Int>): String {
val accentIndex = ACCENTS.indexOf(newAccent)
check(accentIndex != -1) { "Invalid accent given" }
return context.getString(ACCENT_NAMES[accentIndex])
}
/**
* Get the name (in bold) and the hex value of a accent.
* @param context [Context] required
* @param newAccent Accent to get the information for
* @return A rendered span with the name in bold + the hex value of the accent.
*/
fun getDetailedAccentSummary(context: Context, newAccent: Pair<Int, Int>): 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()
}