music: improve sorting
Update sorting usage in-app so that it's only done when absolutely necessary.
This commit is contained in:
parent
c2def19aee
commit
b037cfb166
8 changed files with 35 additions and 39 deletions
|
@ -11,8 +11,10 @@
|
||||||
"appears on" section in the artist view
|
"appears on" section in the artist view
|
||||||
|
|
||||||
#### What's Fixed
|
#### What's Fixed
|
||||||
- Prevented options such as "Add to queue" from being selected on empty
|
- Prevented options such as "Add to queue" from being selected on empty artists and playlists
|
||||||
artists and playlists
|
- Fixed issue where an item would be indicated as "playing" after playback ended
|
||||||
|
- Items should no longer be indicated as playing if the currently playing song is not contained
|
||||||
|
within it
|
||||||
|
|
||||||
## 3.1.0
|
## 3.1.0
|
||||||
|
|
||||||
|
|
|
@ -430,27 +430,25 @@ constructor(
|
||||||
val list = mutableListOf<Item>()
|
val list = mutableListOf<Item>()
|
||||||
|
|
||||||
val grouping =
|
val grouping =
|
||||||
Sort(Sort.Mode.ByDate, Sort.Direction.DESCENDING)
|
artist.explicitAlbums.groupByTo(sortedMapOf()) {
|
||||||
.albums(artist.explicitAlbums)
|
// Remap the complicated ReleaseType data structure into an easier
|
||||||
.groupByTo(sortedMapOf()) {
|
// "AlbumGrouping" enum that will automatically group and sort
|
||||||
// Remap the complicated ReleaseType data structure into an easier
|
// the artist's albums.
|
||||||
// "AlbumGrouping" enum that will automatically group and sort
|
when (it.releaseType.refinement) {
|
||||||
// the artist's albums.
|
ReleaseType.Refinement.LIVE -> AlbumGrouping.LIVE
|
||||||
when (it.releaseType.refinement) {
|
ReleaseType.Refinement.REMIX -> AlbumGrouping.REMIXES
|
||||||
ReleaseType.Refinement.LIVE -> AlbumGrouping.LIVE
|
null ->
|
||||||
ReleaseType.Refinement.REMIX -> AlbumGrouping.REMIXES
|
when (it.releaseType) {
|
||||||
null ->
|
is ReleaseType.Album -> AlbumGrouping.ALBUMS
|
||||||
when (it.releaseType) {
|
is ReleaseType.EP -> AlbumGrouping.EPS
|
||||||
is ReleaseType.Album -> AlbumGrouping.ALBUMS
|
is ReleaseType.Single -> AlbumGrouping.SINGLES
|
||||||
is ReleaseType.EP -> AlbumGrouping.EPS
|
is ReleaseType.Compilation -> AlbumGrouping.COMPILATIONS
|
||||||
is ReleaseType.Single -> AlbumGrouping.SINGLES
|
is ReleaseType.Soundtrack -> AlbumGrouping.SOUNDTRACKS
|
||||||
is ReleaseType.Compilation -> AlbumGrouping.COMPILATIONS
|
is ReleaseType.Mix -> AlbumGrouping.DJMIXES
|
||||||
is ReleaseType.Soundtrack -> AlbumGrouping.SOUNDTRACKS
|
is ReleaseType.Mixtape -> AlbumGrouping.MIXTAPES
|
||||||
is ReleaseType.Mix -> AlbumGrouping.DJMIXES
|
}
|
||||||
is ReleaseType.Mixtape -> AlbumGrouping.MIXTAPES
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (artist.implicitAlbums.isNotEmpty()) {
|
if (artist.implicitAlbums.isNotEmpty()) {
|
||||||
// groupByTo normally returns a mapping to a MutableList mapping. Since MutableList
|
// groupByTo normally returns a mapping to a MutableList mapping. Since MutableList
|
||||||
|
@ -458,7 +456,7 @@ constructor(
|
||||||
// implicit album list into the mapping.
|
// implicit album list into the mapping.
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
(grouping as MutableMap<AlbumGrouping, List<Album>>)[AlbumGrouping.APPEARANCES] =
|
(grouping as MutableMap<AlbumGrouping, List<Album>>)[AlbumGrouping.APPEARANCES] =
|
||||||
Sort(Sort.Mode.ByDate, Sort.Direction.DESCENDING).albums(artist.implicitAlbums)
|
artist.implicitAlbums
|
||||||
}
|
}
|
||||||
|
|
||||||
logD("Release groups for this artist: ${grouping.keys}")
|
logD("Release groups for this artist: ${grouping.keys}")
|
||||||
|
|
|
@ -29,6 +29,7 @@ import org.oxycblt.auxio.music.resolveNames
|
||||||
import org.oxycblt.auxio.util.context
|
import org.oxycblt.auxio.util.context
|
||||||
import org.oxycblt.auxio.util.getPlural
|
import org.oxycblt.auxio.util.getPlural
|
||||||
import org.oxycblt.auxio.util.inflater
|
import org.oxycblt.auxio.util.inflater
|
||||||
|
import org.oxycblt.auxio.util.logD
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A [DetailHeaderAdapter] that shows [Artist] information.
|
* A [DetailHeaderAdapter] that shows [Artist] information.
|
||||||
|
@ -91,6 +92,7 @@ private constructor(private val binding: ItemDetailHeaderBinding) :
|
||||||
// The artist does not have any songs, so hide functionality that makes no sense.
|
// The artist does not have any songs, so hide functionality that makes no sense.
|
||||||
// ex. Play and Shuffle, Song Counts, and Genre Information.
|
// ex. Play and Shuffle, Song Counts, and Genre Information.
|
||||||
// Artists are always guaranteed to have albums however, so continue to show those.
|
// Artists are always guaranteed to have albums however, so continue to show those.
|
||||||
|
logD("Artist is empty, disabling genres and playback")
|
||||||
binding.detailSubhead.isVisible = false
|
binding.detailSubhead.isVisible = false
|
||||||
binding.detailPlayButton.isEnabled = false
|
binding.detailPlayButton.isEnabled = false
|
||||||
binding.detailShuffleButton.isEnabled = false
|
binding.detailShuffleButton.isEnabled = false
|
||||||
|
|
|
@ -83,7 +83,6 @@ private constructor(private val binding: ItemDetailHeaderBinding) :
|
||||||
editedPlaylist: List<Song>?,
|
editedPlaylist: List<Song>?,
|
||||||
listener: DetailHeaderAdapter.Listener
|
listener: DetailHeaderAdapter.Listener
|
||||||
) {
|
) {
|
||||||
// TODO: Debug perpetually re-binding images
|
|
||||||
binding.detailCover.bind(playlist, editedPlaylist)
|
binding.detailCover.bind(playlist, editedPlaylist)
|
||||||
binding.detailType.text = binding.context.getString(R.string.lbl_playlist)
|
binding.detailType.text = binding.context.getString(R.string.lbl_playlist)
|
||||||
binding.detailName.text = playlist.name.resolve(binding.context)
|
binding.detailName.text = playlist.name.resolve(binding.context)
|
||||||
|
|
|
@ -50,6 +50,7 @@ import okio.buffer
|
||||||
import okio.source
|
import okio.source
|
||||||
import org.oxycblt.auxio.image.CoverMode
|
import org.oxycblt.auxio.image.CoverMode
|
||||||
import org.oxycblt.auxio.image.ImageSettings
|
import org.oxycblt.auxio.image.ImageSettings
|
||||||
|
import org.oxycblt.auxio.list.Sort
|
||||||
import org.oxycblt.auxio.music.Album
|
import org.oxycblt.auxio.music.Album
|
||||||
import org.oxycblt.auxio.music.Song
|
import org.oxycblt.auxio.music.Song
|
||||||
import org.oxycblt.auxio.util.logD
|
import org.oxycblt.auxio.util.logD
|
||||||
|
@ -81,7 +82,12 @@ constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun computeAlbumOrdering(songs: List<Song>) =
|
fun computeAlbumOrdering(songs: List<Song>) =
|
||||||
songs.groupBy { it.album }.entries.sortedByDescending { it.value.size }.map { it.key }
|
Sort(Sort.Mode.ByAlbum, Sort.Direction.ASCENDING)
|
||||||
|
.songs(songs)
|
||||||
|
.groupBy { it.album }
|
||||||
|
.entries
|
||||||
|
.sortedByDescending { it.value.size }
|
||||||
|
.map { it.key }
|
||||||
|
|
||||||
private suspend fun openInputStream(album: Album): InputStream? =
|
private suspend fun openInputStream(album: Album): InputStream? =
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -341,8 +341,6 @@ interface Artist : MusicParent {
|
||||||
* @author Alexander Capehart (OxygenCobalt)
|
* @author Alexander Capehart (OxygenCobalt)
|
||||||
*/
|
*/
|
||||||
interface Genre : MusicParent {
|
interface Genre : MusicParent {
|
||||||
/** The albums indirectly linked to by the [Song]s of this [Genre]. */
|
|
||||||
val albums: List<Album>
|
|
||||||
/** The artists indirectly linked to by the [Artist]s of this [Genre]. */
|
/** The artists indirectly linked to by the [Artist]s of this [Genre]. */
|
||||||
val artists: List<Artist>
|
val artists: List<Artist>
|
||||||
/** The total duration of the songs in this genre, in milliseconds. */
|
/** The total duration of the songs in this genre, in milliseconds. */
|
||||||
|
@ -355,8 +353,6 @@ interface Genre : MusicParent {
|
||||||
* @author Alexander Capehart (OxygenCobalt)
|
* @author Alexander Capehart (OxygenCobalt)
|
||||||
*/
|
*/
|
||||||
interface Playlist : MusicParent {
|
interface Playlist : MusicParent {
|
||||||
/** The albums indirectly linked to by the [Song]s of this [Playlist]. */
|
|
||||||
val albums: List<Album>
|
|
||||||
/** The total duration of the songs in this genre, in milliseconds. */
|
/** The total duration of the songs in this genre, in milliseconds. */
|
||||||
val durationMs: Long
|
val durationMs: Long
|
||||||
}
|
}
|
||||||
|
|
|
@ -387,9 +387,9 @@ class ArtistImpl(
|
||||||
}
|
}
|
||||||
|
|
||||||
songs = distinctSongs.toList()
|
songs = distinctSongs.toList()
|
||||||
albums = albumMap.keys.toList()
|
albums = Sort(Sort.Mode.ByDate, Sort.Direction.DESCENDING).albums(albumMap.keys)
|
||||||
explicitAlbums = albumMap.entries.filter { it.value }.map { it.key }
|
explicitAlbums = albums.filter { unlikelyToBeNull(albumMap[it]) }
|
||||||
implicitAlbums = albumMap.entries.filterNot { it.value }.map { it.key }
|
implicitAlbums = albums.filterNot { unlikelyToBeNull(albumMap[it]) }
|
||||||
durationMs = songs.sumOf { it.durationMs }.nonZeroOrNull()
|
durationMs = songs.sumOf { it.durationMs }.nonZeroOrNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -436,7 +436,6 @@ class GenreImpl(
|
||||||
rawGenre.name?.let { Name.Known.from(it, rawGenre.name, musicSettings) }
|
rawGenre.name?.let { Name.Known.from(it, rawGenre.name, musicSettings) }
|
||||||
?: Name.Unknown(R.string.def_genre)
|
?: Name.Unknown(R.string.def_genre)
|
||||||
|
|
||||||
override val albums: List<Album>
|
|
||||||
override val artists: List<Artist>
|
override val artists: List<Artist>
|
||||||
override val durationMs: Long
|
override val durationMs: Long
|
||||||
|
|
||||||
|
@ -462,10 +461,6 @@ class GenreImpl(
|
||||||
totalDuration += song.durationMs
|
totalDuration += song.durationMs
|
||||||
}
|
}
|
||||||
|
|
||||||
albums =
|
|
||||||
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)
|
artists = Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING).artists(distinctArtists)
|
||||||
durationMs = totalDuration
|
durationMs = totalDuration
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,8 +33,6 @@ private constructor(
|
||||||
override val songs: List<Song>
|
override val songs: List<Song>
|
||||||
) : Playlist {
|
) : Playlist {
|
||||||
override val durationMs = songs.sumOf { it.durationMs }
|
override val durationMs = songs.sumOf { it.durationMs }
|
||||||
override val albums =
|
|
||||||
songs.groupBy { it.album }.entries.sortedByDescending { it.value.size }.map { it.key }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clone the data in this instance to a new [PlaylistImpl] with the given [name].
|
* Clone the data in this instance to a new [PlaylistImpl] with the given [name].
|
||||||
|
|
Loading…
Reference in a new issue