mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-10 15:11:58 +01:00
put the mixed menu back to two rows, and only badge real progress
The split bar read badly; a partly downloaded list goes back to stacked Download and Delete items. The badge showed progress for any list with a downloaded song in it, which made a mostly-downloaded album look like it was fetching. It now shows only when that list is complete or has a download actually in flight; a partly downloaded idle list shows nothing. The album and playlist detail screens' more-menus had no download entries at all, leaving delete reachable only via the hero's long press. They now take the same status-driven items as everywhere else.
This commit is contained in:
@@ -24,9 +24,10 @@ enum class DownloadIndicator { Hidden, InProgress, Complete }
|
||||
|
||||
fun ListDownloadStatus.indicator(): DownloadIndicator =
|
||||
when {
|
||||
total == 0L || (downloaded == 0L && downloading == 0L) -> DownloadIndicator.Hidden
|
||||
total == 0L -> DownloadIndicator.Hidden
|
||||
complete -> DownloadIndicator.Complete
|
||||
else -> DownloadIndicator.InProgress
|
||||
downloading > 0 -> DownloadIndicator.InProgress
|
||||
else -> DownloadIndicator.Hidden
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.subtracks.ui.components
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
@@ -32,7 +31,6 @@ import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.ModalBottomSheet
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.VerticalDivider
|
||||
import androidx.compose.material3.rememberModalBottomSheetState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
@@ -353,55 +351,15 @@ private fun BulkDownloadItem(
|
||||
dismiss: (() -> Unit) -> Unit,
|
||||
) {
|
||||
val bulk = actions.bulkDownload ?: return
|
||||
val offered = (target.listDownload() ?: ListDownloadStatus()).actions()
|
||||
if (offered.size > 1) {
|
||||
SplitDownloadItem(offered, target, bulk, dismiss)
|
||||
return
|
||||
}
|
||||
offered.singleOrNull()?.let { action ->
|
||||
MenuItem(bulkIcon(action), bulkLabel(action)) { dismiss { bulk(target, action) } }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SplitDownloadItem(
|
||||
offered: List<BulkDownloadAction>,
|
||||
target: MenuTarget,
|
||||
bulk: (MenuTarget, BulkDownloadAction) -> Unit,
|
||||
dismiss: (() -> Unit) -> Unit,
|
||||
) {
|
||||
Row(Modifier.fillMaxWidth().height(56.dp)) {
|
||||
offered.forEachIndexed { index, action ->
|
||||
if (index > 0) {
|
||||
VerticalDivider(color = MaterialTheme.colorScheme.outlineVariant)
|
||||
}
|
||||
Row(
|
||||
modifier = Modifier.weight(1f).clickable { dismiss { bulk(target, action) } },
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Icon(bulkIcon(action), contentDescription = null)
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Text(bulkLabel(action))
|
||||
}
|
||||
for (action in (target.listDownload() ?: ListDownloadStatus()).actions()) {
|
||||
when (action) {
|
||||
BulkDownloadAction.Delete -> MenuItem(Icons.Rounded.Delete, "Delete downloads") { dismiss { bulk(target, action) } }
|
||||
BulkDownloadAction.Cancel -> MenuItem(Icons.Rounded.Cancel, "Cancel downloads") { dismiss { bulk(target, action) } }
|
||||
BulkDownloadAction.Download -> MenuItem(Icons.Rounded.Download, "Download") { dismiss { bulk(target, action) } }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun bulkIcon(action: BulkDownloadAction): ImageVector =
|
||||
when (action) {
|
||||
BulkDownloadAction.Download -> Icons.Rounded.Download
|
||||
BulkDownloadAction.Cancel -> Icons.Rounded.Cancel
|
||||
BulkDownloadAction.Delete -> Icons.Rounded.Delete
|
||||
}
|
||||
|
||||
private fun bulkLabel(action: BulkDownloadAction): String =
|
||||
when (action) {
|
||||
BulkDownloadAction.Download -> "Download"
|
||||
BulkDownloadAction.Cancel -> "Cancel downloads"
|
||||
BulkDownloadAction.Delete -> "Delete downloads"
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun StarItem(
|
||||
current: Long?,
|
||||
|
||||
@@ -70,6 +70,13 @@ fun AlbumDetailRoute(
|
||||
val playback by playbackController.state.collectAsStateWithLifecycle()
|
||||
val context = playback.context
|
||||
val shortcutArt = remember(coverArtId) { coverArtId?.let { viewModel.coverArt(it, true) } }
|
||||
val requestDownloadAction: (BulkDownloadAction) -> Unit = { action ->
|
||||
if (action == BulkDownloadAction.Delete) {
|
||||
scope.launch { pendingDelete = viewModel.downloadedBytes() }
|
||||
} else {
|
||||
viewModel.onDownloadAction(action)
|
||||
}
|
||||
}
|
||||
val actions =
|
||||
ItemActions(
|
||||
playSong = { song -> songs.indexOfFirst { it.id == song.id }.takeIf { it >= 0 }?.let(viewModel::play) },
|
||||
@@ -80,6 +87,7 @@ fun AlbumDetailRoute(
|
||||
download = viewModel::download,
|
||||
cancelDownload = viewModel::cancelDownload,
|
||||
deleteDownload = viewModel::deleteDownload,
|
||||
bulkDownload = { _, action -> requestDownloadAction(action) },
|
||||
setStar = setStar,
|
||||
viewArtist = onViewArtist,
|
||||
)
|
||||
@@ -91,19 +99,20 @@ fun AlbumDetailRoute(
|
||||
artwork = rememberArtworkColors(shortcutArt ?: viewModel.coverArt(album?.coverArt, true), THEME_TRANSITION_MS),
|
||||
downloads = downloads,
|
||||
downloadStatus = downloadStatus,
|
||||
onDownloadAction = { action ->
|
||||
if (action == BulkDownloadAction.Delete) {
|
||||
scope.launch { pendingDelete = viewModel.downloadedBytes() }
|
||||
} else {
|
||||
viewModel.onDownloadAction(action)
|
||||
}
|
||||
},
|
||||
onDownloadAction = requestDownloadAction,
|
||||
onBack = onBack,
|
||||
onSongClick = viewModel::play,
|
||||
onSongLongClick = { contextMenuHost?.show(it, actions) },
|
||||
onShuffle = viewModel::shuffle,
|
||||
onPlay = viewModel::playAll,
|
||||
onMore = { album?.let { contextMenuHost?.show(MenuTarget.Album(it, viewModel.coverArt(it.coverArt, true)), actions) } },
|
||||
onMore = {
|
||||
album?.let {
|
||||
contextMenuHost?.show(
|
||||
MenuTarget.Album(it, viewModel.coverArt(it.coverArt, true), downloadStatus),
|
||||
actions,
|
||||
)
|
||||
}
|
||||
},
|
||||
onArtistClick =
|
||||
album
|
||||
?.takeIf { !it.albumArtist.isNullOrBlank() }
|
||||
|
||||
@@ -55,6 +55,13 @@ fun PlaylistDetailRoute(
|
||||
var pendingDelete by remember { mutableStateOf<Long?>(null) }
|
||||
val playback by playbackController.state.collectAsStateWithLifecycle()
|
||||
val context = playback.context
|
||||
val requestDownloadAction: (BulkDownloadAction) -> Unit = { action ->
|
||||
if (action == BulkDownloadAction.Delete) {
|
||||
scope.launch { pendingDelete = viewModel.downloadedBytes() }
|
||||
} else {
|
||||
viewModel.onDownloadAction(action)
|
||||
}
|
||||
}
|
||||
val actions =
|
||||
ItemActions(
|
||||
playPlaylist = { viewModel.playAll() },
|
||||
@@ -64,6 +71,7 @@ fun PlaylistDetailRoute(
|
||||
download = viewModel::download,
|
||||
cancelDownload = viewModel::cancelDownload,
|
||||
deleteDownload = viewModel::deleteDownload,
|
||||
bulkDownload = { _, action -> requestDownloadAction(action) },
|
||||
setStar = setStar,
|
||||
viewAlbum = onViewAlbum,
|
||||
viewArtist = onViewArtist,
|
||||
@@ -75,19 +83,15 @@ fun PlaylistDetailRoute(
|
||||
artwork = rememberArtworkColors(viewModel.coverArt(playlist?.coverArt, true), THEME_TRANSITION_MS),
|
||||
downloads = downloads,
|
||||
downloadStatus = downloadStatus,
|
||||
onDownloadAction = { action ->
|
||||
if (action == BulkDownloadAction.Delete) {
|
||||
scope.launch { pendingDelete = viewModel.downloadedBytes() }
|
||||
} else {
|
||||
viewModel.onDownloadAction(action)
|
||||
}
|
||||
},
|
||||
onDownloadAction = requestDownloadAction,
|
||||
onBack = onBack,
|
||||
onSongClick = viewModel::play,
|
||||
onSongLongClick = { contextMenuHost?.show(it, actions) },
|
||||
onShuffle = viewModel::shuffle,
|
||||
onPlay = viewModel::playAll,
|
||||
onMore = { playlist?.let { contextMenuHost?.show(MenuTarget.Playlist(it, viewModel.coverArt(it.coverArt, true)), actions) } },
|
||||
onMore = {
|
||||
playlist?.let { contextMenuHost?.show(MenuTarget.Playlist(it, viewModel.coverArt(it.coverArt, true), downloadStatus), actions) }
|
||||
},
|
||||
playingSongId = playback.item?.id.takeIf { context?.kind == QueueKind.Playlist && context.refId == playlistId },
|
||||
)
|
||||
|
||||
|
||||
@@ -21,8 +21,13 @@ class DownloadIndicatorTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aPartlyDownloadedListShowsProgress() {
|
||||
assertEquals(DownloadIndicator.InProgress, ListDownloadStatus(total = 4, downloaded = 2).indicator())
|
||||
fun aPartlyDownloadedIdleListShowsNothing() {
|
||||
assertEquals(DownloadIndicator.Hidden, ListDownloadStatus(total = 4, downloaded = 2).indicator())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aPartlyDownloadedListWithSomethingInFlightShowsProgress() {
|
||||
assertEquals(DownloadIndicator.InProgress, ListDownloadStatus(total = 4, downloaded = 2, downloading = 1).indicator())
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user