media: Browse and Up next run right down to the nav bar

This commit is contained in:
Seb3thehacker committed 2026-10-26 20:55:06 -07:00
1 parent 746b0b7325
commit d915b0ce45
2 files changed
+23 -13

No files matched your search

@@ -124,7 +124,11 @@ private fun BrowseList(entries: List<MediaEntry>, media: CarMedia) {
BoxWithConstraints(Modifier.fillMaxSize()) { BoxWithConstraints(Modifier.fillMaxSize()) {
val onlyGrid = sections.size == 1 && sections[0].grid && sections[0].heading == null val onlyGrid = sections.size == 1 && sections[0].grid && sections[0].heading == null
val columns = ((maxWidth + SHELF_GAP) / (SHELF_COVER + SHELF_GAP)).toInt().coerceAtLeast(2) val columns = ((maxWidth + SHELF_GAP) / (SHELF_COVER + SHELF_GAP)).toInt().coerceAtLeast(2)
LazyColumn(Modifier.fillMaxSize(), verticalArrangement = Arrangement.spacedBy(10.dp)) { LazyColumn(
Modifier.fillMaxSize(),
contentPadding = PaddingValues(bottom = 8.dp),
verticalArrangement = Arrangement.spacedBy(10.dp),
) {
sections.forEachIndexed { i, section -> sections.forEachIndexed { i, section ->
val heading = section.heading val heading = section.heading
if (heading != null && sections.getOrNull(i - 1)?.heading != heading) { if (heading != null && sections.getOrNull(i - 1)?.heading != heading) {
@@ -234,7 +238,11 @@ internal fun QueuePanel(queue: List<QueueTrack>, now: NowPlaying, media: CarMedi
stringResource(if (now.title.isEmpty()) R.string.media_queue_empty_idle else R.string.media_queue_empty_playing), stringResource(if (now.title.isEmpty()) R.string.media_queue_empty_idle else R.string.media_queue_empty_playing),
) )
} else { } else {
LazyColumn(Modifier.fillMaxSize(), verticalArrangement = Arrangement.spacedBy(8.dp)) { LazyColumn(
Modifier.fillMaxSize(),
contentPadding = PaddingValues(bottom = 8.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
items(upNext, key = { it.queueId }) { track -> QueueRow(track, media) } items(upNext, key = { it.queueId }) { track -> QueueRow(track, media) }
} }
} }
@@ -165,6 +165,10 @@ fun MediaScreen(app: MediaApp, onExit: () -> Unit) {
return@Surface return@Surface
} }
// The page runs down under the see-through nav bar, so the cover's glow carries on behind
// it; the content stops at the bar's top edge. Lists run right to it; the rest keeps a gap.
val barTop = LocalNavBarInset.current
val barInset = barTop + 8.dp
val tabs: @Composable (Modifier) -> Unit = { tabModifier -> val tabs: @Composable (Modifier) -> Unit = { tabModifier ->
MediaTab(stringResource(R.string.media_now_playing), tab == Tab.NOW_PLAYING, tabModifier) { tab = Tab.NOW_PLAYING } MediaTab(stringResource(R.string.media_now_playing), tab == Tab.NOW_PLAYING, tabModifier) { tab = Tab.NOW_PLAYING }
MediaTab(stringResource(R.string.media_up_next), tab == Tab.QUEUE, tabModifier) { tab = Tab.QUEUE } MediaTab(stringResource(R.string.media_up_next), tab == Tab.QUEUE, tabModifier) { tab = Tab.QUEUE }
@@ -186,21 +190,19 @@ fun MediaScreen(app: MediaApp, onExit: () -> Unit) {
val tabContent: @Composable (Modifier) -> Unit = { contentModifier -> val tabContent: @Composable (Modifier) -> Unit = { contentModifier ->
Box(contentModifier) { Box(contentModifier) {
when (tab) { when (tab) {
Tab.NOW_PLAYING -> StageControls(now, media, Modifier.fillMaxSize()) Tab.NOW_PLAYING -> StageControls(now, media, Modifier.fillMaxSize().padding(bottom = barInset))
Tab.BROWSE -> BrowsePanel(browse, media, app.label, Modifier.fillMaxSize()) Tab.BROWSE -> BrowsePanel(browse, media, app.label, Modifier.fillMaxSize().padding(bottom = barTop))
Tab.QUEUE -> QueuePanel(queue, now, media, Modifier.fillMaxSize()) Tab.QUEUE -> QueuePanel(queue, now, media, Modifier.fillMaxSize().padding(bottom = barTop))
Tab.LYRICS -> LyricsPanel(now, Modifier.fillMaxSize()) Tab.LYRICS -> LyricsPanel(now, Modifier.fillMaxSize().padding(bottom = barInset))
} }
} }
} }
BoxWithConstraints( BoxWithConstraints(Modifier.fillMaxSize().padding(start = 16.dp, end = 16.dp, top = 10.dp)) {
Modifier.fillMaxSize().padding(start = 16.dp, end = 16.dp, top = 10.dp, bottom = 8.dp + LocalNavBarInset.current),
) {
// A small screen, or a big one at Extra large size, has no room for two columns: the // A small screen, or a big one at Extra large size, has no room for two columns: the
// app and the tabs share one bar, and a list takes the whole width. The nav bar keeps // app and the tabs share one bar, and a list takes the whole width. The nav bar keeps
// the controls, so nothing is lost. // the controls, so nothing is lost.
if (maxWidth < NARROW_WIDTH || maxHeight < NARROW_HEIGHT) { if (maxWidth < NARROW_WIDTH || maxHeight - barInset < NARROW_HEIGHT) {
Column(Modifier.fillMaxSize(), verticalArrangement = Arrangement.spacedBy(8.dp)) { Column(Modifier.fillMaxSize(), verticalArrangement = Arrangement.spacedBy(8.dp)) {
Row( Row(
Modifier.fillMaxWidth(), Modifier.fillMaxWidth(),
@@ -215,7 +217,7 @@ fun MediaScreen(app: MediaApp, onExit: () -> Unit) {
searchButton() searchButton()
} }
search?.let { SearchStatus(it, app.label, media::dismissSearch) } search?.let { SearchStatus(it, app.label, media::dismissSearch) }
if (tab == Tab.NOW_PLAYING) NowPlayingPage(now, media, Modifier.weight(1f).fillMaxWidth(), padded = false) if (tab == Tab.NOW_PLAYING) NowPlayingPage(now, media, Modifier.weight(1f).fillMaxWidth().padding(bottom = barInset), padded = false)
else tabContent(Modifier.weight(1f).fillMaxWidth()) else tabContent(Modifier.weight(1f).fillMaxWidth())
} }
return@BoxWithConstraints return@BoxWithConstraints
@@ -225,7 +227,7 @@ fun MediaScreen(app: MediaApp, onExit: () -> Unit) {
// and the art (or, beside a list, the compact player) on the left; the tabs across the // and the art (or, beside a list, the compact player) on the left; the tabs across the
// top of the right column, over whatever the tab shows. // top of the right column, over whatever the tab shows.
Row(Modifier.fillMaxSize(), horizontalArrangement = Arrangement.spacedBy(24.dp)) { Row(Modifier.fillMaxSize(), horizontalArrangement = Arrangement.spacedBy(24.dp)) {
Column(Modifier.weight(0.8f).fillMaxHeight()) { Column(Modifier.weight(0.8f).fillMaxHeight().padding(bottom = barInset)) {
AppIdentity(app, onExit) AppIdentity(app, onExit)
Spacer(Modifier.height(12.dp)) Spacer(Modifier.height(12.dp))
if (tab == Tab.NOW_PLAYING) { if (tab == Tab.NOW_PLAYING) {
@@ -686,7 +688,7 @@ private fun StageControls(now: NowPlaying, media: CarMedia, modifier: Modifier)
val compact = maxHeight < 360.dp val compact = maxHeight < 360.dp
val showTimes = maxHeight >= 260.dp val showTimes = maxHeight >= 260.dp
val titleRoom = maxHeight * 0.4f val titleRoom = maxHeight * 0.4f
Column(Modifier.fillMaxSize().padding(start = 4.dp, end = 4.dp, bottom = 4.dp)) { Column(Modifier.fillMaxSize().padding(start = 4.dp, end = 4.dp, top = if (compact) 6.dp else 16.dp, bottom = 4.dp)) {
// The title gives up its height first and scrolls, so the controls keep theirs. // The title gives up its height first and scrolls, so the controls keep theirs.
Column(Modifier.heightIn(max = titleRoom).verticalScroll(rememberScrollState())) { Column(Modifier.heightIn(max = titleRoom).verticalScroll(rememberScrollState())) {
Text( Text(