diff --git a/app/src/main/kotlin/com/subtracks/ui/components/DownloadIndicator.kt b/app/src/main/kotlin/com/subtracks/ui/components/DownloadIndicator.kt index 0ff225b0..4db5a484 100644 --- a/app/src/main/kotlin/com/subtracks/ui/components/DownloadIndicator.kt +++ b/app/src/main/kotlin/com/subtracks/ui/components/DownloadIndicator.kt @@ -1,17 +1,17 @@ package com.subtracks.ui.components import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.size -import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.DownloadDone import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.Icon -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Surface import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.blur +import androidx.compose.ui.graphics.Color import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp @@ -38,34 +38,44 @@ fun ListDownloadIndicator( val current = status ?: return val kind = current.indicator() if (kind == DownloadIndicator.Hidden) return - Surface( - shape = CircleShape, - color = MaterialTheme.colorScheme.surface.copy(alpha = 0.85f), - modifier = modifier.size(24.dp), - ) { - Box(contentAlignment = Alignment.Center) { - when (kind) { - DownloadIndicator.Complete -> { - Icon( - imageVector = Icons.Rounded.DownloadDone, - contentDescription = DOWNLOADED_INDICATOR_TAG, - tint = MaterialTheme.colorScheme.primary, - modifier = Modifier.size(16.dp), - ) - } + Box(modifier = modifier.size(20.dp), contentAlignment = Alignment.Center) { + when (kind) { + DownloadIndicator.Complete -> { + Icon( + imageVector = Icons.Rounded.DownloadDone, + contentDescription = null, + tint = ICON_SHADOW, + modifier = Modifier.size(18.dp).blur(3.dp).offset(y = 1.dp), + ) + Icon( + imageVector = Icons.Rounded.DownloadDone, + contentDescription = DOWNLOADED_INDICATOR_TAG, + tint = Color.White, + modifier = Modifier.size(18.dp), + ) + } - DownloadIndicator.InProgress -> { - CircularProgressIndicator( - progress = { current.downloaded.toFloat() / current.total }, - strokeWidth = 2.dp, - modifier = Modifier.size(14.dp).semantics { contentDescription = DOWNLOADING_INDICATOR_TAG }, - ) - } + DownloadIndicator.InProgress -> { + val progress = { current.downloaded.toFloat() / current.total } + CircularProgressIndicator( + progress = progress, + color = ICON_SHADOW, + strokeWidth = 2.dp, + modifier = Modifier.size(16.dp).blur(3.dp).offset(y = 1.dp), + ) + CircularProgressIndicator( + progress = progress, + color = Color.White, + strokeWidth = 2.dp, + modifier = Modifier.size(16.dp).semantics { contentDescription = DOWNLOADING_INDICATOR_TAG }, + ) + } - DownloadIndicator.Hidden -> { - Unit - } + DownloadIndicator.Hidden -> { + Unit } } } } + +private val ICON_SHADOW = Color.Black.copy(alpha = 0.45f) diff --git a/app/src/main/kotlin/com/subtracks/ui/components/ItemContextMenu.kt b/app/src/main/kotlin/com/subtracks/ui/components/ItemContextMenu.kt index df04357d..06328b80 100644 --- a/app/src/main/kotlin/com/subtracks/ui/components/ItemContextMenu.kt +++ b/app/src/main/kotlin/com/subtracks/ui/components/ItemContextMenu.kt @@ -18,8 +18,6 @@ import androidx.compose.material.icons.rounded.Cancel import androidx.compose.material.icons.rounded.Delete import androidx.compose.material.icons.rounded.Download import androidx.compose.material.icons.rounded.Person -import androidx.compose.material.icons.rounded.PlayArrow -import androidx.compose.material.icons.rounded.Shuffle import androidx.compose.material.icons.rounded.SkipNext import androidx.compose.material.icons.rounded.Star import androidx.compose.material.icons.rounded.StarBorder @@ -137,11 +135,6 @@ fun MenuTarget.listDownload(): ListDownloadStatus? = } class ItemActions( - val playSong: ((SongModel) -> Unit)? = null, - val playAlbum: (AlbumModel) -> Unit = {}, - val shuffleAlbum: (AlbumModel) -> Unit = {}, - val playPlaylist: (PlaylistModel) -> Unit = {}, - val shufflePlaylist: (PlaylistModel) -> Unit = {}, val playNext: ((QueueRef) -> Unit)? = null, val addToQueue: ((QueueRef) -> Unit)? = null, val download: ((SongModel) -> Unit)? = null, @@ -213,9 +206,6 @@ fun ItemContextMenu( MenuHeader(target) when (target) { is MenuTarget.Song -> { - actions.playSong?.let { play -> - MenuItem(Icons.Rounded.PlayArrow, "Play") { dismiss { play(target.song) } } - } queueItems() DownloadItem(target.download, target.song, actions, ::dismiss) StarItem( @@ -240,8 +230,6 @@ fun ItemContextMenu( } is MenuTarget.Album -> { - MenuItem(Icons.Rounded.PlayArrow, "Play") { dismiss { actions.playAlbum(target.album) } } - MenuItem(Icons.Rounded.Shuffle, "Shuffle") { dismiss { actions.shuffleAlbum(target.album) } } queueItems() BulkDownloadItem(target, actions, ::dismiss) StarItem( @@ -268,8 +256,6 @@ fun ItemContextMenu( } is MenuTarget.Playlist -> { - MenuItem(Icons.Rounded.PlayArrow, "Play") { dismiss { actions.playPlaylist(target.playlist) } } - MenuItem(Icons.Rounded.Shuffle, "Shuffle") { dismiss { actions.shufflePlaylist(target.playlist) } } queueItems() BulkDownloadItem(target, actions, ::dismiss) } diff --git a/app/src/main/kotlin/com/subtracks/ui/library/AlbumDetailScreen.kt b/app/src/main/kotlin/com/subtracks/ui/library/AlbumDetailScreen.kt index 7ea89ab5..b7bd4eb0 100644 --- a/app/src/main/kotlin/com/subtracks/ui/library/AlbumDetailScreen.kt +++ b/app/src/main/kotlin/com/subtracks/ui/library/AlbumDetailScreen.kt @@ -79,9 +79,6 @@ fun AlbumDetailRoute( } val actions = ItemActions( - playSong = { song -> songs.indexOfFirst { it.id == song.id }.takeIf { it >= 0 }?.let(viewModel::play) }, - playAlbum = { viewModel.playAll() }, - shuffleAlbum = { viewModel.shuffle() }, playNext = { playbackController.playNext(it.sourceId, it.kind, it.refId) }, addToQueue = { playbackController.addToQueue(it.sourceId, it.kind, it.refId) }, download = viewModel::download, diff --git a/app/src/main/kotlin/com/subtracks/ui/library/ArtistDetailScreen.kt b/app/src/main/kotlin/com/subtracks/ui/library/ArtistDetailScreen.kt index b0d849a6..7e652796 100644 --- a/app/src/main/kotlin/com/subtracks/ui/library/ArtistDetailScreen.kt +++ b/app/src/main/kotlin/com/subtracks/ui/library/ArtistDetailScreen.kt @@ -154,8 +154,6 @@ fun ArtistDetailRoute( val shortcutArt = remember(coverArtId) { coverArtId?.let { viewModel.coverArt(it, true) } } val actions = ItemActions( - playAlbum = { viewModel.playAlbum(it.id) }, - shuffleAlbum = { viewModel.shuffleAlbum(it.id) }, playNext = { playbackController.playNext(it.sourceId, it.kind, it.refId) }, addToQueue = { playbackController.addToQueue(it.sourceId, it.kind, it.refId) }, bulkDownload = { target, action -> diff --git a/app/src/main/kotlin/com/subtracks/ui/library/ArtistDetailViewModel.kt b/app/src/main/kotlin/com/subtracks/ui/library/ArtistDetailViewModel.kt index a400347c..ffcca189 100644 --- a/app/src/main/kotlin/com/subtracks/ui/library/ArtistDetailViewModel.kt +++ b/app/src/main/kotlin/com/subtracks/ui/library/ArtistDetailViewModel.kt @@ -99,16 +99,4 @@ class ArtistDetailViewModel( coverArt: String?, thumbnail: Boolean, ): CoverArtRef? = sourceRepository.coverArt(coverArt, thumbnail) - - fun playAlbum(albumId: String) { - viewModelScope.launch { - playbackController.playAlbum(sourceId.first(), albumId, 0) - } - } - - fun shuffleAlbum(albumId: String) { - viewModelScope.launch { - playbackController.shuffleAlbum(sourceId.first(), albumId) - } - } } diff --git a/app/src/main/kotlin/com/subtracks/ui/library/LibraryScreen.kt b/app/src/main/kotlin/com/subtracks/ui/library/LibraryScreen.kt index 23816ce7..17a9d9ed 100644 --- a/app/src/main/kotlin/com/subtracks/ui/library/LibraryScreen.kt +++ b/app/src/main/kotlin/com/subtracks/ui/library/LibraryScreen.kt @@ -216,17 +216,11 @@ fun LibraryRoute( } val playback by playbackController.state.collectAsStateWithLifecycle() val artwork = rememberArtworkColors(playbackController.coverArt(playback.item, thumbnail = true)) - val albumDownloads by viewModel.albumDownloads.collectAsStateWithLifecycle() - val artistDownloads by viewModel.artistDownloads.collectAsStateWithLifecycle() - val playlistDownloads by viewModel.playlistDownloads.collectAsStateWithLifecycle() + val downloads by viewModel.downloads(listTab).collectAsStateWithLifecycle() val scope = rememberCoroutineScope() var pendingDelete by remember { mutableStateOf(null) } val itemActions = ItemActions( - playAlbum = { viewModel.playAlbum(it.id) }, - shuffleAlbum = { viewModel.shuffleAlbum(it.id) }, - playPlaylist = { viewModel.playPlaylist(it.id) }, - shufflePlaylist = { viewModel.shufflePlaylist(it.id) }, playNext = { playbackController.playNext(it.sourceId, it.kind, it.refId) }, addToQueue = { playbackController.addToQueue(it.sourceId, it.kind, it.refId) }, bulkDownload = { target, action -> @@ -282,9 +276,9 @@ fun LibraryRoute( }, search = search, onSearchChange = { viewModel.setSearch(listTab, it) }, - albumDownloads = albumDownloads, - artistDownloads = artistDownloads, - playlistDownloads = playlistDownloads, + albumDownloads = downloads.takeIf { listTab == LibraryListTab.Albums }.orEmpty(), + artistDownloads = downloads.takeIf { listTab == LibraryListTab.Artists }.orEmpty(), + playlistDownloads = downloads.takeIf { listTab == LibraryListTab.Playlists }.orEmpty(), ) pendingDelete?.let { pending -> diff --git a/app/src/main/kotlin/com/subtracks/ui/library/LibraryViewModel.kt b/app/src/main/kotlin/com/subtracks/ui/library/LibraryViewModel.kt index 36fa1451..1c2654cb 100644 --- a/app/src/main/kotlin/com/subtracks/ui/library/LibraryViewModel.kt +++ b/app/src/main/kotlin/com/subtracks/ui/library/LibraryViewModel.kt @@ -95,21 +95,28 @@ class LibraryViewModel( private val activeSourceId = libraryRepository.activeSourceId.filterNotNull() - val albumDownloads: StateFlow> = + private val albumDownloads: StateFlow> = activeSourceId .flatMapLatest { downloadRepository.statuses(it, DownloadList.Album) } .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), emptyMap()) - val artistDownloads: StateFlow> = + private val artistDownloads: StateFlow> = activeSourceId .flatMapLatest { downloadRepository.statuses(it, DownloadList.Artist) } .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), emptyMap()) - val playlistDownloads: StateFlow> = + private val playlistDownloads: StateFlow> = activeSourceId .flatMapLatest { downloadRepository.statuses(it, DownloadList.Playlist) } .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), emptyMap()) + fun downloads(tab: LibraryListTab): StateFlow> = + when (tab) { + LibraryListTab.Albums -> albumDownloads + LibraryListTab.Artists -> artistDownloads + LibraryListTab.Playlists -> playlistDownloads + } + suspend fun downloadedBytes( list: DownloadList, refId: String, @@ -149,30 +156,6 @@ class LibraryViewModel( thumbnail: Boolean, ): CoverArtRef? = sourceRepository.coverArt(coverArt, thumbnail) - fun playAlbum(albumId: String) { - viewModelScope.launch { - sourceRepository.activeSourceIdOnce()?.let { playbackController.playAlbum(it, albumId, 0) } - } - } - - fun shuffleAlbum(albumId: String) { - viewModelScope.launch { - sourceRepository.activeSourceIdOnce()?.let { playbackController.shuffleAlbum(it, albumId) } - } - } - - fun playPlaylist(playlistId: String) { - viewModelScope.launch { - sourceRepository.activeSourceIdOnce()?.let { playbackController.playPlaylist(it, playlistId, 0) } - } - } - - fun shufflePlaylist(playlistId: String) { - viewModelScope.launch { - sourceRepository.activeSourceIdOnce()?.let { playbackController.shufflePlaylist(it, playlistId) } - } - } - fun sync() = syncManager.requestSync() } diff --git a/app/src/main/kotlin/com/subtracks/ui/library/PlaylistDetailScreen.kt b/app/src/main/kotlin/com/subtracks/ui/library/PlaylistDetailScreen.kt index 6d730123..3701a055 100644 --- a/app/src/main/kotlin/com/subtracks/ui/library/PlaylistDetailScreen.kt +++ b/app/src/main/kotlin/com/subtracks/ui/library/PlaylistDetailScreen.kt @@ -64,8 +64,6 @@ fun PlaylistDetailRoute( } val actions = ItemActions( - playPlaylist = { viewModel.playAll() }, - shufflePlaylist = { viewModel.shuffle() }, playNext = { playbackController.playNext(it.sourceId, it.kind, it.refId) }, addToQueue = { playbackController.addToQueue(it.sourceId, it.kind, it.refId) }, download = viewModel::download,