media: the title and seek bar move to the top, so play, next and the buttons under them can be bigger

This commit is contained in:
Seb3thehacker committed 2026-10-26 20:39:43 -07:00
1 parent de370751a0
commit 746b0b7325
2 files changed
+26 -26

No files matched your search

@@ -675,29 +675,29 @@ private fun CoverArt(art: android.graphics.Bitmap?, modifier: Modifier, alignmen
} }
/** /**
* Now playing beside the big cover: the title in large type, then the seek bar and every control, * Now playing beside the big cover: the title, artist and seek bar along the top, and the
* all settled at the bottom. On a wide screen the transport and like, shuffle and repeat share * controls in two rows under them, as big as the height left over allows - the transport, then
* one row; narrower, they take a row each. * like, shuffle, repeat and the app's own buttons.
*/ */
@Composable @Composable
private fun StageControls(now: NowPlaying, media: CarMedia, modifier: Modifier) { private fun StageControls(now: NowPlaying, media: CarMedia, modifier: Modifier) {
BoxWithConstraints(modifier) { BoxWithConstraints(modifier) {
val oneRow = maxWidth >= 820.dp // Short of height (a small screen, or Extra large size), the title steps down a size.
// Short of height (a small screen, or Extra large size), everything steps down a size.
val compact = maxHeight < 360.dp val compact = maxHeight < 360.dp
val showTimes = maxHeight >= 260.dp val showTimes = maxHeight >= 260.dp
val gap = if (compact) 8.dp else 16.dp val titleRoom = maxHeight * 0.4f
Column( Column(Modifier.fillMaxSize().padding(start = 4.dp, end = 4.dp, bottom = 4.dp)) {
Modifier.fillMaxSize().padding(start = 4.dp, end = 4.dp, bottom = 4.dp), // The title gives up its height first and scrolls, so the controls keep theirs.
verticalArrangement = Arrangement.spacedBy(gap, Alignment.Bottom), Column(Modifier.heightIn(max = titleRoom).verticalScroll(rememberScrollState())) {
) {
// The title gives up its height first and scrolls, so the controls never leave the screen.
Column(Modifier.weight(1f, fill = false).verticalScroll(rememberScrollState())) {
Text( Text(
now.title.ifEmpty { stringResource(R.string.media_nothing_playing) }, now.title.ifEmpty { stringResource(R.string.media_nothing_playing) },
style = MaterialTheme.typography.displaySmall, fontWeight = FontWeight.Bold, style = MaterialTheme.typography.displaySmall, fontWeight = FontWeight.Bold,
maxLines = 2, overflow = TextOverflow.Ellipsis, maxLines = 2, overflow = TextOverflow.Ellipsis,
autoSize = TextAutoSize.StepBased(minFontSize = 22.sp, maxFontSize = MaterialTheme.typography.displaySmall.fontSize, stepSize = 2.sp), autoSize = TextAutoSize.StepBased(
minFontSize = if (compact) 20.sp else 22.sp,
maxFontSize = MaterialTheme.typography.displaySmall.fontSize,
stepSize = 2.sp,
),
) )
Text( Text(
listOf(now.artist, now.album).filter { it.isNotEmpty() }.joinToString(" · "), listOf(now.artist, now.album).filter { it.isNotEmpty() }.joinToString(" · "),
@@ -713,17 +713,17 @@ private fun StageControls(now: NowPlaying, media: CarMedia, modifier: Modifier)
) )
} }
} }
PlayerProgress(now, media, Modifier.fillMaxWidth(), showTimes = showTimes) PlayerProgress(now, media, Modifier.fillMaxWidth().padding(top = if (compact) 4.dp else 12.dp), showTimes = showTimes)
val skip = if (compact) 48.dp else 64.dp // What's left goes to the buttons: play takes about half of it, the row below a third,
val mode = if (compact) 46.dp else 54.dp // and neither grows past what a row of them fits across.
if (oneRow) { BoxWithConstraints(Modifier.weight(1f).fillMaxWidth(), contentAlignment = Alignment.Center) {
Row(verticalAlignment = Alignment.CenterVertically) { val gap = (maxHeight * 0.08f).coerceIn(6.dp, 20.dp)
TransportRow(now, media, skip = if (compact) skip else 66.dp, modifier = Modifier.weight(1f)) val play = minOf(maxHeight * 0.5f, maxWidth / 3.2f, 128.dp).coerceAtLeast(56.dp)
PlayModeRow(now, media, size = mode, modifier = Modifier.weight(1f), maxOther = 2) val mode = minOf(maxHeight * 0.32f, maxWidth / 6.5f, 80.dp).coerceAtLeast(44.dp)
Column(verticalArrangement = Arrangement.spacedBy(gap), horizontalAlignment = Alignment.CenterHorizontally) {
TransportRow(now, media, skip = play / 1.5f, playScale = 1.5f, modifier = Modifier.fillMaxWidth())
PlayModeRow(now, media, size = mode, modifier = Modifier.fillMaxWidth(), maxOther = 2)
} }
} else {
TransportRow(now, media, skip = skip, modifier = Modifier.fillMaxWidth())
PlayModeRow(now, media, size = mode, modifier = Modifier.fillMaxWidth(), maxOther = 2)
} }
} }
} }
@@ -96,10 +96,10 @@ internal fun formatDuration(ms: Long): String {
return if (hours > 0) "%d:%02d:%02d".format(hours, minutes, seconds) else "%d:%02d".format(minutes, seconds) return if (hours > 0) "%d:%02d:%02d".format(hours, minutes, seconds) else "%d:%02d".format(minutes, seconds)
} }
/** Previous, play/pause, next. [skip] sizes the outer two; play is a step bigger. */ /** Previous, play/pause, next. [skip] sizes the outer two; play is [playScale] times bigger. */
@Composable @Composable
internal fun TransportRow(now: NowPlaying, media: CarMedia, skip: Dp, modifier: Modifier = Modifier) { internal fun TransportRow(now: NowPlaying, media: CarMedia, skip: Dp, modifier: Modifier = Modifier, playScale: Float = 1.25f) {
val play = skip * 1.25f val play = skip * playScale
Row(modifier, horizontalArrangement = Arrangement.SpaceEvenly, verticalAlignment = Alignment.CenterVertically) { Row(modifier, horizontalArrangement = Arrangement.SpaceEvenly, verticalAlignment = Alignment.CenterVertically) {
GsIconButton( GsIconButton(
MediaIcons.Previous, stringResource(R.string.player_previous), media::previous, MediaIcons.Previous, stringResource(R.string.player_previous), media::previous,