mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-11 15:29:15 +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 =
|
fun ListDownloadStatus.indicator(): DownloadIndicator =
|
||||||
when {
|
when {
|
||||||
total == 0L || (downloaded == 0L && downloading == 0L) -> DownloadIndicator.Hidden
|
total == 0L -> DownloadIndicator.Hidden
|
||||||
complete -> DownloadIndicator.Complete
|
complete -> DownloadIndicator.Complete
|
||||||
else -> DownloadIndicator.InProgress
|
downloading > 0 -> DownloadIndicator.InProgress
|
||||||
|
else -> DownloadIndicator.Hidden
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package com.subtracks.ui.components
|
package com.subtracks.ui.components
|
||||||
|
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
@@ -32,7 +31,6 @@ import androidx.compose.material3.LocalContentColor
|
|||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.ModalBottomSheet
|
import androidx.compose.material3.ModalBottomSheet
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.VerticalDivider
|
|
||||||
import androidx.compose.material3.rememberModalBottomSheetState
|
import androidx.compose.material3.rememberModalBottomSheetState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
@@ -353,55 +351,15 @@ private fun BulkDownloadItem(
|
|||||||
dismiss: (() -> Unit) -> Unit,
|
dismiss: (() -> Unit) -> Unit,
|
||||||
) {
|
) {
|
||||||
val bulk = actions.bulkDownload ?: return
|
val bulk = actions.bulkDownload ?: return
|
||||||
val offered = (target.listDownload() ?: ListDownloadStatus()).actions()
|
for (action in (target.listDownload() ?: ListDownloadStatus()).actions()) {
|
||||||
if (offered.size > 1) {
|
when (action) {
|
||||||
SplitDownloadItem(offered, target, bulk, dismiss)
|
BulkDownloadAction.Delete -> MenuItem(Icons.Rounded.Delete, "Delete downloads") { dismiss { bulk(target, action) } }
|
||||||
return
|
BulkDownloadAction.Cancel -> MenuItem(Icons.Rounded.Cancel, "Cancel downloads") { dismiss { bulk(target, action) } }
|
||||||
}
|
BulkDownloadAction.Download -> MenuItem(Icons.Rounded.Download, "Download") { dismiss { bulk(target, action) } }
|
||||||
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))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
@Composable
|
||||||
private fun StarItem(
|
private fun StarItem(
|
||||||
current: Long?,
|
current: Long?,
|
||||||
|
|||||||
@@ -70,6 +70,13 @@ fun AlbumDetailRoute(
|
|||||||
val playback by playbackController.state.collectAsStateWithLifecycle()
|
val playback by playbackController.state.collectAsStateWithLifecycle()
|
||||||
val context = playback.context
|
val context = playback.context
|
||||||
val shortcutArt = remember(coverArtId) { coverArtId?.let { viewModel.coverArt(it, true) } }
|
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 =
|
val actions =
|
||||||
ItemActions(
|
ItemActions(
|
||||||
playSong = { song -> songs.indexOfFirst { it.id == song.id }.takeIf { it >= 0 }?.let(viewModel::play) },
|
playSong = { song -> songs.indexOfFirst { it.id == song.id }.takeIf { it >= 0 }?.let(viewModel::play) },
|
||||||
@@ -80,6 +87,7 @@ fun AlbumDetailRoute(
|
|||||||
download = viewModel::download,
|
download = viewModel::download,
|
||||||
cancelDownload = viewModel::cancelDownload,
|
cancelDownload = viewModel::cancelDownload,
|
||||||
deleteDownload = viewModel::deleteDownload,
|
deleteDownload = viewModel::deleteDownload,
|
||||||
|
bulkDownload = { _, action -> requestDownloadAction(action) },
|
||||||
setStar = setStar,
|
setStar = setStar,
|
||||||
viewArtist = onViewArtist,
|
viewArtist = onViewArtist,
|
||||||
)
|
)
|
||||||
@@ -91,19 +99,20 @@ fun AlbumDetailRoute(
|
|||||||
artwork = rememberArtworkColors(shortcutArt ?: viewModel.coverArt(album?.coverArt, true), THEME_TRANSITION_MS),
|
artwork = rememberArtworkColors(shortcutArt ?: viewModel.coverArt(album?.coverArt, true), THEME_TRANSITION_MS),
|
||||||
downloads = downloads,
|
downloads = downloads,
|
||||||
downloadStatus = downloadStatus,
|
downloadStatus = downloadStatus,
|
||||||
onDownloadAction = { action ->
|
onDownloadAction = requestDownloadAction,
|
||||||
if (action == BulkDownloadAction.Delete) {
|
|
||||||
scope.launch { pendingDelete = viewModel.downloadedBytes() }
|
|
||||||
} else {
|
|
||||||
viewModel.onDownloadAction(action)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onBack = onBack,
|
onBack = onBack,
|
||||||
onSongClick = viewModel::play,
|
onSongClick = viewModel::play,
|
||||||
onSongLongClick = { contextMenuHost?.show(it, actions) },
|
onSongLongClick = { contextMenuHost?.show(it, actions) },
|
||||||
onShuffle = viewModel::shuffle,
|
onShuffle = viewModel::shuffle,
|
||||||
onPlay = viewModel::playAll,
|
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 =
|
onArtistClick =
|
||||||
album
|
album
|
||||||
?.takeIf { !it.albumArtist.isNullOrBlank() }
|
?.takeIf { !it.albumArtist.isNullOrBlank() }
|
||||||
|
|||||||
@@ -55,6 +55,13 @@ fun PlaylistDetailRoute(
|
|||||||
var pendingDelete by remember { mutableStateOf<Long?>(null) }
|
var pendingDelete by remember { mutableStateOf<Long?>(null) }
|
||||||
val playback by playbackController.state.collectAsStateWithLifecycle()
|
val playback by playbackController.state.collectAsStateWithLifecycle()
|
||||||
val context = playback.context
|
val context = playback.context
|
||||||
|
val requestDownloadAction: (BulkDownloadAction) -> Unit = { action ->
|
||||||
|
if (action == BulkDownloadAction.Delete) {
|
||||||
|
scope.launch { pendingDelete = viewModel.downloadedBytes() }
|
||||||
|
} else {
|
||||||
|
viewModel.onDownloadAction(action)
|
||||||
|
}
|
||||||
|
}
|
||||||
val actions =
|
val actions =
|
||||||
ItemActions(
|
ItemActions(
|
||||||
playPlaylist = { viewModel.playAll() },
|
playPlaylist = { viewModel.playAll() },
|
||||||
@@ -64,6 +71,7 @@ fun PlaylistDetailRoute(
|
|||||||
download = viewModel::download,
|
download = viewModel::download,
|
||||||
cancelDownload = viewModel::cancelDownload,
|
cancelDownload = viewModel::cancelDownload,
|
||||||
deleteDownload = viewModel::deleteDownload,
|
deleteDownload = viewModel::deleteDownload,
|
||||||
|
bulkDownload = { _, action -> requestDownloadAction(action) },
|
||||||
setStar = setStar,
|
setStar = setStar,
|
||||||
viewAlbum = onViewAlbum,
|
viewAlbum = onViewAlbum,
|
||||||
viewArtist = onViewArtist,
|
viewArtist = onViewArtist,
|
||||||
@@ -75,19 +83,15 @@ fun PlaylistDetailRoute(
|
|||||||
artwork = rememberArtworkColors(viewModel.coverArt(playlist?.coverArt, true), THEME_TRANSITION_MS),
|
artwork = rememberArtworkColors(viewModel.coverArt(playlist?.coverArt, true), THEME_TRANSITION_MS),
|
||||||
downloads = downloads,
|
downloads = downloads,
|
||||||
downloadStatus = downloadStatus,
|
downloadStatus = downloadStatus,
|
||||||
onDownloadAction = { action ->
|
onDownloadAction = requestDownloadAction,
|
||||||
if (action == BulkDownloadAction.Delete) {
|
|
||||||
scope.launch { pendingDelete = viewModel.downloadedBytes() }
|
|
||||||
} else {
|
|
||||||
viewModel.onDownloadAction(action)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onBack = onBack,
|
onBack = onBack,
|
||||||
onSongClick = viewModel::play,
|
onSongClick = viewModel::play,
|
||||||
onSongLongClick = { contextMenuHost?.show(it, actions) },
|
onSongLongClick = { contextMenuHost?.show(it, actions) },
|
||||||
onShuffle = viewModel::shuffle,
|
onShuffle = viewModel::shuffle,
|
||||||
onPlay = viewModel::playAll,
|
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 },
|
playingSongId = playback.item?.id.takeIf { context?.kind == QueueKind.Playlist && context.refId == playlistId },
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -21,8 +21,13 @@ class DownloadIndicatorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun aPartlyDownloadedListShowsProgress() {
|
fun aPartlyDownloadedIdleListShowsNothing() {
|
||||||
assertEquals(DownloadIndicator.InProgress, ListDownloadStatus(total = 4, downloaded = 2).indicator())
|
assertEquals(DownloadIndicator.Hidden, ListDownloadStatus(total = 4, downloaded = 2).indicator())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun aPartlyDownloadedListWithSomethingInFlightShowsProgress() {
|
||||||
|
assertEquals(DownloadIndicator.InProgress, ListDownloadStatus(total = 4, downloaded = 2, downloading = 1).indicator())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user