From 63279dec50c366876d7c0bb721bf837de1d573f6 Mon Sep 17 00:00:00 2001 From: austinried <4966622+austinried@users.noreply.github.com> Date: Sat, 26 Sep 2026 04:37:29 +0000 Subject: [PATCH] scroll the artist detail background and match its bar to the hero The artist background used a static gradient and a scroll-0 bar colour. It now scrolls with the grid (fading to a dark single colour) and the bar colour comes from heroBarColor at the real scroll, like the album/playlist hero. The gradient's scroll origin is the hero image bottom, since the image is full-width and covers the top. --- .../ui/library/ArtistDetailScreen.kt | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/app/src/main/kotlin/com/subtracks/ui/library/ArtistDetailScreen.kt b/app/src/main/kotlin/com/subtracks/ui/library/ArtistDetailScreen.kt index 1060aba3..853787bb 100644 --- a/app/src/main/kotlin/com/subtracks/ui/library/ArtistDetailScreen.kt +++ b/app/src/main/kotlin/com/subtracks/ui/library/ArtistDetailScreen.kt @@ -41,7 +41,9 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha @@ -51,6 +53,7 @@ import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Shadow import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.testTag import androidx.compose.ui.text.style.TextOverflow @@ -159,6 +162,20 @@ fun ArtistDetailScreen( } } } + var imageHeightPx by remember { mutableFloatStateOf(0f) } + var albumHeightPx by remember { mutableFloatStateOf(0f) } + val albumRowGapPx = with(density) { 16.dp.toPx() } + val scrollPx by remember { + derivedStateOf { + val index = listState.firstVisibleItemIndex + val offset = listState.firstVisibleItemScrollOffset.toFloat() + if (index <= 0) { + offset + } else { + imageHeightPx + (albumHeightPx + albumRowGapPx) * ((index - 1) / 2) + offset + } + } + } val nameTextStyle = MaterialTheme.typography.headlineLarge val imageNameStyle = nameTextStyle.copy( @@ -178,10 +195,10 @@ fun ArtistDetailScreen( BoxWithConstraints(modifier.fillMaxSize().background(Color.Black)) { val screenHeightPx = with(density) { maxHeight.toPx() } val barHeightPx = with(density) { barHeight.toPx() } - val barColor = heroBarColor(effectiveArtwork, 0f, barHeightPx, screenHeightPx) + val barColor = heroBarColor(effectiveArtwork, scrollPx, barHeightPx, screenHeightPx) HeroGradient( colors = effectiveArtwork, - scrollPx = { 0f }, + scrollPx = { scrollPx - imageHeightPx }, modifier = Modifier.fillMaxSize(), ) LazyVerticalGrid( @@ -193,7 +210,12 @@ fun ArtistDetailScreen( modifier = Modifier.fillMaxSize(), ) { item(span = { GridItemSpan(maxLineSpan) }) { - Box(Modifier.fillMaxWidth().padding(bottom = 12.dp)) { + Box( + Modifier + .fillMaxWidth() + .onSizeChanged { imageHeightPx = it.height.toFloat() } + .padding(bottom = 12.dp), + ) { CoverArt( ref = art, name = artist?.name.orEmpty(), @@ -237,7 +259,7 @@ fun ArtistDetailScreen( ).combinedClickable( onClick = { onAlbumClick(album) }, onLongClick = { onAlbumLongClick(MenuTarget.Album(album, coverArt(album.coverArt, true))) }, - ), + ).onSizeChanged { albumHeightPx = it.height.toFloat() }, ) { Box { CoverArt(