mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-11 15:29:15 +01:00
overlay a translucent header onto the library content
This commit is contained in:
@@ -43,6 +43,7 @@ fun AlbumsContent(
|
|||||||
filtered: Boolean = false,
|
filtered: Boolean = false,
|
||||||
onClearFilters: () -> Unit = {},
|
onClearFilters: () -> Unit = {},
|
||||||
resetKey: Any? = null,
|
resetKey: Any? = null,
|
||||||
|
topInset: Dp = 0.dp,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
when {
|
when {
|
||||||
@@ -65,7 +66,7 @@ fun AlbumsContent(
|
|||||||
LazyVerticalGrid(
|
LazyVerticalGrid(
|
||||||
state = gridState,
|
state = gridState,
|
||||||
columns = GridCells.Fixed(3),
|
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),
|
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||||
verticalArrangement = Arrangement.spacedBy(4.dp),
|
verticalArrangement = Arrangement.spacedBy(4.dp),
|
||||||
modifier = modifier.fillMaxSize(),
|
modifier = modifier.fillMaxSize(),
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ fun ArtistsContent(
|
|||||||
filtered: Boolean = false,
|
filtered: Boolean = false,
|
||||||
onClearFilters: () -> Unit = {},
|
onClearFilters: () -> Unit = {},
|
||||||
resetKey: Any? = null,
|
resetKey: Any? = null,
|
||||||
|
topInset: Dp = 0.dp,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
when {
|
when {
|
||||||
@@ -63,7 +64,7 @@ fun ArtistsContent(
|
|||||||
LazyColumn(
|
LazyColumn(
|
||||||
state = listState,
|
state = listState,
|
||||||
modifier = modifier.fillMaxSize(),
|
modifier = modifier.fillMaxSize(),
|
||||||
contentPadding = PaddingValues(bottom = bottomInset),
|
contentPadding = PaddingValues(top = topInset, bottom = bottomInset),
|
||||||
) {
|
) {
|
||||||
items(count = items.itemCount, key = items.itemKey { it.id }) { index ->
|
items(count = items.itemCount, key = items.itemKey { it.id }) { index ->
|
||||||
val artist = items[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.boundsInParent
|
||||||
import androidx.compose.ui.layout.layout
|
import androidx.compose.ui.layout.layout
|
||||||
import androidx.compose.ui.layout.onGloballyPositioned
|
import androidx.compose.ui.layout.onGloballyPositioned
|
||||||
|
import androidx.compose.ui.layout.onSizeChanged
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.semantics.clearAndSetSemantics
|
import androidx.compose.ui.semantics.clearAndSetSemantics
|
||||||
import androidx.compose.ui.unit.Constraints
|
import androidx.compose.ui.unit.Constraints
|
||||||
@@ -312,33 +313,18 @@ fun LibraryScreen(
|
|||||||
val filtersActive = listQuery.starred != StarredFilter.Any || search.isNotEmpty()
|
val filtersActive = listQuery.starred != StarredFilter.Any || search.isNotEmpty()
|
||||||
val listBottomInset = bottomInset + if (searchActive) SEARCH_BAR_CLEARANCE else FAB_CLEARANCE
|
val listBottomInset = bottomInset + if (searchActive) SEARCH_BAR_CLEARANCE else FAB_CLEARANCE
|
||||||
|
|
||||||
Box(modifier.fillMaxSize()) {
|
var headerHeightPx by remember { mutableFloatStateOf(0f) }
|
||||||
Column(
|
val listTopInset = with(density) { headerHeightPx.toDp() }
|
||||||
|
|
||||||
|
Box(
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.background(artwork?.let(::librarySurfaceColor) ?: MaterialTheme.colorScheme.background),
|
.background(artwork?.let(::librarySurfaceColor) ?: MaterialTheme.colorScheme.background),
|
||||||
) {
|
) {
|
||||||
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(
|
HorizontalPager(
|
||||||
state = pagerState,
|
state = pagerState,
|
||||||
modifier = Modifier.fillMaxWidth().weight(1f),
|
modifier = Modifier.fillMaxSize(),
|
||||||
) { page ->
|
) { page ->
|
||||||
val pageTab = LibraryTab.entries[page]
|
val pageTab = LibraryTab.entries[page]
|
||||||
val resetKey = resetKeys[pageTab]
|
val resetKey = resetKeys[pageTab]
|
||||||
@@ -352,6 +338,7 @@ fun LibraryScreen(
|
|||||||
filtered = filtersActive,
|
filtered = filtersActive,
|
||||||
onClearFilters = onClearFilters,
|
onClearFilters = onClearFilters,
|
||||||
resetKey = resetKey,
|
resetKey = resetKey,
|
||||||
|
topInset = listTopInset,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -364,6 +351,7 @@ fun LibraryScreen(
|
|||||||
filtered = filtersActive,
|
filtered = filtersActive,
|
||||||
onClearFilters = onClearFilters,
|
onClearFilters = onClearFilters,
|
||||||
resetKey = resetKey,
|
resetKey = resetKey,
|
||||||
|
topInset = listTopInset,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,6 +365,7 @@ fun LibraryScreen(
|
|||||||
filtered = filtersActive,
|
filtered = filtersActive,
|
||||||
onClearFilters = onClearFilters,
|
onClearFilters = onClearFilters,
|
||||||
resetKey = resetKey,
|
resetKey = resetKey,
|
||||||
|
topInset = listTopInset,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -389,10 +378,31 @@ fun LibraryScreen(
|
|||||||
filtered = filtersActive,
|
filtered = filtersActive,
|
||||||
onClearFilters = onClearFilters,
|
onClearFilters = onClearFilters,
|
||||||
resetKey = resetKey,
|
resetKey = resetKey,
|
||||||
|
topInset = listTopInset,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier =
|
||||||
|
Modifier
|
||||||
|
.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),
|
||||||
|
) {
|
||||||
|
LibraryTabs(
|
||||||
|
pagerState = pagerState,
|
||||||
|
onTabSelected = onTabSelected,
|
||||||
|
syncing = syncing,
|
||||||
|
onSync = onSync,
|
||||||
|
onOpenSettings = onOpenSettings,
|
||||||
|
artwork = artwork,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (searchActive) {
|
if (searchActive) {
|
||||||
@@ -582,6 +592,7 @@ private fun ListOptionsSheet(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val FAB_CLEARANCE = 80.dp
|
private val FAB_CLEARANCE = 80.dp
|
||||||
|
private const val HEADER_ALPHA = 0.72f
|
||||||
private val SEARCH_BAR_CLEARANCE = 80.dp
|
private val SEARCH_BAR_CLEARANCE = 80.dp
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ fun PlaylistsContent(
|
|||||||
filtered: Boolean = false,
|
filtered: Boolean = false,
|
||||||
onClearFilters: () -> Unit = {},
|
onClearFilters: () -> Unit = {},
|
||||||
resetKey: Any? = null,
|
resetKey: Any? = null,
|
||||||
|
topInset: Dp = 0.dp,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
when {
|
when {
|
||||||
@@ -62,7 +63,7 @@ fun PlaylistsContent(
|
|||||||
LazyColumn(
|
LazyColumn(
|
||||||
state = listState,
|
state = listState,
|
||||||
modifier = modifier.fillMaxSize(),
|
modifier = modifier.fillMaxSize(),
|
||||||
contentPadding = PaddingValues(bottom = bottomInset),
|
contentPadding = PaddingValues(top = topInset, bottom = bottomInset),
|
||||||
) {
|
) {
|
||||||
items(count = items.itemCount, key = items.itemKey { it.id }) { index ->
|
items(count = items.itemCount, key = items.itemKey { it.id }) { index ->
|
||||||
val playlist = items[index]
|
val playlist = items[index]
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ fun SongsContent(
|
|||||||
filtered: Boolean = false,
|
filtered: Boolean = false,
|
||||||
onClearFilters: () -> Unit = {},
|
onClearFilters: () -> Unit = {},
|
||||||
resetKey: Any? = null,
|
resetKey: Any? = null,
|
||||||
|
topInset: Dp = 0.dp,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
when {
|
when {
|
||||||
@@ -74,7 +75,7 @@ fun SongsContent(
|
|||||||
LazyColumn(
|
LazyColumn(
|
||||||
state = listState,
|
state = listState,
|
||||||
modifier = modifier.fillMaxSize(),
|
modifier = modifier.fillMaxSize(),
|
||||||
contentPadding = PaddingValues(bottom = bottomInset),
|
contentPadding = PaddingValues(top = topInset, bottom = bottomInset),
|
||||||
) {
|
) {
|
||||||
items(count = items.itemCount, key = items.itemKey { it.song.id }) { index ->
|
items(count = items.itemCount, key = items.itemKey { it.song.id }) { index ->
|
||||||
val item = items[index]
|
val item = items[index]
|
||||||
|
|||||||
@@ -96,6 +96,35 @@ class AppScreenshotTest {
|
|||||||
composeRule.onRoot().captureRoboImage("src/test/screenshots/library_albums.png")
|
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
|
@Test
|
||||||
fun libraryArtists() {
|
fun libraryArtists() {
|
||||||
setLibraryContent(LibraryTab.Artists)
|
setLibraryContent(LibraryTab.Artists)
|
||||||
|
|||||||
Reference in New Issue
Block a user