Release: web UX overhaul + Android native port + server polish #59
@@ -709,10 +709,18 @@ enum class OfflinePoolKind(val label: String) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds the Home Playlists row. When [offline], the two cache-backed
|
* Builds the Home Playlists row. When [offline], the two cache-backed
|
||||||
* pool cards (Recently played, Liked) lead the row — mirrors Flutter's
|
* pool cards (Recently played, Liked) lead the row. Then For You +
|
||||||
* `_buildPlaylistsRow`. Then For You + Discover + 3× Songs-like fixed
|
* Discover + 3× Songs-like fixed slots (real card when generated,
|
||||||
* slots (real card when generated, placeholder otherwise), then any
|
* placeholder otherwise), then the secondary system kinds (deep cuts /
|
||||||
* user-owned playlists.
|
* 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(
|
private fun buildPlaylistsRow(
|
||||||
owned: List<PlaylistRef>,
|
owned: List<PlaylistRef>,
|
||||||
@@ -736,6 +744,15 @@ private fun buildPlaylistsRow(
|
|||||||
?.let { PlaylistRowItem.Real(it) }
|
?.let { PlaylistRowItem.Real(it) }
|
||||||
?: PlaylistRowItem.Placeholder("Songs like…", variantFor("songs-like", status))
|
?: 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) }
|
owned.filter { it.systemVariant == null }.forEach { out += PlaylistRowItem.Real(it) }
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
@@ -749,6 +766,19 @@ private fun variantFor(slot: String, s: SystemPlaylistsStatus): String = when {
|
|||||||
|
|
||||||
private const val SONGS_LIKE_SLOTS = 3
|
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
|
@Composable
|
||||||
private fun ArtistsRow(
|
private fun ArtistsRow(
|
||||||
title: String,
|
title: String,
|
||||||
|
|||||||
+5
-1
@@ -159,7 +159,11 @@ private fun systemLabelFor(variant: String?): String = when (variant) {
|
|||||||
"for_you" -> "For You"
|
"for_you" -> "For You"
|
||||||
"discover" -> "Discover"
|
"discover" -> "Discover"
|
||||||
"songs_like_artist" -> "Songs like…"
|
"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 -> ""
|
null -> ""
|
||||||
else -> variant.replace('_', ' ').replaceFirstChar { it.uppercase() }
|
else -> variant.replace('_', ' ').replaceFirstChar { it.uppercase() }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user