diff --git a/CHANGELOG.md b/CHANGELOG.md
index 27f6edc84..aa4645cab 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,11 @@
- Music loader no longer spawns thousands of threads when scanning
- Excessive CPU no longer spent showing music loading process
+## 3.5.1
+
+#### What's Fixed
+- Fixed music loading failure from improper sort systems
+
## 3.5.0
#### What's New
diff --git a/README.md b/README.md
index f5bd807ad..add156e6e 100644
--- a/README.md
+++ b/README.md
@@ -2,8 +2,8 @@
Auxio
A simple, rational music player for android.
-
-
+
+
diff --git a/app/build.gradle b/app/build.gradle
index b6bcca099..54ce9e917 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -21,8 +21,8 @@ android {
defaultConfig {
applicationId namespace
- versionName "3.5.0"
- versionCode 46
+ versionName "3.5.1"
+ versionCode 47
minSdk 24
targetSdk 34
diff --git a/app/src/main/java/org/oxycblt/auxio/list/sort/Sort.kt b/app/src/main/java/org/oxycblt/auxio/list/sort/Sort.kt
index 0f9fd3cb0..78e5d4388 100644
--- a/app/src/main/java/org/oxycblt/auxio/list/sort/Sort.kt
+++ b/app/src/main/java/org/oxycblt/auxio/list/sort/Sort.kt
@@ -20,17 +20,11 @@ package org.oxycblt.auxio.list.sort
import org.oxycblt.auxio.IntegerTable
import org.oxycblt.auxio.R
-import org.oxycblt.auxio.list.sort.Sort.Direction
-import org.oxycblt.auxio.list.sort.Sort.Mode
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre
-import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.Playlist
import org.oxycblt.auxio.music.Song
-import org.oxycblt.auxio.music.info.Date
-import org.oxycblt.auxio.music.info.Disc
-import kotlin.math.max
/**
* A sorting method.
@@ -48,9 +42,9 @@ data class Sort(val mode: Mode, val direction: Direction) {
* @param songs The list of [Song]s.
* @return A new list of [Song]s sorted by this [Sort]'s configuration.
*/
- fun songs(songs: Collection): List {
+ fun songs(songs: Collection): List {
val mutable = songs.toMutableList()
- songsInPlace(mutable)
+ mode.sortSongs(mutable, direction)
return mutable
}
@@ -60,9 +54,9 @@ data class Sort(val mode: Mode, val direction: Direction) {
* @param albums The list of [Album]s.
* @return A new list of [Album]s sorted by this [Sort]'s configuration.
*/
- fun albums(albums: Collection): List {
+ fun albums(albums: Collection): List {
val mutable = albums.toMutableList()
- albumsInPlace(mutable)
+ mode.sortAlbums(mutable, direction)
return mutable
}
@@ -72,9 +66,9 @@ data class Sort(val mode: Mode, val direction: Direction) {
* @param artists The list of [Artist]s.
* @return A new list of [Artist]s sorted by this [Sort]'s configuration.
*/
- fun artists(artists: Collection): List {
+ fun artists(artists: Collection): List {
val mutable = artists.toMutableList()
- artistsInPlace(mutable)
+ mode.sortArtists(mutable, direction)
return mutable
}
@@ -84,9 +78,9 @@ data class Sort(val mode: Mode, val direction: Direction) {
* @param genres The list of [Genre]s.
* @return A new list of [Genre]s sorted by this [Sort]'s configuration.
*/
- fun genres(genres: Collection): List {
+ fun genres(genres: Collection): List {
val mutable = genres.toMutableList()
- genresInPlace(mutable)
+ mode.sortGenres(mutable, direction)
return mutable
}
@@ -96,37 +90,12 @@ data class Sort(val mode: Mode, val direction: Direction) {
* @param playlists The list of [Playlist]s.
* @return A new list of [Playlist]s sorted by this [Sort]'s configuration
*/
- fun playlists(playlists: Collection): List {
+ fun playlists(playlists: Collection): List {
val mutable = playlists.toMutableList()
- playlistsInPlace(mutable)
+ mode.sortPlaylists(mutable, direction)
return mutable
}
- private fun songsInPlace(songs: MutableList) {
- val comparator = mode.getSongComparator(direction) ?: return
- songs.sortWith(comparator)
- }
-
- private fun albumsInPlace(albums: MutableList) {
- val comparator = mode.getAlbumComparator(direction) ?: return
- albums.sortWith(comparator)
- }
-
- private fun artistsInPlace(artists: MutableList) {
- val comparator = mode.getArtistComparator(direction) ?: return
- artists.sortWith(comparator)
- }
-
- private fun genresInPlace(genres: MutableList) {
- val comparator = mode.getGenreComparator(direction) ?: return
- genres.sortWith(comparator)
- }
-
- private fun playlistsInPlace(playlists: MutableList) {
- val comparator = mode.getPlaylistComparator(direction) ?: return
- playlists.sortWith(comparator)
- }
-
/**
* The integer representation of this instance.
*
@@ -143,289 +112,270 @@ data class Sort(val mode: Mode, val direction: Direction) {
Direction.DESCENDING -> 0
}
- /** Describes the type of data to sort with. */
sealed interface Mode {
- /** The integer representation of this sort mode. */
val intCode: Int
- /** The string resource of the human-readable name of this sort mode. */
val stringRes: Int
- /**
- * Get a [Comparator] that sorts [Song]s according to this [Mode].
- *
- * @param direction The direction to sort in.
- * @return A [Comparator] that can be used to sort a [Song] list according to this [Mode],
- * or null to not sort at all.
- */
- fun getSongComparator(direction: Direction): Comparator? = null
+ fun sortSongs(songs: MutableList, direction: Direction) {
+ throw NotImplementedError("Sorting songs is not supported for this mode")
+ }
- /**
- * Get a [Comparator] that sorts [Album]s according to this [Mode].
- *
- * @param direction The direction to sort in.
- * @return A [Comparator] that can be used to sort a [Album] list according to this [Mode],
- * or null to not sort at all.
- */
- fun getAlbumComparator(direction: Direction): Comparator? = null
+ fun sortAlbums(albums: MutableList, direction: Direction) {
+ throw NotImplementedError("Sorting albums is not supported for this mode")
+ }
- /**
- * Return a [Comparator] that sorts [Artist]s according to this [Mode].
- *
- * @param direction The direction to sort in.
- * @return A [Comparator] that can be used to sort a [Artist] list according to this [Mode].
- * or null to not sort at all.
- */
- fun getArtistComparator(direction: Direction): Comparator? = null
+ fun sortArtists(artists: MutableList, direction: Direction) {
+ throw NotImplementedError("Sorting artists is not supported for this mode")
+ }
- /**
- * Return a [Comparator] that sorts [Genre]s according to this [Mode].
- *
- * @param direction The direction to sort in.
- * @return A [Comparator] that can be used to sort a [Genre] list according to this [Mode].
- * or null to not sort at all.
- */
- fun getGenreComparator(direction: Direction): Comparator? = null
+ fun sortGenres(genres: MutableList, direction: Direction) {
+ throw NotImplementedError("Sorting genres is not supported for this mode")
+ }
- /**
- * Return a [Comparator] that sorts [Playlist]s according to this [Mode].
- *
- * @param direction The direction to sort in.
- * @return A [Comparator] that can be used to sort a [Genre] list according to this [Mode].
- * or null to not sort at all.
- */
- fun getPlaylistComparator(direction: Direction): Comparator? = null
+ fun sortPlaylists(playlists: MutableList, direction: Direction) {
+ throw NotImplementedError("Sorting playlists is not supported for this mode")
+ }
- /**
- * Sort by the item's name.
- *
- * @see Music.name
- */
data object ByName : Mode {
- override val intCode: Int
- get() = IntegerTable.SORT_BY_NAME
+ override val intCode = IntegerTable.SORT_BY_NAME
+ override val stringRes = R.string.lbl_name
- override val stringRes: Int
- get() = R.string.lbl_name
+ override fun sortSongs(songs: MutableList, direction: Direction) {
+ when (direction) {
+ Direction.ASCENDING -> songs.sortBy { it.name }
+ Direction.DESCENDING -> songs.sortByDescending { it.name }
+ }
+ }
- override fun getSongComparator(direction: Direction) =
- compareByDynamic(direction, BasicComparator.SONG)
+ override fun sortAlbums(albums: MutableList, direction: Direction) {
+ when (direction) {
+ Direction.ASCENDING -> albums.sortBy { it.name }
+ Direction.DESCENDING -> albums.sortByDescending { it.name }
+ }
+ }
- override fun getAlbumComparator(direction: Direction) =
- compareByDynamic(direction, BasicComparator.ALBUM)
+ override fun sortArtists(artists: MutableList, direction: Direction) {
+ when (direction) {
+ Direction.ASCENDING -> artists.sortBy { it.name }
+ Direction.DESCENDING -> artists.sortByDescending { it.name }
+ }
+ }
- override fun getArtistComparator(direction: Direction) =
- compareByDynamic(direction, BasicComparator.ARTIST)
+ override fun sortGenres(genres: MutableList, direction: Direction) {
+ when (direction) {
+ Direction.ASCENDING -> genres.sortBy { it.name }
+ Direction.DESCENDING -> genres.sortByDescending { it.name }
+ }
+ }
- override fun getGenreComparator(direction: Direction) =
- compareByDynamic(direction, BasicComparator.GENRE)
-
- override fun getPlaylistComparator(direction: Direction) =
- compareByDynamic(direction, BasicComparator.PLAYLIST)
+ override fun sortPlaylists(playlists: MutableList, direction: Direction) {
+ when (direction) {
+ Direction.ASCENDING -> playlists.sortBy { it.name }
+ Direction.DESCENDING -> playlists.sortByDescending { it.name }
+ }
+ }
}
- /**
- * Sort by the [Album] of an item. Only available for [Song]s.
- *
- * @see Album.name
- */
data object ByAlbum : Mode {
- override val intCode: Int
- get() = IntegerTable.SORT_BY_ALBUM
+ override val intCode = IntegerTable.SORT_BY_ALBUM
+ override val stringRes = R.string.lbl_album
- override val stringRes: Int
- get() = R.string.lbl_album
-
- override fun getSongComparator(direction: Direction): Comparator =
- MultiComparator(
- compareByDynamic(direction, BasicComparator.ALBUM) { it.album },
- compareBy(NullableComparator.DISC) { it.disc },
- compareBy(NullableComparator.INT) { it.track },
- compareBy(BasicComparator.SONG))
+ override fun sortSongs(songs: MutableList, direction: Direction) {
+ songs.sortBy { it.name }
+ songs.sortBy { it.track }
+ songs.sortBy { it.disc }
+ when (direction) {
+ Direction.ASCENDING -> songs.sortBy { it.album.name }
+ Direction.DESCENDING -> songs.sortByDescending { it.album.name }
+ }
+ }
}
- /**
- * Sort by the [Artist] name of an item. Only available for [Song] and [Album].
- *
- * @see Artist.name
- */
data object ByArtist : Mode {
- override val intCode: Int
- get() = IntegerTable.SORT_BY_ARTIST
+ override val intCode = IntegerTable.SORT_BY_ARTIST
+ override val stringRes = R.string.lbl_artist
- override val stringRes: Int
- get() = R.string.lbl_artist
+ override fun sortSongs(songs: MutableList, direction: Direction) {
+ songs.sortBy { it.name }
+ songs.sortBy { it.track }
+ songs.sortBy { it.disc }
+ songs.sortBy { it.album.name }
+ songs.sortByDescending { it.album.dates }
+ when (direction) {
+ Direction.ASCENDING -> songs.sortBy { it.artists.firstOrNull()?.name }
+ Direction.DESCENDING ->
+ songs.sortByDescending { it.artists.firstOrNull()?.name }
+ }
+ }
- override fun getSongComparator(direction: Direction): Comparator =
- MultiComparator(
- 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(direction: Direction): Comparator =
- MultiComparator(
- compareByDynamic(direction, ListComparator.ARTISTS) { it.artists },
- compareByDescending(NullableComparator.DATE_RANGE) { it.dates },
- compareBy(BasicComparator.ALBUM))
+ override fun sortAlbums(albums: MutableList, direction: Direction) {
+ albums.sortBy { it.name }
+ albums.sortByDescending { it.dates }
+ when (direction) {
+ Direction.ASCENDING -> albums.sortBy { it.artists.firstOrNull()?.name }
+ Direction.DESCENDING ->
+ albums.sortByDescending { it.artists.firstOrNull()?.name }
+ }
+ }
}
- /**
- * Sort by the [Date] of an item. Only available for [Song] and [Album].
- *
- * @see Song.date
- * @see Album.dates
- */
data object ByDate : Mode {
- override val intCode: Int
- get() = IntegerTable.SORT_BY_YEAR
+ override val intCode = IntegerTable.SORT_BY_YEAR
+ override val stringRes = R.string.lbl_date
- override val stringRes: Int
- get() = R.string.lbl_date
+ override fun sortSongs(songs: MutableList, direction: Direction) {
+ songs.sortBy { it.name }
+ songs.sortBy { it.track }
+ songs.sortBy { it.disc }
+ songs.sortByDescending { it.album.name }
+ when (direction) {
+ Direction.ASCENDING -> songs.sortBy { it.album.dates }
+ Direction.DESCENDING -> songs.sortByDescending { it.album.dates }
+ }
+ }
- override fun getSongComparator(direction: Direction): Comparator =
- MultiComparator(
- compareByDynamic(direction, NullableComparator.DATE) { it.date },
- compareByDescending(BasicComparator.ALBUM) { it.album },
- compareBy(NullableComparator.DISC) { it.disc },
- compareBy(NullableComparator.INT) { it.track },
- compareBy(BasicComparator.SONG))
-
- override fun getAlbumComparator(direction: Direction): Comparator =
- MultiComparator(
- compareByDynamic(direction, NullableComparator.DATE_RANGE) { it.dates },
- compareBy(BasicComparator.ALBUM))
+ override fun sortAlbums(albums: MutableList, direction: Direction) {
+ albums.sortBy { it.name }
+ when (direction) {
+ Direction.ASCENDING -> albums.sortBy { it.dates }
+ Direction.DESCENDING -> albums.sortByDescending { it.dates }
+ }
+ }
}
- /** Sort by the duration of an item. */
data object ByDuration : Mode {
- override val intCode: Int
- get() = IntegerTable.SORT_BY_DURATION
+ override val intCode = IntegerTable.SORT_BY_DURATION
+ override val stringRes = R.string.lbl_duration
- override val stringRes: Int
- get() = R.string.lbl_duration
+ override fun sortSongs(songs: MutableList, direction: Direction) {
+ songs.sortBy { it.name }
+ when (direction) {
+ Direction.ASCENDING -> songs.sortBy { it.durationMs }
+ Direction.DESCENDING -> songs.sortByDescending { it.durationMs }
+ }
+ }
- override fun getSongComparator(direction: Direction): Comparator =
- MultiComparator(
- compareByDynamic(direction) { it.durationMs }, compareBy(BasicComparator.SONG))
+ override fun sortAlbums(albums: MutableList, direction: Direction) {
+ albums.sortBy { it.name }
+ when (direction) {
+ Direction.ASCENDING -> albums.sortBy { it.durationMs }
+ Direction.DESCENDING -> albums.sortByDescending { it.durationMs }
+ }
+ }
- override fun getAlbumComparator(direction: Direction): Comparator =
- MultiComparator(
- compareByDynamic(direction) { it.durationMs }, compareBy(BasicComparator.ALBUM))
+ override fun sortArtists(artists: MutableList, direction: Direction) {
+ artists.sortBy { it.name }
+ when (direction) {
+ Direction.ASCENDING -> artists.sortBy { it.durationMs }
+ Direction.DESCENDING -> artists.sortByDescending { it.durationMs }
+ }
+ }
- override fun getArtistComparator(direction: Direction): Comparator =
- MultiComparator(
- compareByDynamic(direction, NullableComparator.LONG) { it.durationMs },
- compareBy(BasicComparator.ARTIST))
+ override fun sortGenres(genres: MutableList, direction: Direction) {
+ genres.sortBy { it.name }
+ when (direction) {
+ Direction.ASCENDING -> genres.sortBy { it.durationMs }
+ Direction.DESCENDING -> genres.sortByDescending { it.durationMs }
+ }
+ }
- override fun getGenreComparator(direction: Direction): Comparator =
- MultiComparator(
- compareByDynamic(direction) { it.durationMs }, compareBy(BasicComparator.GENRE))
-
- override fun getPlaylistComparator(direction: Direction): Comparator =
- MultiComparator(
- compareByDynamic(direction) { it.durationMs },
- compareBy(BasicComparator.PLAYLIST))
+ override fun sortPlaylists(playlists: MutableList, direction: Direction) {
+ playlists.sortBy { it.name }
+ when (direction) {
+ Direction.ASCENDING -> playlists.sortBy { it.durationMs }
+ Direction.DESCENDING -> playlists.sortByDescending { it.durationMs }
+ }
+ }
}
- /** Sort by the amount of songs an item contains. Only available for MusicParents. */
data object ByCount : Mode {
- override val intCode: Int
- get() = IntegerTable.SORT_BY_COUNT
+ override val intCode = IntegerTable.SORT_BY_COUNT
+ override val stringRes = R.string.lbl_song_count
- override val stringRes: Int
- get() = R.string.lbl_song_count
+ override fun sortAlbums(albums: MutableList, direction: Direction) {
+ albums.sortBy { it.name }
+ when (direction) {
+ Direction.ASCENDING -> albums.sortBy { it.songs.size }
+ Direction.DESCENDING -> albums.sortByDescending { it.songs.size }
+ }
+ }
- override fun getAlbumComparator(direction: Direction): Comparator =
- MultiComparator(
- compareByDynamic(direction) { it.songs.size }, compareBy(BasicComparator.ALBUM))
+ override fun sortArtists(artists: MutableList, direction: Direction) {
+ artists.sortBy { it.name }
+ when (direction) {
+ Direction.ASCENDING -> artists.sortBy { it.songs.size }
+ Direction.DESCENDING -> artists.sortByDescending { it.songs.size }
+ }
+ }
- override fun getArtistComparator(direction: Direction): Comparator =
- MultiComparator(
- compareByDynamic(direction, NullableComparator.INT) { it.songs.size },
- compareBy(BasicComparator.ARTIST))
+ override fun sortGenres(genres: MutableList, direction: Direction) {
+ genres.sortBy { it.name }
+ when (direction) {
+ Direction.ASCENDING -> genres.sortBy { it.songs.size }
+ Direction.DESCENDING -> genres.sortByDescending { it.songs.size }
+ }
+ }
- override fun getGenreComparator(direction: Direction): Comparator =
- MultiComparator(
- compareByDynamic(direction) { it.songs.size }, compareBy(BasicComparator.GENRE))
-
- override fun getPlaylistComparator(direction: Direction): Comparator =
- MultiComparator(
- compareByDynamic(direction) { it.songs.size },
- compareBy(BasicComparator.PLAYLIST))
+ override fun sortPlaylists(playlists: MutableList, direction: Direction) {
+ playlists.sortBy { it.name }
+ when (direction) {
+ Direction.ASCENDING -> playlists.sortBy { it.songs.size }
+ Direction.DESCENDING -> playlists.sortByDescending { it.songs.size }
+ }
+ }
}
- /**
- * Sort by the disc number of an item. Only available for [Song]s.
- *
- * @see Song.disc
- */
data object ByDisc : Mode {
- override val intCode: Int
- get() = IntegerTable.SORT_BY_DISC
+ override val intCode = IntegerTable.SORT_BY_DISC
+ override val stringRes = R.string.lbl_disc
- override val stringRes: Int
- get() = R.string.lbl_disc
-
- override fun getSongComparator(direction: Direction): Comparator =
- MultiComparator(
- compareByDynamic(direction, NullableComparator.DISC) { it.disc },
- compareBy(NullableComparator.INT) { it.track },
- compareBy(BasicComparator.SONG))
+ override fun sortSongs(songs: MutableList, direction: Direction) {
+ songs.sortBy { it.name }
+ songs.sortBy { it.track }
+ when (direction) {
+ Direction.ASCENDING -> songs.sortBy { it.disc }
+ Direction.DESCENDING -> songs.sortByDescending { it.disc }
+ }
+ }
}
- /**
- * Sort by the track number of an item. Only available for [Song]s.
- *
- * @see Song.track
- */
data object ByTrack : Mode {
- override val intCode: Int
- get() = IntegerTable.SORT_BY_TRACK
+ override val intCode = IntegerTable.SORT_BY_TRACK
+ override val stringRes = R.string.lbl_track
- override val stringRes: Int
- get() = R.string.lbl_track
-
- override fun getSongComparator(direction: Direction): Comparator =
- MultiComparator(
- compareBy(NullableComparator.DISC) { it.disc },
- compareByDynamic(direction, NullableComparator.INT) { it.track },
- compareBy(BasicComparator.SONG))
+ override fun sortSongs(songs: MutableList, direction: Direction) {
+ songs.sortBy { it.name }
+ when (direction) {
+ Direction.ASCENDING -> songs.sortBy { it.track }
+ Direction.DESCENDING -> songs.sortByDescending { it.track }
+ }
+ songs.sortBy { it.disc }
+ }
}
- /**
- * Sort by the date an item was added. Only supported by [Song]s and [Album]s.
- *
- * @see Song.dateAdded
- * @see Album.dates
- */
data object ByDateAdded : Mode {
- override val intCode: Int
- get() = IntegerTable.SORT_BY_DATE_ADDED
+ override val intCode = IntegerTable.SORT_BY_DATE_ADDED
+ override val stringRes = R.string.lbl_date_added
- override val stringRes: Int
- get() = R.string.lbl_date_added
+ override fun sortSongs(songs: MutableList, direction: Direction) {
+ songs.sortBy { it.name }
+ when (direction) {
+ Direction.ASCENDING -> songs.sortBy { it.dateAdded }
+ Direction.DESCENDING -> songs.sortByDescending { it.dateAdded }
+ }
+ }
- override fun getSongComparator(direction: Direction): Comparator =
- MultiComparator(
- compareByDynamic(direction) { it.dateAdded }, compareBy(BasicComparator.SONG))
-
- override fun getAlbumComparator(direction: Direction): Comparator =
- MultiComparator(
- compareByDynamic(direction) { album -> album.dateAdded },
- compareBy(BasicComparator.ALBUM))
+ override fun sortAlbums(albums: MutableList, direction: Direction) {
+ albums.sortBy { it.name }
+ when (direction) {
+ Direction.ASCENDING -> albums.sortBy { it.dateAdded }
+ Direction.DESCENDING -> albums.sortByDescending { it.dateAdded }
+ }
+ }
}
companion object {
- /**
- * Convert a [Mode] integer representation into an instance.
- *
- * @param intCode An integer representation of a [Mode]
- * @return The corresponding [Mode], or null if the [Mode] is invalid.
- * @see intCode
- */
- fun fromIntCode(intCode: Int) =
+ fun fromIntCode(intCode: Int): Mode? =
when (intCode) {
ByName.intCode -> ByName
ByArtist.intCode -> ByArtist
@@ -465,169 +415,3 @@ data class Sort(val mode: Mode, val direction: Direction) {
}
}
}
-
-/**
- * Utility function to create a [Comparator] in a dynamic way determined by [direction].
- *
- * @param direction The [Sort.Direction] to sort in.
- * @see compareBy
- * @see compareByDescending
- */
-private inline fun > compareByDynamic(
- direction: Sort.Direction,
- crossinline selector: (T) -> K
-) =
- when (direction) {
- Sort.Direction.ASCENDING -> compareBy(selector)
- Sort.Direction.DESCENDING -> compareByDescending(selector)
- }
-
-/**
- * Utility function to create a [Comparator] in a dynamic way determined by [direction]
- *
- * @param direction The [Sort.Direction] to sort in.
- * @param comparator A [Comparator] to wrap.
- * @return A new [Comparator] with the specified configuration.
- * @see compareBy
- * @see compareByDescending
- */
-private fun compareByDynamic(
- direction: Sort.Direction,
- comparator: Comparator
-): Comparator = compareByDynamic(direction, comparator) { it }
-
-/**
- * Utility function to create a [Comparator] a dynamic way determined by [direction]
- *
- * @param direction The [Sort.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.
- * @see compareBy
- * @see compareByDescending
- */
-private inline fun compareByDynamic(
- direction: Sort.Direction,
- comparator: Comparator,
- crossinline selector: (T) -> K
-) =
- when (direction) {
- Sort.Direction.ASCENDING -> compareBy(comparator, selector)
- Sort.Direction.DESCENDING -> compareByDescending(comparator, selector)
- }
-
-/**
- * Utility function to create a [Comparator] that sorts in ascending order based on the given
- * [Comparator], with a selector based on the item itself.
- *
- * @param comparator The [Comparator] to wrap.
- * @return A new [Comparator] with the specified configuration.
- * @see compareBy
- */
-private fun compareBy(comparator: Comparator): Comparator =
- compareBy(comparator) { it }
-
-/**
- * A [Comparator] that chains several other [Comparator]s together to form one comparison.
- *
- * @param comparators The [Comparator]s to chain. These will be iterated through in order during a
- * comparison, with the first non-equal result becoming the result.
- */
-private class MultiComparator(vararg comparators: Comparator) : Comparator {
- private val _comparators = comparators
-
- override fun compare(a: T?, b: T?): Int {
- for (comparator in _comparators) {
- val result = comparator.compare(a, b)
- if (result != 0) {
- return result
- }
- }
-
- return 0
- }
-}
-
-/**
- * Wraps a [Comparator], extending it to compare two lists.
- *
- * @param inner The [Comparator] to use.
- */
-private class ListComparator(private val inner: Comparator) : Comparator> {
- override fun compare(a: List, b: List): Int {
- for (i in 0 until max(a.size, b.size)) {
- val ai = a.getOrNull(i)
- val bi = b.getOrNull(i)
- when {
- ai != null && bi != null -> {
- val result = inner.compare(ai, bi)
- if (result != 0) {
- return result
- }
- }
- ai == null && bi != null -> return -1 // a < b
- ai == null && bi == null -> return 0 // a = b
- else -> return 1 // a < b
- }
- }
-
- return 0
- }
-
- companion object {
- /** A re-usable configured for [Artist]s.. */
- val ARTISTS: Comparator> = ListComparator(BasicComparator.ARTIST)
- }
-}
-
-/**
- * A [Comparator] that compares abstract [Music] values. Internally, this is similar to
- * [NullableComparator], however comparing [Music.name] instead of [Comparable].
- *
- * @see NullableComparator
- * @see Music.name
- */
-private class BasicComparator private constructor() : Comparator {
- override fun compare(a: T, b: T) = a.name.compareTo(b.name)
-
- companion object {
- /** A re-usable instance configured for [Song]s. */
- val SONG: Comparator = BasicComparator()
- /** A re-usable instance configured for [Album]s. */
- val ALBUM: Comparator = BasicComparator()
- /** A re-usable instance configured for [Artist]s. */
- val ARTIST: Comparator = BasicComparator()
- /** A re-usable instance configured for [Genre]s. */
- val GENRE: Comparator = BasicComparator()
- /** A re-usable instance configured for [Playlist]s. */
- val PLAYLIST: Comparator = BasicComparator()
- }
-}
-
-/**
- * A [Comparator] that compares two possibly null values. Values will be considered lesser if they
- * are null, and greater if they are non-null.
- */
-private class NullableComparator> private constructor() : Comparator {
- override fun compare(a: T?, b: T?) =
- when {
- a != null && b != null -> a.compareTo(b)
- a == null && b != null -> -1 // a < b
- a == null && b == null -> 0 // a = b
- else -> 1 // a < b
- }
-
- companion object {
- /** A re-usable instance configured for [Int]s. */
- val INT = NullableComparator()
- /** A re-usable instance configured for [Long]s. */
- val LONG = NullableComparator()
- /** A re-usable instance configured for [Disc]s */
- val DISC = NullableComparator()
- /** A re-usable instance configured for [Date.Range]s. */
- val DATE_RANGE = NullableComparator()
-
- /** A re-usable instance configured for [Date]s. */
- val DATE = NullableComparator()
- }
-}
diff --git a/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt b/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt
index ff449b029..b8a3d2b26 100644
--- a/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt
+++ b/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt
@@ -438,7 +438,8 @@ constructor(
// to cascade to and cancel all other routines before finally bubbling up
// to the main extractor loop.
logE("MediaStore extraction failed: $e")
- incompleteSongs.close(Exception("MediaStore extraction failed: $e"))
+ incompleteSongs.close(
+ Exception("MediaStore extraction failed: ${e.stackTraceToString()}"))
return@async
}
incompleteSongs.close()
@@ -453,7 +454,8 @@ constructor(
tagExtractor.consume(incompleteSongs, completeSongs)
} catch (e: Exception) {
logE("Tag extraction failed: $e")
- completeSongs.close(Exception("Tag extraction failed: $e"))
+ completeSongs.close(
+ Exception("Tag extraction failed: ${e.stackTraceToString()}"))
return@async
}
completeSongs.close()
@@ -470,7 +472,8 @@ constructor(
completeSongs, processedSongs, separators, nameFactory)
} catch (e: Exception) {
logE("DeviceLibrary creation failed: $e")
- processedSongs.close(Exception("DeviceLibrary creation failed: $e"))
+ processedSongs.close(
+ Exception("DeviceLibrary creation failed: ${e.stackTraceToString()}"))
return@async Result.failure(e)
}
processedSongs.close()
diff --git a/fastlane/metadata/android/en-US/changelogs/47.txt b/fastlane/metadata/android/en-US/changelogs/47.txt
new file mode 100644
index 000000000..ed07d5398
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/47.txt
@@ -0,0 +1,3 @@
+Auxio 3.5.1 adds support for android auto alongside various playback and music quality of life improvements.
+This release fixes a critical bug with the music loader.
+For more information, see https://github.com/OxygenCobalt/Auxio/releases/tag/v3.5.0
\ No newline at end of file