metadata: stack the miniplayer above the library tabs

Render the miniplayer in a column below the screen instead of overlaying it, so
the library tab bar and the list-options FAB are no longer covered. Use Ugress
for the artist screen, drop Various Artists from the home artist rows, and have
the album screen play its first track so the row indicator and the miniplayer
colours match the album.
This commit is contained in:
austinried
2026-10-04 00:30:08 +00:00
parent 0e96b5872c
commit 9976fbeb20
7 changed files with 49 additions and 32 deletions
@@ -5,7 +5,7 @@ import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Color
import androidx.activity.ComponentActivity
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
@@ -13,7 +13,6 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.test.junit4.v2.createAndroidComposeRule
import androidx.compose.ui.test.onRoot
@@ -141,14 +140,19 @@ class DemoScreenshotTest {
}
Screen.Albums -> {
Box(Modifier.fillMaxSize()) {
AlbumsScreen(demo.albums, demo.coverArt, demo.artwork(demo.albums.first().coverArt))
demo.MiniPlayerOverlay(Modifier.align(Alignment.BottomCenter))
Column(Modifier.fillMaxSize()) {
AlbumsScreen(
demo.albums,
demo.coverArt,
demo.artwork(demo.albums.first().coverArt),
modifier = Modifier.weight(1f),
)
demo.MiniPlayerOverlay(demo.nowPlayingSong, demo.nowPlayingAlbum)
}
}
Screen.AlbumDetail -> {
Box(Modifier.fillMaxSize()) {
Column(Modifier.fillMaxSize()) {
AlbumDetailScreen(
album = demo.album,
songs = demo.albumSongs,
@@ -156,10 +160,10 @@ class DemoScreenshotTest {
artwork = demo.artwork(demo.album.coverArt),
onBack = {},
onSongClick = {},
playingSongId = demo.nowPlayingSong.id,
modifier = Modifier.fillMaxSize(),
playingSongId = demo.albumSongs.first().id,
modifier = Modifier.weight(1f),
)
demo.MiniPlayerOverlay(Modifier.align(Alignment.BottomCenter))
demo.MiniPlayerOverlay(demo.albumSongs.first(), demo.album)
}
}
@@ -178,7 +182,7 @@ class DemoScreenshotTest {
}
Screen.Artists -> {
Box(Modifier.fillMaxSize()) {
Column(Modifier.fillMaxSize()) {
LibraryScreen(
selectedTab = LibraryTab.Artists,
onTabSelected = {},
@@ -192,14 +196,14 @@ class DemoScreenshotTest {
onSync = {},
onOpenSettings = {},
artwork = demo.artwork(demo.artists.first().coverArt),
modifier = Modifier.fillMaxSize(),
modifier = Modifier.weight(1f),
)
demo.MiniPlayerOverlay(Modifier.align(Alignment.BottomCenter))
demo.MiniPlayerOverlay(demo.nowPlayingSong, demo.nowPlayingAlbum)
}
}
Screen.Search -> {
Box(Modifier.fillMaxSize()) {
Column(Modifier.fillMaxSize()) {
LibraryScreen(
selectedTab = LibraryTab.Albums,
onTabSelected = {},
@@ -218,9 +222,9 @@ class DemoScreenshotTest {
search = DEMO_SEARCH,
onSearchChange = {},
artwork = demo.artwork(demo.searchAlbums.first().coverArt),
modifier = Modifier.fillMaxSize(),
modifier = Modifier.weight(1f),
)
demo.MiniPlayerOverlay(Modifier.align(Alignment.BottomCenter))
demo.MiniPlayerOverlay(demo.nowPlayingSong, demo.nowPlayingAlbum)
}
}
}
@@ -242,6 +246,7 @@ class DemoScreenshotTest {
albums: List<Album>,
coverArt: (String?, Boolean) -> CoverArtRef?,
artwork: ArtworkColors,
modifier: Modifier = Modifier,
) {
LibraryScreen(
selectedTab = LibraryTab.Albums,
@@ -259,7 +264,7 @@ class DemoScreenshotTest {
sortOptions = sortOptionsFor(LibraryTab.Albums),
starredSupported = true,
artwork = artwork,
modifier = Modifier.fillMaxSize(),
modifier = modifier,
)
}
@@ -276,12 +281,16 @@ class DemoScreenshotTest {
}
@Composable
private fun DemoData.MiniPlayerOverlay(modifier: Modifier = Modifier) {
private fun DemoData.MiniPlayerOverlay(
song: Song,
album: Album,
modifier: Modifier = Modifier,
) {
MiniPlayer(
state = playbackState,
positionMs = positionMs,
coverArt = coverArt(nowPlayingAlbum.coverArt, true),
artwork = artwork(nowPlayingAlbum.coverArt),
state = playbackFor(song, album),
positionMs = positionFor(song),
coverArt = coverArt(album.coverArt, true),
artwork = artwork(album.coverArt),
onExpand = {},
onPlayPause = {},
onNext = {},
@@ -308,23 +317,29 @@ class DemoScreenshotTest {
val engine: FakeImageLoaderEngine,
private val bitmaps: Map<String, Bitmap>,
) {
val playbackState =
val playbackState = playbackFor(nowPlayingSong, nowPlayingAlbum)
val positionMs: Long = positionFor(nowPlayingSong)
fun playbackFor(
song: Song,
album: Album,
): PlaybackState =
PlaybackState(
item =
QueueItem(
id = nowPlayingSong.id,
title = nowPlayingSong.title,
artist = nowPlayingSong.artist,
album = nowPlayingSong.album,
coverArtId = nowPlayingAlbum.coverArt,
id = song.id,
title = song.title,
artist = song.artist,
album = song.album,
coverArtId = album.coverArt,
),
isPlaying = true,
durationMs = (nowPlayingSong.duration ?: 0) * 1000,
durationMs = (song.duration ?: 0) * 1000,
hasNext = true,
hasPrevious = false,
)
val positionMs: Long = (nowPlayingSong.duration ?: 0) * 1000 * 35 / 100
fun positionFor(song: Song): Long = (song.duration ?: 0) * 1000 * 35 / 100
fun artwork(coverArtId: String?): ArtworkColors {
val bitmap = coverArtId?.let(bitmaps::get) ?: return artworkColorsFromSeeds(FALLBACK_SEED, null)
@@ -381,16 +396,18 @@ class DemoScreenshotTest {
val homePlayingAlbum = albums.firstOrNull { it.name == "Shaking The Habitual" } ?: albums.last()
val homePlayingSong = dao.songsByAlbum(1, homePlayingAlbum.id).first().first()
val artist =
artists.maxByOrNull { it.albumCount }
artists.firstOrNull { it.name == "Ugress" }
?: artists.maxByOrNull { it.albumCount }
?: artists.first()
val artistAlbums = dao.albumsForArtist(1, artist.id).first()
fun namedArtists(artists: List<Artist>) = artists.filterNot { it.name.equals("Various Artists", ignoreCase = true) }
val feed =
HomeFeed(
recentlyPlayedAlbums = dao.recentlyPlayedAlbums(1, 10).first(),
recentlyPlayedArtists = dao.recentlyPlayedArtists(1, 10).first(),
recentlyPlayedArtists = namedArtists(dao.recentlyPlayedArtists(1, 10).first()),
mostPlayedAlbums = dao.mostPlayedAlbums(1, 10).first(),
mostPlayedArtists = dao.mostPlayedArtists(1, 10).first(),
mostPlayedArtists = namedArtists(dao.mostPlayedArtists(1, 10).first()),
genres = dao.genresByMostPlayed(1).first(),
decades = dao.decades(1).first(),
recentlyStarredSongs = dao.recentlyStarredSongs(1, 10).first(),
Binary file not shown.

Before

Width:  |  Height:  |  Size: 483 KiB

After

Width:  |  Height:  |  Size: 484 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 993 KiB

After

Width:  |  Height:  |  Size: 867 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 476 KiB

After

Width:  |  Height:  |  Size: 496 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 161 KiB

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 313 KiB

After

Width:  |  Height:  |  Size: 319 KiB