diff --git a/gearslip/src/main/java/app/seb3thehacker/gearslip/car/MediaBrowse.kt b/gearslip/src/main/java/app/seb3thehacker/gearslip/car/MediaBrowse.kt index 38560ad..d434840 100644 --- a/gearslip/src/main/java/app/seb3thehacker/gearslip/car/MediaBrowse.kt +++ b/gearslip/src/main/java/app/seb3thehacker/gearslip/car/MediaBrowse.kt @@ -84,14 +84,15 @@ internal fun BrowsePanel(browse: app.seb3thehacker.gearslip.media.BrowseState, m // row could say that the app's name in the top-left corner hasn't already - showing it // again here (as "Browse", or as the app's own name) was just the same label twice. if (media.canGoUp || browse.trail.isNotEmpty()) { - Row(verticalAlignment = Alignment.CenterVertically) { + Row(Modifier.padding(bottom = 12.dp), verticalAlignment = Alignment.CenterVertically) { if (media.canGoUp) { - GsIconButton(Icons.Filled.ArrowBack, "Up", media::up) + GsIconButton(Icons.Filled.ArrowBack, "Up", media::up, size = 44.dp, shape = CircleShape) + Spacer(Modifier.width(14.dp)) } browse.trail.lastOrNull()?.let { Text( it, - style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.SemiBold, + style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold, maxLines = 1, overflow = TextOverflow.Ellipsis, ) } @@ -251,9 +252,9 @@ private fun QueueRow(track: QueueTrack, media: CarMedia) { color = MaterialTheme.colorScheme.surfaceContainer, modifier = Modifier.fillMaxWidth(), ) { - Row(Modifier.padding(10.dp), verticalAlignment = Alignment.CenterVertically) { + Row(Modifier.padding(8.dp), verticalAlignment = Alignment.CenterVertically) { RowArt(icon, MediaIcons.MusicNote) - Column(Modifier.weight(1f).padding(horizontal = 12.dp)) { + Column(Modifier.weight(1f).padding(horizontal = 14.dp)) { Text(track.title, style = MaterialTheme.typography.titleMedium, maxLines = 1, overflow = TextOverflow.Ellipsis) if (track.subtitle.isNotEmpty()) { Text(track.subtitle, style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant, maxLines = 1, overflow = TextOverflow.Ellipsis) @@ -276,9 +277,9 @@ internal fun EntryRow(entry: MediaEntry, media: CarMedia, onClick: () -> Unit = color = MaterialTheme.colorScheme.surfaceContainer, modifier = Modifier.fillMaxWidth(), ) { - Row(Modifier.padding(10.dp), verticalAlignment = Alignment.CenterVertically) { + Row(Modifier.padding(8.dp), verticalAlignment = Alignment.CenterVertically) { RowArt(icon, if (entry.browsable) MediaIcons.Folder else MediaIcons.MusicNote) - Column(Modifier.weight(1f).padding(horizontal = 12.dp)) { + Column(Modifier.weight(1f).padding(horizontal = 14.dp)) { Text(entry.title, style = MaterialTheme.typography.titleMedium, maxLines = 1, overflow = TextOverflow.Ellipsis) if (entry.subtitle.isNotEmpty()) { Text(entry.subtitle, style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant, maxLines = 1, overflow = TextOverflow.Ellipsis) @@ -296,7 +297,7 @@ internal fun EntryRow(entry: MediaEntry, media: CarMedia, onClick: () -> Unit = @Composable private fun RowArt(icon: android.graphics.Bitmap?, fallback: ImageVector) { Box( - Modifier.size(62.dp).clip(MaterialTheme.shapes.medium).background(MaterialTheme.colorScheme.surfaceContainerHigh), + Modifier.size(56.dp).clip(RoundedCornerShape(12.dp)).background(MaterialTheme.colorScheme.surfaceContainerHigh), contentAlignment = Alignment.Center, ) { if (icon != null) Image(icon.asImageBitmap(), null, Modifier.fillMaxSize(), contentScale = ContentScale.Crop) diff --git a/gearslip/src/main/java/app/seb3thehacker/gearslip/car/MediaScreen.kt b/gearslip/src/main/java/app/seb3thehacker/gearslip/car/MediaScreen.kt index ea66bdd..9135927 100644 --- a/gearslip/src/main/java/app/seb3thehacker/gearslip/car/MediaScreen.kt +++ b/gearslip/src/main/java/app/seb3thehacker/gearslip/car/MediaScreen.kt @@ -175,14 +175,14 @@ fun MediaScreen(app: MediaApp, onExit: () -> Unit) { if (tab == Tab.NOW_PLAYING) { CoverArt(art, Modifier.weight(1f).fillMaxWidth()) } else { - CompactPlayer(now, media, Modifier.weight(1f).fillMaxWidth()) + CompactPlayer(now, media, art, Modifier.weight(1f).fillMaxWidth()) } } Column(Modifier.weight(1.2f).fillMaxHeight()) { Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(8.dp)) { MediaTab("Now playing", tab == Tab.NOW_PLAYING, Modifier.weight(1f)) { tab = Tab.NOW_PLAYING } - MediaTab("Browse", tab == Tab.BROWSE, Modifier.weight(1f)) { tab = Tab.BROWSE } MediaTab("Up next", tab == Tab.QUEUE, Modifier.weight(1f)) { tab = Tab.QUEUE } + MediaTab("Browse", tab == Tab.BROWSE, Modifier.weight(1f)) { tab = Tab.BROWSE } MediaTab("Lyrics", tab == Tab.LYRICS, Modifier.weight(1f)) { tab = Tab.LYRICS } if (now.canSearch || media.canSearchLibrary) { GsIconButton( @@ -603,8 +603,8 @@ internal fun NowPlayingPage(now: NowPlaying, media: CarMedia, modifier: Modifier /** The cover, as big a square as its space allows, centred in it. */ @Composable -private fun CoverArt(art: android.graphics.Bitmap?, modifier: Modifier) { - BoxWithConstraints(modifier, contentAlignment = Alignment.Center) { +private fun CoverArt(art: android.graphics.Bitmap?, modifier: Modifier, alignment: Alignment = Alignment.Center) { + BoxWithConstraints(modifier, contentAlignment = alignment) { val shape = RoundedCornerShape(22.dp) Surface( shape = shape, @@ -707,30 +707,33 @@ private fun NowPlayingControls(now: NowPlaying, media: CarMedia, modifier: Modif } /** - * The player beside the browse list, the queue and the lyrics: no art, which the list needs the - * room for, just what's playing, the seek bar and the controls. + * The player beside the browse list, the queue and the lyrics: the same card as beside the map on + * Home, the cover taking whatever the title and controls leave, so every tab keeps the song in + * sight and the controls in one place. */ @Composable -private fun CompactPlayer(now: NowPlaying, media: CarMedia, modifier: Modifier) { - Column( - modifier.verticalScroll(rememberScrollState()), - verticalArrangement = Arrangement.spacedBy(14.dp), - ) { - Column { +private fun CompactPlayer(now: NowPlaying, media: CarMedia, art: android.graphics.Bitmap?, modifier: Modifier) { + val shape = RoundedCornerShape(24.dp) + Surface(modifier.gsPanelShadow(shape), shape = shape, color = MaterialTheme.colorScheme.surfaceContainer) { + AlbumGlow(art, Modifier.fillMaxSize()) + Column(Modifier.fillMaxSize().padding(14.dp), horizontalAlignment = Alignment.CenterHorizontally) { + CoverArt(art, Modifier.weight(1f).fillMaxWidth(), Alignment.BottomCenter) + Spacer(Modifier.height(10.dp)) Text( now.title.ifEmpty { "Nothing playing" }, - style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold, - maxLines = 2, overflow = TextOverflow.Ellipsis, + style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold, + maxLines = 1, overflow = TextOverflow.Ellipsis, ) Text( now.artist, - style = MaterialTheme.typography.bodyLarge, color = MaterialTheme.colorScheme.onSurfaceVariant, + style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant, maxLines = 1, overflow = TextOverflow.Ellipsis, ) + PlayerProgress(now, media, Modifier.fillMaxWidth().padding(vertical = 2.dp), showTimes = false) + TransportRow(now, media, skip = 52.dp, modifier = Modifier.fillMaxWidth()) + Spacer(Modifier.height(8.dp)) + PlayModeRow(now, media, size = 46.dp, modifier = Modifier.fillMaxWidth()) } - PlayerProgress(now, media, Modifier.fillMaxWidth()) - TransportRow(now, media, skip = 52.dp, modifier = Modifier.fillMaxWidth()) - PlayModeRow(now, media, size = 48.dp, modifier = Modifier.fillMaxWidth()) } }