diff --git a/android/app/src/main/java/com/fabledsword/minstrel/home/ui/HomeScreen.kt b/android/app/src/main/java/com/fabledsword/minstrel/home/ui/HomeScreen.kt index 276caae4..0de419dd 100644 --- a/android/app/src/main/java/com/fabledsword/minstrel/home/ui/HomeScreen.kt +++ b/android/app/src/main/java/com/fabledsword/minstrel/home/ui/HomeScreen.kt @@ -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, @@ -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, diff --git a/android/app/src/main/java/com/fabledsword/minstrel/playlists/widgets/PlaylistCard.kt b/android/app/src/main/java/com/fabledsword/minstrel/playlists/widgets/PlaylistCard.kt index 60f06ca8..da12d8e4 100644 --- a/android/app/src/main/java/com/fabledsword/minstrel/playlists/widgets/PlaylistCard.kt +++ b/android/app/src/main/java/com/fabledsword/minstrel/playlists/widgets/PlaylistCard.kt @@ -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() } }