keep the artist title's top line clear of the shuffle button

Render the wrapped artist name as two rows: the first line spans the full
width on its own row above, and the last line shares a row with the
shuffle button, so the text can never run under it.
This commit is contained in:
austinried
2026-10-04 00:30:02 +00:00
parent af9b4e304c
commit 5c3daed968
@@ -99,6 +99,7 @@ private val ROW_GAP = 16.dp
private val SHUFFLE_WIDTH = 68.dp private val SHUFFLE_WIDTH = 68.dp
private val SHUFFLE_HEIGHT = 48.dp private val SHUFFLE_HEIGHT = 48.dp
private val SHUFFLE_ICON = 30.dp private val SHUFFLE_ICON = 30.dp
private val SHUFFLE_GAP = 12.dp
private val SHUFFLE_RESERVE = 80.dp private val SHUFFLE_RESERVE = 80.dp
internal fun estimateScrollPx( internal fun estimateScrollPx(
@@ -280,28 +281,24 @@ fun ArtistDetailScreen(
) )
} }
Box(Modifier.align(Alignment.BottomStart).fillMaxWidth()) { Box(Modifier.align(Alignment.BottomStart).fillMaxWidth()) {
HangingTitle( ArtistTitle(
text = artist?.name.orEmpty(), text = artist?.name.orEmpty(),
style = imageNameStyle, style = imageNameStyle,
color = Color.White, color = Color.White,
endReserve = SHUFFLE_RESERVE, endReserve = SHUFFLE_RESERVE,
modifier = Modifier.align(Alignment.BottomStart).fillMaxWidth().padding(TITLE_INSET), modifier = Modifier.align(Alignment.BottomStart).fillMaxWidth().padding(TITLE_INSET),
)
FilledIconButton(
onClick = onShuffle,
shape = RoundedCornerShape(24.dp),
modifier =
Modifier
.align(Alignment.BottomEnd)
.padding(end = TITLE_INSET, bottom = TITLE_INSET)
.width(SHUFFLE_WIDTH)
.height(SHUFFLE_HEIGHT),
) { ) {
Icon( FilledIconButton(
imageVector = Icons.Rounded.Shuffle, onClick = onShuffle,
contentDescription = "Shuffle artist", shape = RoundedCornerShape(24.dp),
modifier = Modifier.size(SHUFFLE_ICON), modifier = Modifier.width(SHUFFLE_WIDTH).height(SHUFFLE_HEIGHT),
) ) {
Icon(
imageVector = Icons.Rounded.Shuffle,
contentDescription = "Shuffle artist",
modifier = Modifier.size(SHUFFLE_ICON),
)
}
} }
} }
} }
@@ -425,12 +422,13 @@ fun ArtistDetailScreen(
} }
@Composable @Composable
private fun HangingTitle( private fun ArtistTitle(
text: String, text: String,
style: TextStyle, style: TextStyle,
color: Color, color: Color,
endReserve: Dp, endReserve: Dp,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
trailing: @Composable () -> Unit,
) { ) {
val measurer = rememberTextMeasurer() val measurer = rememberTextMeasurer()
val density = LocalDensity.current val density = LocalDensity.current
@@ -439,19 +437,31 @@ private fun HangingTitle(
val reserve = with(density) { endReserve.roundToPx() } val reserve = with(density) { endReserve.roundToPx() }
val lines = remember(text, style, fullWidth, reserve) { splitTitle(measurer, text, style, fullWidth, reserve) } val lines = remember(text, style, fullWidth, reserve) { splitTitle(measurer, text, style, fullWidth, reserve) }
Column { Column {
lines.forEachIndexed { index, line -> if (lines.size > 1) {
Text( Text(
text = line, text = lines.first(),
style = style, style = style,
color = color, color = color,
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
modifier = modifier = Modifier.fillMaxWidth(),
Modifier
.fillMaxWidth()
.then(if (index == lines.lastIndex) Modifier.padding(end = endReserve) else Modifier),
) )
} }
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth(),
) {
Text(
text = lines.last(),
style = style,
color = color,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.weight(1f),
)
Spacer(Modifier.width(SHUFFLE_GAP))
trailing()
}
} }
} }
} }