From 216990181e52ecea099206982dcdfe7f3ede2869 Mon Sep 17 00:00:00 2001 From: austinried <4966622+austinried@users.noreply.github.com> Date: Fri, 25 Sep 2026 09:21:02 +0000 Subject: [PATCH] address the review: source title after a queue reorder, scrim timing, thumbnail painter - derive the now playing fallback title from the current item for every kind except the songs list, so a track reordered into the album queue (now a Song entry) still shows its album - reset the resolved title to the fallback when the queue context changes, so crossing albums does not briefly show the previous name - start the now playing scrim fade later (0.85) so it darkens the sheet, not the library, while the sheet is still sliding up - reuse the thumbnail's onSuccess painter ratio instead of loading a second thumbnail painter for the aspect ratio - drop the now-unneeded ExperimentalLayoutApi opt-in on AddSourceScreen (imePadding is stable) --- .../main/kotlin/com/subtracks/ui/AppRoot.kt | 2 +- .../com/subtracks/ui/components/Components.kt | 18 +++++++++++------- .../subtracks/ui/playback/NowPlayingScreen.kt | 8 +++++++- .../subtracks/ui/settings/AddSourceScreen.kt | 3 +-- 4 files changed, 20 insertions(+), 11 deletions(-) diff --git a/app/src/main/kotlin/com/subtracks/ui/AppRoot.kt b/app/src/main/kotlin/com/subtracks/ui/AppRoot.kt index 88e2bd7d..0522c751 100644 --- a/app/src/main/kotlin/com/subtracks/ui/AppRoot.kt +++ b/app/src/main/kotlin/com/subtracks/ui/AppRoot.kt @@ -94,7 +94,7 @@ private const val OVERLAY_DURATION_MS = 200 private const val EXPAND_FADE = 0.1f private const val FLING_VELOCITY = 1000f private const val MINI_PLAYER_ANIM_MS = 200 -private const val SCRIM_FADE_START = 0.6f +private const val SCRIM_FADE_START = 0.85f private object Routes { const val LIBRARY = "library" diff --git a/app/src/main/kotlin/com/subtracks/ui/components/Components.kt b/app/src/main/kotlin/com/subtracks/ui/components/Components.kt index 3ecc08a8..c19aa659 100644 --- a/app/src/main/kotlin/com/subtracks/ui/components/Components.kt +++ b/app/src/main/kotlin/com/subtracks/ui/components/Components.kt @@ -49,6 +49,7 @@ fun CoverArt( val context = LocalPlatformContext.current var failed by remember(ref, thumbnailRef) { mutableStateOf(false) } var thumbnailLoaded by remember(ref, thumbnailRef) { mutableStateOf(false) } + var thumbnailRatio by remember(ref, thumbnailRef) { mutableStateOf(null) } val model = remember(ref, thumbnailRef) { ref?.let { imageRequest(context, it, crossfade = thumbnailRef != null) } } val frameModifier = Modifier @@ -65,6 +66,7 @@ fun CoverArt( failed = failed, thumbnailLoaded = thumbnailLoaded, onThumbnailLoaded = { thumbnailLoaded = true }, + onThumbnailRatio = { thumbnailRatio = it }, contentScale = ContentScale.Crop, ) { if (ref != null) { @@ -85,15 +87,10 @@ fun CoverArt( onError = { failed = true }, contentScale = ContentScale.Fit, ) - val thumbnailPainter = - rememberAsyncImagePainter( - model = remember(thumbnailRef) { thumbnailRef?.let { imageRequest(context, it, crossfade = false) } }, - contentScale = ContentScale.Fit, - ) BoxWithConstraints(modifier, contentAlignment = Alignment.Center) { val ratio = painter.intrinsicSize.ratioOrNull() - ?: thumbnailPainter.intrinsicSize.ratioOrNull() + ?: thumbnailRatio ?: 1f val width = if (ratio > maxWidth.value / maxHeight.value) maxWidth else maxHeight * ratio Box(Modifier.size(width, width / ratio).then(frameModifier)) { @@ -105,6 +102,7 @@ fun CoverArt( failed = failed, thumbnailLoaded = thumbnailLoaded, onThumbnailLoaded = { thumbnailLoaded = true }, + onThumbnailRatio = { thumbnailRatio = it }, contentScale = ContentScale.Fit, ) { if (ref != null) { @@ -130,6 +128,7 @@ private fun BoxScope.CoverArtContent( failed: Boolean, thumbnailLoaded: Boolean, onThumbnailLoaded: () -> Unit, + onThumbnailRatio: (Float) -> Unit, contentScale: ContentScale, main: @Composable () -> Unit, ) { @@ -147,7 +146,12 @@ private fun BoxScope.CoverArtContent( model = remember(thumbnailRef) { imageRequest(context, thumbnailRef, crossfade = false) }, contentDescription = null, contentScale = contentScale, - onSuccess = { onThumbnailLoaded() }, + onSuccess = { success -> + onThumbnailLoaded() + success.painter.intrinsicSize + .ratioOrNull() + ?.let(onThumbnailRatio) + }, modifier = Modifier.fillMaxSize(), ) } diff --git a/app/src/main/kotlin/com/subtracks/ui/playback/NowPlayingScreen.kt b/app/src/main/kotlin/com/subtracks/ui/playback/NowPlayingScreen.kt index 1fd3fd9d..96f24ad5 100644 --- a/app/src/main/kotlin/com/subtracks/ui/playback/NowPlayingScreen.kt +++ b/app/src/main/kotlin/com/subtracks/ui/playback/NowPlayingScreen.kt @@ -83,8 +83,14 @@ fun NowPlayingRoute( val art = controller.coverArt(state.item) val thumbnail = controller.coverArt(state.item, thumbnail = true) val queueContext = state.context - val fallbackTitle = if (queueContext?.kind == QueueKind.Album) state.item?.album.orEmpty() else "Library" + val fallbackTitle = + if (queueContext?.kind == QueueKind.Songs) { + "Library" + } else { + state.item?.album?.takeIf { it.isNotBlank() } ?: "Library" + } val sourceTitle by produceState(initialValue = fallbackTitle, queueContext) { + value = fallbackTitle value = controller.sourceTitle(queueContext) ?: fallbackTitle } LaunchedEffect(state.item?.id, state.hasNext) { diff --git a/app/src/main/kotlin/com/subtracks/ui/settings/AddSourceScreen.kt b/app/src/main/kotlin/com/subtracks/ui/settings/AddSourceScreen.kt index 77b38bcd..6c475bb7 100644 --- a/app/src/main/kotlin/com/subtracks/ui/settings/AddSourceScreen.kt +++ b/app/src/main/kotlin/com/subtracks/ui/settings/AddSourceScreen.kt @@ -2,7 +2,6 @@ package com.subtracks.ui.settings import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -58,7 +57,7 @@ fun AddSourceRoute( ) } -@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class) +@OptIn(ExperimentalMaterial3Api::class) @Composable fun AddSourceScreen( state: AddSourceState,