mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-11 15:29:15 +01:00
show the now playing gradient behind the library lists
This commit is contained in:
@@ -56,8 +56,7 @@ import com.subtracks.ui.playback.NowPlayingRoute
|
|||||||
import com.subtracks.ui.playback.QueueRoute
|
import com.subtracks.ui.playback.QueueRoute
|
||||||
import com.subtracks.ui.settings.AddSourceRoute
|
import com.subtracks.ui.settings.AddSourceRoute
|
||||||
import com.subtracks.ui.settings.SettingsRoute
|
import com.subtracks.ui.settings.SettingsRoute
|
||||||
import com.subtracks.ui.theme.LocalPlayerSurfaceColor
|
import com.subtracks.ui.theme.LocalPlayerArtwork
|
||||||
import com.subtracks.ui.theme.playerSurfaceColor
|
|
||||||
import com.subtracks.ui.theme.rememberArtworkColors
|
import com.subtracks.ui.theme.rememberArtworkColors
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
@@ -148,11 +147,11 @@ private fun MainNavigation() {
|
|||||||
}
|
}
|
||||||
val miniArt = playbackController.coverArt(playback.item, thumbnail = true)
|
val miniArt = playbackController.coverArt(playback.item, thumbnail = true)
|
||||||
val miniArtwork = rememberArtworkColors(miniArt)
|
val miniArtwork = rememberArtworkColors(miniArt)
|
||||||
val playerSurface = playerSurfaceColor(miniArtwork)
|
val libraryArtwork = miniArtwork.takeIf { miniArt != null }
|
||||||
val density = LocalDensity.current
|
val density = LocalDensity.current
|
||||||
val navBarInset = with(density) { WindowInsets.navigationBars.getBottom(this).toDp() }
|
val navBarInset = with(density) { WindowInsets.navigationBars.getBottom(this).toDp() }
|
||||||
|
|
||||||
CompositionLocalProvider(LocalPlayerSurfaceColor provides playerSurface) {
|
CompositionLocalProvider(LocalPlayerArtwork provides libraryArtwork) {
|
||||||
Box(Modifier.fillMaxSize()) {
|
Box(Modifier.fillMaxSize()) {
|
||||||
Column(Modifier.fillMaxSize()) {
|
Column(Modifier.fillMaxSize()) {
|
||||||
NavHost(
|
NavHost(
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.draw.clipToBounds
|
import androidx.compose.ui.draw.clipToBounds
|
||||||
import androidx.compose.ui.geometry.Rect
|
import androidx.compose.ui.geometry.Rect
|
||||||
import androidx.compose.ui.graphics.isSpecified
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.lerp
|
import androidx.compose.ui.graphics.lerp
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
@@ -69,7 +69,9 @@ import com.subtracks.data.model.Artist
|
|||||||
import com.subtracks.data.model.CoverArtRef
|
import com.subtracks.data.model.CoverArtRef
|
||||||
import com.subtracks.data.model.Playlist
|
import com.subtracks.data.model.Playlist
|
||||||
import com.subtracks.data.model.SongListItem
|
import com.subtracks.data.model.SongListItem
|
||||||
import com.subtracks.ui.theme.LocalPlayerSurfaceColor
|
import com.subtracks.ui.theme.HeroGradient
|
||||||
|
import com.subtracks.ui.theme.LocalPlayerArtwork
|
||||||
|
import com.subtracks.ui.theme.playerSurfaceColor
|
||||||
import org.koin.compose.viewmodel.koinViewModel
|
import org.koin.compose.viewmodel.koinViewModel
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
@@ -169,10 +171,8 @@ fun LibraryScreen(
|
|||||||
val titleFraction = scrollBehavior.state.collapsedFraction
|
val titleFraction = scrollBehavior.state.collapsedFraction
|
||||||
|
|
||||||
val statusBarTop = with(density) { WindowInsets.statusBars.getTop(this).toDp() }
|
val statusBarTop = with(density) { WindowInsets.statusBars.getTop(this).toDp() }
|
||||||
val headerColor =
|
val artwork = LocalPlayerArtwork.current
|
||||||
LocalPlayerSurfaceColor.current.let {
|
val headerColor = artwork?.let(::playerSurfaceColor) ?: MaterialTheme.colorScheme.surfaceContainerHigh
|
||||||
if (it.isSpecified) it else MaterialTheme.colorScheme.surfaceContainerHigh
|
|
||||||
}
|
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier =
|
modifier =
|
||||||
@@ -213,12 +213,21 @@ fun LibraryScreen(
|
|||||||
syncing = syncing,
|
syncing = syncing,
|
||||||
onSync = onSync,
|
onSync = onSync,
|
||||||
onOpenSettings = onOpenSettings,
|
onOpenSettings = onOpenSettings,
|
||||||
|
selectedColor = headerColor,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Box(Modifier.fillMaxWidth().weight(1f)) {
|
||||||
|
if (artwork != null) {
|
||||||
|
HeroGradient(
|
||||||
|
colors = artwork,
|
||||||
|
scrollPx = { 0f },
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
)
|
||||||
|
}
|
||||||
HorizontalPager(
|
HorizontalPager(
|
||||||
state = pagerState,
|
state = pagerState,
|
||||||
modifier = Modifier.fillMaxWidth().weight(1f),
|
modifier = Modifier.fillMaxSize(),
|
||||||
) { page ->
|
) { page ->
|
||||||
when (LibraryTab.entries[page]) {
|
when (LibraryTab.entries[page]) {
|
||||||
LibraryTab.Albums -> AlbumsContent(albums, coverArt, bottomInset, onAlbumClick)
|
LibraryTab.Albums -> AlbumsContent(albums, coverArt, bottomInset, onAlbumClick)
|
||||||
@@ -228,6 +237,7 @@ fun LibraryScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@@ -238,6 +248,7 @@ private fun LibraryTabs(
|
|||||||
syncing: Boolean,
|
syncing: Boolean,
|
||||||
onSync: () -> Unit,
|
onSync: () -> Unit,
|
||||||
onOpenSettings: () -> Unit,
|
onOpenSettings: () -> Unit,
|
||||||
|
selectedColor: Color,
|
||||||
) {
|
) {
|
||||||
val iconFadeThreshold = 0.65f
|
val iconFadeThreshold = 0.65f
|
||||||
val indicatorStretch = 18.dp
|
val indicatorStretch = 18.dp
|
||||||
@@ -281,6 +292,7 @@ private fun LibraryTabs(
|
|||||||
((iconFadeThreshold - abs(position - index)) / iconFadeThreshold)
|
((iconFadeThreshold - abs(position - index)) / iconFadeThreshold)
|
||||||
.coerceIn(0f, 1f),
|
.coerceIn(0f, 1f),
|
||||||
onClick = { onTabSelected(tab) },
|
onClick = { onTabSelected(tab) },
|
||||||
|
selectedColor = selectedColor,
|
||||||
modifier =
|
modifier =
|
||||||
Modifier.onGloballyPositioned { coordinates ->
|
Modifier.onGloballyPositioned { coordinates ->
|
||||||
bounds[index] = coordinates.boundsInParent()
|
bounds[index] = coordinates.boundsInParent()
|
||||||
@@ -318,9 +330,10 @@ private fun TabButton(
|
|||||||
tab: LibraryTab,
|
tab: LibraryTab,
|
||||||
progress: Float,
|
progress: Float,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
|
selectedColor: Color,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
val content = lerp(MaterialTheme.colorScheme.onBackground, MaterialTheme.colorScheme.background, progress)
|
val content = lerp(MaterialTheme.colorScheme.onBackground, selectedColor, progress)
|
||||||
Box(
|
Box(
|
||||||
modifier =
|
modifier =
|
||||||
modifier
|
modifier
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ fun ArtworkTheme(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val LocalPlayerSurfaceColor = compositionLocalOf { Color.Unspecified }
|
val LocalPlayerArtwork = compositionLocalOf<ArtworkColors?> { null }
|
||||||
|
|
||||||
fun playerSurfaceColor(artwork: ArtworkColors): Color = lerp(artwork.scheme.surfaceContainerHigh, artwork.gradientHigh, 0.5f)
|
fun playerSurfaceColor(artwork: ArtworkColors): Color = lerp(artwork.scheme.surfaceContainerHigh, artwork.gradientHigh, 0.5f)
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import androidx.activity.ComponentActivity
|
|||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.test.junit4.v2.createAndroidComposeRule
|
import androidx.compose.ui.test.junit4.v2.createAndroidComposeRule
|
||||||
@@ -49,6 +50,7 @@ import com.subtracks.ui.playback.QueueScreen
|
|||||||
import com.subtracks.ui.settings.AddSourceScreen
|
import com.subtracks.ui.settings.AddSourceScreen
|
||||||
import com.subtracks.ui.settings.AddSourceState
|
import com.subtracks.ui.settings.AddSourceState
|
||||||
import com.subtracks.ui.settings.SettingsScreen
|
import com.subtracks.ui.settings.SettingsScreen
|
||||||
|
import com.subtracks.ui.theme.LocalPlayerArtwork
|
||||||
import com.subtracks.ui.theme.SubtracksTheme
|
import com.subtracks.ui.theme.SubtracksTheme
|
||||||
import com.subtracks.ui.theme.artworkColorsFromSeed
|
import com.subtracks.ui.theme.artworkColorsFromSeed
|
||||||
import com.subtracks.ui.theme.artworkColorsFromSeeds
|
import com.subtracks.ui.theme.artworkColorsFromSeeds
|
||||||
@@ -327,6 +329,7 @@ class AppScreenshotTest {
|
|||||||
private fun setLibraryContent(tab: LibraryTab) {
|
private fun setLibraryContent(tab: LibraryTab) {
|
||||||
composeRule.setContent {
|
composeRule.setContent {
|
||||||
SubtracksTheme {
|
SubtracksTheme {
|
||||||
|
CompositionLocalProvider(LocalPlayerArtwork provides artworkColorsFromSeed(Color.rgb(120, 80, 200))) {
|
||||||
LibraryScreen(
|
LibraryScreen(
|
||||||
selectedTab = tab,
|
selectedTab = tab,
|
||||||
onTabSelected = {},
|
onTabSelected = {},
|
||||||
@@ -345,6 +348,7 @@ class AppScreenshotTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun awaitText(text: String) {
|
private fun awaitText(text: String) {
|
||||||
composeRule.waitUntil(timeoutMillis = 5_000) {
|
composeRule.waitUntil(timeoutMillis = 5_000) {
|
||||||
|
|||||||
Reference in New Issue
Block a user