feat(android): surface secondary system playlists on Home + drop dead todays_mix label
Server's playlists registry has 8 system kinds (internal/playlists/ system.go:281-290) but Flutter Home only ever showed 5 slots: For You + Discover + 3 Songs-like. Operator request 2026-06-01: have the Android Home view also surface the 5 secondary kinds so the user can find them without digging into the Library > Playlists list. Android buildPlaylistsRow now appends deep_cuts, rediscover, new_for_you, on_this_day, first_listens in server-registry order after the existing Songs-like slots, when those playlists actually exist. No placeholders for the new 5 since they depend on library shape (deep albums for Deep cuts, prior history for On this day, etc.) and an empty placeholder would imply they're still building when they may just have no candidates. PlaylistCard.kt systemLabelFor gains explicit labels for the new kinds and drops the dead "todays_mix" branch (no such variant in the server registry). This diverges from Flutter Home which never surfaces the secondary kinds; web UI catch-up tracked as task #53. Naming note: the "Rediscover" playlist tile and the unrelated "Rediscover" recommendations section on the same Home both read "Rediscover" - operator follow-up to disambiguate.
This commit is contained in:
@@ -709,10 +709,18 @@ enum class OfflinePoolKind(val label: String) {
|
||||
|
||||
/**
|
||||
* Builds the Home Playlists row. When [offline], the two cache-backed
|
||||
* pool cards (Recently played, Liked) lead the row — mirrors Flutter's
|
||||
* `_buildPlaylistsRow`. Then For You + Discover + 3× Songs-like fixed
|
||||
* slots (real card when generated, placeholder otherwise), then any
|
||||
* user-owned playlists.
|
||||
* pool cards (Recently played, Liked) lead the row. Then For You +
|
||||
* Discover + 3× Songs-like fixed slots (real card when generated,
|
||||
* placeholder otherwise), then the secondary system kinds (deep cuts /
|
||||
* rediscover / new for you / on this day / first listens) when they
|
||||
* exist — no placeholders for these since they're conditional on
|
||||
* library shape, not guaranteed singletons. Finally user-owned
|
||||
* playlists.
|
||||
*
|
||||
* Diverges from Flutter (`flutter_client/lib/library/home_screen.dart`
|
||||
* `_buildPlaylistsRow`) which only shows the 5 fixed slots and never
|
||||
* surfaces the secondary kinds on Home. Operator authorized the
|
||||
* divergence on 2026-06-01; web UI catch-up tracked as task #53.
|
||||
*/
|
||||
private fun buildPlaylistsRow(
|
||||
owned: List<PlaylistRef>,
|
||||
@@ -736,6 +744,15 @@ private fun buildPlaylistsRow(
|
||||
?.let { PlaylistRowItem.Real(it) }
|
||||
?: PlaylistRowItem.Placeholder("Songs like…", variantFor("songs-like", status))
|
||||
}
|
||||
// Secondary system kinds in server-registry order. Only included
|
||||
// when actually generated — these depend on library shape (Deep
|
||||
// cuts needs deep albums, On this day needs prior history, etc.)
|
||||
// so a missing one means "not enough data" rather than "still
|
||||
// building".
|
||||
for (variant in SECONDARY_SYSTEM_VARIANTS) {
|
||||
owned.firstOrNull { it.systemVariant == variant }
|
||||
?.let { out += PlaylistRowItem.Real(it) }
|
||||
}
|
||||
owned.filter { it.systemVariant == null }.forEach { out += PlaylistRowItem.Real(it) }
|
||||
return out
|
||||
}
|
||||
@@ -749,6 +766,19 @@ private fun variantFor(slot: String, s: SystemPlaylistsStatus): String = when {
|
||||
|
||||
private const val SONGS_LIKE_SLOTS = 3
|
||||
|
||||
/**
|
||||
* The 5 system playlist kinds the server generates that aren't pinned
|
||||
* to Home's primary slots. Order matches `systemPlaylistRegistry` in
|
||||
* `internal/playlists/system.go`.
|
||||
*/
|
||||
private val SECONDARY_SYSTEM_VARIANTS = listOf(
|
||||
"deep_cuts",
|
||||
"rediscover",
|
||||
"new_for_you",
|
||||
"on_this_day",
|
||||
"first_listens",
|
||||
)
|
||||
|
||||
@Composable
|
||||
private fun ArtistsRow(
|
||||
title: String,
|
||||
|
||||
+5
-1
@@ -159,7 +159,11 @@ private fun systemLabelFor(variant: String?): String = when (variant) {
|
||||
"for_you" -> "For You"
|
||||
"discover" -> "Discover"
|
||||
"songs_like_artist" -> "Songs like…"
|
||||
"todays_mix" -> "Today's mix"
|
||||
"deep_cuts" -> "Deep cuts"
|
||||
"rediscover" -> "Rediscover"
|
||||
"new_for_you" -> "New for you"
|
||||
"on_this_day" -> "On this day"
|
||||
"first_listens" -> "First listens"
|
||||
null -> ""
|
||||
else -> variant.replace('_', ' ').replaceFirstChar { it.uppercase() }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user