Completely refactor accents
Completely refactor the accent system to be much more understandable.
This commit is contained in:
parent
2889e6fdfd
commit
c4bc86cb05
15 changed files with 181 additions and 184 deletions
|
@ -11,7 +11,7 @@ import androidx.databinding.DataBindingUtil
|
||||||
import org.oxycblt.auxio.databinding.ActivityMainBinding
|
import org.oxycblt.auxio.databinding.ActivityMainBinding
|
||||||
import org.oxycblt.auxio.playback.PlaybackService
|
import org.oxycblt.auxio.playback.PlaybackService
|
||||||
import org.oxycblt.auxio.settings.SettingsManager
|
import org.oxycblt.auxio.settings.SettingsManager
|
||||||
import org.oxycblt.auxio.ui.accent
|
import org.oxycblt.auxio.ui.Accent
|
||||||
import org.oxycblt.auxio.ui.isEdgeOn
|
import org.oxycblt.auxio.ui.isEdgeOn
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,10 +30,10 @@ class MainActivity : AppCompatActivity() {
|
||||||
|
|
||||||
AppCompatDelegate.setDefaultNightMode(settingsManager.theme)
|
AppCompatDelegate.setDefaultNightMode(settingsManager.theme)
|
||||||
|
|
||||||
accent = settingsManager.accent
|
val accent = Accent.set(settingsManager.accent)
|
||||||
|
|
||||||
// Apply the theme
|
// Apply the theme
|
||||||
setTheme(accent.second)
|
setTheme(accent.theme)
|
||||||
|
|
||||||
if (isEdgeOn()) {
|
if (isEdgeOn()) {
|
||||||
doEdgeToEdgeSetup(binding)
|
doEdgeToEdgeSetup(binding)
|
||||||
|
|
|
@ -6,6 +6,7 @@ import android.view.LayoutInflater
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.graphics.ColorUtils
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.navigation.NavController
|
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.MusicStore
|
||||||
import org.oxycblt.auxio.music.Song
|
import org.oxycblt.auxio.music.Song
|
||||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||||
import org.oxycblt.auxio.ui.accent
|
import org.oxycblt.auxio.ui.Accent
|
||||||
import org.oxycblt.auxio.ui.getTransparentAccent
|
|
||||||
import org.oxycblt.auxio.ui.isLandscape
|
import org.oxycblt.auxio.ui.isLandscape
|
||||||
import org.oxycblt.auxio.ui.toColor
|
import org.oxycblt.auxio.ui.toColor
|
||||||
|
|
||||||
|
@ -45,10 +45,8 @@ class MainFragment : Fragment() {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
val colorActive = accent.first.toColor(requireContext())
|
val colorActive = Accent.get().color.toColor(requireContext())
|
||||||
val colorInactive = getTransparentAccent(
|
val colorInactive = ColorUtils.setAlphaComponent(colorActive, 150)
|
||||||
requireContext(), accent.first, 150
|
|
||||||
)
|
|
||||||
|
|
||||||
// Set up the tints for the navigation icons + text
|
// Set up the tints for the navigation icons + text
|
||||||
val navTints = ColorStateList(
|
val navTints = ColorStateList(
|
||||||
|
|
|
@ -16,7 +16,7 @@ import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||||
import org.oxycblt.auxio.recycler.DiffCallback
|
import org.oxycblt.auxio.recycler.DiffCallback
|
||||||
import org.oxycblt.auxio.recycler.viewholders.BaseViewHolder
|
import org.oxycblt.auxio.recycler.viewholders.BaseViewHolder
|
||||||
import org.oxycblt.auxio.recycler.viewholders.Highlightable
|
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.applyAccents
|
||||||
import org.oxycblt.auxio.ui.disable
|
import org.oxycblt.auxio.ui.disable
|
||||||
import org.oxycblt.auxio.ui.setTextColorResource
|
import org.oxycblt.auxio.ui.setTextColorResource
|
||||||
|
@ -138,8 +138,10 @@ class AlbumDetailAdapter(
|
||||||
|
|
||||||
override fun setHighlighted(isHighlighted: Boolean) {
|
override fun setHighlighted(isHighlighted: Boolean) {
|
||||||
if (isHighlighted) {
|
if (isHighlighted) {
|
||||||
binding.songName.setTextColorResource(accent.first)
|
val accent = Accent.get()
|
||||||
binding.songTrack.setTextColorResource(accent.first)
|
|
||||||
|
binding.songName.setTextColorResource(accent.color)
|
||||||
|
binding.songTrack.setTextColorResource(accent.color)
|
||||||
} else {
|
} else {
|
||||||
binding.songName.setTextColor(normalTextColor)
|
binding.songName.setTextColor(normalTextColor)
|
||||||
binding.songTrack.setTextColor(inactiveTextColor)
|
binding.songTrack.setTextColor(inactiveTextColor)
|
||||||
|
|
|
@ -16,7 +16,7 @@ import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||||
import org.oxycblt.auxio.recycler.DiffCallback
|
import org.oxycblt.auxio.recycler.DiffCallback
|
||||||
import org.oxycblt.auxio.recycler.viewholders.BaseViewHolder
|
import org.oxycblt.auxio.recycler.viewholders.BaseViewHolder
|
||||||
import org.oxycblt.auxio.recycler.viewholders.Highlightable
|
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.applyAccents
|
||||||
import org.oxycblt.auxio.ui.disable
|
import org.oxycblt.auxio.ui.disable
|
||||||
import org.oxycblt.auxio.ui.setTextColorResource
|
import org.oxycblt.auxio.ui.setTextColorResource
|
||||||
|
@ -137,7 +137,7 @@ class ArtistDetailAdapter(
|
||||||
|
|
||||||
override fun setHighlighted(isHighlighted: Boolean) {
|
override fun setHighlighted(isHighlighted: Boolean) {
|
||||||
if (isHighlighted) {
|
if (isHighlighted) {
|
||||||
binding.albumName.setTextColorResource(accent.first)
|
binding.albumName.setTextColorResource(Accent.get().color)
|
||||||
} else {
|
} else {
|
||||||
binding.albumName.setTextColor(normalTextColor)
|
binding.albumName.setTextColor(normalTextColor)
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||||
import org.oxycblt.auxio.recycler.DiffCallback
|
import org.oxycblt.auxio.recycler.DiffCallback
|
||||||
import org.oxycblt.auxio.recycler.viewholders.BaseViewHolder
|
import org.oxycblt.auxio.recycler.viewholders.BaseViewHolder
|
||||||
import org.oxycblt.auxio.recycler.viewholders.Highlightable
|
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.applyAccents
|
||||||
import org.oxycblt.auxio.ui.disable
|
import org.oxycblt.auxio.ui.disable
|
||||||
import org.oxycblt.auxio.ui.setTextColorResource
|
import org.oxycblt.auxio.ui.setTextColorResource
|
||||||
|
@ -138,7 +138,7 @@ class GenreDetailAdapter(
|
||||||
|
|
||||||
override fun setHighlighted(isHighlighted: Boolean) {
|
override fun setHighlighted(isHighlighted: Boolean) {
|
||||||
if (isHighlighted) {
|
if (isHighlighted) {
|
||||||
binding.songName.setTextColorResource(accent.first)
|
binding.songName.setTextColorResource(Accent.get().color)
|
||||||
} else {
|
} else {
|
||||||
binding.songName.setTextColor(normalTextColor)
|
binding.songName.setTextColor(normalTextColor)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ import org.oxycblt.auxio.databinding.FragmentPlaybackBinding
|
||||||
import org.oxycblt.auxio.detail.DetailViewModel
|
import org.oxycblt.auxio.detail.DetailViewModel
|
||||||
import org.oxycblt.auxio.logD
|
import org.oxycblt.auxio.logD
|
||||||
import org.oxycblt.auxio.playback.state.LoopMode
|
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.memberBinding
|
||||||
import org.oxycblt.auxio.ui.toColor
|
import org.oxycblt.auxio.ui.toColor
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ class PlaybackFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
|
||||||
|
|
||||||
// Colors
|
// Colors
|
||||||
private val accentColor: ColorStateList by lazy {
|
private val accentColor: ColorStateList by lazy {
|
||||||
ColorStateList.valueOf(accent.first.toColor(requireContext()))
|
Accent.get().getStateList(requireContext())
|
||||||
}
|
}
|
||||||
|
|
||||||
private val controlColor: ColorStateList by lazy {
|
private val controlColor: ColorStateList by lazy {
|
||||||
|
|
|
@ -22,7 +22,7 @@ import androidx.dynamicanimation.animation.SpringForce
|
||||||
import com.reddit.indicatorfastscroll.FastScrollItemIndicator
|
import com.reddit.indicatorfastscroll.FastScrollItemIndicator
|
||||||
import com.reddit.indicatorfastscroll.FastScrollerView
|
import com.reddit.indicatorfastscroll.FastScrollerView
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.ui.accent
|
import org.oxycblt.auxio.ui.Accent
|
||||||
import org.oxycblt.auxio.ui.toColor
|
import org.oxycblt.auxio.ui.toColor
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -40,7 +40,7 @@ class NoLeakThumbView @JvmOverloads constructor(
|
||||||
) : ConstraintLayout(context, attrs, defStyleAttr),
|
) : ConstraintLayout(context, attrs, defStyleAttr),
|
||||||
FastScrollerView.ItemIndicatorSelectedCallback {
|
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 iconColor = R.color.background.toColor(context)
|
||||||
private val textAppearanceRes = R.style.TextAppearance_ThumbIndicator
|
private val textAppearanceRes = R.style.TextAppearance_ThumbIndicator
|
||||||
private val textColor = R.color.background.toColor(context)
|
private val textColor = R.color.background.toColor(context)
|
||||||
|
|
|
@ -5,7 +5,6 @@ import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.core.graphics.toColor
|
|
||||||
import androidx.core.widget.addTextChangedListener
|
import androidx.core.widget.addTextChangedListener
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.activityViewModels
|
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.Header
|
||||||
import org.oxycblt.auxio.music.Song
|
import org.oxycblt.auxio.music.Song
|
||||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||||
|
import org.oxycblt.auxio.ui.Accent
|
||||||
import org.oxycblt.auxio.ui.ActionMenu
|
import org.oxycblt.auxio.ui.ActionMenu
|
||||||
import org.oxycblt.auxio.ui.accent
|
|
||||||
import org.oxycblt.auxio.ui.fixAnimationInfoMemoryLeak
|
import org.oxycblt.auxio.ui.fixAnimationInfoMemoryLeak
|
||||||
import org.oxycblt.auxio.ui.getLandscapeSpans
|
import org.oxycblt.auxio.ui.getLandscapeSpans
|
||||||
import org.oxycblt.auxio.ui.isLandscape
|
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
|
// 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.
|
// 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 ->
|
val searchAdapter = SearchAdapter(::onItemSelection) { view, data ->
|
||||||
ActionMenu(requireCompatActivity(), view, data, ActionMenu.FLAG_NONE)
|
ActionMenu(requireCompatActivity(), view, data, ActionMenu.FLAG_NONE)
|
||||||
|
|
|
@ -20,9 +20,8 @@ import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||||
import org.oxycblt.auxio.recycler.DisplayMode
|
import org.oxycblt.auxio.recycler.DisplayMode
|
||||||
import org.oxycblt.auxio.settings.ui.AccentAdapter
|
import org.oxycblt.auxio.settings.ui.AccentAdapter
|
||||||
import org.oxycblt.auxio.ui.ACCENTS
|
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.createToast
|
||||||
import org.oxycblt.auxio.ui.getDetailedAccentSummary
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The actual fragment containing the settings menu. Inherits [PreferenceFragmentCompat].
|
* The actual fragment containing the settings menu. Inherits [PreferenceFragmentCompat].
|
||||||
|
@ -84,7 +83,7 @@ class SettingsListFragment : PreferenceFragmentCompat() {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
summary = getDetailedAccentSummary(requireActivity(), accent)
|
summary = Accent.get().getDetailedSummary(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsManager.Keys.KEY_EDGE_TO_EDGE -> {
|
SettingsManager.Keys.KEY_EDGE_TO_EDGE -> {
|
||||||
|
@ -153,7 +152,7 @@ class SettingsListFragment : PreferenceFragmentCompat() {
|
||||||
// This is why I hate using third party libraries.
|
// This is why I hate using third party libraries.
|
||||||
val recycler = RecyclerView(requireContext()).apply {
|
val recycler = RecyclerView(requireContext()).apply {
|
||||||
adapter = AccentAdapter {
|
adapter = AccentAdapter {
|
||||||
if (it.first != accent.first) {
|
if (it != Accent.get()) {
|
||||||
SettingsManager.getInstance().accent = it
|
SettingsManager.getInstance().accent = it
|
||||||
|
|
||||||
requireActivity().recreate()
|
requireActivity().recreate()
|
||||||
|
@ -169,7 +168,7 @@ class SettingsListFragment : PreferenceFragmentCompat() {
|
||||||
|
|
||||||
(layoutManager as LinearLayoutManager)
|
(layoutManager as LinearLayoutManager)
|
||||||
.scrollToPositionWithOffset(
|
.scrollToPositionWithOffset(
|
||||||
ACCENTS.indexOf(accent),
|
ACCENTS.indexOf(Accent.get()),
|
||||||
(width / 2) - childWidth
|
(width / 2) - childWidth
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import org.oxycblt.auxio.playback.state.PlaybackMode
|
||||||
import org.oxycblt.auxio.recycler.DisplayMode
|
import org.oxycblt.auxio.recycler.DisplayMode
|
||||||
import org.oxycblt.auxio.recycler.SortMode
|
import org.oxycblt.auxio.recycler.SortMode
|
||||||
import org.oxycblt.auxio.ui.ACCENTS
|
import org.oxycblt.auxio.ui.ACCENTS
|
||||||
|
import org.oxycblt.auxio.ui.Accent
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper around the [SharedPreferences] class that writes & reads values without a context.
|
* 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.
|
* The current accent.
|
||||||
*/
|
*/
|
||||||
var accent: Pair<Int, Int>
|
var accent: Accent
|
||||||
get() {
|
get() {
|
||||||
val accentIndex = sharedPrefs.getInt(Keys.KEY_ACCENT, 5)
|
|
||||||
|
|
||||||
// Accent is stored as an index [to be efficient], so retrieve it when done.
|
// 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) {
|
set(value) {
|
||||||
val accentIndex = ACCENTS.indexOf(value)
|
val accentIndex = ACCENTS.indexOf(value)
|
||||||
|
@ -200,14 +199,14 @@ class SettingsManager private constructor(context: Context) :
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@Volatile
|
@Volatile
|
||||||
private lateinit var INSTANCE: SettingsManager
|
private var INSTANCE: SettingsManager? = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Init the single instance of [SettingsManager]. Done so that every object
|
* Init the single instance of [SettingsManager]. Done so that every object
|
||||||
* can have access to it regardless of if it has a context.
|
* can have access to it regardless of if it has a context.
|
||||||
*/
|
*/
|
||||||
fun init(context: Context): SettingsManager {
|
fun init(context: Context): SettingsManager {
|
||||||
if (!::INSTANCE.isInitialized) {
|
if (INSTANCE == null) {
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
INSTANCE = SettingsManager(context)
|
INSTANCE = SettingsManager(context)
|
||||||
}
|
}
|
||||||
|
@ -220,10 +219,13 @@ class SettingsManager private constructor(context: Context) :
|
||||||
* Get the single instance of [SettingsManager].
|
* Get the single instance of [SettingsManager].
|
||||||
*/
|
*/
|
||||||
fun getInstance(): SettingsManager {
|
fun getInstance(): SettingsManager {
|
||||||
check(::INSTANCE.isInitialized) {
|
val instance = INSTANCE
|
||||||
"SettingsManager must be initialized with init() before getting its instance."
|
|
||||||
|
if (instance != null) {
|
||||||
|
return instance
|
||||||
}
|
}
|
||||||
return INSTANCE
|
|
||||||
|
error("SettingsManager must be initialized with init() before getting its instance.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,7 @@ import androidx.recyclerview.widget.RecyclerView
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.databinding.ItemAccentBinding
|
import org.oxycblt.auxio.databinding.ItemAccentBinding
|
||||||
import org.oxycblt.auxio.ui.ACCENTS
|
import org.oxycblt.auxio.ui.ACCENTS
|
||||||
import org.oxycblt.auxio.ui.accent
|
import org.oxycblt.auxio.ui.Accent
|
||||||
import org.oxycblt.auxio.ui.getAccentItemSummary
|
|
||||||
import org.oxycblt.auxio.ui.toColor
|
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.
|
* @param doOnAccentConfirm What to do when an accent is confirmed.
|
||||||
*/
|
*/
|
||||||
class AccentAdapter(
|
class AccentAdapter(
|
||||||
private val doOnAccentConfirm: (accent: Pair<Int, Int>) -> Unit
|
private val doOnAccentConfirm: (accent: Accent) -> Unit
|
||||||
) : RecyclerView.Adapter<AccentAdapter.ViewHolder>() {
|
) : RecyclerView.Adapter<AccentAdapter.ViewHolder>() {
|
||||||
override fun getItemCount(): Int = ACCENTS.size
|
override fun getItemCount(): Int = ACCENTS.size
|
||||||
|
|
||||||
|
@ -33,31 +32,25 @@ class AccentAdapter(
|
||||||
private val binding: ItemAccentBinding
|
private val binding: ItemAccentBinding
|
||||||
) : RecyclerView.ViewHolder(binding.root) {
|
) : RecyclerView.ViewHolder(binding.root) {
|
||||||
|
|
||||||
fun bind(accentData: Pair<Int, Int>) {
|
fun bind(accent: Accent) {
|
||||||
binding.accent.apply {
|
binding.accent.apply {
|
||||||
contentDescription = getAccentItemSummary(context, accentData)
|
contentDescription = accent.getDetailedSummary(context)
|
||||||
|
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
doOnAccentConfirm(accentData)
|
doOnAccentConfirm(accent)
|
||||||
}
|
}
|
||||||
|
|
||||||
imageTintList = if (accentData.first == accent.first) {
|
imageTintList = if (accent == Accent.get()) {
|
||||||
isEnabled = false
|
isEnabled = false
|
||||||
|
|
||||||
ColorStateList.valueOf(
|
ColorStateList.valueOf(R.color.background.toColor(context))
|
||||||
R.color.background.toColor(context)
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
isEnabled = true
|
isEnabled = true
|
||||||
|
|
||||||
ColorStateList.valueOf(
|
ColorStateList.valueOf(android.R.color.transparent.toColor(context))
|
||||||
android.R.color.transparent.toColor(context)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
backgroundTintList = ColorStateList.valueOf(
|
backgroundTintList = accent.getStateList(context)
|
||||||
accentData.first.toColor(context)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package org.oxycblt.auxio.songs
|
package org.oxycblt.auxio.songs
|
||||||
|
|
||||||
import android.content.res.ColorStateList
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
|
@ -18,12 +17,11 @@ import org.oxycblt.auxio.databinding.FragmentSongsBinding
|
||||||
import org.oxycblt.auxio.logD
|
import org.oxycblt.auxio.logD
|
||||||
import org.oxycblt.auxio.music.MusicStore
|
import org.oxycblt.auxio.music.MusicStore
|
||||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||||
|
import org.oxycblt.auxio.ui.Accent
|
||||||
import org.oxycblt.auxio.ui.ActionMenu
|
import org.oxycblt.auxio.ui.ActionMenu
|
||||||
import org.oxycblt.auxio.ui.accent
|
|
||||||
import org.oxycblt.auxio.ui.getLandscapeSpans
|
import org.oxycblt.auxio.ui.getLandscapeSpans
|
||||||
import org.oxycblt.auxio.ui.isLandscape
|
import org.oxycblt.auxio.ui.isLandscape
|
||||||
import org.oxycblt.auxio.ui.requireCompatActivity
|
import org.oxycblt.auxio.ui.requireCompatActivity
|
||||||
import org.oxycblt.auxio.ui.toColor
|
|
||||||
import kotlin.math.ceil
|
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.
|
// API 22 and below don't support the state color, so just use the accent.
|
||||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
|
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
|
||||||
textColor = ColorStateList.valueOf(accent.first.toColor(requireContext()))
|
textColor = Accent.get().getStateList(requireContext())
|
||||||
}
|
}
|
||||||
|
|
||||||
setupWithRecyclerView(
|
setupWithRecyclerView(
|
||||||
|
|
111
app/src/main/java/org/oxycblt/auxio/ui/Accent.kt
Normal file
111
app/src/main/java/org/oxycblt/auxio/ui/Accent.kt
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,9 +14,11 @@ import android.view.WindowManager
|
||||||
import android.widget.ImageButton
|
import android.widget.ImageButton
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.annotation.ColorInt
|
||||||
import androidx.annotation.ColorRes
|
import androidx.annotation.ColorRes
|
||||||
import androidx.annotation.PluralsRes
|
import androidx.annotation.PluralsRes
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.text.HtmlCompat
|
import androidx.core.text.HtmlCompat
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import com.google.android.material.button.MaterialButton
|
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
|
* Required because you cant determine a style of a view before API 29
|
||||||
*/
|
*/
|
||||||
fun MaterialButton.applyAccents(highlighted: Boolean) {
|
fun MaterialButton.applyAccents(highlighted: Boolean) {
|
||||||
val accent = accent.first.toColor(context)
|
val accent = Accent.get().color.toColor(context)
|
||||||
|
|
||||||
if (highlighted) {
|
if (highlighted) {
|
||||||
backgroundTintList = ColorStateList.valueOf(accent)
|
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 ---
|
// --- CONFIGURATION ---
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -177,8 +196,9 @@ private fun isSystemBarOnBottom(activity: Activity): Boolean {
|
||||||
// --- HACKY NIGHTMARES ---
|
// --- 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.
|
* its focused view.
|
||||||
|
*
|
||||||
* I can't believe I have to do this.
|
* I can't believe I have to do this.
|
||||||
*/
|
*/
|
||||||
fun Fragment.fixAnimationInfoMemoryLeak() {
|
fun Fragment.fixAnimationInfoMemoryLeak() {
|
||||||
|
|
|
@ -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()
|
|
||||||
}
|
|
Loading…
Reference in a new issue