From b0d0936c564013efabd815828bc80349e53e8cda Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Wed, 27 May 2026 20:57:41 -0400 Subject: [PATCH] =?UTF-8?q?feat(android):=20Home=20per-section=20empty=20m?= =?UTF-8?q?essages=20(audit=20v3=20=C2=A74.5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Audit v3 §4.5: Flutter renders explanatory copy for each empty Home section ("No forgotten favourites yet. Like albums or artists to fill this in." for Rediscover, "Play some music..." for Most played, etc). Android was hiding empty sections entirely, which made the home view look sparse even when 2-3 sections had data and contributed to the user's emulator complaint about missing rows. Now: every section slot renders either the populated HorizontalScrollRow OR an EmptySection card (sentence-case title + understated body copy) so the page structure is always visible. Playlists row keeps its "hide-when-empty" behaviour for now since it leads the page — empty copy at the top would feel like an error. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../minstrel/home/ui/HomeScreen.kt | 65 ++++++++++++++++--- 1 file changed, 57 insertions(+), 8 deletions(-) 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 0b90b4d0..e9c4f84c 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 @@ -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