mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-10 23:21:59 +01:00
overlay a translucent header onto the library content
This commit is contained in:
@@ -43,6 +43,7 @@ fun AlbumsContent(
|
||||
filtered: Boolean = false,
|
||||
onClearFilters: () -> Unit = {},
|
||||
resetKey: Any? = null,
|
||||
topInset: Dp = 0.dp,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
when {
|
||||
@@ -65,7 +66,7 @@ fun AlbumsContent(
|
||||
LazyVerticalGrid(
|
||||
state = gridState,
|
||||
columns = GridCells.Fixed(3),
|
||||
contentPadding = PaddingValues(start = 8.dp, top = 8.dp, end = 8.dp, bottom = bottomInset + 8.dp),
|
||||
contentPadding = PaddingValues(start = 8.dp, top = topInset + 8.dp, end = 8.dp, bottom = bottomInset + 8.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(4.dp),
|
||||
modifier = modifier.fillMaxSize(),
|
||||
|
||||
@@ -41,6 +41,7 @@ fun ArtistsContent(
|
||||
filtered: Boolean = false,
|
||||
onClearFilters: () -> Unit = {},
|
||||
resetKey: Any? = null,
|
||||
topInset: Dp = 0.dp,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
when {
|
||||
@@ -63,7 +64,7 @@ fun ArtistsContent(
|
||||
LazyColumn(
|
||||
state = listState,
|
||||
modifier = modifier.fillMaxSize(),
|
||||
contentPadding = PaddingValues(bottom = bottomInset),
|
||||
contentPadding = PaddingValues(top = topInset, bottom = bottomInset),
|
||||
) {
|
||||
items(count = items.itemCount, key = items.itemKey { it.id }) { index ->
|
||||
val artist = items[index]
|
||||
|
||||
@@ -91,6 +91,7 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.layout.boundsInParent
|
||||
import androidx.compose.ui.layout.layout
|
||||
import androidx.compose.ui.layout.onGloballyPositioned
|
||||
import androidx.compose.ui.layout.onSizeChanged
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.semantics.clearAndSetSemantics
|
||||
import androidx.compose.ui.unit.Constraints
|
||||
@@ -312,87 +313,96 @@ fun LibraryScreen(
|
||||
val filtersActive = listQuery.starred != StarredFilter.Any || search.isNotEmpty()
|
||||
val listBottomInset = bottomInset + if (searchActive) SEARCH_BAR_CLEARANCE else FAB_CLEARANCE
|
||||
|
||||
Box(modifier.fillMaxSize()) {
|
||||
var headerHeightPx by remember { mutableFloatStateOf(0f) }
|
||||
val listTopInset = with(density) { headerHeightPx.toDp() }
|
||||
|
||||
Box(
|
||||
modifier =
|
||||
modifier
|
||||
.fillMaxSize()
|
||||
.background(artwork?.let(::librarySurfaceColor) ?: MaterialTheme.colorScheme.background),
|
||||
) {
|
||||
HorizontalPager(
|
||||
state = pagerState,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
) { page ->
|
||||
val pageTab = LibraryTab.entries[page]
|
||||
val resetKey = resetKeys[pageTab]
|
||||
when (pageTab) {
|
||||
LibraryTab.Albums -> {
|
||||
AlbumsContent(
|
||||
albums,
|
||||
coverArt,
|
||||
listBottomInset,
|
||||
onAlbumClick,
|
||||
filtered = filtersActive,
|
||||
onClearFilters = onClearFilters,
|
||||
resetKey = resetKey,
|
||||
topInset = listTopInset,
|
||||
)
|
||||
}
|
||||
|
||||
LibraryTab.Artists -> {
|
||||
ArtistsContent(
|
||||
artists,
|
||||
coverArt,
|
||||
listBottomInset,
|
||||
onArtistClick,
|
||||
filtered = filtersActive,
|
||||
onClearFilters = onClearFilters,
|
||||
resetKey = resetKey,
|
||||
topInset = listTopInset,
|
||||
)
|
||||
}
|
||||
|
||||
LibraryTab.Songs -> {
|
||||
SongsContent(
|
||||
songs,
|
||||
coverArt,
|
||||
listBottomInset,
|
||||
onSongClick,
|
||||
playingSongId,
|
||||
filtered = filtersActive,
|
||||
onClearFilters = onClearFilters,
|
||||
resetKey = resetKey,
|
||||
topInset = listTopInset,
|
||||
)
|
||||
}
|
||||
|
||||
LibraryTab.Playlists -> {
|
||||
PlaylistsContent(
|
||||
playlists,
|
||||
coverArt,
|
||||
listBottomInset,
|
||||
onPlaylistClick,
|
||||
filtered = filtersActive,
|
||||
onClearFilters = onClearFilters,
|
||||
resetKey = resetKey,
|
||||
topInset = listTopInset,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxSize()
|
||||
.background(artwork?.let(::librarySurfaceColor) ?: MaterialTheme.colorScheme.background),
|
||||
.fillMaxWidth()
|
||||
.align(Alignment.TopStart)
|
||||
.onSizeChanged { headerHeightPx = it.height.toFloat() }
|
||||
.background(
|
||||
(artwork?.let(::playerSurfaceColor) ?: MaterialTheme.colorScheme.background)
|
||||
.copy(alpha = HEADER_ALPHA),
|
||||
).padding(top = statusBarTop + 2.dp, bottom = 2.dp),
|
||||
) {
|
||||
Column(
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.background(artwork?.let(::playerSurfaceColor) ?: MaterialTheme.colorScheme.background)
|
||||
.padding(top = statusBarTop + 2.dp, bottom = 2.dp),
|
||||
) {
|
||||
LibraryTabs(
|
||||
pagerState = pagerState,
|
||||
onTabSelected = onTabSelected,
|
||||
syncing = syncing,
|
||||
onSync = onSync,
|
||||
onOpenSettings = onOpenSettings,
|
||||
artwork = artwork,
|
||||
)
|
||||
}
|
||||
|
||||
HorizontalPager(
|
||||
state = pagerState,
|
||||
modifier = Modifier.fillMaxWidth().weight(1f),
|
||||
) { page ->
|
||||
val pageTab = LibraryTab.entries[page]
|
||||
val resetKey = resetKeys[pageTab]
|
||||
when (pageTab) {
|
||||
LibraryTab.Albums -> {
|
||||
AlbumsContent(
|
||||
albums,
|
||||
coverArt,
|
||||
listBottomInset,
|
||||
onAlbumClick,
|
||||
filtered = filtersActive,
|
||||
onClearFilters = onClearFilters,
|
||||
resetKey = resetKey,
|
||||
)
|
||||
}
|
||||
|
||||
LibraryTab.Artists -> {
|
||||
ArtistsContent(
|
||||
artists,
|
||||
coverArt,
|
||||
listBottomInset,
|
||||
onArtistClick,
|
||||
filtered = filtersActive,
|
||||
onClearFilters = onClearFilters,
|
||||
resetKey = resetKey,
|
||||
)
|
||||
}
|
||||
|
||||
LibraryTab.Songs -> {
|
||||
SongsContent(
|
||||
songs,
|
||||
coverArt,
|
||||
listBottomInset,
|
||||
onSongClick,
|
||||
playingSongId,
|
||||
filtered = filtersActive,
|
||||
onClearFilters = onClearFilters,
|
||||
resetKey = resetKey,
|
||||
)
|
||||
}
|
||||
|
||||
LibraryTab.Playlists -> {
|
||||
PlaylistsContent(
|
||||
playlists,
|
||||
coverArt,
|
||||
listBottomInset,
|
||||
onPlaylistClick,
|
||||
filtered = filtersActive,
|
||||
onClearFilters = onClearFilters,
|
||||
resetKey = resetKey,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
LibraryTabs(
|
||||
pagerState = pagerState,
|
||||
onTabSelected = onTabSelected,
|
||||
syncing = syncing,
|
||||
onSync = onSync,
|
||||
onOpenSettings = onOpenSettings,
|
||||
artwork = artwork,
|
||||
)
|
||||
}
|
||||
|
||||
if (searchActive) {
|
||||
@@ -582,6 +592,7 @@ private fun ListOptionsSheet(
|
||||
}
|
||||
|
||||
private val FAB_CLEARANCE = 80.dp
|
||||
private const val HEADER_ALPHA = 0.72f
|
||||
private val SEARCH_BAR_CLEARANCE = 80.dp
|
||||
|
||||
@Composable
|
||||
|
||||
@@ -40,6 +40,7 @@ fun PlaylistsContent(
|
||||
filtered: Boolean = false,
|
||||
onClearFilters: () -> Unit = {},
|
||||
resetKey: Any? = null,
|
||||
topInset: Dp = 0.dp,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
when {
|
||||
@@ -62,7 +63,7 @@ fun PlaylistsContent(
|
||||
LazyColumn(
|
||||
state = listState,
|
||||
modifier = modifier.fillMaxSize(),
|
||||
contentPadding = PaddingValues(bottom = bottomInset),
|
||||
contentPadding = PaddingValues(top = topInset, bottom = bottomInset),
|
||||
) {
|
||||
items(count = items.itemCount, key = items.itemKey { it.id }) { index ->
|
||||
val playlist = items[index]
|
||||
|
||||
@@ -52,6 +52,7 @@ fun SongsContent(
|
||||
filtered: Boolean = false,
|
||||
onClearFilters: () -> Unit = {},
|
||||
resetKey: Any? = null,
|
||||
topInset: Dp = 0.dp,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
when {
|
||||
@@ -74,7 +75,7 @@ fun SongsContent(
|
||||
LazyColumn(
|
||||
state = listState,
|
||||
modifier = modifier.fillMaxSize(),
|
||||
contentPadding = PaddingValues(bottom = bottomInset),
|
||||
contentPadding = PaddingValues(top = topInset, bottom = bottomInset),
|
||||
) {
|
||||
items(count = items.itemCount, key = items.itemKey { it.song.id }) { index ->
|
||||
val item = items[index]
|
||||
|
||||
@@ -96,6 +96,35 @@ class AppScreenshotTest {
|
||||
composeRule.onRoot().captureRoboImage("src/test/screenshots/library_albums.png")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun libraryScrolledUnderHeader() {
|
||||
val albums = (1..60).map { Fixtures.albums.first().copy(id = "scrolled-$it", name = "Album $it") }
|
||||
composeRule.setContent {
|
||||
SubtracksTheme {
|
||||
LibraryScreen(
|
||||
selectedTab = LibraryTab.Albums,
|
||||
onTabSelected = {},
|
||||
albums = remember { flowOf(PagingData.from(albums)) }.collectAsLazyPagingItems(),
|
||||
artists = remember { flowOf(PagingData.empty<Artist>()) }.collectAsLazyPagingItems(),
|
||||
songs = remember { flowOf(PagingData.empty<SongListItem>()) }.collectAsLazyPagingItems(),
|
||||
playlists = remember { flowOf(PagingData.empty<Playlist>()) }.collectAsLazyPagingItems(),
|
||||
coverArt = { id, _ -> id?.let { CoverArtRef(it, "test:$it") } },
|
||||
onAlbumClick = {},
|
||||
onArtistClick = {},
|
||||
onPlaylistClick = {},
|
||||
onSongClick = {},
|
||||
onSync = {},
|
||||
onOpenSettings = {},
|
||||
artwork = artworkColorsFromSeed(Color.rgb(120, 80, 200)),
|
||||
)
|
||||
}
|
||||
}
|
||||
awaitTag(ALBUM_COVER_TAG)
|
||||
composeRule.onRoot().performTouchInput { swipeUp(startY = centerY + 600f, endY = centerY - 600f, durationMillis = 400) }
|
||||
composeRule.waitForIdle()
|
||||
composeRule.onRoot().captureRoboImage("src/test/screenshots/library_scrolled_under_header.png")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun libraryArtists() {
|
||||
setLibraryContent(LibraryTab.Artists)
|
||||
|
||||
Reference in New Issue
Block a user