feat: M3 weighted shuffle v1 — real /api/radio with scoring #21

Merged
bvandeusen merged 262 commits from dev into main 2026-04-27 11:00:29 -04:00
Showing only changes of commit 1d1a27540a - Show all commits
@@ -75,6 +75,7 @@ import javax.inject.Inject
private const val SHARE_STOP_TIMEOUT_MS = 5_000L
private const val BOTTOM_PADDING_FOR_MINIPLAYER_DP = 140
private const val RECENTLY_ADDED_CHUNK = 25
// ─── State ───────────────────────────────────────────────────────────
@@ -290,10 +291,24 @@ private fun HomeSuccessContent(
if (sections.playlists.isNotEmpty()) {
item { PlaylistsRow(sections.playlists, onPlaylistClick) }
}
item {
if (sections.recentlyAddedAlbums.isNotEmpty()) {
AlbumsRow("Recently added", sections.recentlyAddedAlbums, onAlbumClick)
} else {
if (sections.recentlyAddedAlbums.isNotEmpty()) {
// Chunk into stacked carousels of 25 so a large library
// reads as multiple rows instead of one unwieldy LazyRow.
// Only the first chunk carries the section title; the rest
// are untitled continuation rows (matches Flutter).
val chunks = sections.recentlyAddedAlbums.chunked(RECENTLY_ADDED_CHUNK)
itemsIndexed(
items = chunks,
key = { index, chunk -> "recent-$index-${chunk.first().id}" },
) { index, chunk ->
AlbumsRow(
title = if (index == 0) "Recently added" else "",
albums = chunk,
onAlbumClick = onAlbumClick,
)
}
} else {
item {
EmptySection(
title = "Recently added",
body = "Albums you add to the library will show up here first.",