suffix repeated disc titles with their disc number

When two discs of an album share a title, showing "Live" alone is
ambiguous, so render "Live: Disc 1"/"Live: Disc 2". Unique titles stay
as-is. Also drop the header from titleLarge to a semibold titleMedium so
longer titles fit on one line.
This commit is contained in:
austinried
2026-10-04 00:29:57 +00:00
parent 863c17be7d
commit 33e47e9654
2 changed files with 35 additions and 10 deletions
@@ -8,6 +8,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.subtracks.data.model.Album import com.subtracks.data.model.Album
@@ -72,7 +73,23 @@ fun AlbumDetailScreen(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
val multiDisc = songs.map { it.disc ?: 1L }.distinct().size > 1 val multiDisc = songs.map { it.disc ?: 1L }.distinct().size > 1
val discTitles = remember(discs) { discs.associate { it.disc to it.title } } val discLabels =
remember(discs) {
val repeated =
discs
.map { it.title }
.filter { it.isNotBlank() }
.groupingBy { it }
.eachCount()
.filterValues { it > 1 }
.keys
discs.associate { disc ->
disc.disc to
disc.title.takeIf { it.isNotBlank() }?.let { title ->
if (title in repeated) "$title: Disc ${disc.disc}" else title
}
}
}
HeroDetailScaffold( HeroDetailScaffold(
artwork = artwork, artwork = artwork,
title = album?.name.orEmpty(), title = album?.name.orEmpty(),
@@ -100,9 +117,9 @@ fun AlbumDetailScreen(
var lastDisc: Long? = null var lastDisc: Long? = null
songs.forEachIndexed { index, song -> songs.forEachIndexed { index, song ->
val disc = song.disc ?: 1L val disc = song.disc ?: 1L
val discTitle = discTitles[disc] val discLabel = discLabels[disc]
if (disc != lastDisc && (multiDisc || !discTitle.isNullOrBlank())) { if (disc != lastDisc && (multiDisc || discLabel != null)) {
item(key = "disc:$disc") { DiscHeader(disc, discTitle) } item(key = "disc:$disc") { DiscHeader(discLabel ?: "Disc $disc") }
} }
lastDisc = disc lastDisc = disc
item(key = song.id) { item(key = song.id) {
@@ -120,13 +137,11 @@ fun AlbumDetailScreen(
} }
@Composable @Composable
private fun DiscHeader( private fun DiscHeader(text: String) {
disc: Long,
title: String?,
) {
Text( Text(
text = title?.takeIf { it.isNotBlank() } ?: "Disc $disc", text = text,
style = MaterialTheme.typography.titleLarge, style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.SemiBold,
color = MaterialTheme.colorScheme.onSurfaceVariant, color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 20.dp, bottom = 4.dp), modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 20.dp, bottom = 4.dp),
) )
@@ -44,6 +44,16 @@ class AlbumDiscsTest {
assertEquals(0, nodesWithText("Disc 1")) assertEquals(0, nodesWithText("Disc 1"))
} }
@Test
fun repeatedDiscTitlesGetTheDiscNumber() {
setContent(
listOf(song("s-a", disc = 1, track = 1), song("s-b", disc = 2, track = 1)),
discs = listOf(disc(1, "Live"), disc(2, "Live")),
)
assertEquals(1, nodesWithText("Live: Disc 1"))
assertEquals(1, nodesWithText("Live: Disc 2"))
}
@Test @Test
fun discHeadersFallBackToTheDiscNumber() { fun discHeadersFallBackToTheDiscNumber() {
setContent(listOf(song("s-a", disc = 1, track = 1), song("s-b", disc = 2, track = 1))) setContent(listOf(song("s-a", disc = 1, track = 1), song("s-b", disc = 2, track = 1)))