music: add support for compilation sub-types

Add support for compilation + live, compilation + remix,
and compilation + dj-mix release types.

This was not included due to the changes it required to the
parser. Turns out these changes are largely trivial if I do
more clever inlining.
This commit is contained in:
Alexander Capehart 2022-09-14 10:16:02 -06:00
parent 780e0dce06
commit 33b0aabc44
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
4 changed files with 69 additions and 27 deletions

View file

@ -7,6 +7,7 @@
#### What's Improved #### What's Improved
- Sorting now takes accented characters into account - Sorting now takes accented characters into account
- Added support for compilation sub-release-types like (DJ) Mix
#### What's Fixed #### What's Fixed
- Fixed issue where the scroll popup would not display correctly in landscape mode [#230] - Fixed issue where the scroll popup would not display correctly in landscape mode [#230]

View file

@ -245,22 +245,23 @@ class DetailViewModel(application: Application) :
val byReleaseGroup = val byReleaseGroup =
albums.groupBy { albums.groupBy {
when (it.releaseType.refinement) { when (it.releaseType.refinement) {
ReleaseType.Refinement.LIVE -> R.string.lbl_live_group ReleaseType.Refinement.LIVE -> ReleaseTypeGrouping.LIVE
ReleaseType.Refinement.REMIX -> R.string.lbl_remix_group ReleaseType.Refinement.REMIX -> ReleaseTypeGrouping.REMIXES
null -> null ->
when (it.releaseType) { when (it.releaseType) {
is ReleaseType.Album -> R.string.lbl_albums is ReleaseType.Album -> ReleaseTypeGrouping.ALBUMS
is ReleaseType.EP -> R.string.lbl_eps is ReleaseType.EP -> ReleaseTypeGrouping.EPS
is ReleaseType.Single -> R.string.lbl_singles is ReleaseType.Single -> ReleaseTypeGrouping.SINGLES
is ReleaseType.Compilation -> R.string.lbl_compilations is ReleaseType.Compilation -> ReleaseTypeGrouping.COMPILATIONS
is ReleaseType.Soundtrack -> R.string.lbl_soundtracks is ReleaseType.Soundtrack -> ReleaseTypeGrouping.SOUNDTRACKS
is ReleaseType.Mixtape -> R.string.lbl_mixtapes is ReleaseType.Mix -> ReleaseTypeGrouping.MIXES
is ReleaseType.Mixtape -> ReleaseTypeGrouping.MIXTAPES
} }
} }
} }
for (entry in byReleaseGroup.entries.sortedBy { it.key }) { for (entry in byReleaseGroup.entries.sortedBy { it.key }) {
data.add(Header(entry.key)) data.add(Header(entry.key.string))
data.addAll(entry.value) data.addAll(entry.value)
} }
@ -324,6 +325,18 @@ class DetailViewModel(application: Application) :
override fun onCleared() { override fun onCleared() {
musicStore.removeCallback(this) musicStore.removeCallback(this)
} }
private enum class ReleaseTypeGrouping(@StringRes val string: Int) {
ALBUMS(R.string.lbl_albums),
EPS(R.string.lbl_eps),
SINGLES(R.string.lbl_singles),
COMPILATIONS(R.string.lbl_compilations),
SOUNDTRACKS(R.string.lbl_compilations),
MIXES(R.string.lbl_mixes),
MIXTAPES(R.string.lbl_mixtapes),
LIVE(R.string.lbl_live_group),
REMIXES(R.string.lbl_remix_group),
}
} }
data class SortHeader(@StringRes val string: Int) : Item data class SortHeader(@StringRes val string: Int) : Item

View file

