all: use sealed interface when possible

Use sealed interface instead of sealed class when no class features are
actually used by the code.
This commit is contained in:
Alexander Capehart 2023-05-11 12:36:58 -06:00
parent 4e5a3f7fe1
commit aa24ea00ea
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
5 changed files with 209 additions and 208 deletions

View file

@ -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<Song>? = null
fun getSongComparator(direction: Direction): Comparator<Song>? = 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<Album>? = null
fun getAlbumComparator(direction: Direction): Comparator<Album>? = 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<Artist>? = null
fun getArtistComparator(direction: Direction): Comparator<Artist>? = 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<Genre>? = null
fun getGenreComparator(direction: Direction): Comparator<Genre>? = 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<Playlist>? = null
fun getPlaylistComparator(direction: Direction): Comparator<Playlist>? = 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 <T : Music, K : Comparable<K>> 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 <T : Music> compareByDynamic(
direction: Direction,
comparator: Comparator<in T>
): Comparator<T> = 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 <T : Music, K> compareByDynamic(
direction: Direction,
comparator: Comparator<in K>,
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 <T : Music> compareBy(comparator: Comparator<T>): Comparator<T> =
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<T>(vararg comparators: Comparator<T>) : Comparator<T> {
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<T>(private val inner: Comparator<T>) : Comparator<List<T>> {
override fun compare(a: List<T>, b: List<T>): 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<List<Artist>> = 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<T : Music> private constructor() : Comparator<T> {
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<Song> = BasicComparator()
/** A re-usable instance configured for [Album]s. */
val ALBUM: Comparator<Album> = BasicComparator()
/** A re-usable instance configured for [Artist]s. */
val ARTIST: Comparator<Artist> = BasicComparator()
/** A re-usable instance configured for [Genre]s. */
val GENRE: Comparator<Genre> = BasicComparator()
/** A re-usable instance configured for [Playlist]s. */
val PLAYLIST: Comparator<Playlist> = 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<T : Comparable<T>> private constructor() : Comparator<T?> {
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<Int>()
/** A re-usable instance configured for [Long]s. */
val LONG = NullableComparator<Long>()
/** A re-usable instance configured for [Disc]s */
val DISC = NullableComparator<Disc>()
/** A re-usable instance configured for [Date.Range]s. */
val DATE_RANGE = NullableComparator<Date.Range>()
}
}
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 <T : Music, K : Comparable<K>> 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 <T : Music> compareByDynamic(
direction: Sort.Direction,
comparator: Comparator<in T>
): Comparator<T> = 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 <T : Music, K> compareByDynamic(
direction: Sort.Direction,
comparator: Comparator<in K>,
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 <T : Music> compareBy(comparator: Comparator<T>): Comparator<T> =
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<T>(vararg comparators: Comparator<T>) : Comparator<T> {
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<T>(private val inner: Comparator<T>) : Comparator<List<T>> {
override fun compare(a: List<T>, b: List<T>): 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<List<Artist>> = 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<T : Music> private constructor() : Comparator<T> {
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<Song> = BasicComparator()
/** A re-usable instance configured for [Album]s. */
val ALBUM: Comparator<Album> = BasicComparator()
/** A re-usable instance configured for [Artist]s. */
val ARTIST: Comparator<Artist> = BasicComparator()
/** A re-usable instance configured for [Genre]s. */
val GENRE: Comparator<Genre> = BasicComparator()
/** A re-usable instance configured for [Playlist]s. */
val PLAYLIST: Comparator<Playlist> = 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<T : Comparable<T>> private constructor() : Comparator<T?> {
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<Int>()
/** A re-usable instance configured for [Long]s. */
val LONG = NullableComparator<Long>()
/** A re-usable instance configured for [Disc]s */
val DISC = NullableComparator<Disc>()
/** A re-usable instance configured for [Date.Range]s. */
val DATE_RANGE = NullableComparator<Date.Range>()
}
}

View file

@ -62,16 +62,16 @@ abstract class FlexibleListAdapter<T, VH : RecyclerView.ViewHolder>(
*
* @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
}
/**

View file

@ -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

View file

@ -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
}

View file

@ -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
}
/**