detail: re-add sorting
Re-add sorting to the detail fragments, now with the new system.
This commit is contained in:
parent
a820724ff2
commit
7a17282c30
10 changed files with 297 additions and 68 deletions
|
@ -85,6 +85,14 @@ class AlbumDetailFragment : DetailFragment() {
|
||||||
detailAdapter.submitList(data)
|
detailAdapter.submitList(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
detailModel.showMenu.observe(viewLifecycleOwner) { config ->
|
||||||
|
if (config != null) {
|
||||||
|
showMenu(config) { id ->
|
||||||
|
id == R.id.option_sort_asc || id == R.id.option_sort_dsc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
detailModel.navToItem.observe(viewLifecycleOwner) { item ->
|
detailModel.navToItem.observe(viewLifecycleOwner) { item ->
|
||||||
when (item) {
|
when (item) {
|
||||||
// Songs should be scrolled to if the album matches, or a new detail
|
// Songs should be scrolled to if the album matches, or a new detail
|
||||||
|
|
|
@ -24,6 +24,7 @@ import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.navigation.fragment.navArgs
|
import androidx.navigation.fragment.navArgs
|
||||||
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.detail.recycler.ArtistDetailAdapter
|
import org.oxycblt.auxio.detail.recycler.ArtistDetailAdapter
|
||||||
import org.oxycblt.auxio.music.ActionHeader
|
import org.oxycblt.auxio.music.ActionHeader
|
||||||
import org.oxycblt.auxio.music.Album
|
import org.oxycblt.auxio.music.Album
|
||||||
|
@ -85,6 +86,14 @@ class ArtistDetailFragment : DetailFragment() {
|
||||||
detailAdapter.submitList(data)
|
detailAdapter.submitList(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
detailModel.showMenu.observe(viewLifecycleOwner) { config ->
|
||||||
|
if (config != null) {
|
||||||
|
showMenu(config) { id ->
|
||||||
|
id != R.id.option_sort_artist
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
detailModel.navToItem.observe(viewLifecycleOwner) { item ->
|
detailModel.navToItem.observe(viewLifecycleOwner) { item ->
|
||||||
when (item) {
|
when (item) {
|
||||||
is Artist -> {
|
is Artist -> {
|
||||||
|
|
|
@ -22,14 +22,18 @@ import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.activity.OnBackPressedCallback
|
import androidx.activity.OnBackPressedCallback
|
||||||
import androidx.annotation.MenuRes
|
import androidx.annotation.MenuRes
|
||||||
|
import androidx.appcompat.widget.PopupMenu
|
||||||
|
import androidx.core.view.forEach
|
||||||
import androidx.core.view.updatePadding
|
import androidx.core.view.updatePadding
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.databinding.FragmentDetailBinding
|
import org.oxycblt.auxio.databinding.FragmentDetailBinding
|
||||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||||
|
import org.oxycblt.auxio.ui.SortMode
|
||||||
import org.oxycblt.auxio.ui.memberBinding
|
import org.oxycblt.auxio.ui.memberBinding
|
||||||
import org.oxycblt.auxio.util.applyEdge
|
import org.oxycblt.auxio.util.applyEdge
|
||||||
import org.oxycblt.auxio.util.isLandscape
|
import org.oxycblt.auxio.util.isLandscape
|
||||||
|
@ -63,6 +67,13 @@ abstract class DetailFragment : Fragment() {
|
||||||
callback.isEnabled = false
|
callback.isEnabled = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onStop() {
|
||||||
|
super.onStop()
|
||||||
|
|
||||||
|
// Cancel all pending menus when this fragment stops to prevent bugs/crashes
|
||||||
|
detailModel.finishShowMenu(null, requireContext())
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shortcut method for doing setup of the detail toolbar.
|
* Shortcut method for doing setup of the detail toolbar.
|
||||||
* @param menu Menu resource to use
|
* @param menu Menu resource to use
|
||||||
|
@ -113,6 +124,37 @@ abstract class DetailFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shortcut method for spinning up the sorting [PopupMenu]
|
||||||
|
* @param config The initial configuration to apply to the menu. This is provided by [DetailViewModel.showMenu].
|
||||||
|
* @param showItem Which menu items to keep
|
||||||
|
*/
|
||||||
|
protected fun showMenu(config: DetailViewModel.MenuConfig, showItem: ((Int) -> Boolean)? = null) {
|
||||||
|
PopupMenu(config.anchor.context, config.anchor).apply {
|
||||||
|
inflate(R.menu.menu_detail_sort)
|
||||||
|
|
||||||
|
setOnMenuItemClickListener { item ->
|
||||||
|
item.isChecked = true
|
||||||
|
detailModel.finishShowMenu(SortMode.fromId(item.itemId)!!, config.anchor.context)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
setOnDismissListener {
|
||||||
|
detailModel.finishShowMenu(null, config.anchor.context)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showItem != null) {
|
||||||
|
menu.forEach { item ->
|
||||||
|
item.isVisible = showItem(item.itemId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
menu.findItem(config.sortMode.itemId).isChecked = true
|
||||||
|
|
||||||
|
show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Override the back button so that going back will only exit the detail fragments instead of
|
// Override the back button so that going back will only exit the detail fragments instead of
|
||||||
// the entire app.
|
// the entire app.
|
||||||
private val callback = object : OnBackPressedCallback(false) {
|
private val callback = object : OnBackPressedCallback(false) {
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
package org.oxycblt.auxio.detail
|
package org.oxycblt.auxio.detail
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.view.View
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
|
@ -30,12 +31,16 @@ import org.oxycblt.auxio.music.BaseModel
|
||||||
import org.oxycblt.auxio.music.Genre
|
import org.oxycblt.auxio.music.Genre
|
||||||
import org.oxycblt.auxio.music.Header
|
import org.oxycblt.auxio.music.Header
|
||||||
import org.oxycblt.auxio.music.MusicStore
|
import org.oxycblt.auxio.music.MusicStore
|
||||||
|
import org.oxycblt.auxio.settings.SettingsManager
|
||||||
|
import org.oxycblt.auxio.ui.DisplayMode
|
||||||
import org.oxycblt.auxio.ui.SortMode
|
import org.oxycblt.auxio.ui.SortMode
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ViewModel that stores data for the [DetailFragment]s, such as what they're showing & what
|
* ViewModel that stores data for the [DetailFragment]s. This includes:
|
||||||
* [SortMode] they are currently on.
|
* - What item the fragment should be showing
|
||||||
* TODO: Re-add sorting
|
* - The RecyclerView data for each fragment
|
||||||
|
* - Menu triggers for each fragment
|
||||||
|
* - Navigation triggers for each fragment [e.g "Go to artist"]
|
||||||
* @author OxygenCobalt
|
* @author OxygenCobalt
|
||||||
*/
|
*/
|
||||||
class DetailViewModel : ViewModel() {
|
class DetailViewModel : ViewModel() {
|
||||||
|
@ -59,93 +64,67 @@ class DetailViewModel : ViewModel() {
|
||||||
private val mAlbumData = MutableLiveData(listOf<BaseModel>())
|
private val mAlbumData = MutableLiveData(listOf<BaseModel>())
|
||||||
val albumData: LiveData<List<BaseModel>> get() = mAlbumData
|
val albumData: LiveData<List<BaseModel>> get() = mAlbumData
|
||||||
|
|
||||||
var isNavigating = false
|
data class MenuConfig(val anchor: View, val sortMode: SortMode)
|
||||||
private set
|
|
||||||
|
private val mShowMenu = MutableLiveData<MenuConfig?>(null)
|
||||||
|
val showMenu: LiveData<MenuConfig?> = mShowMenu
|
||||||
|
|
||||||
private val mNavToItem = MutableLiveData<BaseModel?>()
|
private val mNavToItem = MutableLiveData<BaseModel?>()
|
||||||
|
|
||||||
/** Flag for unified navigation. Observe this to coordinate navigation to an item's UI. */
|
/** Flag for unified navigation. Observe this to coordinate navigation to an item's UI. */
|
||||||
val navToItem: LiveData<BaseModel?> get() = mNavToItem
|
val navToItem: LiveData<BaseModel?> get() = mNavToItem
|
||||||
|
|
||||||
|
var isNavigating = false
|
||||||
|
private set
|
||||||
|
|
||||||
|
private var currentMenuContext: DisplayMode? = null
|
||||||
|
|
||||||
private val musicStore = MusicStore.getInstance()
|
private val musicStore = MusicStore.getInstance()
|
||||||
|
private val settingsManager = SettingsManager.getInstance()
|
||||||
|
|
||||||
fun setGenre(id: Long, context: Context) {
|
fun setGenre(id: Long, context: Context) {
|
||||||
if (mCurGenre.value?.id == id) return
|
if (mCurGenre.value?.id == id) return
|
||||||
|
|
||||||
mCurGenre.value = musicStore.genres.find { it.id == id }
|
mCurGenre.value = musicStore.genres.find { it.id == id }
|
||||||
|
refreshGenreData(context)
|
||||||
val data = mutableListOf<BaseModel>(curGenre.value!!)
|
|
||||||
|
|
||||||
data.add(
|
|
||||||
ActionHeader(
|
|
||||||
id = -2,
|
|
||||||
name = context.getString(R.string.lbl_songs),
|
|
||||||
icon = R.drawable.ic_sort,
|
|
||||||
desc = R.string.lbl_sort,
|
|
||||||
onClick = {
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
data.addAll(SortMode.ASCENDING.sortGenre(curGenre.value!!))
|
|
||||||
|
|
||||||
mGenreData.value = data
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setArtist(id: Long, context: Context) {
|
fun setArtist(id: Long, context: Context) {
|
||||||
if (mCurArtist.value?.id == id) return
|
if (mCurArtist.value?.id == id) return
|
||||||
|
|
||||||
mCurArtist.value = musicStore.artists.find { it.id == id }
|
mCurArtist.value = musicStore.artists.find { it.id == id }
|
||||||
|
refreshArtistData(context)
|
||||||
val artist = curArtist.value!!
|
|
||||||
val data = mutableListOf<BaseModel>(artist)
|
|
||||||
|
|
||||||
data.add(
|
|
||||||
Header(
|
|
||||||
id = -2,
|
|
||||||
name = context.getString(R.string.lbl_albums)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
data.addAll(SortMode.YEAR.sortAlbums(artist.albums))
|
|
||||||
|
|
||||||
data.add(
|
|
||||||
ActionHeader(
|
|
||||||
id = -3,
|
|
||||||
name = context.getString(R.string.lbl_songs),
|
|
||||||
icon = R.drawable.ic_sort,
|
|
||||||
desc = R.string.lbl_sort,
|
|
||||||
onClick = {
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
data.addAll(SortMode.YEAR.sortArtist(artist))
|
|
||||||
|
|
||||||
mArtistData.value = data.toList()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setAlbum(id: Long, context: Context) {
|
fun setAlbum(id: Long, context: Context) {
|
||||||
if (mCurAlbum.value?.id == id) return
|
if (mCurAlbum.value?.id == id) return
|
||||||
|
|
||||||
mCurAlbum.value = musicStore.albums.find { it.id == id }
|
mCurAlbum.value = musicStore.albums.find { it.id == id }
|
||||||
|
refreshAlbumData(context)
|
||||||
val data = mutableListOf<BaseModel>(curAlbum.value!!)
|
|
||||||
|
|
||||||
data.add(
|
|
||||||
ActionHeader(
|
|
||||||
id = -2,
|
|
||||||
name = context.getString(R.string.lbl_songs),
|
|
||||||
icon = R.drawable.ic_sort,
|
|
||||||
desc = R.string.lbl_sort,
|
|
||||||
onClick = {
|
|
||||||
}
|
}
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
data.addAll(SortMode.ASCENDING.sortAlbum(curAlbum.value!!))
|
/**
|
||||||
|
* Mark that the menu process is done with the new [SortMode].
|
||||||
|
* Pass null if there was no change.
|
||||||
|
*/
|
||||||
|
fun finishShowMenu(newMode: SortMode?, context: Context) {
|
||||||
|
mShowMenu.value = null
|
||||||
|
|
||||||
mAlbumData.value = data
|
if (newMode != null) {
|
||||||
|
when (currentMenuContext) {
|
||||||
|
DisplayMode.SHOW_ALBUMS -> {
|
||||||
|
settingsManager.albumSortMode = newMode
|
||||||
|
refreshAlbumData(context)
|
||||||
|
}
|
||||||
|
DisplayMode.SHOW_ARTISTS -> {
|
||||||
|
settingsManager.artistSortMode = newMode
|
||||||
|
refreshArtistData(context)
|
||||||
|
}
|
||||||
|
DisplayMode.SHOW_GENRES -> {
|
||||||
|
settingsManager.genreSortMode = newMode
|
||||||
|
refreshGenreData(context)
|
||||||
|
}
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
currentMenuContext = null
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -168,4 +147,77 @@ class DetailViewModel : ViewModel() {
|
||||||
fun setNavigating(navigating: Boolean) {
|
fun setNavigating(navigating: Boolean) {
|
||||||
isNavigating = navigating
|
isNavigating = navigating
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun refreshGenreData(context: Context) {
|
||||||
|
val data = mutableListOf<BaseModel>(curGenre.value!!)
|
||||||
|
|
||||||
|
data.add(
|
||||||
|
ActionHeader(
|
||||||
|
id = -2,
|
||||||
|
name = context.getString(R.string.lbl_songs),
|
||||||
|
icon = R.drawable.ic_sort,
|
||||||
|
desc = R.string.lbl_sort,
|
||||||
|
onClick = { view ->
|
||||||
|
currentMenuContext = DisplayMode.SHOW_GENRES
|
||||||
|
mShowMenu.value = MenuConfig(view, settingsManager.genreSortMode)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
data.addAll(settingsManager.genreSortMode.sortGenre(curGenre.value!!))
|
||||||
|
|
||||||
|
mGenreData.value = data
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun refreshArtistData(context: Context) {
|
||||||
|
val artist = curArtist.value!!
|
||||||
|
val data = mutableListOf<BaseModel>(artist)
|
||||||
|
|
||||||
|
data.add(
|
||||||
|
Header(
|
||||||
|
id = -2,
|
||||||
|
name = context.getString(R.string.lbl_albums)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
data.addAll(SortMode.YEAR.sortAlbums(artist.albums))
|
||||||
|
|
||||||
|
data.add(
|
||||||
|
ActionHeader(
|
||||||
|
id = -3,
|
||||||
|
name = context.getString(R.string.lbl_songs),
|
||||||
|
icon = R.drawable.ic_sort,
|
||||||
|
desc = R.string.lbl_sort,
|
||||||
|
onClick = { view ->
|
||||||
|
currentMenuContext = DisplayMode.SHOW_ARTISTS
|
||||||
|
mShowMenu.value = MenuConfig(view, settingsManager.artistSortMode)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
data.addAll(settingsManager.artistSortMode.sortArtist(artist))
|
||||||
|
|
||||||
|
mArtistData.value = data.toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun refreshAlbumData(context: Context) {
|
||||||
|
val data = mutableListOf<BaseModel>(curAlbum.value!!)
|
||||||
|
|
||||||
|
data.add(
|
||||||
|
ActionHeader(
|
||||||
|
id = -2,
|
||||||
|
name = context.getString(R.string.lbl_songs),
|
||||||
|
icon = R.drawable.ic_sort,
|
||||||
|
desc = R.string.lbl_sort,
|
||||||
|
onClick = { view ->
|
||||||
|
currentMenuContext = DisplayMode.SHOW_ALBUMS
|
||||||
|
mShowMenu.value = MenuConfig(view, settingsManager.albumSortMode)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
data.addAll(settingsManager.albumSortMode.sortAlbum(curAlbum.value!!))
|
||||||
|
|
||||||
|
mAlbumData.value = data
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,6 +109,12 @@ class GenreDetailFragment : DetailFragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
detailModel.showMenu.observe(viewLifecycleOwner) { config ->
|
||||||
|
if (config != null) {
|
||||||
|
showMenu(config)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
playbackModel.isInUserQueue.observe(viewLifecycleOwner) { inUserQueue ->
|
playbackModel.isInUserQueue.observe(viewLifecycleOwner) { inUserQueue ->
|
||||||
if (inUserQueue) {
|
if (inUserQueue) {
|
||||||
detailAdapter.highlightSong(null, binding.detailRecycler)
|
detailAdapter.highlightSong(null, binding.detailRecycler)
|
||||||
|
|
|
@ -237,5 +237,28 @@ data class ActionHeader(
|
||||||
override val name: String,
|
override val name: String,
|
||||||
@DrawableRes val icon: Int,
|
@DrawableRes val icon: Int,
|
||||||
@StringRes val desc: Int,
|
@StringRes val desc: Int,
|
||||||
val onClick: (View) -> Unit
|
val onClick: (View) -> Unit,
|
||||||
) : BaseModel()
|
) : BaseModel() {
|
||||||
|
// JVM can't into comparing lambdas, so we override equals/hashCode and exclude them.
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (other !is ActionHeader) return false
|
||||||
|
|
||||||
|
if (id != other.id) return false
|
||||||
|
if (name != other.name) return false
|
||||||
|
if (icon != other.icon) return false
|
||||||
|
if (desc != other.desc) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = id.hashCode()
|
||||||
|
result = 31 * result + name.hashCode()
|
||||||
|
result = 31 * result + icon
|
||||||
|
result = 31 * result + desc
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ import org.oxycblt.auxio.accent.ACCENTS
|
||||||
import org.oxycblt.auxio.accent.Accent
|
import org.oxycblt.auxio.accent.Accent
|
||||||
import org.oxycblt.auxio.playback.state.PlaybackMode
|
import org.oxycblt.auxio.playback.state.PlaybackMode
|
||||||
import org.oxycblt.auxio.ui.DisplayMode
|
import org.oxycblt.auxio.ui.DisplayMode
|
||||||
|
import org.oxycblt.auxio.ui.SortMode
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper around the [SharedPreferences] class that writes & reads values without a context.
|
* Wrapper around the [SharedPreferences] class that writes & reads values without a context.
|
||||||
|
@ -118,6 +119,36 @@ class SettingsManager private constructor(context: Context) :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var albumSortMode: SortMode
|
||||||
|
get() = SortMode.fromInt(sharedPrefs.getInt(KEY_ALBUM_SORT, Int.MIN_VALUE))
|
||||||
|
?: SortMode.ASCENDING
|
||||||
|
set(value) {
|
||||||
|
sharedPrefs.edit {
|
||||||
|
putInt(KEY_ALBUM_SORT, value.toInt())
|
||||||
|
apply()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var artistSortMode: SortMode
|
||||||
|
get() = SortMode.fromInt(sharedPrefs.getInt(KEY_ARTIST_SORT, Int.MIN_VALUE))
|
||||||
|
?: SortMode.YEAR
|
||||||
|
set(value) {
|
||||||
|
sharedPrefs.edit {
|
||||||
|
putInt(KEY_ARTIST_SORT, value.toInt())
|
||||||
|
apply()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var genreSortMode: SortMode
|
||||||
|
get() = SortMode.fromInt(sharedPrefs.getInt(KEY_GENRE_SORT, Int.MIN_VALUE))
|
||||||
|
?: SortMode.ASCENDING
|
||||||
|
set(value) {
|
||||||
|
sharedPrefs.edit {
|
||||||
|
putInt(KEY_GENRE_SORT, value.toInt())
|
||||||
|
apply()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// --- CALLBACKS ---
|
// --- CALLBACKS ---
|
||||||
|
|
||||||
private val callbacks = mutableListOf<Callback>()
|
private val callbacks = mutableListOf<Callback>()
|
||||||
|
@ -181,6 +212,9 @@ class SettingsManager private constructor(context: Context) :
|
||||||
const val KEY_BLACKLIST = "KEY_BLACKLIST"
|
const val KEY_BLACKLIST = "KEY_BLACKLIST"
|
||||||
|
|
||||||
const val KEY_SEARCH_FILTER_MODE = "KEY_SEARCH_FILTER"
|
const val KEY_SEARCH_FILTER_MODE = "KEY_SEARCH_FILTER"
|
||||||
|
const val KEY_ALBUM_SORT = "KEY_ALBUM_SORT"
|
||||||
|
const val KEY_ARTIST_SORT = "KEY_ARTIST_SORT"
|
||||||
|
const val KEY_GENRE_SORT = "KEY_GENRE_SORT"
|
||||||
|
|
||||||
@Volatile
|
@Volatile
|
||||||
private var INSTANCE: SettingsManager? = null
|
private var INSTANCE: SettingsManager? = null
|
||||||
|
|
|
@ -147,7 +147,36 @@ enum class SortMode(@IdRes val itemId: Int) {
|
||||||
return sortSongs(genre.songs)
|
return sortSongs(genre.songs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts this mode into an integer constant. Use this when writing a [SortMode]
|
||||||
|
* to storage, as it will be more efficent.
|
||||||
|
*/
|
||||||
|
fun toInt(): Int {
|
||||||
|
return ordinal + INT_ASCENDING
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
private const val INT_ASCENDING = 0xA10C
|
||||||
|
private const val INT_DESCENDING = 0xA10D
|
||||||
|
private const val INT_ARTIST = 0xA10E
|
||||||
|
private const val INT_ALBUM = 0xA10F
|
||||||
|
private const val INT_YEAR = 0xA110
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a [SortMode] depending on the integer constant, use this when restoring
|
||||||
|
* a [SortMode] from storage.
|
||||||
|
*/
|
||||||
|
fun fromInt(value: Int): SortMode? {
|
||||||
|
return when (value) {
|
||||||
|
INT_ASCENDING -> ASCENDING
|
||||||
|
INT_DESCENDING -> DESCENDING
|
||||||
|
INT_ARTIST -> ASCENDING
|
||||||
|
INT_ALBUM -> ALBUM
|
||||||
|
INT_YEAR -> YEAR
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a menu [id] to an instance of [SortMode].
|
* Convert a menu [id] to an instance of [SortMode].
|
||||||
*/
|
*/
|
||||||
|
|
20
app/src/main/res/menu/menu_detail_sort.xml
Normal file
20
app/src/main/res/menu/menu_detail_sort.xml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<group android:checkableBehavior="single">
|
||||||
|
<item
|
||||||
|
android:id="@+id/option_sort_asc"
|
||||||
|
android:title="@string/lbl_sort_asc" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/option_sort_dsc"
|
||||||
|
android:title="@string/lbl_sort_dsc" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/option_sort_artist"
|
||||||
|
android:title="@string/lbl_sort_artist" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/option_sort_album"
|
||||||
|
android:title="@string/lbl_sort_album" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/option_sort_year"
|
||||||
|
android:title="@string/lbl_sort_year" />
|
||||||
|
</group>
|
||||||
|
</menu>
|
|
@ -76,6 +76,12 @@ To prevent any strange bugs, all integer representations must be unique. A table
|
||||||
0xA109 | DisplayMode.SHOW_ARTISTS
|
0xA109 | DisplayMode.SHOW_ARTISTS
|
||||||
0xA10A | DisplayMode.SHOW_ALBUMS
|
0xA10A | DisplayMode.SHOW_ALBUMS
|
||||||
0xA10B | DisplayMode.SHOW_SONGS
|
0xA10B | DisplayMode.SHOW_SONGS
|
||||||
|
|
||||||
|
0xA10C | SortMode.ASCENDING
|
||||||
|
0xA10D | SortMode.DESCENDING
|
||||||
|
0xA10E | SortMode.ARTIST
|
||||||
|
0xA10F | SortMode.ALBUM
|
||||||
|
0xA110 | SortMode.YEAR
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Package structure overview
|
#### Package structure overview
|
||||||
|
|
Loading…
Reference in a new issue