list: make sorting direction explicit
Make sorting direction (ascending/descending) explicit in the UI and in the code. Instead of a boolean flag, two distinct "ascending" and "descending" options are used instead. This should be much clearer.
This commit is contained in:
parent
8536c3da31
commit
3c211a1d17
24 changed files with 217 additions and 151 deletions
|
@ -8,6 +8,8 @@
|
|||
#### What's Improved
|
||||
- Auxio will now accept zeroed track/disc numbers in the presence of non-zero total
|
||||
track/disc fields
|
||||
- Music loading has been made slightly faster
|
||||
- Improved sort menu usability
|
||||
|
||||
#### What's Fixed
|
||||
- Fixed non-functioning "repeat all" repeat mode
|
||||
|
|
|
@ -40,7 +40,7 @@ import org.oxycblt.auxio.music.Music
|
|||
import org.oxycblt.auxio.music.MusicMode
|
||||
import org.oxycblt.auxio.music.MusicParent
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.music.library.Sort
|
||||
import org.oxycblt.auxio.list.Sort
|
||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||
import org.oxycblt.auxio.ui.NavigationViewModel
|
||||
import org.oxycblt.auxio.util.*
|
||||
|
@ -151,14 +151,19 @@ class AlbumDetailFragment :
|
|||
openMenu(anchor, R.menu.menu_album_sort) {
|
||||
val sort = detailModel.albumSongSort
|
||||
unlikelyToBeNull(menu.findItem(sort.mode.itemId)).isChecked = true
|
||||
unlikelyToBeNull(menu.findItem(R.id.option_sort_asc)).isChecked = sort.isAscending
|
||||
val directionItemId =
|
||||
when (sort.direction) {
|
||||
Sort.Direction.ASCENDING -> R.id.option_sort_asc
|
||||
Sort.Direction.DESCENDING -> R.id.option_sort_dec
|
||||
}
|
||||
unlikelyToBeNull(menu.findItem(directionItemId)).isChecked = true
|
||||
setOnMenuItemClickListener { item ->
|
||||
item.isChecked = !item.isChecked
|
||||
detailModel.albumSongSort =
|
||||
if (item.itemId == R.id.option_sort_asc) {
|
||||
sort.withAscending(item.isChecked)
|
||||
} else {
|
||||
sort.withMode(unlikelyToBeNull(Sort.Mode.fromItemId(item.itemId)))
|
||||
when (item.itemId) {
|
||||
R.id.option_sort_asc -> sort.withDirection(Sort.Direction.ASCENDING)
|
||||
R.id.option_sort_dec -> sort.withDirection(Sort.Direction.DESCENDING)
|
||||
else -> sort.withMode(unlikelyToBeNull(Sort.Mode.fromItemId(item.itemId)))
|
||||
}
|
||||
true
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ import org.oxycblt.auxio.music.Artist
|
|||
import org.oxycblt.auxio.music.Music
|
||||
import org.oxycblt.auxio.music.MusicParent
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.music.library.Sort
|
||||
import org.oxycblt.auxio.list.Sort
|
||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||
import org.oxycblt.auxio.ui.NavigationViewModel
|
||||
import org.oxycblt.auxio.util.collect
|
||||
|
@ -167,15 +167,20 @@ class ArtistDetailFragment :
|
|||
openMenu(anchor, R.menu.menu_artist_sort) {
|
||||
val sort = detailModel.artistSongSort
|
||||
unlikelyToBeNull(menu.findItem(sort.mode.itemId)).isChecked = true
|
||||
unlikelyToBeNull(menu.findItem(R.id.option_sort_asc)).isChecked = sort.isAscending
|
||||
val directionItemId =
|
||||
when (sort.direction) {
|
||||
Sort.Direction.ASCENDING -> R.id.option_sort_asc
|
||||
Sort.Direction.DESCENDING -> R.id.option_sort_dec
|
||||
}
|
||||
unlikelyToBeNull(menu.findItem(directionItemId)).isChecked = true
|
||||
setOnMenuItemClickListener { item ->
|
||||
item.isChecked = !item.isChecked
|
||||
|
||||
detailModel.artistSongSort =
|
||||
if (item.itemId == R.id.option_sort_asc) {
|
||||
sort.withAscending(item.isChecked)
|
||||
} else {
|
||||
sort.withMode(unlikelyToBeNull(Sort.Mode.fromItemId(item.itemId)))
|
||||
when (item.itemId) {
|
||||
R.id.option_sort_asc -> sort.withDirection(Sort.Direction.ASCENDING)
|
||||
R.id.option_sort_dec -> sort.withDirection(Sort.Direction.DESCENDING)
|
||||
else -> sort.withMode(unlikelyToBeNull(Sort.Mode.fromItemId(item.itemId)))
|
||||
}
|
||||
|
||||
true
|
||||
|
|
|
@ -34,7 +34,7 @@ import org.oxycblt.auxio.list.BasicHeader
|
|||
import org.oxycblt.auxio.list.Item
|
||||
import org.oxycblt.auxio.music.*
|
||||
import org.oxycblt.auxio.music.library.Library
|
||||
import org.oxycblt.auxio.music.library.Sort
|
||||
import org.oxycblt.auxio.list.Sort
|
||||
import org.oxycblt.auxio.music.metadata.AudioInfo
|
||||
import org.oxycblt.auxio.music.metadata.Disc
|
||||
import org.oxycblt.auxio.music.metadata.ReleaseType
|
||||
|
@ -280,7 +280,7 @@ constructor(
|
|||
private fun refreshArtistList(artist: Artist) {
|
||||
logD("Refreshing artist data")
|
||||
val data = mutableListOf<Item>(artist)
|
||||
val albums = Sort(Sort.Mode.ByDate, false).albums(artist.albums)
|
||||
val albums = Sort(Sort.Mode.ByDate, Sort.Direction.DESCENDING).albums(artist.albums)
|
||||
|
||||
val byReleaseGroup =
|
||||
albums.groupBy {
|
||||
|
|
|
@ -40,7 +40,7 @@ import org.oxycblt.auxio.music.Genre
|
|||
import org.oxycblt.auxio.music.Music
|
||||
import org.oxycblt.auxio.music.MusicParent
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.music.library.Sort
|
||||
import org.oxycblt.auxio.list.Sort
|
||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||
import org.oxycblt.auxio.ui.NavigationViewModel
|
||||
import org.oxycblt.auxio.util.collect
|
||||
|
@ -166,14 +166,19 @@ class GenreDetailFragment :
|
|||
openMenu(anchor, R.menu.menu_genre_sort) {
|
||||
val sort = detailModel.genreSongSort
|
||||
unlikelyToBeNull(menu.findItem(sort.mode.itemId)).isChecked = true
|
||||
unlikelyToBeNull(menu.findItem(R.id.option_sort_asc)).isChecked = sort.isAscending
|
||||
val directionItemId =
|
||||
when (sort.direction) {
|
||||
Sort.Direction.ASCENDING -> R.id.option_sort_asc
|
||||
Sort.Direction.DESCENDING -> R.id.option_sort_dec
|
||||
}
|
||||
unlikelyToBeNull(menu.findItem(directionItemId)).isChecked = true
|
||||
setOnMenuItemClickListener { item ->
|
||||
item.isChecked = !item.isChecked
|
||||
detailModel.genreSongSort =
|
||||
if (item.itemId == R.id.option_sort_asc) {
|
||||
sort.withAscending(item.isChecked)
|
||||
} else {
|
||||
sort.withMode(unlikelyToBeNull(Sort.Mode.fromItemId(item.itemId)))
|
||||
when (item.itemId) {
|
||||
R.id.option_sort_asc -> sort.withDirection(Sort.Direction.ASCENDING)
|
||||
R.id.option_sort_dec -> sort.withDirection(Sort.Direction.DESCENDING)
|
||||
else -> sort.withMode(unlikelyToBeNull(Sort.Mode.fromItemId(item.itemId)))
|
||||
}
|
||||
true
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import android.view.MenuItem
|
|||
import android.view.View
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.core.view.MenuCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.iterator
|
||||
import androidx.core.view.updatePadding
|
||||
|
@ -53,7 +54,7 @@ import org.oxycblt.auxio.list.selection.SelectionFragment
|
|||
import org.oxycblt.auxio.list.selection.SelectionViewModel
|
||||
import org.oxycblt.auxio.music.*
|
||||
import org.oxycblt.auxio.music.library.Library
|
||||
import org.oxycblt.auxio.music.library.Sort
|
||||
import org.oxycblt.auxio.list.Sort
|
||||
import org.oxycblt.auxio.music.system.Indexer
|
||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||
import org.oxycblt.auxio.ui.MainNavigationAction
|
||||
|
@ -104,7 +105,10 @@ class HomeFragment :
|
|||
|
||||
// --- UI SETUP ---
|
||||
binding.homeAppbar.addOnOffsetChangedListener(this)
|
||||
binding.homeToolbar.setOnMenuItemClickListener(this)
|
||||
binding.homeToolbar.apply {
|
||||
setOnMenuItemClickListener(this@HomeFragment)
|
||||
MenuCompat.setGroupDividerEnabled(menu, true)
|
||||
}
|
||||
|
||||
// Load the track color in manually as it's unclear whether the track actually supports
|
||||
// using a ColorStateList in the resources
|
||||
|
@ -213,11 +217,18 @@ class HomeFragment :
|
|||
// Junk click event when opening the menu
|
||||
}
|
||||
R.id.option_sort_asc -> {
|
||||
item.isChecked = !item.isChecked
|
||||
item.isChecked = true
|
||||
homeModel.setSortForCurrentTab(
|
||||
homeModel
|
||||
.getSortForTab(homeModel.currentTabMode.value)
|
||||
.withAscending(item.isChecked))
|
||||
.withDirection(Sort.Direction.ASCENDING))
|
||||
}
|
||||
R.id.option_sort_dec -> {
|
||||
item.isChecked = true
|
||||
homeModel.setSortForCurrentTab(
|
||||
homeModel
|
||||
.getSortForTab(homeModel.currentTabMode.value)
|
||||
.withDirection(Sort.Direction.DESCENDING))
|
||||
}
|
||||
else -> {
|
||||
// Sorting option was selected, mark it as selected and update the mode
|
||||
|
@ -270,6 +281,7 @@ class HomeFragment :
|
|||
// Only allow sorting by name, count, and duration for artists
|
||||
MusicMode.ARTISTS -> { id ->
|
||||
id == R.id.option_sort_asc ||
|
||||
id == R.id.option_sort_dec ||
|
||||
id == R.id.option_sort_name ||
|
||||
id == R.id.option_sort_count ||
|
||||
id == R.id.option_sort_duration
|
||||
|
@ -277,6 +289,7 @@ class HomeFragment :
|
|||
// Only allow sorting by name, count, and duration for genres
|
||||
MusicMode.GENRES -> { id ->
|
||||
id == R.id.option_sort_asc ||
|
||||
id == R.id.option_sort_dec ||
|
||||
id == R.id.option_sort_name ||
|
||||
id == R.id.option_sort_count ||
|
||||
id == R.id.option_sort_duration
|
||||
|
@ -292,7 +305,10 @@ class HomeFragment :
|
|||
// Check the ascending option and corresponding sort option to align with
|
||||
// the current sort of the tab.
|
||||
if (option.itemId == toHighlight.mode.itemId ||
|
||||
(option.itemId == R.id.option_sort_asc && toHighlight.isAscending)) {
|
||||
(option.itemId == R.id.option_sort_asc &&
|
||||
toHighlight.direction == Sort.Direction.ASCENDING) ||
|
||||
(option.itemId == R.id.option_sort_dec &&
|
||||
toHighlight.direction == Sort.Direction.DESCENDING)) {
|
||||
option.isChecked = true
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ import kotlinx.coroutines.flow.StateFlow
|
|||
import org.oxycblt.auxio.home.tabs.Tab
|
||||
import org.oxycblt.auxio.music.*
|
||||
import org.oxycblt.auxio.music.library.Library
|
||||
import org.oxycblt.auxio.music.library.Sort
|
||||
import org.oxycblt.auxio.list.Sort
|
||||
import org.oxycblt.auxio.playback.PlaybackSettings
|
||||
import org.oxycblt.auxio.util.logD
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
|
|||
import org.oxycblt.auxio.list.recycler.AlbumViewHolder
|
||||
import org.oxycblt.auxio.list.selection.SelectionViewModel
|
||||
import org.oxycblt.auxio.music.*
|
||||
import org.oxycblt.auxio.music.library.Sort
|
||||
import org.oxycblt.auxio.list.Sort
|
||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||
import org.oxycblt.auxio.playback.formatDurationMs
|
||||
import org.oxycblt.auxio.playback.secsToMs
|
||||
|
|
|
@ -38,7 +38,7 @@ import org.oxycblt.auxio.music.Artist
|
|||
import org.oxycblt.auxio.music.Music
|
||||
import org.oxycblt.auxio.music.MusicMode
|
||||
import org.oxycblt.auxio.music.MusicParent
|
||||
import org.oxycblt.auxio.music.library.Sort
|
||||
import org.oxycblt.auxio.list.Sort
|
||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||
import org.oxycblt.auxio.playback.formatDurationMs
|
||||
import org.oxycblt.auxio.ui.NavigationViewModel
|
||||
|
|
|
@ -38,7 +38,7 @@ import org.oxycblt.auxio.music.Genre
|
|||
import org.oxycblt.auxio.music.Music
|
||||
import org.oxycblt.auxio.music.MusicMode
|
||||
import org.oxycblt.auxio.music.MusicParent
|
||||
import org.oxycblt.auxio.music.library.Sort
|
||||
import org.oxycblt.auxio.list.Sort
|
||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||
import org.oxycblt.auxio.playback.formatDurationMs
|
||||
import org.oxycblt.auxio.ui.NavigationViewModel
|
||||
|
|
|
@ -40,7 +40,7 @@ import org.oxycblt.auxio.music.Music
|
|||
import org.oxycblt.auxio.music.MusicMode
|
||||
import org.oxycblt.auxio.music.MusicParent
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.music.library.Sort
|
||||
import org.oxycblt.auxio.list.Sort
|
||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||
import org.oxycblt.auxio.playback.formatDurationMs
|
||||
import org.oxycblt.auxio.playback.secsToMs
|
||||
|
|
|
@ -35,7 +35,7 @@ import org.oxycblt.auxio.music.Artist
|
|||
import org.oxycblt.auxio.music.Genre
|
||||
import org.oxycblt.auxio.music.Music
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.music.library.Sort
|
||||
import org.oxycblt.auxio.list.Sort
|
||||
|
||||
/**
|
||||
* A [Keyer] implementation for [Music] data.
|
||||
|
@ -91,7 +91,7 @@ private constructor(
|
|||
) : Fetcher {
|
||||
override suspend fun fetch(): FetchResult? {
|
||||
// Pick the "most prominent" albums (i.e albums with the most songs) to show in the image.
|
||||
val albums = Sort(Sort.Mode.ByCount, false).albums(artist.albums)
|
||||
val albums = Sort(Sort.Mode.ByCount, Sort.Direction.DESCENDING).albums(artist.albums)
|
||||
val results = albums.mapAtMostNotNull(4) { album -> Covers.fetch(context, album) }
|
||||
return Images.createMosaic(context, results, size)
|
||||
}
|
||||
|
|
|
@ -21,6 +21,8 @@ import android.view.MenuItem
|
|||
import android.view.View
|
||||
import androidx.annotation.MenuRes
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.core.internal.view.SupportMenu
|
||||
import androidx.core.view.MenuCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import org.oxycblt.auxio.MainFragmentDirections
|
||||
|
@ -237,6 +239,8 @@ abstract class ListFragment<in T : Music, VB : ViewBinding> :
|
|||
currentMenu =
|
||||
PopupMenu(requireContext(), anchor).apply {
|
||||
inflate(menuRes)
|
||||
logD(menu is SupportMenu)
|
||||
MenuCompat.setGroupDividerEnabled(menu, true)
|
||||
block()
|
||||
setOnDismissListener { currentMenu = null }
|
||||
show()
|
||||
|
|
|
@ -15,14 +15,14 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.auxio.music.library
|
||||
package org.oxycblt.auxio.list
|
||||
|
||||
import androidx.annotation.IdRes
|
||||
import kotlin.math.max
|
||||
import org.oxycblt.auxio.IntegerTable
|
||||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.music.*
|
||||
import org.oxycblt.auxio.music.library.Sort.Mode
|
||||
import org.oxycblt.auxio.list.Sort.Mode
|
||||
import org.oxycblt.auxio.music.metadata.Date
|
||||
import org.oxycblt.auxio.music.metadata.Disc
|
||||
|
||||
|
@ -32,23 +32,23 @@ import org.oxycblt.auxio.music.metadata.Disc
|
|||
* This can be used not only to sort items, but also represent a sorting mode within the UI.
|
||||
*
|
||||
* @param mode A [Mode] dictating how to sort the list.
|
||||
* @param isAscending Whether to sort in ascending or descending order.
|
||||
* @param direction The [Direction] to sort in.
|
||||
* @author Alexander Capehart (OxygenCobalt)
|
||||
*/
|
||||
data class Sort(val mode: Mode, val isAscending: Boolean) {
|
||||
data class Sort(val mode: Mode, val direction: Direction) {
|
||||
/**
|
||||
* Create a new [Sort] with the same [mode], but different [isAscending] value.
|
||||
* @param isAscending Whether the new sort should be in ascending order or not.
|
||||
* @return A new sort with the same mode, but with the new [isAscending] value applied.
|
||||
* Create a new [Sort] with the same [mode], but a different [Direction].
|
||||
* @param direction The new [Direction] to sort in.
|
||||
* @return A new sort with the same mode, but with the new [Direction] value applied.
|
||||
*/
|
||||
fun withAscending(isAscending: Boolean) = Sort(mode, isAscending)
|
||||
fun withDirection(direction: Direction) = Sort(mode, direction)
|
||||
|
||||
/**
|
||||
* Create a new [Sort] with the same [isAscending] value, but different [mode] value.
|
||||
* Create a new [Sort] with the same [direction] value, but different [mode] value.
|
||||
* @param mode Tbe new mode to use for the Sort.
|
||||
* @return A new sort with the same [isAscending] value, but with the new [mode] applied.
|
||||
* @return A new sort with the same [direction] value, but with the new [mode] applied.
|
||||
*/
|
||||
fun withMode(mode: Mode) = Sort(mode, isAscending)
|
||||
fun withMode(mode: Mode) = Sort(mode, direction)
|
||||
|
||||
/**
|
||||
* Sort a list of [Song]s.
|
||||
|
@ -99,7 +99,7 @@ data class Sort(val mode: Mode, val isAscending: Boolean) {
|
|||
* @param songs The [Song]s to sort.
|
||||
*/
|
||||
private fun songsInPlace(songs: MutableList<out Song>) {
|
||||
songs.sortWith(mode.getSongComparator(isAscending))
|
||||
songs.sortWith(mode.getSongComparator(direction))
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -107,7 +107,7 @@ data class Sort(val mode: Mode, val isAscending: Boolean) {
|
|||
* @param albums The [Album]s to sort.
|
||||
*/
|
||||
private fun albumsInPlace(albums: MutableList<out Album>) {
|
||||
albums.sortWith(mode.getAlbumComparator(isAscending))
|
||||
albums.sortWith(mode.getAlbumComparator(direction))
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -115,7 +115,7 @@ data class Sort(val mode: Mode, val isAscending: Boolean) {
|
|||
* @param artists The [Album]s to sort.
|
||||
*/
|
||||
private fun artistsInPlace(artists: MutableList<out Artist>) {
|
||||
artists.sortWith(mode.getArtistComparator(isAscending))
|
||||
artists.sortWith(mode.getArtistComparator(direction))
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -123,7 +123,7 @@ data class Sort(val mode: Mode, val isAscending: Boolean) {
|
|||
* @param genres The [Genre]s to sort.
|
||||
*/
|
||||
private fun genresInPlace(genres: MutableList<out Genre>) {
|
||||
genres.sortWith(mode.getGenreComparator(isAscending))
|
||||
genres.sortWith(mode.getGenreComparator(direction))
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -134,8 +134,14 @@ data class Sort(val mode: Mode, val isAscending: Boolean) {
|
|||
// Sort's integer representation is formatted as AMMMM, where A is a bitflag
|
||||
// representing if the sort is in ascending or descending order, and M is the
|
||||
// integer representation of the sort mode.
|
||||
get() = mode.intCode.shl(1) or if (isAscending) 1 else 0
|
||||
get() =
|
||||
mode.intCode.shl(1) or
|
||||
when (direction) {
|
||||
Direction.ASCENDING -> 1
|
||||
Direction.DESCENDING -> 0
|
||||
}
|
||||
|
||||
/** Describes the type of data to sort with. */
|
||||
sealed class Mode {
|
||||
/** The integer representation of this sort mode. */
|
||||
abstract val intCode: Int
|
||||
|
@ -144,37 +150,37 @@ data class Sort(val mode: Mode, val isAscending: Boolean) {
|
|||
|
||||
/**
|
||||
* Get a [Comparator] that sorts [Song]s according to this [Mode].
|
||||
* @param isAscending Whether to sort in ascending or descending order.
|
||||
* @param direction The direction to sort in.
|
||||
* @return A [Comparator] that can be used to sort a [Song] list according to this [Mode].
|
||||
*/
|
||||
open fun getSongComparator(isAscending: Boolean): Comparator<Song> {
|
||||
open fun getSongComparator(direction: Direction): Comparator<Song> {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a [Comparator] that sorts [Album]s according to this [Mode].
|
||||
* @param isAscending Whether to sort in ascending or descending order.
|
||||
* @param direction The direction to sort in.
|
||||
* @return A [Comparator] that can be used to sort a [Album] list according to this [Mode].
|
||||
*/
|
||||
open fun getAlbumComparator(isAscending: Boolean): Comparator<Album> {
|
||||
open fun getAlbumComparator(direction: Direction): Comparator<Album> {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a [Comparator] that sorts [Artist]s according to this [Mode].
|
||||
* @param isAscending Whether to sort in ascending or descending order.
|
||||
* @param direction The direction to sort in.
|
||||
* @return A [Comparator] that can be used to sort a [Artist] list according to this [Mode].
|
||||
*/
|
||||
open fun getArtistComparator(isAscending: Boolean): Comparator<Artist> {
|
||||
open fun getArtistComparator(direction: Direction): Comparator<Artist> {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a [Comparator] that sorts [Genre]s according to this [Mode].
|
||||
* @param isAscending Whether to sort in ascending or descending order.
|
||||
* @param direction The direction to sort in.
|
||||
* @return A [Comparator] that can be used to sort a [Genre] list according to this [Mode].
|
||||
*/
|
||||
open fun getGenreComparator(isAscending: Boolean): Comparator<Genre> {
|
||||
open fun getGenreComparator(direction: Direction): Comparator<Genre> {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
|
@ -189,17 +195,17 @@ data class Sort(val mode: Mode, val isAscending: Boolean) {
|
|||
override val itemId: Int
|
||||
get() = R.id.option_sort_name
|
||||
|
||||
override fun getSongComparator(isAscending: Boolean) =
|
||||
compareByDynamic(isAscending, BasicComparator.SONG)
|
||||
override fun getSongComparator(direction: Direction) =
|
||||
compareByDynamic(direction, BasicComparator.SONG)
|
||||
|
||||
override fun getAlbumComparator(isAscending: Boolean) =
|
||||
compareByDynamic(isAscending, BasicComparator.ALBUM)
|
||||
override fun getAlbumComparator(direction: Direction) =
|
||||
compareByDynamic(direction, BasicComparator.ALBUM)
|
||||
|
||||
override fun getArtistComparator(isAscending: Boolean) =
|
||||
compareByDynamic(isAscending, BasicComparator.ARTIST)
|
||||
override fun getArtistComparator(direction: Direction) =
|
||||
compareByDynamic(direction, BasicComparator.ARTIST)
|
||||
|
||||
override fun getGenreComparator(isAscending: Boolean) =
|
||||
compareByDynamic(isAscending, BasicComparator.GENRE)
|
||||
override fun getGenreComparator(direction: Direction) =
|
||||
compareByDynamic(direction, BasicComparator.GENRE)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -213,9 +219,9 @@ data class Sort(val mode: Mode, val isAscending: Boolean) {
|
|||
override val itemId: Int
|
||||
get() = R.id.option_sort_album
|
||||
|
||||
override fun getSongComparator(isAscending: Boolean): Comparator<Song> =
|
||||
override fun getSongComparator(direction: Direction): Comparator<Song> =
|
||||
MultiComparator(
|
||||
compareByDynamic(isAscending, BasicComparator.ALBUM) { it.album },
|
||||
compareByDynamic(direction, BasicComparator.ALBUM) { it.album },
|
||||
compareBy(NullableComparator.DISC) { it.disc },
|
||||
compareBy(NullableComparator.INT) { it.track },
|
||||
compareBy(BasicComparator.SONG))
|
||||
|
@ -232,18 +238,18 @@ data class Sort(val mode: Mode, val isAscending: Boolean) {
|
|||
override val itemId: Int
|
||||
get() = R.id.option_sort_artist
|
||||
|
||||
override fun getSongComparator(isAscending: Boolean): Comparator<Song> =
|
||||
override fun getSongComparator(direction: Direction): Comparator<Song> =
|
||||
MultiComparator(
|
||||
compareByDynamic(isAscending, ListComparator.ARTISTS) { it.artists },
|
||||
compareByDynamic(direction, ListComparator.ARTISTS) { it.artists },
|
||||
compareByDescending(NullableComparator.DATE_RANGE) { it.album.dates },
|
||||
compareByDescending(BasicComparator.ALBUM) { it.album },
|
||||
compareBy(NullableComparator.DISC) { it.disc },
|
||||
compareBy(NullableComparator.INT) { it.track },
|
||||
compareBy(BasicComparator.SONG))
|
||||
|
||||
override fun getAlbumComparator(isAscending: Boolean): Comparator<Album> =
|
||||
override fun getAlbumComparator(direction: Direction): Comparator<Album> =
|
||||
MultiComparator(
|
||||
compareByDynamic(isAscending, ListComparator.ARTISTS) { it.artists },
|
||||
compareByDynamic(direction, ListComparator.ARTISTS) { it.artists },
|
||||
compareByDescending(NullableComparator.DATE_RANGE) { it.dates },
|
||||
compareBy(BasicComparator.ALBUM))
|
||||
}
|
||||
|
@ -260,17 +266,17 @@ data class Sort(val mode: Mode, val isAscending: Boolean) {
|
|||
override val itemId: Int
|
||||
get() = R.id.option_sort_year
|
||||
|
||||
override fun getSongComparator(isAscending: Boolean): Comparator<Song> =
|
||||
override fun getSongComparator(direction: Direction): Comparator<Song> =
|
||||
MultiComparator(
|
||||
compareByDynamic(isAscending, NullableComparator.DATE_RANGE) { it.album.dates },
|
||||
compareByDynamic(direction, NullableComparator.DATE_RANGE) { it.album.dates },
|
||||
compareByDescending(BasicComparator.ALBUM) { it.album },
|
||||
compareBy(NullableComparator.DISC) { it.disc },
|
||||
compareBy(NullableComparator.INT) { it.track },
|
||||
compareBy(BasicComparator.SONG))
|
||||
|
||||
override fun getAlbumComparator(isAscending: Boolean): Comparator<Album> =
|
||||
override fun getAlbumComparator(direction: Direction): Comparator<Album> =
|
||||
MultiComparator(
|
||||
compareByDynamic(isAscending, NullableComparator.DATE_RANGE) { it.dates },
|
||||
compareByDynamic(direction, NullableComparator.DATE_RANGE) { it.dates },
|
||||
compareBy(BasicComparator.ALBUM))
|
||||
}
|
||||
|
||||
|
@ -282,25 +288,22 @@ data class Sort(val mode: Mode, val isAscending: Boolean) {
|
|||
override val itemId: Int
|
||||
get() = R.id.option_sort_duration
|
||||
|
||||
override fun getSongComparator(isAscending: Boolean): Comparator<Song> =
|
||||
override fun getSongComparator(direction: Direction): Comparator<Song> =
|
||||
MultiComparator(
|
||||
compareByDynamic(isAscending) { it.durationMs },
|
||||
compareBy(BasicComparator.SONG))
|
||||
compareByDynamic(direction) { it.durationMs }, compareBy(BasicComparator.SONG))
|
||||
|
||||
override fun getAlbumComparator(isAscending: Boolean): Comparator<Album> =
|
||||
override fun getAlbumComparator(direction: Direction): Comparator<Album> =
|
||||
MultiComparator(
|
||||
compareByDynamic(isAscending) { it.durationMs },
|
||||
compareBy(BasicComparator.ALBUM))
|
||||
compareByDynamic(direction) { it.durationMs }, compareBy(BasicComparator.ALBUM))
|
||||
|
||||
override fun getArtistComparator(isAscending: Boolean): Comparator<Artist> =
|
||||
override fun getArtistComparator(direction: Direction): Comparator<Artist> =
|
||||
MultiComparator(
|
||||
compareByDynamic(isAscending, NullableComparator.LONG) { it.durationMs },
|
||||
compareByDynamic(direction, NullableComparator.LONG) { it.durationMs },
|
||||
compareBy(BasicComparator.ARTIST))
|
||||
|
||||
override fun getGenreComparator(isAscending: Boolean): Comparator<Genre> =
|
||||
override fun getGenreComparator(direction: Direction): Comparator<Genre> =
|
||||
MultiComparator(
|
||||
compareByDynamic(isAscending) { it.durationMs },
|
||||
compareBy(BasicComparator.GENRE))
|
||||
compareByDynamic(direction) { it.durationMs }, compareBy(BasicComparator.GENRE))
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -314,20 +317,18 @@ data class Sort(val mode: Mode, val isAscending: Boolean) {
|
|||
override val itemId: Int
|
||||
get() = R.id.option_sort_count
|
||||
|
||||
override fun getAlbumComparator(isAscending: Boolean): Comparator<Album> =
|
||||
override fun getAlbumComparator(direction: Direction): Comparator<Album> =
|
||||
MultiComparator(
|
||||
compareByDynamic(isAscending) { it.songs.size },
|
||||
compareBy(BasicComparator.ALBUM))
|
||||
compareByDynamic(direction) { it.songs.size }, compareBy(BasicComparator.ALBUM))
|
||||
|
||||
override fun getArtistComparator(isAscending: Boolean): Comparator<Artist> =
|
||||
override fun getArtistComparator(direction: Direction): Comparator<Artist> =
|
||||
MultiComparator(
|
||||
compareByDynamic(isAscending, NullableComparator.INT) { it.songs.size },
|
||||
compareByDynamic(direction, NullableComparator.INT) { it.songs.size },
|
||||
compareBy(BasicComparator.ARTIST))
|
||||
|
||||
override fun getGenreComparator(isAscending: Boolean): Comparator<Genre> =
|
||||
override fun getGenreComparator(direction: Direction): Comparator<Genre> =
|
||||
MultiComparator(
|
||||
compareByDynamic(isAscending) { it.songs.size },
|
||||
compareBy(BasicComparator.GENRE))
|
||||
compareByDynamic(direction) { it.songs.size }, compareBy(BasicComparator.GENRE))
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -341,9 +342,9 @@ data class Sort(val mode: Mode, val isAscending: Boolean) {
|
|||
override val itemId: Int
|
||||
get() = R.id.option_sort_disc
|
||||
|
||||
override fun getSongComparator(isAscending: Boolean): Comparator<Song> =
|
||||
override fun getSongComparator(direction: Direction): Comparator<Song> =
|
||||
MultiComparator(
|
||||
compareByDynamic(isAscending, NullableComparator.DISC) { it.disc },
|
||||
compareByDynamic(direction, NullableComparator.DISC) { it.disc },
|
||||
compareBy(NullableComparator.INT) { it.track },
|
||||
compareBy(BasicComparator.SONG))
|
||||
}
|
||||
|
@ -359,10 +360,10 @@ data class Sort(val mode: Mode, val isAscending: Boolean) {
|
|||
override val itemId: Int
|
||||
get() = R.id.option_sort_track
|
||||
|
||||
override fun getSongComparator(isAscending: Boolean): Comparator<Song> =
|
||||
override fun getSongComparator(direction: Direction): Comparator<Song> =
|
||||
MultiComparator(
|
||||
compareBy(NullableComparator.DISC) { it.disc },
|
||||
compareByDynamic(isAscending, NullableComparator.INT) { it.track },
|
||||
compareByDynamic(direction, NullableComparator.INT) { it.track },
|
||||
compareBy(BasicComparator.SONG))
|
||||
}
|
||||
|
||||
|
@ -378,48 +379,47 @@ data class Sort(val mode: Mode, val isAscending: Boolean) {
|
|||
override val itemId: Int
|
||||
get() = R.id.option_sort_date_added
|
||||
|
||||
override fun getSongComparator(isAscending: Boolean): Comparator<Song> =
|
||||
override fun getSongComparator(direction: Direction): Comparator<Song> =
|
||||
MultiComparator(
|
||||
compareByDynamic(isAscending) { it.dateAdded }, compareBy(BasicComparator.SONG))
|
||||
compareByDynamic(direction) { it.dateAdded }, compareBy(BasicComparator.SONG))
|
||||
|
||||
override fun getAlbumComparator(isAscending: Boolean): Comparator<Album> =
|
||||
override fun getAlbumComparator(direction: Direction): Comparator<Album> =
|
||||
MultiComparator(
|
||||
compareByDynamic(isAscending) { album -> album.dateAdded },
|
||||
compareByDynamic(direction) { album -> album.dateAdded },
|
||||
compareBy(BasicComparator.ALBUM))
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function to create a [Comparator] in a dynamic way determined by [isAscending].
|
||||
* @param isAscending Whether to sort in ascending or descending order.
|
||||
* Utility function to create a [Comparator] in a dynamic way determined by [direction].
|
||||
* @param direction The [Direction] to sort in.
|
||||
* @see compareBy
|
||||
* @see compareByDescending
|
||||
*/
|
||||
protected inline fun <T : Music, K : Comparable<K>> compareByDynamic(
|
||||
isAscending: Boolean,
|
||||
direction: Direction,
|
||||
crossinline selector: (T) -> K
|
||||
) =
|
||||
if (isAscending) {
|
||||
compareBy(selector)
|
||||
} else {
|
||||
compareByDescending(selector)
|
||||
when (direction) {
|
||||
Direction.ASCENDING -> compareBy(selector)
|
||||
Direction.DESCENDING -> compareByDescending(selector)
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function to create a [Comparator] in a dynamic way determined by [isAscending]
|
||||
* @param isAscending Whether to sort in ascending or descending order.
|
||||
* Utility function to create a [Comparator] in a dynamic way determined by [direction]
|
||||
* @param direction The [Direction] to sort in.
|
||||
* @param comparator A [Comparator] to wrap.
|
||||
* @return A new [Comparator] with the specified configuration.
|
||||
* @see compareBy
|
||||
* @see compareByDescending
|
||||
*/
|
||||
protected fun <T : Music> compareByDynamic(
|
||||
isAscending: Boolean,
|
||||
direction: Direction,
|
||||
comparator: Comparator<in T>
|
||||
): Comparator<T> = compareByDynamic(isAscending, comparator) { it }
|
||||
): Comparator<T> = compareByDynamic(direction, comparator) { it }
|
||||
|
||||
/**
|
||||
* Utility function to create a [Comparator] a dynamic way determined by [isAscending]
|
||||
* @param isAscending Whether to sort in ascending or descending order.
|
||||
* Utility function to create a [Comparator] a dynamic way determined by [direction]
|
||||
* @param direction The [Direction] to sort in.
|
||||
* @param comparator A [Comparator] to wrap.
|
||||
* @param selector Called to obtain a specific attribute to sort by.
|
||||
* @return A new [Comparator] with the specified configuration.
|
||||
|
@ -427,14 +427,13 @@ data class Sort(val mode: Mode, val isAscending: Boolean) {
|
|||
* @see compareByDescending
|
||||
*/
|
||||
protected inline fun <T : Music, K> compareByDynamic(
|
||||
isAscending: Boolean,
|
||||
direction: Direction,
|
||||
comparator: Comparator<in K>,
|
||||
crossinline selector: (T) -> K
|
||||
) =
|
||||
if (isAscending) {
|
||||
compareBy(comparator, selector)
|
||||
} else {
|
||||
compareByDescending(comparator, selector)
|
||||
when (direction) {
|
||||
Direction.ASCENDING -> compareBy(comparator, selector)
|
||||
Direction.DESCENDING -> compareByDescending(comparator, selector)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -596,6 +595,12 @@ data class Sort(val mode: Mode, val isAscending: Boolean) {
|
|||
}
|
||||
}
|
||||
|
||||
/** The direction to sort items in. */
|
||||
enum class Direction {
|
||||
ASCENDING,
|
||||
DESCENDING
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Convert a [Sort] integer representation into an instance.
|
||||
|
@ -607,9 +612,9 @@ data class Sort(val mode: Mode, val isAscending: Boolean) {
|
|||
// Sort's integer representation is formatted as AMMMM, where A is a bitflag
|
||||
// representing on if the mode is ascending or descending, and M is the integer
|
||||
// representation of the sort mode.
|
||||
val isAscending = (intCode and 1) == 1
|
||||
val direction = if ((intCode and 1) == 1) Direction.ASCENDING else Direction.DESCENDING
|
||||
val mode = Mode.fromIntCode(intCode.shr(1)) ?: return null
|
||||
return Sort(mode, isAscending)
|
||||
return Sort(mode, direction)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,7 +21,7 @@ import android.content.Context
|
|||
import android.os.storage.StorageManager
|
||||
import androidx.core.content.edit
|
||||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.music.library.Sort
|
||||
import org.oxycblt.auxio.list.Sort
|
||||
import org.oxycblt.auxio.music.storage.Directory
|
||||
import org.oxycblt.auxio.music.storage.MusicDirectories
|
||||
import org.oxycblt.auxio.settings.Settings
|
||||
|
@ -116,7 +116,7 @@ private class RealMusicSettings(context: Context) :
|
|||
get() =
|
||||
Sort.fromIntCode(
|
||||
sharedPreferences.getInt(getString(R.string.set_key_songs_sort), Int.MIN_VALUE))
|
||||
?: Sort(Sort.Mode.ByName, true)
|
||||
?: Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING)
|
||||
set(value) {
|
||||
sharedPreferences.edit {
|
||||
putInt(getString(R.string.set_key_songs_sort), value.intCode)
|
||||
|
@ -128,7 +128,7 @@ private class RealMusicSettings(context: Context) :
|
|||
get() =
|
||||
Sort.fromIntCode(
|
||||
sharedPreferences.getInt(getString(R.string.set_key_albums_sort), Int.MIN_VALUE))
|
||||
?: Sort(Sort.Mode.ByName, true)
|
||||
?: Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING)
|
||||
set(value) {
|
||||
sharedPreferences.edit {
|
||||
putInt(getString(R.string.set_key_albums_sort), value.intCode)
|
||||
|
@ -140,7 +140,7 @@ private class RealMusicSettings(context: Context) :
|
|||
get() =
|
||||
Sort.fromIntCode(
|
||||
sharedPreferences.getInt(getString(R.string.set_key_artists_sort), Int.MIN_VALUE))
|
||||
?: Sort(Sort.Mode.ByName, true)
|
||||
?: Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING)
|
||||
set(value) {
|
||||
sharedPreferences.edit {
|
||||
putInt(getString(R.string.set_key_artists_sort), value.intCode)
|
||||
|
@ -152,7 +152,7 @@ private class RealMusicSettings(context: Context) :
|
|||
get() =
|
||||
Sort.fromIntCode(
|
||||
sharedPreferences.getInt(getString(R.string.set_key_genres_sort), Int.MIN_VALUE))
|
||||
?: Sort(Sort.Mode.ByName, true)
|
||||
?: Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING)
|
||||
set(value) {
|
||||
sharedPreferences.edit {
|
||||
putInt(getString(R.string.set_key_genres_sort), value.intCode)
|
||||
|
@ -166,7 +166,7 @@ private class RealMusicSettings(context: Context) :
|
|||
Sort.fromIntCode(
|
||||
sharedPreferences.getInt(
|
||||
getString(R.string.set_key_album_songs_sort), Int.MIN_VALUE))
|
||||
?: Sort(Sort.Mode.ByDisc, true)
|
||||
?: Sort(Sort.Mode.ByDisc, Sort.Direction.ASCENDING)
|
||||
|
||||
// Correct legacy album sort modes to Disc
|
||||
if (sort.mode is Sort.Mode.ByName) {
|
||||
|
@ -187,7 +187,7 @@ private class RealMusicSettings(context: Context) :
|
|||
Sort.fromIntCode(
|
||||
sharedPreferences.getInt(
|
||||
getString(R.string.set_key_artist_songs_sort), Int.MIN_VALUE))
|
||||
?: Sort(Sort.Mode.ByDate, false)
|
||||
?: Sort(Sort.Mode.ByDate, Sort.Direction.DESCENDING)
|
||||
set(value) {
|
||||
sharedPreferences.edit {
|
||||
putInt(getString(R.string.set_key_artist_songs_sort), value.intCode)
|
||||
|
@ -200,7 +200,7 @@ private class RealMusicSettings(context: Context) :
|
|||
Sort.fromIntCode(
|
||||
sharedPreferences.getInt(
|
||||
getString(R.string.set_key_genre_songs_sort), Int.MIN_VALUE))
|
||||
?: Sort(Sort.Mode.ByName, true)
|
||||
?: Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING)
|
||||
set(value) {
|
||||
sharedPreferences.edit {
|
||||
putInt(getString(R.string.set_key_genre_songs_sort), value.intCode)
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.oxycblt.auxio.music.library
|
|||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.provider.OpenableColumns
|
||||
import org.oxycblt.auxio.list.Sort
|
||||
import org.oxycblt.auxio.music.*
|
||||
import org.oxycblt.auxio.music.storage.contentResolverSafe
|
||||
import org.oxycblt.auxio.music.storage.useQuery
|
||||
|
@ -76,7 +77,7 @@ interface Library {
|
|||
|
||||
companion object {
|
||||
/**
|
||||
* Create a library-backed instance of [Library].
|
||||
* Create an instance of [Library].
|
||||
* @param rawSongs [RawSong]s to create the library out of.
|
||||
* @param settings [MusicSettings] required.
|
||||
*/
|
||||
|
@ -93,10 +94,10 @@ private class RealLibrary(rawSongs: List<RawSong>, settings: MusicSettings) : Li
|
|||
|
||||
// Use a mapping to make finding information based on it's UID much faster.
|
||||
private val uidMap = buildMap {
|
||||
songs.forEach { this[it.uid] = it.finalize() }
|
||||
albums.forEach { this[it.uid] = it.finalize() }
|
||||
artists.forEach { this[it.uid] = it.finalize() }
|
||||
genres.forEach { this[it.uid] = it.finalize() }
|
||||
songs.forEach { put(it.uid, it.finalize()) }
|
||||
albums.forEach { put(it.uid, it.finalize()) }
|
||||
artists.forEach { put(it.uid, it.finalize()) }
|
||||
genres.forEach { put(it.uid, it.finalize()) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -131,7 +132,8 @@ private class RealLibrary(rawSongs: List<RawSong>, settings: MusicSettings) : Li
|
|||
* grouping.
|
||||
*/
|
||||
private fun buildSongs(rawSongs: List<RawSong>, settings: MusicSettings) =
|
||||
Sort(Sort.Mode.ByName, true).songs(rawSongs.map { RealSong(it, settings) }.distinct())
|
||||
Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING)
|
||||
.songs(rawSongs.map { RealSong(it, settings) }.distinct())
|
||||
|
||||
/**
|
||||
* Build a list of [Album]s from the given [Song]s.
|
||||
|
|
|
@ -24,6 +24,7 @@ import java.text.CollationKey
|
|||
import java.text.Collator
|
||||
import kotlin.math.max
|
||||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.list.Sort
|
||||
import org.oxycblt.auxio.music.Album
|
||||
import org.oxycblt.auxio.music.Artist
|
||||
import org.oxycblt.auxio.music.Genre
|
||||
|
@ -418,7 +419,7 @@ class RealArtist(private val rawArtist: RawArtist, songAlbums: List<Music>) : Ar
|
|||
fun finalize(): Artist {
|
||||
check(songs.isNotEmpty() || albums.isNotEmpty()) { "Malformed artist: Empty" }
|
||||
genres =
|
||||
Sort(Sort.Mode.ByName, true)
|
||||
Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING)
|
||||
.genres(songs.flatMapTo(mutableSetOf()) { it.genres })
|
||||
.sortedByDescending { genre -> songs.count { it.genres.contains(genre) } }
|
||||
return this
|
||||
|
@ -458,10 +459,10 @@ class RealGenre(private val rawGenre: RawGenre, override val songs: List<RealSon
|
|||
}
|
||||
|
||||
albums =
|
||||
Sort(Sort.Mode.ByName, true).albums(distinctAlbums).sortedByDescending { album ->
|
||||
album.songs.count { it.genres.contains(this) }
|
||||
}
|
||||
artists = Sort(Sort.Mode.ByName, true).artists(distinctArtists)
|
||||
Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING)
|
||||
.albums(distinctAlbums)
|
||||
.sortedByDescending { album -> album.songs.count { it.genres.contains(this) } }
|
||||
artists = Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING).artists(distinctArtists)
|
||||
durationMs = totalDuration
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ import org.oxycblt.auxio.list.BasicHeader
|
|||
import org.oxycblt.auxio.list.Item
|
||||
import org.oxycblt.auxio.music.*
|
||||
import org.oxycblt.auxio.music.library.Library
|
||||
import org.oxycblt.auxio.music.library.Sort
|
||||
import org.oxycblt.auxio.list.Sort
|
||||
import org.oxycblt.auxio.playback.PlaybackSettings
|
||||
import org.oxycblt.auxio.util.logD
|
||||
|
||||
|
@ -176,6 +176,6 @@ constructor(
|
|||
}
|
||||
|
||||
private companion object {
|
||||
val SORT = Sort(Sort.Mode.ByName, true)
|
||||
val SORT = Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<group android:checkableBehavior="single">
|
||||
<group android:checkableBehavior="single"
|
||||
android:id="@+id/sort_modes">
|
||||
<item
|
||||
android:id="@+id/option_sort_disc"
|
||||
android:title="@string/lbl_sort_disc" />
|
||||
|
@ -8,9 +9,13 @@
|
|||
android:id="@+id/option_sort_track"
|
||||
android:title="@string/lbl_sort_track" />
|
||||
</group>
|
||||
<group android:checkableBehavior="all">
|
||||
<group android:checkableBehavior="single"
|
||||
android:id="@+id/sort_direction">
|
||||
<item
|
||||
android:id="@+id/option_sort_asc"
|
||||
android:title="@string/lbl_sort_asc" />
|
||||
<item
|
||||
android:id="@+id/option_sort_dec"
|
||||
android:title="@string/lbl_sort_dec" />
|
||||
</group>
|
||||
</menu>
|
|
@ -1,6 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<group android:checkableBehavior="single">
|
||||
<group android:checkableBehavior="single"
|
||||
android:id="@+id/sort_modes">
|
||||
<item
|
||||
android:id="@+id/option_sort_name"
|
||||
android:title="@string/lbl_sort_name" />
|
||||
|
@ -14,9 +15,13 @@
|
|||
android:id="@+id/option_sort_duration"
|
||||
android:title="@string/lbl_sort_duration" />
|
||||
</group>
|
||||
<group android:checkableBehavior="all">
|
||||
<group android:checkableBehavior="single"
|
||||
android:id="@+id/sort_direction">
|
||||
<item
|
||||
android:id="@+id/option_sort_asc"
|
||||
android:title="@string/lbl_sort_asc" />
|
||||
<item
|
||||
android:id="@+id/option_sort_dec"
|
||||
android:title="@string/lbl_sort_dec" />
|
||||
</group>
|
||||
</menu>
|
|
@ -1,6 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<group android:checkableBehavior="single">
|
||||
<group android:checkableBehavior="single"
|
||||
android:id="@+id/sort_modes">
|
||||
<item
|
||||
android:id="@+id/option_sort_name"
|
||||
android:title="@string/lbl_sort_name" />
|
||||
|
@ -17,9 +18,13 @@
|
|||
android:id="@+id/option_sort_duration"
|
||||
android:title="@string/lbl_sort_duration" />
|
||||
</group>
|
||||
<group android:checkableBehavior="all">
|
||||
<group android:checkableBehavior="single"
|
||||
android:id="@+id/sort_direction">
|
||||
<item
|
||||
android:id="@+id/option_sort_asc"
|
||||
android:title="@string/lbl_sort_asc" />
|
||||
<item
|
||||
android:id="@+id/option_sort_dec"
|
||||
android:title="@string/lbl_sort_dec" />
|
||||
</group>
|
||||
</menu>
|
|
@ -14,7 +14,8 @@
|
|||
android:title="@string/lbl_sort"
|
||||
app:showAsAction="ifRoom">
|
||||
<menu>
|
||||
<group android:checkableBehavior="single">
|
||||
<group android:checkableBehavior="single"
|
||||
android:id="@+id/sort_modes">
|
||||
<item
|
||||
android:id="@+id/option_sort_name"
|
||||
android:title="@string/lbl_sort_name" />
|
||||
|
@ -37,10 +38,14 @@
|
|||
android:id="@+id/option_sort_date_added"
|
||||
android:title="@string/lbl_sort_date_added" />
|
||||
</group>
|
||||
<group android:checkableBehavior="all">
|
||||
<group android:checkableBehavior="single"
|
||||
android:id="@+id/sort_direction">
|
||||
<item
|
||||
android:id="@+id/option_sort_asc"
|
||||
android:title="@string/lbl_sort_asc" />
|
||||
<item
|
||||
android:id="@+id/option_sort_dec"
|
||||
android:title="@string/lbl_sort_dec" />
|
||||
</group>
|
||||
</menu>
|
||||
</item>
|
||||
|
|
|
@ -92,6 +92,7 @@
|
|||
<string name="lbl_sort_track">Track</string>
|
||||
<string name="lbl_sort_date_added">Date added</string>
|
||||
<string name="lbl_sort_asc">Ascending</string>
|
||||
<string name="lbl_sort_dec">Descending</string>
|
||||
|
||||
<string name="lbl_playback">Now playing</string>
|
||||
<string name="lbl_equalizer">Equalizer</string>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
package org.oxycblt.auxio.music
|
||||
|
||||
import org.oxycblt.auxio.music.library.Sort
|
||||
import org.oxycblt.auxio.list.Sort
|
||||
import org.oxycblt.auxio.music.storage.MusicDirectories
|
||||
|
||||
interface FakeMusicSettings : MusicSettings {
|
||||
|
|
Loading…
Reference in a new issue