play the starred list from the home row, and reorder the home sections

This commit is contained in:
austinried
2026-10-04 00:30:06 +00:00
parent 82b62b8d9d
commit 3affe7e049
4 changed files with 40 additions and 25 deletions
@@ -210,6 +210,16 @@ class PlaybackController(
songId: String, songId: String,
) = playContext(queueRepository.songEntry(sourceId, songId), 0) ) = playContext(queueRepository.songEntry(sourceId, songId), 0)
fun playSongs(
sourceId: Long,
songIds: List<String>,
startIndex: Int,
) {
if (songIds.isEmpty()) return
val entries = songIds.map { id -> QueueEntry(position = 0, sourceId = sourceId, kind = QueueKind.Song, refId = id) }
play(entries, startIndex.toLong().coerceIn(0L, songIds.lastIndex.toLong()))
}
fun playPlaylist( fun playPlaylist(
sourceId: Long, sourceId: Long,
playlistId: String, playlistId: String,
@@ -16,6 +16,7 @@ import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.AssistChip import androidx.compose.material3.AssistChip
@@ -61,7 +62,7 @@ enum class HomeSection(
Decades("Decades"), Decades("Decades"),
RecentlyStarredSongs("Recently starred"), RecentlyStarredSongs("Recently starred"),
RecentlyAddedAlbums("Recently added"), RecentlyAddedAlbums("Recently added"),
Rediscover("On repeat"), Rediscover("Rediscover"),
; ;
companion object { companion object {
@@ -103,7 +104,7 @@ fun HomeRoute(
bottomInset = bottomInset, bottomInset = bottomInset,
onAlbumClick = onAlbumClick, onAlbumClick = onAlbumClick,
onArtistClick = onArtistClick, onArtistClick = onArtistClick,
onSongClick = viewModel::play, onPlayStarred = viewModel::playStarred,
onLongClick = { contextMenuHost?.show(it, actions) }, onLongClick = { contextMenuHost?.show(it, actions) },
onMore = onMore, onMore = onMore,
onGenreClick = onGenreClick, onGenreClick = onGenreClick,
@@ -121,7 +122,7 @@ fun HomeScreen(
bottomInset: Dp = 0.dp, bottomInset: Dp = 0.dp,
onAlbumClick: (Album) -> Unit = {}, onAlbumClick: (Album) -> Unit = {},
onArtistClick: (Artist) -> Unit = {}, onArtistClick: (Artist) -> Unit = {},
onSongClick: (Song) -> Unit = {}, onPlayStarred: (List<Song>, Int) -> Unit = { _, _ -> },
onLongClick: (MenuTarget) -> Unit = {}, onLongClick: (MenuTarget) -> Unit = {},
onMore: (HomeSection) -> Unit = {}, onMore: (HomeSection) -> Unit = {},
onGenreClick: (String) -> Unit = {}, onGenreClick: (String) -> Unit = {},
@@ -148,8 +149,8 @@ fun HomeScreen(
contentPadding = PaddingValues(top = topInset + 8.dp, bottom = bottomInset + 24.dp), contentPadding = PaddingValues(top = topInset + 8.dp, bottom = bottomInset + 24.dp),
) { ) {
albumRow( albumRow(
HomeSection.RecentlyPlayedAlbums, HomeSection.RecentlyAddedAlbums,
feed.recentlyPlayedAlbums, feed.recentlyAddedAlbums,
coverArt, coverArt,
onAlbumClick, onAlbumClick,
onLongClick, onLongClick,
@@ -163,6 +164,15 @@ fun HomeScreen(
onLongClick, onLongClick,
onMore, onMore,
) )
starredSongs(
HomeSection.RecentlyStarredSongs,
feed.recentlyStarredSongs,
coverArt,
playingSongId,
onPlayStarred,
onLongClick,
onMore,
)
albumRow( albumRow(
HomeSection.MostPlayedAlbums, HomeSection.MostPlayedAlbums,
feed.mostPlayedAlbums, feed.mostPlayedAlbums,
@@ -171,6 +181,7 @@ fun HomeScreen(
onLongClick, onLongClick,
onMore, onMore,
) )
genreBlock(HomeSection.Genres, feed.genres, onGenreClick, onMore)
artistRow( artistRow(
HomeSection.MostPlayedArtists, HomeSection.MostPlayedArtists,
feed.mostPlayedArtists, feed.mostPlayedArtists,
@@ -179,28 +190,18 @@ fun HomeScreen(
onLongClick, onLongClick,
onMore, onMore,
) )
genreBlock(HomeSection.Genres, feed.genres, onGenreClick, onMore)
decadeRow(HomeSection.Decades, feed.decades, onDecadeClick, onMore) decadeRow(HomeSection.Decades, feed.decades, onDecadeClick, onMore)
starredSongs(
HomeSection.RecentlyStarredSongs,
feed.recentlyStarredSongs,
coverArt,
playingSongId,
onSongClick,
onLongClick,
onMore,
)
albumRow( albumRow(
HomeSection.RecentlyAddedAlbums, HomeSection.Rediscover,
feed.recentlyAddedAlbums, feed.rediscoverAlbums,
coverArt, coverArt,
onAlbumClick, onAlbumClick,
onLongClick, onLongClick,
onMore, onMore,
) )
albumRow( albumRow(
HomeSection.Rediscover, HomeSection.RecentlyPlayedAlbums,
feed.rediscoverAlbums, feed.recentlyPlayedAlbums,
coverArt, coverArt,
onAlbumClick, onAlbumClick,
onLongClick, onLongClick,
@@ -360,7 +361,7 @@ private fun LazyListScope.starredSongs(
songs: List<AlbumSongItem>, songs: List<AlbumSongItem>,
coverArt: (String?, Boolean) -> CoverArtRef?, coverArt: (String?, Boolean) -> CoverArtRef?,
playingSongId: String?, playingSongId: String?,
onSongClick: (Song) -> Unit, onPlayStarred: (List<Song>, Int) -> Unit,
onLongClick: (MenuTarget) -> Unit, onLongClick: (MenuTarget) -> Unit,
onMore: (HomeSection) -> Unit, onMore: (HomeSection) -> Unit,
) { ) {
@@ -368,7 +369,7 @@ private fun LazyListScope.starredSongs(
item(key = "${section.name}-header") { item(key = "${section.name}-header") {
HomeSectionHeader(section.title) { onMore(section) } HomeSectionHeader(section.title) { onMore(section) }
} }
items(songs, key = { it.song.id }) { item -> itemsIndexed(songs, key = { _, item -> item.song.id }) { index, item ->
SongRow( SongRow(
song = item.song, song = item.song,
coverArtId = item.coverArt, coverArtId = item.coverArt,
@@ -377,7 +378,7 @@ private fun LazyListScope.starredSongs(
durationSeconds = item.song.duration, durationSeconds = item.song.duration,
modifier = modifier =
Modifier.combinedClickable( Modifier.combinedClickable(
onClick = { onSongClick(item.song) }, onClick = { onPlayStarred(songs.map { it.song }, index) },
onLongClick = { onLongClick(MenuTarget.Song(item.song, coverArt(item.coverArt, true))) }, onLongClick = { onLongClick(MenuTarget.Song(item.song, coverArt(item.coverArt, true))) },
), ),
) )
@@ -101,8 +101,12 @@ class HomeViewModel(
thumbnail: Boolean, thumbnail: Boolean,
): CoverArtRef? = sourceRepository.coverArt(coverArt, thumbnail) ): CoverArtRef? = sourceRepository.coverArt(coverArt, thumbnail)
fun play(song: Song) { fun playStarred(
viewModelScope.playSongInContext(libraryRepository, playbackController, song) songs: List<Song>,
startIndex: Int,
) {
val sourceId = songs.getOrNull(startIndex)?.sourceId ?: return
playbackController.playSongs(sourceId, songs.map { it.id }, startIndex)
} }
fun sync() = syncManager.requestSync() fun sync() = syncManager.requestSync()
@@ -43,7 +43,7 @@ class HomeScreenshotTest {
} }
} }
composeRule.waitUntil(timeoutMillis = 5_000) { composeRule.waitUntil(timeoutMillis = 5_000) {
composeRule.onAllNodesWithText("Recently played").fetchSemanticsNodes().isNotEmpty() composeRule.onAllNodesWithText("Recently added").fetchSemanticsNodes().isNotEmpty()
} }
composeRule.onRoot().captureRoboImage("src/test/screenshots/home.png") composeRule.onRoot().captureRoboImage("src/test/screenshots/home.png")
} }