Android v1 polish + Web UI flavor pass #65
@@ -101,7 +101,12 @@ import javax.inject.Inject
|
|||||||
private const val SHARE_STOP_TIMEOUT_MS = 5_000L
|
private const val SHARE_STOP_TIMEOUT_MS = 5_000L
|
||||||
private const val PLAYLIST_FETCH_TIMEOUT_MS = 8_000L
|
private const val PLAYLIST_FETCH_TIMEOUT_MS = 8_000L
|
||||||
private const val BOTTOM_PADDING_FOR_MINIPLAYER_DP = 140
|
private const val BOTTOM_PADDING_FOR_MINIPLAYER_DP = 140
|
||||||
private const val RECENTLY_ADDED_CHUNK = 25
|
// Recently Added is laid out in a multi-row LazyHorizontalGrid that
|
||||||
|
// scrolls as one panel (same pattern as Most Played). Two rows trades
|
||||||
|
// a tall block for fewer columns to scroll past — a 200dp tile × 2 =
|
||||||
|
// ~440dp section still leaves room for the rest of Home.
|
||||||
|
private const val RECENTLY_ADDED_GRID_ROWS = 2
|
||||||
|
private const val RECENTLY_ADDED_GRID_HEIGHT_DP = 440
|
||||||
|
|
||||||
// ─── State ───────────────────────────────────────────────────────────
|
// ─── State ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -512,23 +517,75 @@ private fun LazyListScope.recentlyAddedSection(
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Chunk into stacked carousels of 25 so a large library reads as
|
item {
|
||||||
// multiple rows instead of one unwieldy LazyRow. Only the first
|
RecentlyAddedGrid(
|
||||||
// chunk carries the section title; the rest are continuation rows.
|
albums = albums,
|
||||||
val chunks = albums.chunked(RECENTLY_ADDED_CHUNK)
|
|
||||||
itemsIndexed(
|
|
||||||
items = chunks,
|
|
||||||
key = { index, chunk -> "recent-$index-${chunk.first().id}" },
|
|
||||||
) { index, chunk ->
|
|
||||||
AlbumsRow(
|
|
||||||
title = if (index == 0) "Recently added" else "",
|
|
||||||
albums = chunk,
|
|
||||||
onAlbumClick = onAlbumClick,
|
onAlbumClick = onAlbumClick,
|
||||||
onPlayAlbum = onPlayAlbum,
|
onPlayAlbum = onPlayAlbum,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multi-row horizontal grid for Recently Added, mirroring the
|
||||||
|
* Most Played pattern: tiles laid out column-major across
|
||||||
|
* [RECENTLY_ADDED_GRID_ROWS] rows inside one LazyHorizontalGrid so
|
||||||
|
* every row scrolls together as one panel. Replaces the previous
|
||||||
|
* stacked-LazyRows layout which scrolled each chunk independently.
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
private fun RecentlyAddedGrid(
|
||||||
|
albums: List<HomeTile<AlbumRef>>,
|
||||||
|
onAlbumClick: (String) -> Unit,
|
||||||
|
onPlayAlbum: suspend (String) -> Unit,
|
||||||
|
) {
|
||||||
|
Column(modifier = Modifier.fillMaxWidth()) {
|
||||||
|
Text(
|
||||||
|
text = "Recently added",
|
||||||
|
style = MaterialTheme.typography.titleLarge,
|
||||||
|
color = MaterialTheme.colorScheme.onBackground,
|
||||||
|
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||||
|
)
|
||||||
|
// Re-flatten column-major to match Web's "ranks across the
|
||||||
|
// top row, then across the middle, then bottom" reading
|
||||||
|
// order. LazyHorizontalGrid otherwise fills column-major
|
||||||
|
// directly from a flat list and would scramble per-rank
|
||||||
|
// expectations.
|
||||||
|
val perRow = (albums.size + RECENTLY_ADDED_GRID_ROWS - 1) / RECENTLY_ADDED_GRID_ROWS
|
||||||
|
val rows = albums.chunked(perRow.coerceAtLeast(1))
|
||||||
|
val cols = rows.maxOfOrNull { it.size } ?: 0
|
||||||
|
val ordered = buildList {
|
||||||
|
for (c in 0 until cols) {
|
||||||
|
for (r in 0 until RECENTLY_ADDED_GRID_ROWS) {
|
||||||
|
rows.getOrNull(r)?.getOrNull(c)?.let { add(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LazyHorizontalGrid(
|
||||||
|
rows = GridCells.Fixed(RECENTLY_ADDED_GRID_ROWS),
|
||||||
|
contentPadding = PaddingValues(horizontal = 16.dp),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(RECENTLY_ADDED_GRID_HEIGHT_DP.dp),
|
||||||
|
) {
|
||||||
|
gridItems(items = ordered, key = { it.id }) { tile ->
|
||||||
|
val album = tile.value
|
||||||
|
if (album == null) {
|
||||||
|
SkeletonAlbumTile()
|
||||||
|
} else {
|
||||||
|
AlbumCard(
|
||||||
|
album = album,
|
||||||
|
onClick = { onAlbumClick(album.id) },
|
||||||
|
onPlay = { onPlayAlbum(album.id) },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun LazyListScope.rediscoverSection(
|
private fun LazyListScope.rediscoverSection(
|
||||||
albums: List<HomeTile<AlbumRef>>,
|
albums: List<HomeTile<AlbumRef>>,
|
||||||
artists: List<HomeTile<ArtistRef>>,
|
artists: List<HomeTile<ArtistRef>>,
|
||||||
|
|||||||
Reference in New Issue
Block a user