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 b0d0936c56 - Show all commits
@@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
@@ -269,31 +270,79 @@ private fun HomeSuccessContent(
if (sections.playlists.isNotEmpty()) {
item { PlaylistsRow(sections.playlists, onPlaylistClick) }
}
if (sections.recentlyAddedAlbums.isNotEmpty()) {
item {
item {
if (sections.recentlyAddedAlbums.isNotEmpty()) {
AlbumsRow("Recently added", sections.recentlyAddedAlbums, onAlbumClick)
} else {
EmptySection(
title = "Recently added",
body = "Albums you add to the library will show up here first.",
)
}
}
if (sections.rediscoverAlbums.isNotEmpty() || sections.rediscoverArtists.isNotEmpty()) {
item {
item {
if (sections.rediscoverAlbums.isNotEmpty() ||
sections.rediscoverArtists.isNotEmpty()
) {
RediscoverBlock(
albums = sections.rediscoverAlbums,
artists = sections.rediscoverArtists,
onAlbumClick = onAlbumClick,
onArtistClick = onArtistClick,
)
} else {
EmptySection(
title = "Rediscover",
body = "No forgotten favourites yet. Like albums or " +
"artists to fill this in.",
)
}
}
if (sections.mostPlayedTracks.isNotEmpty()) {
item { MostPlayedRow(sections.mostPlayedTracks, onAlbumClick) }
item {
if (sections.mostPlayedTracks.isNotEmpty()) {
MostPlayedRow(sections.mostPlayedTracks, onAlbumClick)
} else {
EmptySection(
title = "Most played",
body = "Play some music — your most-listened tracks will appear here.",
)
}
}
if (sections.lastPlayedArtists.isNotEmpty()) {
item { ArtistsRow("Last played", sections.lastPlayedArtists, onArtistClick) }
item {
if (sections.lastPlayedArtists.isNotEmpty()) {
ArtistsRow("Last played", sections.lastPlayedArtists, onArtistClick)
} else {
EmptySection(
title = "Last played",
body = "Recently played artists will show up here.",
)
}
}
item { Spacer(Modifier.height(BOTTOM_PADDING_FOR_MINIPLAYER_DP.dp)) }
}
}
@Composable
private fun EmptySection(title: String, body: String) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 12.dp),
) {
Text(
text = title,
style = MaterialTheme.typography.titleLarge,
color = MaterialTheme.colorScheme.onBackground,
)
Spacer(Modifier.height(4.dp))
Text(
text = body,
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
}
/**
* Rediscover may have both an albums sub-row and an artists sub-row. When
* both are present the artist row gets an empty title so the section