diff --git a/app/src/main/java/org/oxycblt/auxio/list/Sort.kt b/app/src/main/java/org/oxycblt/auxio/list/Sort.kt index c0cce8a5c..8b5120a7a 100644 --- a/app/src/main/java/org/oxycblt/auxio/list/Sort.kt +++ b/app/src/main/java/org/oxycblt/auxio/list/Sort.kt @@ -155,11 +155,11 @@ data class Sort(val mode: Mode, val direction: Direction) { } /** Describes the type of data to sort with. */ - sealed class Mode { + sealed interface Mode { /** The integer representation of this sort mode. */ - abstract val intCode: Int + val intCode: Int /** The item ID of this sort mode in menu resources. */ - abstract val itemId: Int + val itemId: Int /** * Get a [Comparator] that sorts [Song]s according to this [Mode]. @@ -168,7 +168,7 @@ data class Sort(val mode: Mode, val direction: Direction) { * @return A [Comparator] that can be used to sort a [Song] list according to this [Mode], * or null to not sort at all. */ - open fun getSongComparator(direction: Direction): Comparator? = null + fun getSongComparator(direction: Direction): Comparator? = null /** * Get a [Comparator] that sorts [Album]s according to this [Mode]. @@ -177,7 +177,8 @@ data class Sort(val mode: Mode, val direction: Direction) { * @return A [Comparator] that can be used to sort a [Album] list according to this [Mode], * or null to not sort at all. */ - open fun getAlbumComparator(direction: Direction): Comparator? = null + fun getAlbumComparator(direction: Direction): Comparator? = null + /** * Return a [Comparator] that sorts [Artist]s according to this [Mode]. * @@ -185,7 +186,7 @@ data class Sort(val mode: Mode, val direction: Direction) { * @return A [Comparator] that can be used to sort a [Artist] list according to this [Mode]. * or null to not sort at all. */ - open fun getArtistComparator(direction: Direction): Comparator? = null + fun getArtistComparator(direction: Direction): Comparator? = null /** * Return a [Comparator] that sorts [Genre]s according to this [Mode]. @@ -194,7 +195,7 @@ data class Sort(val mode: Mode, val direction: Direction) { * @return A [Comparator] that can be used to sort a [Genre] list according to this [Mode]. * or null to not sort at all. */ - open fun getGenreComparator(direction: Direction): Comparator? = null + fun getGenreComparator(direction: Direction): Comparator? = null /** * Return a [Comparator] that sorts [Playlist]s according to this [Mode]. @@ -203,14 +204,14 @@ data class Sort(val mode: Mode, val direction: Direction) { * @return A [Comparator] that can be used to sort a [Genre] list according to this [Mode]. * or null to not sort at all. */ - open fun getPlaylistComparator(direction: Direction): Comparator? = null + fun getPlaylistComparator(direction: Direction): Comparator? = null /** * Sort by the item's natural order. * - * @see Music.sortName + * @see Music.name */ - object ByNone : Mode() { + object ByNone : Mode { override val intCode: Int get() = IntegerTable.SORT_BY_NONE @@ -223,7 +224,7 @@ data class Sort(val mode: Mode, val direction: Direction) { * * @see Music.sortName */ - object ByName : Mode() { + object ByName : Mode { override val intCode: Int get() = IntegerTable.SORT_BY_NAME @@ -249,9 +250,9 @@ data class Sort(val mode: Mode, val direction: Direction) { /** * Sort by the [Album] of an item. Only available for [Song]s. * - * @see Album.sortName + * @see Album.name */ - object ByAlbum : Mode() { + object ByAlbum : Mode { override val intCode: Int get() = IntegerTable.SORT_BY_ALBUM @@ -269,9 +270,9 @@ data class Sort(val mode: Mode, val direction: Direction) { /** * Sort by the [Artist] name of an item. Only available for [Song] and [Album]. * - * @see Artist.sortName + * @see Artist.name */ - object ByArtist : Mode() { + object ByArtist : Mode { override val intCode: Int get() = IntegerTable.SORT_BY_ARTIST @@ -300,7 +301,7 @@ data class Sort(val mode: Mode, val direction: Direction) { * @see Song.date * @see Album.dates */ - object ByDate : Mode() { + object ByDate : Mode { override val intCode: Int get() = IntegerTable.SORT_BY_YEAR @@ -322,7 +323,7 @@ data class Sort(val mode: Mode, val direction: Direction) { } /** Sort by the duration of an item. */ - object ByDuration : Mode() { + object ByDuration : Mode { override val intCode: Int get() = IntegerTable.SORT_BY_DURATION @@ -357,7 +358,7 @@ data class Sort(val mode: Mode, val direction: Direction) { * * @see MusicParent.songs */ - object ByCount : Mode() { + object ByCount : Mode { override val intCode: Int get() = IntegerTable.SORT_BY_COUNT @@ -388,7 +389,7 @@ data class Sort(val mode: Mode, val direction: Direction) { * * @see Song.disc */ - object ByDisc : Mode() { + object ByDisc : Mode { override val intCode: Int get() = IntegerTable.SORT_BY_DISC @@ -407,7 +408,7 @@ data class Sort(val mode: Mode, val direction: Direction) { * * @see Song.track */ - object ByTrack : Mode() { + object ByTrack : Mode { override val intCode: Int get() = IntegerTable.SORT_BY_TRACK @@ -427,7 +428,7 @@ data class Sort(val mode: Mode, val direction: Direction) { * @see Song.dateAdded * @see Album.dates */ - object ByDateAdded : Mode() { + object ByDateAdded : Mode { override val intCode: Int get() = IntegerTable.SORT_BY_DATE_ADDED @@ -444,169 +445,6 @@ data class Sort(val mode: Mode, val direction: Direction) { compareBy(BasicComparator.ALBUM)) } - /** - * 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 > compareByDynamic( - direction: Direction, - crossinline selector: (T) -> K - ) = - when (direction) { - Direction.ASCENDING -> compareBy(selector) - Direction.DESCENDING -> compareByDescending(selector) - } - - /** - * 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 compareByDynamic( - direction: Direction, - comparator: Comparator - ): Comparator = compareByDynamic(direction, comparator) { it } - - /** - * 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. - * @see compareBy - * @see compareByDescending - */ - protected inline fun compareByDynamic( - direction: Direction, - comparator: Comparator, - crossinline selector: (T) -> K - ) = - when (direction) { - Direction.ASCENDING -> compareBy(comparator, selector) - 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 - */ - protected 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.collationKey] instead of [Comparable]. - * - * @see NullableComparator - * @see Music.collationKey - */ - 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() - } - } - companion object { /** * Convert a [Mode] integer representation into an instance. @@ -678,3 +516,166 @@ 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 [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 [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() + } +} \ No newline at end of file diff --git a/app/src/main/java/org/oxycblt/auxio/list/adapter/FlexibleListAdapter.kt b/app/src/main/java/org/oxycblt/auxio/list/adapter/FlexibleListAdapter.kt index 63096dbf5..c76ffaae6 100644 --- a/app/src/main/java/org/oxycblt/auxio/list/adapter/FlexibleListAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/list/adapter/FlexibleListAdapter.kt @@ -62,16 +62,16 @@ abstract class FlexibleListAdapter( * * @author Alexander Capehart (OxygenCobalt) */ -sealed class UpdateInstructions { +sealed interface UpdateInstructions { /** Use an asynchronous diff. Useful for unpredictable updates, but looks chaotic and janky. */ - object Diff : UpdateInstructions() + object Diff : UpdateInstructions /** * Visually replace all items from a given point. More visually coherent than [Diff]. * * @param from The index at which to start replacing items (inclusive) */ - data class Replace(val from: Int) : UpdateInstructions() + data class Replace(val from: Int) : UpdateInstructions /** * Add a new set of items. @@ -79,7 +79,7 @@ sealed class UpdateInstructions { * @param at The position at which to add. * @param size The amount of items to add. */ - data class Add(val at: Int, val size: Int) : UpdateInstructions() + data class Add(val at: Int, val size: Int) : UpdateInstructions /** * Move one item to another location. @@ -87,14 +87,14 @@ sealed class UpdateInstructions { * @param from The index of the item to move. * @param to The index to move the item to. */ - data class Move(val from: Int, val to: Int) : UpdateInstructions() + data class Move(val from: Int, val to: Int) : UpdateInstructions /** * Remove an item. * * @param at The location that the item should be removed from. */ - data class Remove(val at: Int) : UpdateInstructions() + data class Remove(val at: Int) : UpdateInstructions } /** diff --git a/app/src/main/java/org/oxycblt/auxio/music/info/ReleaseType.kt b/app/src/main/java/org/oxycblt/auxio/music/info/ReleaseType.kt index bc676228b..20ac60034 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/info/ReleaseType.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/info/ReleaseType.kt @@ -28,15 +28,15 @@ import org.oxycblt.auxio.R * * @author Alexander Capehart (OxygenCobalt) */ -sealed class ReleaseType { +sealed interface ReleaseType { /** * A specification of what kind of performance this release is. If null, the release is * considered "Plain". */ - abstract val refinement: Refinement? + val refinement: Refinement? /** The string resource corresponding to the name of this release type to show in the UI. */ - abstract val stringRes: Int + val stringRes: Int /** * A plain album. @@ -44,7 +44,7 @@ sealed class ReleaseType { * @param refinement A specification of what kind of performance this release is. If null, the * release is considered "Plain". */ - data class Album(override val refinement: Refinement?) : ReleaseType() { + data class Album(override val refinement: Refinement?) : ReleaseType { override val stringRes: Int get() = when (refinement) { @@ -61,7 +61,7 @@ sealed class ReleaseType { * @param refinement A specification of what kind of performance this release is. If null, the * release is considered "Plain". */ - data class EP(override val refinement: Refinement?) : ReleaseType() { + data class EP(override val refinement: Refinement?) : ReleaseType { override val stringRes: Int get() = when (refinement) { @@ -78,7 +78,7 @@ sealed class ReleaseType { * @param refinement A specification of what kind of performance this release is. If null, the * release is considered "Plain". */ - data class Single(override val refinement: Refinement?) : ReleaseType() { + data class Single(override val refinement: Refinement?) : ReleaseType { override val stringRes: Int get() = when (refinement) { @@ -95,7 +95,7 @@ sealed class ReleaseType { * @param refinement A specification of what kind of performance this release is. If null, the * release is considered "Plain". */ - data class Compilation(override val refinement: Refinement?) : ReleaseType() { + data class Compilation(override val refinement: Refinement?) : ReleaseType { override val stringRes: Int get() = when (refinement) { @@ -110,7 +110,7 @@ sealed class ReleaseType { * A soundtrack. Similar to a [Compilation], but created for a specific piece of (usually * visual) media. */ - object Soundtrack : ReleaseType() { + object Soundtrack : ReleaseType { override val refinement: Refinement? get() = null @@ -122,7 +122,7 @@ sealed class ReleaseType { * A (DJ) Mix. These are usually one large track consisting of the artist playing several * sub-tracks with smooth transitions between them. */ - object Mix : ReleaseType() { + object Mix : ReleaseType { override val refinement: Refinement? get() = null @@ -134,7 +134,7 @@ sealed class ReleaseType { * A Mix-tape. These are usually [EP]-sized releases of music made to promote an Artist or a * future release. */ - object Mixtape : ReleaseType() { + object Mixtape : ReleaseType { override val refinement: Refinement? get() = null diff --git a/app/src/main/java/org/oxycblt/auxio/navigation/MainNavigationAction.kt b/app/src/main/java/org/oxycblt/auxio/navigation/MainNavigationAction.kt index 36eec45f7..59c778320 100644 --- a/app/src/main/java/org/oxycblt/auxio/navigation/MainNavigationAction.kt +++ b/app/src/main/java/org/oxycblt/auxio/navigation/MainNavigationAction.kt @@ -27,12 +27,12 @@ import androidx.navigation.NavDirections * * @author Alexander Capehart (OxygenCobalt) */ -sealed class MainNavigationAction { +sealed interface MainNavigationAction { /** Expand the playback panel. */ - object OpenPlaybackPanel : MainNavigationAction() + object OpenPlaybackPanel : MainNavigationAction /** Collapse the playback bottom sheet. */ - object ClosePlaybackPanel : MainNavigationAction() + object ClosePlaybackPanel : MainNavigationAction /** * Navigate to the given [NavDirections]. @@ -40,5 +40,5 @@ sealed class MainNavigationAction { * @param directions The [NavDirections] to navigate to. Assumed to be part of the main * navigation graph. */ - data class Directions(val directions: NavDirections) : MainNavigationAction() + data class Directions(val directions: NavDirections) : MainNavigationAction } diff --git a/app/src/main/java/org/oxycblt/auxio/playback/state/InternalPlayer.kt b/app/src/main/java/org/oxycblt/auxio/playback/state/InternalPlayer.kt index 3edbf8633..17186e181 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/state/InternalPlayer.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/state/InternalPlayer.kt @@ -75,22 +75,22 @@ interface InternalPlayer { fun setPlaying(isPlaying: Boolean) /** Possible long-running background tasks handled by the background playback task. */ - sealed class Action { + sealed interface Action { /** Restore the previously saved playback state. */ - object RestoreState : Action() + object RestoreState : Action /** * Start shuffled playback of the entire music library. Analogous to the "Shuffle All" * shortcut. */ - object ShuffleAll : Action() + object ShuffleAll : Action /** * Start playing an audio file at the given [Uri]. * * @param uri The [Uri] of the audio file to start playing. */ - data class Open(val uri: Uri) : Action() + data class Open(val uri: Uri) : Action } /**