Update codebase
Do a variety of small things across the codebase.
This commit is contained in:
parent
8c107d66a0
commit
f04ffdb59b
24 changed files with 137 additions and 199 deletions
|
@ -18,8 +18,11 @@ sealed class BaseModel {
|
||||||
/**
|
/**
|
||||||
* [BaseModel] variant that denotes that this object is a parent of other data objects, such
|
* [BaseModel] variant that denotes that this object is a parent of other data objects, such
|
||||||
* as an [Album] or [Artist]
|
* as an [Album] or [Artist]
|
||||||
|
* @property displayName Name that handles the usage of [Genre.resolvedName] and the normal [BaseModel.name]
|
||||||
*/
|
*/
|
||||||
sealed class Parent : BaseModel()
|
sealed class Parent : BaseModel() {
|
||||||
|
val displayName: String get() = if (this is Genre) resolvedName else name
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The data object for a song. Inherits [BaseModel].
|
* The data object for a song. Inherits [BaseModel].
|
||||||
|
@ -47,6 +50,9 @@ data class Song(
|
||||||
val genre: Genre? get() = mGenre
|
val genre: Genre? get() = mGenre
|
||||||
val album: Album get() = requireNotNull(mAlbum)
|
val album: Album get() = requireNotNull(mAlbum)
|
||||||
|
|
||||||
|
val seconds = duration / 1000
|
||||||
|
val formattedDuration: String = seconds.toDuration()
|
||||||
|
|
||||||
fun linkAlbum(album: Album) {
|
fun linkAlbum(album: Album) {
|
||||||
if (mAlbum == null) {
|
if (mAlbum == null) {
|
||||||
mAlbum = album
|
mAlbum = album
|
||||||
|
@ -58,9 +64,6 @@ data class Song(
|
||||||
mGenre = genre
|
mGenre = genre
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val seconds = duration / 1000
|
|
||||||
val formattedDuration: String = seconds.toDuration()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -119,7 +122,7 @@ data class Artist(
|
||||||
}
|
}
|
||||||
|
|
||||||
val genre: Genre? by lazy {
|
val genre: Genre? by lazy {
|
||||||
songs.map { it.genre }.maxByOrNull { it?.songs?.size ?: 0 }
|
songs.groupBy { it.genre }.entries.maxByOrNull { it.value.size }?.key
|
||||||
}
|
}
|
||||||
|
|
||||||
val songs: List<Song> by lazy {
|
val songs: List<Song> by lazy {
|
||||||
|
@ -130,17 +133,14 @@ data class Artist(
|
||||||
/**
|
/**
|
||||||
* The data object for a genre. Inherits [Parent]
|
* The data object for a genre. Inherits [Parent]
|
||||||
* @property songs The list of all [Song]s in this genre.
|
* @property songs The list of all [Song]s in this genre.
|
||||||
* @property displayName A name that can be displayed without it showing up as an integer. ***USE THIS INSTEAD OF [name]!!!!***
|
* @property resolvedName A name that has been resolved from its int-genre form to its named form.
|
||||||
* @author OxygenCobalt
|
* @author OxygenCobalt
|
||||||
*/
|
*/
|
||||||
data class Genre(
|
data class Genre(
|
||||||
override val id: Long = -1,
|
override val id: Long = -1,
|
||||||
override val name: String,
|
override val name: String,
|
||||||
) : Parent() {
|
) : Parent() {
|
||||||
private val mSongs = mutableListOf<Song>()
|
val resolvedName: String by lazy {
|
||||||
val songs: List<Song> get() = mSongs
|
|
||||||
|
|
||||||
val displayName: String by lazy {
|
|
||||||
if (name.contains(Regex("[0123456789)]"))) {
|
if (name.contains(Regex("[0123456789)]"))) {
|
||||||
name.toNamedGenre() ?: name
|
name.toNamedGenre() ?: name
|
||||||
} else {
|
} else {
|
||||||
|
@ -148,6 +148,9 @@ data class Genre(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val mSongs = mutableListOf<Song>()
|
||||||
|
val songs: List<Song> get() = mSongs
|
||||||
|
|
||||||
val totalDuration: String get() = songs.sumOf { it.seconds }.toDuration()
|
val totalDuration: String get() = songs.sumOf { it.seconds }.toDuration()
|
||||||
|
|
||||||
fun linkSong(song: Song) {
|
fun linkSong(song: Song) {
|
||||||
|
|
|
@ -113,7 +113,7 @@ fun Int.toYear(context: Context): String {
|
||||||
*/
|
*/
|
||||||
@BindingAdapter("artistGenre")
|
@BindingAdapter("artistGenre")
|
||||||
fun TextView.bindArtistGenre(artist: Artist) {
|
fun TextView.bindArtistGenre(artist: Artist) {
|
||||||
text = artist.genre?.displayName ?: context.getString(R.string.placeholder_genre)
|
text = artist.genre?.resolvedName ?: context.getString(R.string.placeholder_genre)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -63,10 +63,6 @@ class CompactPlaybackFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
playbackModel.positionAsProgress.observe(viewLifecycleOwner) {
|
|
||||||
binding.playbackProgress.progress = it
|
|
||||||
}
|
|
||||||
|
|
||||||
logD("Fragment Created")
|
logD("Fragment Created")
|
||||||
|
|
||||||
return binding.root
|
return binding.root
|
||||||
|
|
|
@ -32,14 +32,8 @@ class PlaybackFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
|
||||||
playbackSong.isSelected = false
|
playbackSong.isSelected = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Colors
|
private lateinit var accentColor: ColorStateList
|
||||||
private val accentColor: ColorStateList by lazy {
|
private lateinit var controlColor: ColorStateList
|
||||||
Accent.get().getStateList(requireContext())
|
|
||||||
}
|
|
||||||
|
|
||||||
private val controlColor: ColorStateList by lazy {
|
|
||||||
R.color.control_color.toStateList(requireContext())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
|
@ -50,12 +44,14 @@ class PlaybackFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
|
||||||
// Would require writing my own variant though to avoid index updates
|
// Would require writing my own variant though to avoid index updates
|
||||||
|
|
||||||
val normalTextColor = binding.playbackDurationCurrent.currentTextColor
|
val normalTextColor = binding.playbackDurationCurrent.currentTextColor
|
||||||
|
accentColor = Accent.get().getStateList(requireContext())
|
||||||
|
controlColor = R.color.control_color.toStateList(requireContext())
|
||||||
|
|
||||||
// Can't set the tint of a MenuItem below Android 8, so use icons instead.
|
// Can't set the tint of a MenuItem below Android 8, so use icons instead.
|
||||||
val iconQueueActive = R.drawable.ic_queue.toDrawable(requireContext())
|
val iconQueueActive = R.drawable.ic_queue.toDrawable(requireContext())
|
||||||
val iconQueueInactive = R.drawable.ic_queue_inactive.toDrawable(requireContext())
|
val iconQueueInactive = R.drawable.ic_queue_inactive.toDrawable(requireContext())
|
||||||
|
|
||||||
val queueMenuItem: MenuItem
|
val queueItem: MenuItem
|
||||||
|
|
||||||
// --- UI SETUP ---
|
// --- UI SETUP ---
|
||||||
|
|
||||||
|
@ -77,7 +73,7 @@ class PlaybackFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
|
||||||
} else false
|
} else false
|
||||||
}
|
}
|
||||||
|
|
||||||
queueMenuItem = menu.findItem(R.id.action_queue)
|
queueItem = menu.findItem(R.id.action_queue)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make marquee of song title work
|
// Make marquee of song title work
|
||||||
|
@ -100,12 +96,7 @@ class PlaybackFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
playbackModel.isShuffling.observe(viewLifecycleOwner) {
|
playbackModel.isShuffling.observe(viewLifecycleOwner) {
|
||||||
// Highlight the shuffle button if Playback is shuffled, and revert it if not.
|
binding.playbackShuffle.imageTintList = if (it) accentColor else controlColor
|
||||||
if (it) {
|
|
||||||
binding.playbackShuffle.imageTintList = accentColor
|
|
||||||
} else {
|
|
||||||
binding.playbackShuffle.imageTintList = controlColor
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
playbackModel.loopMode.observe(viewLifecycleOwner) {
|
playbackModel.loopMode.observe(viewLifecycleOwner) {
|
||||||
|
@ -114,10 +105,12 @@ class PlaybackFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
|
||||||
binding.playbackLoop.imageTintList = controlColor
|
binding.playbackLoop.imageTintList = controlColor
|
||||||
binding.playbackLoop.setImageResource(R.drawable.ic_loop)
|
binding.playbackLoop.setImageResource(R.drawable.ic_loop)
|
||||||
}
|
}
|
||||||
|
|
||||||
LoopMode.ONCE -> {
|
LoopMode.ONCE -> {
|
||||||
binding.playbackLoop.imageTintList = accentColor
|
binding.playbackLoop.imageTintList = accentColor
|
||||||
binding.playbackLoop.setImageResource(R.drawable.ic_loop_one)
|
binding.playbackLoop.setImageResource(R.drawable.ic_loop_one)
|
||||||
}
|
}
|
||||||
|
|
||||||
LoopMode.INFINITE -> {
|
LoopMode.INFINITE -> {
|
||||||
binding.playbackLoop.imageTintList = accentColor
|
binding.playbackLoop.imageTintList = accentColor
|
||||||
binding.playbackLoop.setImageResource(R.drawable.ic_loop)
|
binding.playbackLoop.setImageResource(R.drawable.ic_loop)
|
||||||
|
@ -128,7 +121,6 @@ class PlaybackFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
playbackModel.isSeeking.observe(viewLifecycleOwner) {
|
playbackModel.isSeeking.observe(viewLifecycleOwner) {
|
||||||
// Highlight the current duration if the user is seeking, and revert it if not.
|
|
||||||
if (it) {
|
if (it) {
|
||||||
binding.playbackDurationCurrent.setTextColor(accentColor)
|
binding.playbackDurationCurrent.setTextColor(accentColor)
|
||||||
} else {
|
} else {
|
||||||
|
@ -136,35 +128,33 @@ class PlaybackFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Updates for the current duration TextView/SeekBar
|
|
||||||
playbackModel.formattedPosition.observe(viewLifecycleOwner) {
|
|
||||||
binding.playbackDurationCurrent.text = it
|
|
||||||
}
|
|
||||||
|
|
||||||
playbackModel.positionAsProgress.observe(viewLifecycleOwner) {
|
playbackModel.positionAsProgress.observe(viewLifecycleOwner) {
|
||||||
if (!playbackModel.isSeeking.value!!) {
|
if (!playbackModel.isSeeking.value!!) {
|
||||||
binding.playbackSeekBar.progress = it
|
binding.playbackSeekBar.progress = it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
playbackModel.nextItemsInQueue.observe(viewLifecycleOwner) {
|
playbackModel.nextItemsInQueue.observe(viewLifecycleOwner) { nextQueue ->
|
||||||
// Disable the option to open the queue if there's nothing in it.
|
val userQueue = playbackModel.userQueue.value!!
|
||||||
if (it.isEmpty() && playbackModel.userQueue.value!!.isEmpty()) {
|
|
||||||
queueMenuItem.isEnabled = false
|
if (userQueue.isEmpty() && nextQueue.isEmpty()) {
|
||||||
queueMenuItem.icon = iconQueueInactive
|
queueItem.icon = iconQueueInactive
|
||||||
|
queueItem.isEnabled = false
|
||||||
} else {
|
} else {
|
||||||
queueMenuItem.isEnabled = true
|
queueItem.icon = iconQueueActive
|
||||||
queueMenuItem.icon = iconQueueActive
|
queueItem.isEnabled = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
playbackModel.userQueue.observe(viewLifecycleOwner) {
|
playbackModel.userQueue.observe(viewLifecycleOwner) { userQueue ->
|
||||||
if (it.isEmpty() && playbackModel.nextItemsInQueue.value!!.isEmpty()) {
|
val nextQueue = playbackModel.nextItemsInQueue.value!!
|
||||||
queueMenuItem.isEnabled = false
|
|
||||||
queueMenuItem.icon = iconQueueInactive
|
if (userQueue.isEmpty() && nextQueue.isEmpty()) {
|
||||||
|
queueItem.icon = iconQueueInactive
|
||||||
|
queueItem.isEnabled = false
|
||||||
} else {
|
} else {
|
||||||
queueMenuItem.isEnabled = true
|
queueItem.icon = iconQueueActive
|
||||||
queueMenuItem.icon = iconQueueActive
|
queueItem.isEnabled = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,11 +14,9 @@ import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.databinding.FragmentQueueBinding
|
import org.oxycblt.auxio.databinding.FragmentQueueBinding
|
||||||
import org.oxycblt.auxio.music.BaseModel
|
import org.oxycblt.auxio.music.BaseModel
|
||||||
import org.oxycblt.auxio.music.Genre
|
|
||||||
import org.oxycblt.auxio.music.Header
|
import org.oxycblt.auxio.music.Header
|
||||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||||
import org.oxycblt.auxio.playback.shouldHandleFileIntent
|
import org.oxycblt.auxio.playback.shouldHandleFileIntent
|
||||||
import org.oxycblt.auxio.playback.state.PlaybackMode
|
|
||||||
import org.oxycblt.auxio.ui.isEdgeOn
|
import org.oxycblt.auxio.ui.isEdgeOn
|
||||||
import org.oxycblt.auxio.ui.isIrregularLandscape
|
import org.oxycblt.auxio.ui.isIrregularLandscape
|
||||||
|
|
||||||
|
@ -145,15 +143,6 @@ class QueueFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getParentName(): String {
|
private fun getParentName(): String {
|
||||||
return if (playbackModel.mode.value == PlaybackMode.ALL_SONGS) {
|
return playbackModel.parent.value?.displayName ?: getString(R.string.label_all_songs)
|
||||||
getString(R.string.label_all_songs)
|
|
||||||
} else {
|
|
||||||
if (playbackModel.parent.value is Genre) {
|
|
||||||
// Use display name for Genres so that numbers dont show up
|
|
||||||
(playbackModel.parent.value as Genre).displayName
|
|
||||||
} else {
|
|
||||||
playbackModel.parent.value!!.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,6 @@ import org.oxycblt.auxio.BuildConfig
|
||||||
import org.oxycblt.auxio.MainActivity
|
import org.oxycblt.auxio.MainActivity
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.coil.loadBitmap
|
import org.oxycblt.auxio.coil.loadBitmap
|
||||||
import org.oxycblt.auxio.music.Genre
|
|
||||||
import org.oxycblt.auxio.music.Parent
|
import org.oxycblt.auxio.music.Parent
|
||||||
import org.oxycblt.auxio.music.Song
|
import org.oxycblt.auxio.music.Song
|
||||||
import org.oxycblt.auxio.playback.state.LoopMode
|
import org.oxycblt.auxio.playback.state.LoopMode
|
||||||
|
@ -119,17 +118,8 @@ class PlaybackNotification private constructor(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parent == null) {
|
// A blank parent always means that the mode is ALL_SONGS
|
||||||
// A blank parent always means that the mode is ALL_SONGS
|
setSubText(parent?.displayName ?: context.getString(R.string.label_all_songs))
|
||||||
setSubText(context.getString(R.string.label_all_songs))
|
|
||||||
} else {
|
|
||||||
if (parent is Genre) {
|
|
||||||
// Use display name for genre
|
|
||||||
setSubText(parent.displayName)
|
|
||||||
} else {
|
|
||||||
setSubText(parent.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- NOTIFICATION ACTION BUILDERS ---
|
// --- NOTIFICATION ACTION BUILDERS ---
|
||||||
|
|
|
@ -412,9 +412,7 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateManager.Ca
|
||||||
ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
|
ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
startForeground(
|
startForeground(PlaybackNotification.NOTIFICATION_ID, notification.build())
|
||||||
PlaybackNotification.NOTIFICATION_ID, notification.build()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// If we are already in foreground just update the notification
|
// If we are already in foreground just update the notification
|
||||||
|
@ -486,51 +484,45 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateManager.Ca
|
||||||
*/
|
*/
|
||||||
private inner class SystemEventReceiver : BroadcastReceiver() {
|
private inner class SystemEventReceiver : BroadcastReceiver() {
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
val action = intent.action
|
when (intent.action) {
|
||||||
|
PlaybackNotification.ACTION_PLAY_PAUSE -> playbackManager.setPlaying(
|
||||||
|
!playbackManager.isPlaying
|
||||||
|
)
|
||||||
|
|
||||||
action?.let {
|
PlaybackNotification.ACTION_LOOP -> playbackManager.setLoopMode(
|
||||||
when (it) {
|
playbackManager.loopMode.increment()
|
||||||
// --- NOTIFICATION CASES ---
|
)
|
||||||
|
|
||||||
PlaybackNotification.ACTION_PLAY_PAUSE -> playbackManager.setPlaying(
|
PlaybackNotification.ACTION_SHUFFLE -> playbackManager.setShuffling(
|
||||||
!playbackManager.isPlaying
|
!playbackManager.isShuffling, keepSong = true
|
||||||
)
|
)
|
||||||
|
|
||||||
PlaybackNotification.ACTION_LOOP -> playbackManager.setLoopMode(
|
PlaybackNotification.ACTION_SKIP_PREV -> playbackManager.prev()
|
||||||
playbackManager.loopMode.increment()
|
PlaybackNotification.ACTION_SKIP_NEXT -> playbackManager.next()
|
||||||
)
|
|
||||||
|
|
||||||
PlaybackNotification.ACTION_SHUFFLE -> playbackManager.setShuffling(
|
PlaybackNotification.ACTION_EXIT -> {
|
||||||
!playbackManager.isShuffling, keepSong = true
|
playbackManager.setPlaying(false)
|
||||||
)
|
stopForegroundAndNotification()
|
||||||
|
}
|
||||||
|
|
||||||
PlaybackNotification.ACTION_SKIP_PREV -> playbackManager.prev()
|
// --- HEADSET CASES ---
|
||||||
PlaybackNotification.ACTION_SKIP_NEXT -> playbackManager.next()
|
|
||||||
|
|
||||||
PlaybackNotification.ACTION_EXIT -> {
|
BluetoothDevice.ACTION_ACL_CONNECTED -> resumeFromPlug()
|
||||||
playbackManager.setPlaying(false)
|
BluetoothDevice.ACTION_ACL_DISCONNECTED -> pauseFromPlug()
|
||||||
stopForegroundAndNotification()
|
|
||||||
|
AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED -> {
|
||||||
|
when (intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -1)) {
|
||||||
|
AudioManager.SCO_AUDIO_STATE_CONNECTED -> resumeFromPlug()
|
||||||
|
AudioManager.SCO_AUDIO_STATE_DISCONNECTED -> pauseFromPlug()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// --- HEADSET CASES ---
|
AudioManager.ACTION_AUDIO_BECOMING_NOISY -> pauseFromPlug()
|
||||||
|
|
||||||
BluetoothDevice.ACTION_ACL_CONNECTED -> resumeFromPlug()
|
Intent.ACTION_HEADSET_PLUG -> {
|
||||||
BluetoothDevice.ACTION_ACL_DISCONNECTED -> pauseFromPlug()
|
when (intent.getIntExtra("state", -1)) {
|
||||||
|
CONNECTED -> resumeFromPlug()
|
||||||
AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED -> {
|
DISCONNECTED -> pauseFromPlug()
|
||||||
when (intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -1)) {
|
|
||||||
AudioManager.SCO_AUDIO_STATE_CONNECTED -> resumeFromPlug()
|
|
||||||
AudioManager.SCO_AUDIO_STATE_DISCONNECTED -> pauseFromPlug()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AudioManager.ACTION_AUDIO_BECOMING_NOISY -> pauseFromPlug()
|
|
||||||
|
|
||||||
Intent.ACTION_HEADSET_PLUG -> {
|
|
||||||
when (intent.getIntExtra("state", -1)) {
|
|
||||||
CONNECTED -> resumeFromPlug()
|
|
||||||
DISCONNECTED -> pauseFromPlug()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,11 +31,11 @@ enum class SortMode(@DrawableRes val iconRes: Int) {
|
||||||
fun getSortedGenreList(genres: List<Genre>): List<Genre> {
|
fun getSortedGenreList(genres: List<Genre>): List<Genre> {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
ALPHA_UP -> genres.sortedWith(
|
ALPHA_UP -> genres.sortedWith(
|
||||||
compareByDescending(String.CASE_INSENSITIVE_ORDER) { it.displayName }
|
compareByDescending(String.CASE_INSENSITIVE_ORDER) { it.resolvedName }
|
||||||
)
|
)
|
||||||
|
|
||||||
ALPHA_DOWN -> genres.sortedWith(
|
ALPHA_DOWN -> genres.sortedWith(
|
||||||
compareBy(String.CASE_INSENSITIVE_ORDER) { it.displayName }
|
compareBy(String.CASE_INSENSITIVE_ORDER) { it.resolvedName }
|
||||||
)
|
)
|
||||||
|
|
||||||
else -> genres
|
else -> genres
|
||||||
|
|
|
@ -197,6 +197,57 @@ class SettingsManager private constructor(context: Context) :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** SharedPreferences keys. */
|
||||||
|
object Keys {
|
||||||
|
const val KEY_THEME = "KEY_THEME"
|
||||||
|
const val KEY_ACCENT = "KEY_ACCENT"
|
||||||
|
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_DEBUG_SAVE = "KEY_SAVE_STATE"
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Values for some settings entries that cant be enums/ints.*/
|
||||||
|
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"
|
||||||
|
|
||||||
|
/** Loop at the end. Similar to Music Player GO. */
|
||||||
|
const val AT_END_LOOP = "LOOP"
|
||||||
|
|
||||||
|
/** Stop at the end. */
|
||||||
|
const val AT_END_STOP = "STOP"
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface for receiving some preference updates. Use/Extend this instead of
|
||||||
|
* [SharedPreferences.OnSharedPreferenceChangeListener] if possible, as it doesn't require a
|
||||||
|
* context.
|
||||||
|
*/
|
||||||
|
interface Callback {
|
||||||
|
fun onColorizeNotifUpdate(doColorize: Boolean) {}
|
||||||
|
fun onNotifActionUpdate(useAltAction: Boolean) {}
|
||||||
|
fun onLibDisplayModeUpdate(displayMode: DisplayMode) {}
|
||||||
|
fun onShowCoverUpdate(showCovers: Boolean) {}
|
||||||
|
fun onQualityCoverUpdate(doQualityCovers: Boolean) {}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@Volatile
|
@Volatile
|
||||||
private var INSTANCE: SettingsManager? = null
|
private var INSTANCE: SettingsManager? = null
|
||||||
|
@ -228,65 +279,4 @@ class SettingsManager private constructor(context: Context) :
|
||||||
error("SettingsManager must be initialized with init() before getting its instance.")
|
error("SettingsManager must be initialized with init() before getting its instance.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* SharedPreferences keys.
|
|
||||||
*/
|
|
||||||
object Keys {
|
|
||||||
const val KEY_THEME = "KEY_THEME"
|
|
||||||
const val KEY_ACCENT = "KEY_ACCENT"
|
|
||||||
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_DEBUG_SAVE = "KEY_SAVE_STATE"
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Values for some settings entries that cant be enums/ints.
|
|
||||||
*/
|
|
||||||
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"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loop at the end. Similar to Music Player GO.
|
|
||||||
*/
|
|
||||||
const val AT_END_LOOP = "LOOP"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stop at the end. Similar to Phonograph.
|
|
||||||
*/
|
|
||||||
const val AT_END_STOP = "STOP"
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An interface for receiving some preference updates. Use/Extend this instead of
|
|
||||||
* [SharedPreferences.OnSharedPreferenceChangeListener] if possible, as it doesn't require a
|
|
||||||
* context.
|
|
||||||
*/
|
|
||||||
interface Callback {
|
|
||||||
fun onColorizeNotifUpdate(doColorize: Boolean) {}
|
|
||||||
fun onNotifActionUpdate(useAltAction: Boolean) {}
|
|
||||||
fun onLibDisplayModeUpdate(displayMode: DisplayMode) {}
|
|
||||||
fun onShowCoverUpdate(showCovers: Boolean) {}
|
|
||||||
fun onQualityCoverUpdate(doQualityCovers: Boolean) {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:tint="?attr/colorControlNormal"
|
|
||||||
android:viewportWidth="24"
|
|
||||||
android:viewportHeight="24">
|
|
||||||
<path
|
|
||||||
android:fillColor="@android:color/white"
|
|
||||||
android:pathData="M4 6H2v16h16v-2H4V6zm18-4H6v16h16V2zm-3 9h-4v4h-2v-4H9V9h4V5h2v4h4v2z" />
|
|
||||||
</vector>
|
|
|
@ -96,6 +96,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="@dimen/height_compact_progress"
|
android:layout_height="@dimen/height_compact_progress"
|
||||||
android:clickable="false"
|
android:clickable="false"
|
||||||
|
android:progress="@{playbackModel.positionAsProgress}"
|
||||||
android:progressBackgroundTint="?attr/colorControlNormal"
|
android:progressBackgroundTint="?attr/colorControlNormal"
|
||||||
android:progressTint="?attr/colorPrimary"
|
android:progressTint="?attr/colorPrimary"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
|
|
@ -145,6 +145,7 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="@dimen/margin_mid_large"
|
android:layout_marginStart="@dimen/margin_mid_large"
|
||||||
|
android:text="@{playbackModel.formattedPosition}"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/playback_play_pause"
|
app:layout_constraintBottom_toTopOf="@+id/playback_play_pause"
|
||||||
app:layout_constraintStart_toEndOf="@+id/playback_cover"
|
app:layout_constraintStart_toEndOf="@+id/playback_cover"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/playback_seek_bar"
|
app:layout_constraintTop_toBottomOf="@+id/playback_seek_bar"
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="@dimen/margin_medium"
|
android:layout_marginStart="@dimen/margin_medium"
|
||||||
android:layout_marginEnd="@dimen/margin_medium"
|
android:layout_marginEnd="@dimen/margin_medium"
|
||||||
android:text="@{genre.displayName}"
|
android:text="@{genre.resolvedName}"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/genre_song_count"
|
app:layout_constraintBottom_toTopOf="@+id/genre_song_count"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintHorizontal_bias="0.5"
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="@dimen/margin_medium"
|
android:layout_marginStart="@dimen/margin_medium"
|
||||||
android:layout_marginEnd="@dimen/margin_medium"
|
android:layout_marginEnd="@dimen/margin_medium"
|
||||||
android:text="@{genre.displayName}"
|
android:text="@{genre.resolvedName}"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/genre_song_count"
|
app:layout_constraintBottom_toTopOf="@+id/genre_song_count"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintHorizontal_bias="0.5"
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
|
|
|
@ -147,6 +147,7 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="@dimen/margin_mid_large"
|
android:layout_marginStart="@dimen/margin_mid_large"
|
||||||
|
android:text="@{playbackModel.formattedPosition}"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/playback_play_pause"
|
app:layout_constraintBottom_toTopOf="@+id/playback_play_pause"
|
||||||
app:layout_constraintStart_toEndOf="@+id/playback_cover"
|
app:layout_constraintStart_toEndOf="@+id/playback_cover"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/playback_seek_bar"
|
app:layout_constraintTop_toBottomOf="@+id/playback_seek_bar"
|
||||||
|
|
|
@ -132,6 +132,7 @@
|
||||||
android:id="@+id/playback_duration_current"
|
android:id="@+id/playback_duration_current"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@{playbackModel.formattedPosition}"
|
||||||
android:layout_marginStart="@dimen/margin_mid_huge"
|
android:layout_marginStart="@dimen/margin_mid_huge"
|
||||||
android:layout_marginBottom="@dimen/margin_medium"
|
android:layout_marginBottom="@dimen/margin_medium"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/playback_play_pause"
|
app:layout_constraintBottom_toTopOf="@+id/playback_play_pause"
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="@dimen/height_compact_progress"
|
android:layout_height="@dimen/height_compact_progress"
|
||||||
android:clickable="false"
|
android:clickable="false"
|
||||||
|
android:progress="@{playbackModel.positionAsProgress}"
|
||||||
android:progressBackgroundTint="?attr/colorControlNormal"
|
android:progressBackgroundTint="?attr/colorControlNormal"
|
||||||
android:progressTint="?attr/colorPrimary"
|
android:progressTint="?attr/colorPrimary"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
|
|
@ -134,6 +134,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="@dimen/margin_mid_large"
|
android:layout_marginStart="@dimen/margin_mid_large"
|
||||||
android:layout_marginBottom="@dimen/margin_medium"
|
android:layout_marginBottom="@dimen/margin_medium"
|
||||||
|
android:text="@{playbackModel.formattedPosition}"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/playback_play_pause"
|
app:layout_constraintBottom_toTopOf="@+id/playback_play_pause"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
tools:text="11:38" />
|
tools:text="11:38" />
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/genre_name"
|
android:id="@+id/genre_name"
|
||||||
style="@style/ItemText.Primary"
|
style="@style/ItemText.Primary"
|
||||||
android:text="@{genre.displayName}"
|
android:text="@{genre.resolvedName}"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/genre_count"
|
app:layout_constraintBottom_toTopOf="@+id/genre_count"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@+id/genre_image"
|
app:layout_constraintStart_toEndOf="@+id/genre_image"
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
android:layout_marginStart="@dimen/margin_medium"
|
android:layout_marginStart="@dimen/margin_medium"
|
||||||
android:layout_marginTop="@dimen/margin_medium"
|
android:layout_marginTop="@dimen/margin_medium"
|
||||||
android:layout_marginEnd="@dimen/margin_medium"
|
android:layout_marginEnd="@dimen/margin_medium"
|
||||||
android:text="@{genre.displayName}"
|
android:text="@{genre.resolvedName}"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintHorizontal_bias="0.5"
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_queue_add"
|
android:id="@+id/action_queue_add"
|
||||||
android:icon="@drawable/ic_queue_add"
|
|
||||||
android:title="@string/label_queue_add"
|
android:title="@string/label_queue_add"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="never" />
|
||||||
</menu>
|
</menu>
|
|
@ -3,17 +3,14 @@
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_play"
|
android:id="@+id/action_play"
|
||||||
android:icon="@drawable/ic_play"
|
|
||||||
android:title="@string/label_play"
|
android:title="@string/label_play"
|
||||||
app:showAsAction="ifRoom" />
|
app:showAsAction="never" />
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_shuffle"
|
android:id="@+id/action_shuffle"
|
||||||
android:icon="@drawable/ic_shuffle"
|
|
||||||
android:title="@string/label_shuffle"
|
android:title="@string/label_shuffle"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="never" />
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_queue_add"
|
android:id="@+id/action_queue_add"
|
||||||
android:icon="@drawable/ic_queue_add"
|
|
||||||
android:title="@string/label_queue_add"
|
android:title="@string/label_queue_add"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="never" />
|
||||||
</menu>
|
</menu>
|
|
@ -2,10 +2,8 @@
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_play"
|
android:id="@+id/action_play"
|
||||||
android:icon="@drawable/ic_play"
|
|
||||||
android:title="@string/label_play" />
|
android:title="@string/label_play" />
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_shuffle"
|
android:id="@+id/action_shuffle"
|
||||||
android:icon="@drawable/ic_shuffle"
|
|
||||||
android:title="@string/label_shuffle" />
|
android:title="@string/label_shuffle" />
|
||||||
</menu>
|
</menu>
|
|
@ -2,7 +2,6 @@
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_queue_add"
|
android:id="@+id/action_queue_add"
|
||||||
android:icon="@drawable/ic_queue_add"
|
|
||||||
android:title="@string/label_queue_add" />
|
android:title="@string/label_queue_add" />
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_go_artist"
|
android:id="@+id/action_go_artist"
|
||||||
|
|
Loading…
Reference in a new issue