all: post-refactor cleanup

This commit is contained in:
Alexander Capehart 2023-01-29 17:45:51 -07:00
parent bfb1033ed7
commit f8d1a880d4
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
11 changed files with 103 additions and 97 deletions

View file

@ -95,7 +95,7 @@ dependencies {
implementation "androidx.preference:preference-ktx:1.2.0"
// Database
def room_version = '2.4.3'
def room_version = '2.5.0'
implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version"
implementation "androidx.room:room-ktx:$room_version"
@ -122,8 +122,8 @@ dependencies {
// Development
debugImplementation "com.squareup.leakcanary:leakcanary-android:2.9.1"
testImplementation "junit:junit:4.13.2"
androidTestImplementation 'androidx.test.ext:junit:1.1.4'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
}
spotless {

View file

@ -225,6 +225,7 @@ sealed interface Music : Item {
* @author Alexander Capehart (OxygenCobalt)
*/
sealed interface MusicParent : Music {
/** The child [Song]s of this [MusicParent]. */
val songs: List<Song>
}
@ -337,10 +338,6 @@ interface Album : MusicParent {
/**
* An abstract artist. These are actually a combination of the artist and album artist tags from
* within the library, derived from [Song]s and [Album]s respectively.
* @param raw The [Artist.Raw] to derive the member data from.
* @param songAlbums A list of the [Song]s and [Album]s that are a part of this [Artist], either
* through artist or album artist tags. Providing [Song]s to the artist is optional. These instances
* will be linked to this [Artist].
* @author Alexander Capehart (OxygenCobalt)
*/
interface Artist : MusicParent {

View file

@ -401,7 +401,7 @@ class RealAlbum(val raw: Raw, override val songs: List<RealSong>) : Album {
val sortName: String?,
/** @see Album.releaseType */
val releaseType: ReleaseType?,
/** @see Artist.Raw.name */
/** @see RealArtist.Raw.name */
val rawArtists: List<RealArtist.Raw>
) {
// Albums are grouped as follows:
@ -694,29 +694,6 @@ fun MessageDigest.update(n: Int?) {
}
}
/** Cached collator instance re-used with [makeCollationKey]. */
private val COLLATOR: Collator = Collator.getInstance().apply { strength = Collator.PRIMARY }
/**
* Provided implementation to create a [CollationKey] in the way described by [collationKey]. This
* should be used in all overrides of all [CollationKey].
* @param music The [Music] to create the [CollationKey] for.
* @return A [CollationKey] that follows the specification described by [collationKey].
*/
private fun makeCollationKey(music: Music): CollationKey? {
val sortName =
(music.rawSortName ?: music.rawName)?.run {
when {
length > 5 && startsWith("the ", ignoreCase = true) -> substring(4)
length > 4 && startsWith("an ", ignoreCase = true) -> substring(3)
length > 3 && startsWith("a ", ignoreCase = true) -> substring(2)
else -> this
}
}
return COLLATOR.getCollationKey(sortName)
}
/**
* Join a list of [Music]'s resolved names into a string in a localized manner, using
* [R.string.fmt_list].
@ -737,3 +714,26 @@ private fun resolveNames(context: Context, values: List<Music>): String {
}
return joined
}
/** Cached collator instance re-used with [makeCollationKey]. */
private val COLLATOR: Collator = Collator.getInstance().apply { strength = Collator.PRIMARY }
/**
* Provided implementation to create a [CollationKey] in the way described by [Music.collationKey].
* This should be used in all overrides of all [CollationKey].
* @param music The [Music] to create the [CollationKey] for.
* @return A [CollationKey] that follows the specification described by [Music.collationKey].
*/
private fun makeCollationKey(music: Music): CollationKey? {
val sortName =
(music.rawSortName ?: music.rawName)?.run {
when {
length > 5 && startsWith("the ", ignoreCase = true) -> substring(4)
length > 4 && startsWith("an ", ignoreCase = true) -> substring(3)
length > 3 && startsWith("a ", ignoreCase = true) -> substring(2)
else -> this
}
}
return COLLATOR.getCollationKey(sortName)
}

View file

@ -202,9 +202,7 @@ private abstract class CacheDatabase : RoomDatabase() {
@Dao
private interface CacheDao {
@Query("SELECT * FROM ${CachedSong.TABLE_NAME}") suspend fun readCache(): List<CachedSong>
@Query("DELETE FROM ${CachedSong.TABLE_NAME}") suspend fun nukeCache()
@Insert suspend fun insertCache(songs: List<CachedSong>)
}
@ -216,49 +214,49 @@ private data class CachedSong(
* unstable and should only be used for accessing the audio file.
*/
@PrimaryKey var mediaStoreId: Long,
/** @see Song.dateAdded */
/** @see RealSong.Raw.dateAdded */
var dateAdded: Long,
/** The latest date the [Song]'s audio file was modified, as a unix epoch timestamp. */
var dateModified: Long,
/** @see Song.size */
/** @see RealSong.Raw.size */
var size: Long? = null,
/** @see Song.durationMs */
/** @see RealSong.Raw */
var durationMs: Long,
/** @see Music.UID */
/** @see RealSong.Raw.musicBrainzId */
var musicBrainzId: String? = null,
/** @see Music.rawName */
/** @see RealSong.Raw.name */
var name: String,
/** @see Music.rawSortName */
/** @see RealSong.Raw.sortName */
var sortName: String? = null,
/** @see Song.track */
/** @see RealSong.Raw.track */
var track: Int? = null,
/** @see Disc.number */
/** @see RealSong.Raw.name */
var disc: Int? = null,
/** @See Disc.name */
/** @See RealSong.Raw.subtitle */
var subtitle: String? = null,
/** @see Song.date */
/** @see RealSong.Raw.date */
var date: Date? = null,
/** @see Album.Raw.musicBrainzId */
/** @see RealSong.Raw.albumMusicBrainzId */
var albumMusicBrainzId: String? = null,
/** @see Album.Raw.name */
/** @see RealSong.Raw.albumName */
var albumName: String,
/** @see Album.Raw.sortName */
/** @see RealSong.Raw.albumSortName */
var albumSortName: String? = null,
/** @see Album.Raw.releaseType */
/** @see RealSong.Raw.releaseTypes */
var releaseTypes: List<String> = listOf(),
/** @see Artist.Raw.musicBrainzId */
/** @see RealSong.Raw.artistMusicBrainzIds */
var artistMusicBrainzIds: List<String> = listOf(),
/** @see Artist.Raw.name */
/** @see RealSong.Raw.artistNames */
var artistNames: List<String> = listOf(),
/** @see Artist.Raw.sortName */
/** @see RealSong.Raw.artistSortNames */
var artistSortNames: List<String> = listOf(),
/** @see Artist.Raw.musicBrainzId */
/** @see RealSong.Raw.albumArtistMusicBrainzIds */
var albumArtistMusicBrainzIds: List<String> = listOf(),
/** @see Artist.Raw.name */
/** @see RealSong.Raw.albumArtistNames */
var albumArtistNames: List<String> = listOf(),
/** @see Artist.Raw.sortName */
/** @see RealSong.Raw.albumArtistSortNames */
var albumArtistSortNames: List<String> = listOf(),
/** @see Genre.Raw.name */
/** @see RealSong.Raw.genreNames */
var genreNames: List<String> = listOf()
) {
fun copyToRaw(rawSong: RealSong.Raw): CachedSong {

View file

@ -125,7 +125,7 @@ sealed class ReleaseType {
}
/**
* A Mix-tape. These are usually [EP]-sized releases of music made to promote an [Artist] or a
* A Mix-tape. These are usually [EP]-sized releases of music made to promote an Artist or a
* future release.
*/
object Mixtape : ReleaseType() {
@ -141,7 +141,7 @@ sealed class ReleaseType {
/** A release consisting of a live performance */
LIVE,
/** A release consisting of another [Artist]s remix of a prior performance. */
/** A release consisting of another Artists remix of a prior performance. */
REMIX
}

View file

@ -86,8 +86,7 @@ interface Library {
}
private class RealLibrary(rawSongs: List<RealSong.Raw>, settings: MusicSettings) : Library {
override val songs =
Sort(Sort.Mode.ByName, true).songs(rawSongs.map { RealSong(it, settings) }.distinct())
override val songs = buildSongs(rawSongs, settings)
override val albums = buildAlbums(songs)
override val artists = buildArtists(songs, albums)
override val genres = buildGenres(songs)
@ -124,6 +123,16 @@ private class RealLibrary(rawSongs: List<RealSong.Raw>, settings: MusicSettings)
songs.find { it.path.name == displayName && it.size == size }
}
/**
* Build a list [RealSong]s from the given [RealSong.Raw].
* @param rawSongs The [RealSong.Raw]s to build the [RealSong]s from.
* @param settings [MusicSettings] required to build [RealSong]s.
* @return A sorted list of [RealSong]s derived from the [RealSong.Raw] that should be suitable
* for grouping.
*/
private fun buildSongs(rawSongs: List<RealSong.Raw>, settings: MusicSettings) =
Sort(Sort.Mode.ByName, true).songs(rawSongs.map { RealSong(it, settings) }.distinct())
/**
* Build a list of [Album]s from the given [Song]s.
* @param songs The [Song]s to build [Album]s from. These will be linked with their respective

View file

@ -96,7 +96,7 @@ fun List<String>.correctWhitespace() = mapNotNull { it.correctWhitespace() }
/**
* Attempt to parse a string by the user's separator preferences.
* @param settings [Settings] required to obtain user separator configuration.
* @param settings [MusicSettings] required to obtain user separator configuration.
* @return A list of one or more [String]s that were split up by the user-defined separators.
*/
private fun String.maybeParseBySeparators(settings: MusicSettings): List<String> {

View file

@ -186,8 +186,9 @@ class EditableQueue : Queue {
/**
* Add [Song]s to the top of the queue. Will start playback if nothing is playing.
* @param songs The [Song]s to add.
* @return [ChangeResult.MAPPING] if added to an existing queue, or [ChangeResult.SONG] if there
* was no prior playback and these enqueued [Song]s start new playback.
* @return [Queue.ChangeResult.MAPPING] if added to an existing queue, or
* [Queue.ChangeResult.SONG] if there was no prior playback and these enqueued [Song]s start new
* playback.
*/
fun playNext(songs: List<Song>): Queue.ChangeResult {
if (orderedMapping.isEmpty()) {

View file

@ -129,7 +129,7 @@ class WidgetComponent(private val context: Context) :
/**
* A condensed form of the playback state that is safe to use in AppWidgets.
* @param song [PlaybackStateManager.song]
* @param song [Queue.currentSong]
* @param cover A pre-loaded album cover [Bitmap] for [song].
* @param isPlaying [PlaybackStateManager.playerState]
* @param repeatMode [PlaybackStateManager.repeatMode]

View file

@ -12,13 +12,14 @@
android:layout_height="match_parent">
<TextView
style="@style/Widget.Auxio.TextView.Header"
android:id="@+id/dirs_mode_header"
style="@style/Widget.Auxio.TextView.Header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="@dimen/spacing_large"
android:paddingEnd="@dimen/spacing_large"
android:text="@string/set_dirs_mode" />
android:text="@string/set_dirs_mode"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.button.MaterialButtonToggleGroup

View file

@ -51,23 +51,23 @@ class MusicTest {
@Test
fun albumRaw_equals_inconsistentCase() {
val a =
Album.Raw(
RealAlbum.Raw(
mediaStoreId = -1,
musicBrainzId = null,
name = "Paraglow",
sortName = null,
releaseType = null,
rawArtists =
listOf(Artist.Raw(name = "Parannoul"), Artist.Raw(name = "Asian Glow")))
listOf(RealArtist.Raw(name = "Parannoul"), RealArtist.Raw(name = "Asian Glow")))
val b =
Album.Raw(
RealAlbum.Raw(
mediaStoreId = -1,
musicBrainzId = null,
name = "paraglow",
sortName = null,
releaseType = null,
rawArtists =
listOf(Artist.Raw(name = "Parannoul"), Artist.Raw(name = "Asian glow")))
listOf(RealArtist.Raw(name = "Parannoul"), RealArtist.Raw(name = "Asian glow")))
assertTrue(a == b)
assertTrue(a.hashCode() == b.hashCode())
}
@ -75,21 +75,21 @@ class MusicTest {
@Test
fun albumRaw_equals_withMbids() {
val a =
Album.Raw(
RealAlbum.Raw(
mediaStoreId = -1,
musicBrainzId = UUID.fromString("c7b245c9-8099-32ea-af95-893acedde2cf"),
name = "Weezer",
sortName = "Blue Album",
releaseType = null,
rawArtists = listOf(Artist.Raw(name = "Weezer")))
rawArtists = listOf(RealArtist.Raw(name = "Weezer")))
val b =
Album.Raw(
RealAlbum.Raw(
mediaStoreId = -1,
musicBrainzId = UUID.fromString("923d5ba6-7eee-3bce-bcb2-c913b2bd69d4"),
name = "Weezer",
sortName = "Green Album",
releaseType = null,
rawArtists = listOf(Artist.Raw(name = "Weezer")))
rawArtists = listOf(RealArtist.Raw(name = "Weezer")))
assertTrue(a != b)
assertTrue(a.hashCode() != b.hashCode())
}
@ -97,51 +97,51 @@ class MusicTest {
@Test
fun albumRaw_equals_inconsistentMbids() {
val a =
Album.Raw(
RealAlbum.Raw(
mediaStoreId = -1,
musicBrainzId = UUID.fromString("c7b245c9-8099-32ea-af95-893acedde2cf"),
name = "Weezer",
sortName = "Blue Album",
releaseType = null,
rawArtists = listOf(Artist.Raw(name = "Weezer")))
rawArtists = listOf(RealArtist.Raw(name = "Weezer")))
val b =
Album.Raw(
RealAlbum.Raw(
mediaStoreId = -1,
musicBrainzId = null,
name = "Weezer",
sortName = "Green Album",
releaseType = null,
rawArtists = listOf(Artist.Raw(name = "Weezer")))
rawArtists = listOf(RealArtist.Raw(name = "Weezer")))
assertTrue(a != b)
assertTrue(a.hashCode() != b.hashCode())
}
@Test
fun albumRaw_equals_withArtists() {
fun albumRaw_equals_withRealArtists() {
val a =
Album.Raw(
RealAlbum.Raw(
mediaStoreId = -1,
musicBrainzId = null,
name = "Album",
sortName = null,
releaseType = null,
rawArtists = listOf(Artist.Raw(name = "Artist A")))
rawArtists = listOf(RealArtist.Raw(name = "RealArtist A")))
val b =
Album.Raw(
RealAlbum.Raw(
mediaStoreId = -1,
musicBrainzId = null,
name = "Album",
sortName = null,
releaseType = null,
rawArtists = listOf(Artist.Raw(name = "Artist B")))
rawArtists = listOf(RealArtist.Raw(name = "RealArtist B")))
assertTrue(a != b)
assertTrue(a.hashCode() != b.hashCode())
}
@Test
fun artistRaw_equals_inconsistentCase() {
val a = Artist.Raw(musicBrainzId = null, name = "Parannoul")
val b = Artist.Raw(musicBrainzId = null, name = "parannoul")
val a = RealArtist.Raw(musicBrainzId = null, name = "Parannoul")
val b = RealArtist.Raw(musicBrainzId = null, name = "parannoul")
assertTrue(a == b)
assertTrue(a.hashCode() == b.hashCode())
}
@ -149,11 +149,11 @@ class MusicTest {
@Test
fun artistRaw_equals_withMbids() {
val a =
Artist.Raw(
RealArtist.Raw(
musicBrainzId = UUID.fromString("677325ef-d850-44bb-8258-0d69bbc0b3f7"),
name = "Artist")
val b =
Artist.Raw(
RealArtist.Raw(
musicBrainzId = UUID.fromString("6b625592-d88d-48c8-ac1a-c5b476d78bcc"),
name = "Artist")
assertTrue(a != b)
@ -163,50 +163,50 @@ class MusicTest {
@Test
fun artistRaw_equals_inconsistentMbids() {
val a =
Artist.Raw(
RealArtist.Raw(
musicBrainzId = UUID.fromString("677325ef-d850-44bb-8258-0d69bbc0b3f7"),
name = "Artist")
val b = Artist.Raw(musicBrainzId = null, name = "Artist")
val b = RealArtist.Raw(musicBrainzId = null, name = "Artist")
assertTrue(a != b)
assertTrue(a.hashCode() != b.hashCode())
}
@Test
fun artistRaw_equals_missingNames() {
val a = Artist.Raw(name = null)
val b = Artist.Raw(name = null)
val a = RealArtist.Raw(name = null)
val b = RealArtist.Raw(name = null)
assertTrue(a == b)
assertTrue(a.hashCode() == b.hashCode())
}
@Test
fun artistRaw_equals_inconsistentNames() {
val a = Artist.Raw(name = null)
val b = Artist.Raw(name = "Parannoul")
val a = RealArtist.Raw(name = null)
val b = RealArtist.Raw(name = "Parannoul")
assertTrue(a != b)
assertTrue(a.hashCode() != b.hashCode())
}
@Test
fun genreRaw_equals_inconsistentCase() {
val a = Genre.Raw("Future Garage")
val b = Genre.Raw("future garage")
val a = RealGenre.Raw("Future Garage")
val b = RealGenre.Raw("future garage")
assertTrue(a == b)
assertTrue(a.hashCode() == b.hashCode())
}
@Test
fun genreRaw_equals_missingNames() {
val a = Genre.Raw(name = null)
val b = Genre.Raw(name = null)
val a = RealGenre.Raw(name = null)
val b = RealGenre.Raw(name = null)
assertTrue(a == b)
assertTrue(a.hashCode() == b.hashCode())
}
@Test
fun genreRaw_equals_inconsistentNames() {
val a = Genre.Raw(name = null)
val b = Genre.Raw(name = "Future Garage")
val a = RealGenre.Raw(name = null)
val b = RealGenre.Raw(name = "Future Garage")
assertTrue(a != b)
assertTrue(a.hashCode() != b.hashCode())
}