feat(android): Search artists/albums as horizontal carousels
Audit v2 #14. Artists + Albums search sections were rendering as plain vertical TextRows (name-only for artists, title+artist for albums). Now match Flutter: * Artists: horizontal LazyRow of ArtistCard (cover + name) * Albums: horizontal LazyRow of AlbumCard (cover + title + artist) * Section headers gain a count suffix ("Artists 12") matching Flutter's _SectionHeader pattern; also applied to the Tracks header for consistency. Removed the now-unused TextRow helper. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -17,6 +17,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
@@ -50,6 +51,8 @@ import androidx.navigation.NavHostController
|
||||
import com.composables.icons.lucide.ArrowLeft
|
||||
import com.composables.icons.lucide.Lucide
|
||||
import com.composables.icons.lucide.X
|
||||
import com.fabledsword.minstrel.library.widgets.AlbumCard
|
||||
import com.fabledsword.minstrel.library.widgets.ArtistCard
|
||||
import com.fabledsword.minstrel.models.AlbumRef
|
||||
import com.fabledsword.minstrel.models.ArtistRef
|
||||
import com.fabledsword.minstrel.models.SearchResponseRef
|
||||
@@ -208,14 +211,16 @@ private fun LazyListScope.artistsSection(
|
||||
onArtistClick: (String) -> Unit,
|
||||
) {
|
||||
if (artists.isEmpty()) return
|
||||
item { SectionHeader("Artists") }
|
||||
items(items = artists, key = { "art-${it.id}" }) { artist ->
|
||||
TextRow(
|
||||
primary = artist.name,
|
||||
secondary = null,
|
||||
onClick = { onArtistClick(artist.id) },
|
||||
)
|
||||
HorizontalDivider()
|
||||
item { SectionHeader("Artists", artists.size) }
|
||||
item {
|
||||
LazyRow(
|
||||
contentPadding = PaddingValues(horizontal = 8.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
items(items = artists, key = { "art-${it.id}" }) { artist ->
|
||||
ArtistCard(artist = artist, onClick = { onArtistClick(artist.id) })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,14 +229,16 @@ private fun LazyListScope.albumsSection(
|
||||
onAlbumClick: (String) -> Unit,
|
||||
) {
|
||||
if (albums.isEmpty()) return
|
||||
item { SectionHeader("Albums") }
|
||||
items(items = albums, key = { "alb-${it.id}" }) { album ->
|
||||
TextRow(
|
||||
primary = album.title,
|
||||
secondary = album.artistName.takeIf { it.isNotEmpty() },
|
||||
onClick = { onAlbumClick(album.id) },
|
||||
)
|
||||
HorizontalDivider()
|
||||
item { SectionHeader("Albums", albums.size) }
|
||||
item {
|
||||
LazyRow(
|
||||
contentPadding = PaddingValues(horizontal = 8.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
items(items = albums, key = { "alb-${it.id}" }) { album ->
|
||||
AlbumCard(album = album, onClick = { onAlbumClick(album.id) })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,7 +250,7 @@ private fun LazyListScope.tracksSection(
|
||||
onNavigateToArtist: (String) -> Unit,
|
||||
) {
|
||||
if (tracks.isEmpty()) return
|
||||
item { SectionHeader("Tracks") }
|
||||
item { SectionHeader("Tracks", tracks.size) }
|
||||
items(items = tracks, key = { "trk-${it.id}" }) { track ->
|
||||
TrackResultRow(
|
||||
track = track,
|
||||
@@ -307,45 +314,24 @@ private fun TrackResultRow(
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SectionHeader(text: String) {
|
||||
Text(
|
||||
text = text,
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
color = MaterialTheme.colorScheme.onBackground,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TextRow(primary: String, secondary: String?, onClick: () -> Unit) {
|
||||
private fun SectionHeader(label: String, count: Int) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable(onClick = onClick)
|
||||
.padding(horizontal = 16.dp, vertical = 12.dp),
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
Column(modifier = Modifier.fillMaxWidth()) {
|
||||
Text(
|
||||
text = primary,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
if (!secondary.isNullOrEmpty()) {
|
||||
Text(
|
||||
text = secondary,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
}
|
||||
Text(
|
||||
text = label,
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
color = MaterialTheme.colorScheme.onBackground,
|
||||
)
|
||||
Text(
|
||||
text = "$count",
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user