@ -771,12 +771,13 @@ sealed class ReleaseType {
} }
} }
object Compilation : ReleaseType() { data class Compilation(override val refinement: Refinement?) : ReleaseType() {
override val refinement: Refinement?
get() = null
override val stringRes: Int override val stringRes: Int
get() = R.string.lbl_compilation get() = when (refinement) {
null -> R.string.lbl_compilation
Refinement.LIVE -> R.string.lbl_compilation_live
Refinement.REMIX -> R.string.lbl_compilation_remix
}
} }
object Soundtrack : ReleaseType() { object Soundtrack : ReleaseType() {
@ -787,6 +788,14 @@ sealed class ReleaseType {
get() = R.string.lbl_soundtrack get() = R.string.lbl_soundtrack
} }
object Mix : ReleaseType() {
override val refinement: Refinement?
get() = null
override val stringRes: Int
get() = R.string.lbl_mix
}
object Mixtape : ReleaseType() { object Mixtape : ReleaseType() {
override val refinement: Refinement? override val refinement: Refinement?
get() = null get() = null
@ -806,6 +815,9 @@ sealed class ReleaseType {
} }
companion object { companion object {
// Note: The parsing code is extremely clever in order to reduce duplication. It's
// better just to read the specification behind release types than follow this code.
fun parse(types: List<String>): ReleaseType { fun parse(types: List<String>): ReleaseType {
val primary = types[0] val primary = types[0]
@ -823,22 +835,31 @@ sealed class ReleaseType {
private inline fun List<String>.parseSecondaryTypes( private inline fun List<String>.parseSecondaryTypes(
secondaryIdx: Int, secondaryIdx: Int,
target: (Refinement?) -> ReleaseType convertRefinement: (Refinement?) -> ReleaseType
): ReleaseType { ): ReleaseType {
val secondary = (getOrNull(secondaryIdx) ?: return target(null)) val secondary = getOrNull(secondaryIdx)
return when { return if (secondary.equals("compilation", true)) {
// Compilation is the only weird secondary release type, as it could // Secondary type is a compilation, actually parse the third type
// theoretically have additional modifiers including soundtrack, remix, // and put that into a compilation if needed.
// live, dj-mix, etc. However, since there is no real demand for me to parseSecondaryTypeImpl(getOrNull(secondaryIdx + 1)) { Compilation(it) }
// respond to those, I don't implement them simply for simplicity. } else {
secondary.equals("compilation", true) -> Compilation // Secondary type is a plain value, use the original values given.
secondary.equals("soundtrack", true) -> Soundtrack parseSecondaryTypeImpl(secondary, convertRefinement)
secondary.equals("mixtape/street", true) -> Mixtape
secondary.equals("live", true) -> target(Refinement.LIVE)
secondary.equals("remix", true) -> target(Refinement.REMIX)
else -> target(null)
} }
} }
private inline fun parseSecondaryTypeImpl(
type: String?,
convertRefinement: (Refinement?) -> ReleaseType
) = when {
// Parse all the types that have no children
type.equals("soundtrack", true) -> Soundtrack
type.equals("mixtape/street", true) -> Mixtape
type.equals("dj-mix", true) -> Mix
type.equals("live", true) -> convertRefinement(Refinement.LIVE)
type.equals("remix", true) -> convertRefinement(Refinement.REMIX)
else -> convertRefinement(null)
}
} }
} }

View file

@ -51,12 +51,19 @@
<string name="lbl_compilations">Compilations</string> <string name="lbl_compilations">Compilations</string>
<!-- As in a compilation of music --> <!-- As in a compilation of music -->
<string name="lbl_compilation">Compilation</string> <string name="lbl_compilation">Compilation</string>
<!-- As in a compilation of live music -->
<string name="lbl_compilation_live">Live compilation</string>
<string name="lbl_compilation_remix">Remix compilations</string>
<string name="lbl_soundtracks">Soundtracks</string> <string name="lbl_soundtracks">Soundtracks</string>
<string name="lbl_soundtrack">Soundtrack</string> <string name="lbl_soundtrack">Soundtrack</string>
<!-- As in the collection of music --> <!-- As in the collection of music -->
<string name="lbl_mixtapes">Mixtapes</string> <string name="lbl_mixtapes">Mixtapes</string>
<!-- As in the collection of music --> <!-- As in the collection of music -->
<string name="lbl_mixtape">Mixtape</string> <string name="lbl_mixtape">Mixtape</string>
<!-- As in a compilation of several performances that blend into a single continuous flow of music -->
<string name="lbl_mixes">Mixes</string>
<!-- As in a compilation of several performances that blend into a single continuous flow of music -->
<string name="lbl_mix">Mix</string>
<!-- As in music that was performed live --> <!-- As in music that was performed live -->
<string name="lbl_live_group">Live</string> <string name="lbl_live_group">Live</string>