diff --git a/app/src/main/java/com/android/swingmusic/presentation/activity/MainActivity.kt b/app/src/main/java/com/android/swingmusic/presentation/activity/MainActivity.kt index ac6d26e1..92f3ab3f 100644 --- a/app/src/main/java/com/android/swingmusic/presentation/activity/MainActivity.kt +++ b/app/src/main/java/com/android/swingmusic/presentation/activity/MainActivity.kt @@ -50,7 +50,7 @@ import androidx.navigation.NavOptionsBuilder import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.rememberNavController import com.android.swingmusic.album.presentation.screen.destinations.AllAlbumScreenDestination -import com.android.swingmusic.artist.presentation.screen.destinations.ArtistsScreenDestination +import com.android.swingmusic.artist.presentation.screen.destinations.AllArtistsScreenDestination import com.android.swingmusic.artist.presentation.screen.destinations.ViewAllScreenDestination import com.android.swingmusic.artist.presentation.viewmodel.ArtistInfoViewModel import com.android.swingmusic.auth.data.workmanager.scheduleTokenRefreshWork @@ -133,7 +133,7 @@ class MainActivity : ComponentActivity() { val showBottomNav = route in listOf( "folder/${FoldersAndTracksScreenDestination.route}", "album/${AllAlbumScreenDestination.route}", - "artist/${ArtistsScreenDestination.route}" + "artist/${AllArtistsScreenDestination.route}" ) val bottomNavHeight by animateDpAsState( @@ -146,7 +146,7 @@ class MainActivity : ComponentActivity() { val showSpacer = route !in listOf( "folder/${FoldersAndTracksScreenDestination.route}", "album/${AllAlbumScreenDestination.route}", - "artist/${ArtistsScreenDestination.route}", + "artist/${AllArtistsScreenDestination.route}", ) val spacerHeight by animateDpAsState( diff --git a/app/src/main/java/com/android/swingmusic/presentation/navigator/NavGraphs.kt b/app/src/main/java/com/android/swingmusic/presentation/navigator/NavGraphs.kt index 61dbec32..f18288e2 100644 --- a/app/src/main/java/com/android/swingmusic/presentation/navigator/NavGraphs.kt +++ b/app/src/main/java/com/android/swingmusic/presentation/navigator/NavGraphs.kt @@ -2,8 +2,8 @@ package com.android.swingmusic.presentation.navigator import com.android.swingmusic.album.presentation.screen.destinations.AlbumWithInfoScreenDestination import com.android.swingmusic.album.presentation.screen.destinations.AllAlbumScreenDestination +import com.android.swingmusic.artist.presentation.screen.destinations.AllArtistsScreenDestination import com.android.swingmusic.artist.presentation.screen.destinations.ArtistInfoScreenDestination -import com.android.swingmusic.artist.presentation.screen.destinations.ArtistsScreenDestination import com.android.swingmusic.artist.presentation.screen.destinations.ViewAllScreenDestination import com.android.swingmusic.auth.presentation.screen.destinations.LoginWithQrCodeDestination import com.android.swingmusic.auth.presentation.screen.destinations.LoginWithUsernameScreenDestination @@ -75,11 +75,11 @@ object NavGraphs { val artist = object : NavGraphSpec { override val route: String = "artist" - override val startRoute: Route = ArtistsScreenDestination routedIn this + override val startRoute: Route = AllArtistsScreenDestination routedIn this override val destinationsByRoute: Map> = listOf>( - ArtistsScreenDestination, + AllArtistsScreenDestination, ArtistInfoScreenDestination, AlbumWithInfoScreenDestination, ViewAllScreenDestination, diff --git a/feature/album/src/main/java/com/android/swingmusic/album/presentation/event/AlbumWithInfoUiEvent.kt b/feature/album/src/main/java/com/android/swingmusic/album/presentation/event/AlbumWithInfoUiEvent.kt index 9d231680..739944c9 100644 --- a/feature/album/src/main/java/com/android/swingmusic/album/presentation/event/AlbumWithInfoUiEvent.kt +++ b/feature/album/src/main/java/com/android/swingmusic/album/presentation/event/AlbumWithInfoUiEvent.kt @@ -8,10 +8,15 @@ interface AlbumWithInfoUiEvent { object OnRefreshAlbumInfo : AlbumWithInfoUiEvent - object ResetState: AlbumWithInfoUiEvent + object ResetState : AlbumWithInfoUiEvent data class OnToggleAlbumFavorite( val isFavorite: Boolean, val albumHash: String, ) : AlbumWithInfoUiEvent + + data class OnToggleAlbumTrackFavorite( + val trackHash: String, + val favorite: Boolean + ) : AlbumWithInfoUiEvent } diff --git a/feature/album/src/main/java/com/android/swingmusic/album/presentation/screen/AlbumWithInfoScreen.kt b/feature/album/src/main/java/com/android/swingmusic/album/presentation/screen/AlbumWithInfo.kt similarity index 97% rename from feature/album/src/main/java/com/android/swingmusic/album/presentation/screen/AlbumWithInfoScreen.kt rename to feature/album/src/main/java/com/android/swingmusic/album/presentation/screen/AlbumWithInfo.kt index 3bc36ea0..e3194133 100644 --- a/feature/album/src/main/java/com/android/swingmusic/album/presentation/screen/AlbumWithInfoScreen.kt +++ b/feature/album/src/main/java/com/android/swingmusic/album/presentation/screen/AlbumWithInfo.kt @@ -115,16 +115,16 @@ fun AlbumWithInfo( playbackState: PlaybackState, albumInfo: AlbumInfo, copyright: String, - albumTracks: Map>, + albumTracksMap: Map>, baseUrl: String, onClickBack: () -> Unit, onClickMore: () -> Unit, onClickArtist: (artistHsh: String) -> Unit, onClickAlbumTrack: (index: Int, queue: List) -> Unit, - onToggleTrackFavorite: (isFavorite: Boolean, trackHash: String) -> Unit, onPlay: (queue: List) -> Unit, onShuffle: () -> Unit, - onToggleFavorite: (Boolean, String) -> Unit, + onToggleAlbumFavorite: (Boolean, String) -> Unit, + onToggleTrackFavorite: (trackHash: String, isFavorite: Boolean) -> Unit, onGetSheetAction: (track: Track, sheetAction: BottomSheetAction) -> Unit, onGotoArtist: (hash: String) -> Unit, ) { @@ -140,12 +140,21 @@ fun AlbumWithInfo( var showTrackBottomSheet by remember { mutableStateOf(false) } var clickedTrack: Track? by remember { mutableStateOf(null) } + LaunchedEffect(albumTracksMap) { + albumTracksMap.forEach { entry -> + clickedTrack = entry.value.find { track -> + track.trackHash == clickedTrack?.trackHash + } ?: clickedTrack + } + } + Scaffold { if (showTrackBottomSheet) { clickedTrack?.let { track -> CustomTrackBottomSheet( scope = scope, sheetState = sheetState, + isFavorite = track.isFavorite, clickedTrack = track, baseUrl = baseUrl, bottomSheetItems = listOf( @@ -186,8 +195,8 @@ fun AlbumWithInfo( onChooseArtist = { hash -> onGotoArtist(hash) }, - onToggleTrackFavorite = { isFavorite, trackHash -> - onToggleTrackFavorite(isFavorite, trackHash) + onToggleTrackFavorite = { trackHash, isFavorite -> + onToggleTrackFavorite(trackHash, isFavorite) } ) } @@ -408,7 +417,7 @@ fun AlbumWithInfo( else R.drawable.fav_not_filled IconButton( onClick = { - onToggleFavorite( + onToggleAlbumFavorite( albumInfo.isFavorite, albumInfo.albumHash ) @@ -456,7 +465,7 @@ fun AlbumWithInfo( Spacer(modifier = Modifier.height(12.dp)) } - albumTracks.forEach { (discNumber, tracks) -> + albumTracksMap.forEach { (discNumber, tracks) -> item { // Disc Number Header Text( @@ -507,6 +516,7 @@ fun AlbumWithInfo( ) { TrackItem( track = track, + baseUrl = baseUrl, isAlbumTrack = true, showMenuIcon = true, isCurrentTrack = track.trackHash == currentTrack?.trackHash, @@ -520,8 +530,7 @@ fun AlbumWithInfo( onClickMoreVert = { clickedTrack = it showTrackBottomSheet = true - }, - baseUrl = baseUrl + } ) } } @@ -775,7 +784,7 @@ fun AlbumWithInfoScreen( playbackState = playerUiState.playbackState, albumInfo = albumWithInfoState.infoResource.data?.albumInfo!!, copyright = albumWithInfoState.infoResource.data?.copyright!!, - albumTracks = albumWithInfoState.infoResource.data!!.groupedTracks, + albumTracksMap = albumWithInfoState.infoResource.data!!.groupedTracks, baseUrl = baseUrl ?: "https://default", onClickBack = { navigator.navigateBack() }, onClickMore = { @@ -828,7 +837,7 @@ fun AlbumWithInfoScreen( ) ) }, - onToggleFavorite = { isFavorite, albumHash -> + onToggleAlbumFavorite = { isFavorite, albumHash -> albumWithInfoViewModel.onAlbumWithInfoUiEvent( AlbumWithInfoUiEvent.OnToggleAlbumFavorite( isFavorite, @@ -899,8 +908,12 @@ fun AlbumWithInfoScreen( onGotoArtist = { hash -> navigator.gotoArtistInfo(artistHash = hash) }, - onToggleTrackFavorite = { isFavorite, trackHash -> - // TODO: Call Album Track fav toggle + onToggleTrackFavorite = { trackHash, isFavorite -> + albumWithInfoViewModel.onAlbumWithInfoUiEvent( + AlbumWithInfoUiEvent.OnToggleAlbumTrackFavorite( + trackHash, isFavorite, + ) + ) } ) } @@ -1068,7 +1081,7 @@ fun AlbumWithInfoScreenPreview() { playbackState = PlaybackState.PLAYING, albumInfo = albumInfo, copyright = "© 2018 Republic Records", - albumTracks = mapOf( + albumTracksMap = mapOf( 1 to listOf(tracks[1], tracks[5]) ), baseUrl = "", @@ -1078,7 +1091,7 @@ fun AlbumWithInfoScreenPreview() { onClickAlbumTrack = { index, queue -> }, onPlay = { queue -> }, onShuffle = {}, - onToggleFavorite = { isFavorite, albumHash -> }, + onToggleAlbumFavorite = { isFavorite, albumHash -> }, onGetSheetAction = { _, _ -> }, onGotoArtist = {}, onToggleTrackFavorite = { _, _ -> } diff --git a/feature/album/src/main/java/com/android/swingmusic/album/presentation/screen/AllAlbumScreen.kt b/feature/album/src/main/java/com/android/swingmusic/album/presentation/screen/AllAlbums.kt similarity index 100% rename from feature/album/src/main/java/com/android/swingmusic/album/presentation/screen/AllAlbumScreen.kt rename to feature/album/src/main/java/com/android/swingmusic/album/presentation/screen/AllAlbums.kt diff --git a/feature/album/src/main/java/com/android/swingmusic/album/presentation/viewmodel/AlbumWithInfoViewModel.kt b/feature/album/src/main/java/com/android/swingmusic/album/presentation/viewmodel/AlbumWithInfoViewModel.kt index eeb75dab..50dc4f69 100644 --- a/feature/album/src/main/java/com/android/swingmusic/album/presentation/viewmodel/AlbumWithInfoViewModel.kt +++ b/feature/album/src/main/java/com/android/swingmusic/album/presentation/viewmodel/AlbumWithInfoViewModel.kt @@ -8,6 +8,7 @@ import com.android.swingmusic.album.presentation.state.AlbumInfoWithGroupedTrack import com.android.swingmusic.album.presentation.state.AlbumWithInfoState import com.android.swingmusic.core.data.util.Resource import com.android.swingmusic.core.domain.model.AlbumWithInfo +import com.android.swingmusic.player.domain.repository.PLayerRepository import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -17,7 +18,8 @@ import javax.inject.Inject @HiltViewModel class AlbumWithInfoViewModel @Inject constructor( - private val albumRepository: AlbumRepository + private val albumRepository: AlbumRepository, + private val pLayerRepository: PLayerRepository ) : ViewModel() { private val _albumWithInfoState: MutableStateFlow = @@ -123,6 +125,113 @@ class AlbumWithInfoViewModel @Inject constructor( } } + private fun toggleAlbumTrackFavorite(trackHash: String, isFavorite: Boolean) { + viewModelScope.launch { + // Optimistically update the Ui + _albumWithInfoState.value = _albumWithInfoState.value.copy( + orderedTracks = _albumWithInfoState.value.orderedTracks.map { track -> + if (track.trackHash == trackHash) { + track.copy(isFavorite = !isFavorite) + } else { + track + } + } + ) + + _albumWithInfoState.value = _albumWithInfoState.value.copy( + infoResource = Resource.Success( + AlbumInfoWithGroupedTracks( + albumInfo = _albumWithInfoState.value.infoResource.data?.albumInfo, + groupedTracks = _albumWithInfoState.value.infoResource.data?.groupedTracks?.mapValues { entry -> + entry.value.map { track -> + if (track.trackHash == trackHash) { + track.copy(isFavorite = !isFavorite) + } else { + track + } + } + } ?: emptyMap(), + copyright = _albumWithInfoState.value.infoResource.data?.copyright + ) + ) + ) + + + val request = if (isFavorite) { + pLayerRepository.removeTrackFromFavorite(trackHash) + } else { + pLayerRepository.addTrackToFavorite(trackHash) + } + + request.collectLatest { + when (it) { + is Resource.Loading -> {} + + is Resource.Success -> { + _albumWithInfoState.value = _albumWithInfoState.value.copy( + orderedTracks = _albumWithInfoState.value.orderedTracks.map { track -> + if (track.trackHash == trackHash) { + track.copy(isFavorite = it.data ?: false) + } else { + track + } + } + ) + + _albumWithInfoState.value = _albumWithInfoState.value.copy( + infoResource = Resource.Success( + AlbumInfoWithGroupedTracks( + albumInfo = _albumWithInfoState.value.infoResource.data?.albumInfo, + groupedTracks = _albumWithInfoState.value.infoResource.data?.groupedTracks?.mapValues { entry -> + entry.value.map { track -> + if (track.trackHash == trackHash) { + track.copy(isFavorite = it.data ?: false) + } else { + track + } + } + } ?: emptyMap(), + copyright = _albumWithInfoState.value.infoResource.data?.copyright + ) + ) + ) + } + + is Resource.Error -> { + // Revert the optimistic updates in case of an error + _albumWithInfoState.value = _albumWithInfoState.value.copy( + orderedTracks = _albumWithInfoState.value.orderedTracks.map { track -> + if (track.trackHash == trackHash) { + track.copy(isFavorite = isFavorite) + } else { + track + } + } + ) + + _albumWithInfoState.value = _albumWithInfoState.value.copy( + infoResource = Resource.Success( + AlbumInfoWithGroupedTracks( + albumInfo = _albumWithInfoState.value.infoResource.data?.albumInfo, + groupedTracks = _albumWithInfoState.value.infoResource.data?.groupedTracks?.mapValues { entry -> + entry.value.map { track -> + if (track.trackHash == trackHash) { + track.copy(isFavorite = isFavorite) + } else { + track + } + } + } ?: emptyMap(), + copyright = _albumWithInfoState.value.infoResource.data?.copyright + ) + ) + ) + } + } + } + } + } + fun onAlbumWithInfoUiEvent(event: AlbumWithInfoUiEvent) { when (event) { is AlbumWithInfoUiEvent.ResetState -> { @@ -163,6 +272,10 @@ class AlbumWithInfoViewModel @Inject constructor( toggleAlbumFavorite(event.albumHash, event.isFavorite) } + is AlbumWithInfoUiEvent.OnToggleAlbumTrackFavorite -> { + toggleAlbumTrackFavorite(event.trackHash, event.favorite) + } + else -> {} } } diff --git a/feature/artist/src/main/java/com/android/swingmusic/artist/presentation/event/ArtistInfoUiEvent.kt b/feature/artist/src/main/java/com/android/swingmusic/artist/presentation/event/ArtistInfoUiEvent.kt index db72a069..c7897a40 100644 --- a/feature/artist/src/main/java/com/android/swingmusic/artist/presentation/event/ArtistInfoUiEvent.kt +++ b/feature/artist/src/main/java/com/android/swingmusic/artist/presentation/event/ArtistInfoUiEvent.kt @@ -12,4 +12,9 @@ interface ArtistInfoUiEvent { ) : ArtistInfoUiEvent data class OnRefresh(val artistHash: String) : ArtistInfoUiEvent + + data class ToggleArtistTrackFavorite( + val trackHash: String, + val isFavorite: Boolean + ) : ArtistInfoUiEvent } diff --git a/feature/artist/src/main/java/com/android/swingmusic/artist/presentation/screen/ArtistsScreen.kt b/feature/artist/src/main/java/com/android/swingmusic/artist/presentation/screen/AllArtists.kt similarity index 99% rename from feature/artist/src/main/java/com/android/swingmusic/artist/presentation/screen/ArtistsScreen.kt rename to feature/artist/src/main/java/com/android/swingmusic/artist/presentation/screen/AllArtists.kt index 38957607..d7e255b4 100644 --- a/feature/artist/src/main/java/com/android/swingmusic/artist/presentation/screen/ArtistsScreen.kt +++ b/feature/artist/src/main/java/com/android/swingmusic/artist/presentation/screen/AllArtists.kt @@ -69,7 +69,7 @@ import com.ramcosta.composedestinations.annotation.Destination import com.android.swingmusic.uicomponent.R as UiComponents @Composable -private fun Artists( +private fun AllArtists( pagingArtists: LazyPagingItems, artistsUiState: ArtistsUiState, sortByPairs: List>, @@ -307,12 +307,12 @@ private fun Artists( } /** - * This Composable is heavily coupled with ArtistsViewModel. [Artists] Compsable has no ties. + * This Composable is heavily coupled with ArtistsViewModel. [AllArtists] Compsable has no ties. **/ @OptIn(ExperimentalMaterial3Api::class) @Destination @Composable -fun ArtistsScreen( +fun AllArtistsScreen( navigator: CommonNavigator, artistsViewModel: ArtistsViewModel = hiltViewModel(), artistInfoViewModel: ArtistInfoViewModel @@ -361,7 +361,7 @@ fun ArtistsScreen( ) } ) { - Artists( + AllArtists( pagingArtists = pagingArtists, artistsUiState = artistsUiState, sortByPairs = sortByPairs, diff --git a/feature/artist/src/main/java/com/android/swingmusic/artist/presentation/screen/ArtistInfoScreen.kt b/feature/artist/src/main/java/com/android/swingmusic/artist/presentation/screen/ArtistInfo.kt similarity index 98% rename from feature/artist/src/main/java/com/android/swingmusic/artist/presentation/screen/ArtistInfoScreen.kt rename to feature/artist/src/main/java/com/android/swingmusic/artist/presentation/screen/ArtistInfo.kt index fd4a0b38..a7f63e06 100644 --- a/feature/artist/src/main/java/com/android/swingmusic/artist/presentation/screen/ArtistInfoScreen.kt +++ b/feature/artist/src/main/java/com/android/swingmusic/artist/presentation/screen/ArtistInfo.kt @@ -103,13 +103,13 @@ private fun ArtistInfo( similarArtists: List, playbackState: PlaybackState, currentTrack: Track?, - onToggleFavorite: (String, Boolean) -> Unit, + onToggleArtistFavorite: (String, Boolean) -> Unit, + onToggleTrackFavorite: (trackHash: String, isFavorite: Boolean) -> Unit, onShuffle: () -> Unit, onPlayAllTracks: () -> Unit, onClickBack: () -> Unit, onClickAlbum: (albumHash: String) -> Unit, onClickArtistTrack: (queue: List, index: Int) -> Unit, - onToggleTrackFavorite: (isFavorite: Boolean, trackHash: String) -> Unit, onClickSimilarArtist: (artistHash: String) -> Unit, onClickViewAll: (artistName: String, viewAllType: String, baseUrl: String) -> Unit, onGetSheetAction: (track: Track, sheetAction: BottomSheetAction) -> Unit, @@ -121,6 +121,13 @@ private fun ArtistInfo( var showTrackBottomSheet by remember { mutableStateOf(false) } var clickedTrack: Track? by remember { mutableStateOf(null) } + LaunchedEffect(artistInfo.tracks) { + clickedTrack?.let { track -> + val updatedTrack = artistInfo.tracks.find { it.trackHash == track.trackHash } + clickedTrack = updatedTrack ?: track + } + } + Scaffold( topBar = { Row( @@ -150,6 +157,7 @@ private fun ArtistInfo( CustomTrackBottomSheet( scope = scope, sheetState = sheetState, + isFavorite = track.isFavorite, clickedTrack = track, baseUrl = baseUrl, currentArtisthash = artistInfo.artist.artistHash, @@ -199,8 +207,8 @@ private fun ArtistInfo( onChooseArtist = { hash -> onGotoArtist(hash) }, - onToggleTrackFavorite = { isFavorite, trackHash -> - onToggleTrackFavorite(isFavorite, trackHash) + onToggleTrackFavorite = { trackHash, isFavorite -> + onToggleTrackFavorite(trackHash, isFavorite) } ) } @@ -321,7 +329,7 @@ private fun ArtistInfo( LazyRow( modifier = Modifier .fillMaxWidth() - .padding(start = 16.dp, end = 20.dp), + .padding(start = 16.dp, end = 12.dp), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { @@ -330,7 +338,7 @@ private fun ArtistInfo( else R.drawable.fav_not_filled IconButton( onClick = { - onToggleFavorite( + onToggleArtistFavorite( artistInfo.artist.artistHash, artistInfo.artist.isFavorite ) @@ -951,7 +959,7 @@ fun ArtistInfoScreen( onClickBack = { commonNavigator.navigateBack() }, - onToggleFavorite = { artistHash, isFavorite -> + onToggleArtistFavorite = { artistHash, isFavorite -> artistInfoViewModel.onArtistInfoUiEvent( ArtistInfoUiEvent.OnToggleArtistFavorite( artistHash = artistHash, @@ -1092,8 +1100,12 @@ fun ArtistInfoScreen( ArtistInfoUiEvent.OnUpdateArtistHash(hash) ) }, - onToggleTrackFavorite = { isFavorite, trackHash -> - // TODO: Call Artist Track fav toggle + onToggleTrackFavorite = { trackHash, isFavorite -> + artistInfoViewModel.onArtistInfoUiEvent( + ArtistInfoUiEvent.ToggleArtistTrackFavorite( + trackHash, isFavorite + ) + ) } ) } @@ -1490,7 +1502,7 @@ fun ArtistInfoPreview() { ), ), onClickBack = {}, - onToggleFavorite = { _, _ -> }, + onToggleArtistFavorite = { _, _ -> }, onShuffle = {}, onPlayAllTracks = {}, onClickAlbum = {}, diff --git a/feature/artist/src/main/java/com/android/swingmusic/artist/presentation/screen/ViewAllScreen.kt b/feature/artist/src/main/java/com/android/swingmusic/artist/presentation/screen/ViewAll.kt similarity index 94% rename from feature/artist/src/main/java/com/android/swingmusic/artist/presentation/screen/ViewAllScreen.kt rename to feature/artist/src/main/java/com/android/swingmusic/artist/presentation/screen/ViewAll.kt index 964840d9..caef7e0f 100644 --- a/feature/artist/src/main/java/com/android/swingmusic/artist/presentation/screen/ViewAllScreen.kt +++ b/feature/artist/src/main/java/com/android/swingmusic/artist/presentation/screen/ViewAll.kt @@ -23,6 +23,7 @@ import androidx.compose.material3.SnackbarResult import androidx.compose.material3.Text import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -31,6 +32,7 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp +import com.android.swingmusic.artist.presentation.event.ArtistInfoUiEvent import com.android.swingmusic.artist.presentation.viewmodel.ArtistInfoViewModel import com.android.swingmusic.common.presentation.navigator.CommonNavigator import com.android.swingmusic.core.domain.model.Album @@ -61,7 +63,7 @@ private fun ViewAll( allTracks: List?, allAlbumsToShow: List?, onClickArtistTrack: (queue: List, index: Int) -> Unit, - onToggleTrackFavorite: (isFavorite: Boolean, trackHash: String) -> Unit, + onToggleTrackFavorite: (trackHash: String, isFavorite: Boolean) -> Unit, onClickAlbum: (hash: String) -> Unit, onGetSheetAction: (track: Track, sheetAction: BottomSheetAction) -> Unit, onGotoArtist: (hash: String) -> Unit @@ -72,6 +74,13 @@ private fun ViewAll( var showTrackBottomSheet by remember { mutableStateOf(false) } var clickedTrack: Track? by remember { mutableStateOf(null) } + LaunchedEffect(allTracks) { + clickedTrack?.let { track -> + val updatedTrack = allTracks?.find { it.trackHash == track.trackHash } + clickedTrack = updatedTrack ?: track + } + } + Scaffold { padding -> Scaffold( modifier = Modifier.padding(padding), @@ -99,6 +108,7 @@ private fun ViewAll( CustomTrackBottomSheet( scope = scope, sheetState = sheetState, + isFavorite = track.isFavorite, clickedTrack = track, baseUrl = baseUrl, currentArtisthash = artistHash, @@ -147,8 +157,8 @@ private fun ViewAll( onChooseArtist = { hash -> onGotoArtist(hash) }, - onToggleTrackFavorite = { isFavorite, trackHash -> - onToggleTrackFavorite(isFavorite, trackHash) + onToggleTrackFavorite = { trackHash, isFavorite -> + onToggleTrackFavorite(trackHash, isFavorite) } ) } @@ -341,8 +351,12 @@ fun ViewAllScreen( onGotoArtist = { hash -> commonNavigator.gotoArtistInfo(hash) }, - onToggleTrackFavorite = { isFavorite, trackHash -> - // TODO: Call ViewAll Track fav toggle + onToggleTrackFavorite = { trackHash, isFavorite -> + artistInfoViewModel.onArtistInfoUiEvent( + ArtistInfoUiEvent.ToggleArtistTrackFavorite( + trackHash, isFavorite + ) + ) } ) } diff --git a/feature/artist/src/main/java/com/android/swingmusic/artist/presentation/viewmodel/ArtistInfoViewModel.kt b/feature/artist/src/main/java/com/android/swingmusic/artist/presentation/viewmodel/ArtistInfoViewModel.kt index 24c2ae68..66139a56 100644 --- a/feature/artist/src/main/java/com/android/swingmusic/artist/presentation/viewmodel/ArtistInfoViewModel.kt +++ b/feature/artist/src/main/java/com/android/swingmusic/artist/presentation/viewmodel/ArtistInfoViewModel.kt @@ -9,17 +9,18 @@ import com.android.swingmusic.core.data.util.Resource import com.android.swingmusic.core.domain.model.AlbumsAndAppearances import com.android.swingmusic.core.domain.model.ArtistExpanded import com.android.swingmusic.core.domain.model.ArtistInfo +import com.android.swingmusic.player.domain.repository.PLayerRepository import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch -import timber.log.Timber import javax.inject.Inject @HiltViewModel class ArtistInfoViewModel @Inject constructor( - private val artistRepository: ArtistRepository + private val artistRepository: ArtistRepository, + private val pLayerRepository: PLayerRepository ) : ViewModel() { private val _artistInfoState: MutableStateFlow = MutableStateFlow(ArtistInfoState()) @@ -109,8 +110,6 @@ class ArtistInfoViewModel @Inject constructor( artistRepository.addArtistToFavorite(artistHash) } - Timber.e("TOGGLE ARTIST FAVORITE TO :${!isFavorite}") - request.collectLatest { when (it) { is Resource.Loading -> {} @@ -151,6 +150,100 @@ class ArtistInfoViewModel @Inject constructor( } } + private fun toggleArtistTrackFavorite(trackHash: String, isFavorite: Boolean) { + viewModelScope.launch { + val emptyAlbumsAndAppearances = AlbumsAndAppearances( + albums = emptyList(), + appearances = emptyList(), + artistName = "", + compilations = emptyList(), + singlesAndEps = emptyList() + ) + val emptyArtistExpanded = ArtistExpanded( + albumCount = 0, + artistHash = "", + color = "", + duration = 0, + genres = emptyList(), + image = "", + isFavorite = false, + name = "", + trackCount = 0 + ) + + // Optimistically update the UI + _artistInfoState.value = _artistInfoState.value.copy( + infoResource = Resource.Success( + ArtistInfo( + albumsAndAppearances = _artistInfoState.value.infoResource.data?.albumsAndAppearances + ?: emptyAlbumsAndAppearances, + artist = _artistInfoState.value.infoResource.data?.artist + ?: emptyArtistExpanded, + tracks = _artistInfoState.value.infoResource.data?.tracks?.map { track -> + if (track.trackHash == trackHash) { + track.copy(isFavorite = !isFavorite) + } else { + track + } + } ?: emptyList() + ) + ) + ) + + val request = if (isFavorite) { + pLayerRepository.removeTrackFromFavorite(trackHash) + } else { + pLayerRepository.addTrackToFavorite(trackHash) + } + + request.collectLatest { + when (it) { + is Resource.Loading -> {} + + is Resource.Success -> { + _artistInfoState.value = _artistInfoState.value.copy( + infoResource = Resource.Success( + ArtistInfo( + albumsAndAppearances = _artistInfoState.value.infoResource.data?.albumsAndAppearances + ?: emptyAlbumsAndAppearances, + artist = _artistInfoState.value.infoResource.data?.artist + ?: emptyArtistExpanded, + tracks = _artistInfoState.value.infoResource.data?.tracks?.map { track -> + if (track.trackHash == trackHash) { + track.copy(isFavorite = it.data ?: false) + } else { + track + } + } ?: emptyList() + ) + ) + ) + } + + is Resource.Error -> { + _artistInfoState.value = _artistInfoState.value.copy( + infoResource = Resource.Success( + ArtistInfo( + albumsAndAppearances = _artistInfoState.value.infoResource.data?.albumsAndAppearances + ?: emptyAlbumsAndAppearances, + artist = _artistInfoState.value.infoResource.data?.artist + ?: emptyArtistExpanded, + tracks = _artistInfoState.value.infoResource.data?.tracks?.map { track -> + if (track.trackHash == trackHash) { + track.copy(isFavorite = isFavorite) + } else { + track + } + } ?: emptyList() + ) + ) + ) + } + } + } + } + } + fun onArtistInfoUiEvent(event: ArtistInfoUiEvent) { when (event) { is ArtistInfoUiEvent.OnLoadArtistInfo -> { @@ -161,10 +254,6 @@ class ArtistInfoViewModel @Inject constructor( getSimilarArtists(event.artistHash) } - is ArtistInfoUiEvent.OnToggleArtistFavorite -> { - toggleArtistFavorite(event.artistHash, event.isFavorite) - } - is ArtistInfoUiEvent.OnRefresh -> { getArtistInfo(event.artistHash) getSimilarArtists(event.artistHash) @@ -177,6 +266,14 @@ class ArtistInfoViewModel @Inject constructor( getSimilarArtists(event.artistHash) } + is ArtistInfoUiEvent.OnToggleArtistFavorite -> { + toggleArtistFavorite(event.artistHash, event.isFavorite) + } + + is ArtistInfoUiEvent.ToggleArtistTrackFavorite -> { + toggleArtistTrackFavorite(event.trackHash, event.isFavorite) + } + else -> { } diff --git a/feature/folder/src/main/java/com/android/swingmusic/folder/data/repository/DataFolderRepository.kt b/feature/folder/src/main/java/com/android/swingmusic/folder/data/repository/DataFolderRepository.kt index 5aa68f81..d190470f 100644 --- a/feature/folder/src/main/java/com/android/swingmusic/folder/data/repository/DataFolderRepository.kt +++ b/feature/folder/src/main/java/com/android/swingmusic/folder/data/repository/DataFolderRepository.kt @@ -55,10 +55,4 @@ class DataFolderRepository @Inject constructor( } } } - - private fun FoldersAndTracks.sort(): FoldersAndTracks { - val folders = this.folders.sortedBy { it.name } - val tracks = this.tracks.sortedBy { it.title } - return FoldersAndTracks(folders, tracks) - } } diff --git a/feature/folder/src/main/java/com/android/swingmusic/folder/presentation/event/FolderUiEvent.kt b/feature/folder/src/main/java/com/android/swingmusic/folder/presentation/event/FolderUiEvent.kt index 4dc03546..4b58c097 100644 --- a/feature/folder/src/main/java/com/android/swingmusic/folder/presentation/event/FolderUiEvent.kt +++ b/feature/folder/src/main/java/com/android/swingmusic/folder/presentation/event/FolderUiEvent.kt @@ -4,7 +4,12 @@ import com.android.swingmusic.core.domain.model.Folder interface FolderUiEvent { data class OnClickFolder(val folder: Folder) : FolderUiEvent + data class OnClickNavPath(val folder: Folder) : FolderUiEvent + data class OnBackNav(val folder: Folder) : FolderUiEvent + data class OnRetry(val event: FolderUiEvent) : FolderUiEvent + + data class ToggleTrackFavorite(val trackHash: String, val isFavorite: Boolean) : FolderUiEvent } diff --git a/feature/folder/src/main/java/com/android/swingmusic/folder/presentation/screen/FoldersAndTracks.kt b/feature/folder/src/main/java/com/android/swingmusic/folder/presentation/screen/FoldersAndTracks.kt index b717c63f..8d3176e8 100644 --- a/feature/folder/src/main/java/com/android/swingmusic/folder/presentation/screen/FoldersAndTracks.kt +++ b/feature/folder/src/main/java/com/android/swingmusic/folder/presentation/screen/FoldersAndTracks.kt @@ -88,7 +88,7 @@ private fun FoldersAndTracks( onPullToRefresh: (FolderUiEvent) -> Unit, onClickFolder: (Folder) -> Unit, onClickTrackItem: (index: Int, queue: List) -> Unit, - onToggleTrackFavorite: (isFavorite: Boolean, trackHash: String) -> Unit, + onToggleTrackFavorite: (trackHash: String, isFavorite: Boolean) -> Unit, onGetSheetAction: (track: Track, sheetAction: BottomSheetAction) -> Unit, onGotoArtist: (hash: String) -> Unit, baseUrl: String @@ -98,6 +98,16 @@ private fun FoldersAndTracks( var showTrackBottomSheet by remember { mutableStateOf(false) } var clickedTrack: Track? by remember { mutableStateOf(null) } + LaunchedEffect(foldersAndTracksState.foldersAndTracks.tracks) { + clickedTrack?.let { track -> + val updatedTrack = + foldersAndTracksState.foldersAndTracks.tracks.find { it.trackHash == track.trackHash } + clickedTrack = updatedTrack ?: track + } + // just in case + if (clickedTrack == null) showTrackBottomSheet = false + } + var showOnRefreshIndicator by remember { mutableStateOf(false) } val refreshState = rememberPullToRefreshState() @@ -157,6 +167,7 @@ private fun FoldersAndTracks( sheetState = sheetState, clickedTrack = track, baseUrl = baseUrl, + isFavorite = track.isFavorite, bottomSheetItems = listOf( BottomSheetItemModel( label = "Go to Artist", @@ -194,8 +205,8 @@ private fun FoldersAndTracks( onChooseArtist = { hash -> onGotoArtist(hash) }, - onToggleTrackFavorite = { isFavorite, trackHash -> - onToggleTrackFavorite(isFavorite, trackHash) + onToggleTrackFavorite = { trackHash, isFavorite -> + onToggleTrackFavorite(trackHash, isFavorite) } ) } @@ -571,8 +582,10 @@ fun FoldersAndTracksScreen( onGotoArtist = { hash -> navigator.gotoArtistInfo(artistHash = hash) }, - onToggleTrackFavorite = { isFavorite, trackHash -> - // TODO: Call Folder Track fav toggle + onToggleTrackFavorite = { trackHash, isFavorite -> + foldersViewModel.onFolderUiEvent( + FolderUiEvent.ToggleTrackFavorite(trackHash, isFavorite) + ) } ) diff --git a/feature/folder/src/main/java/com/android/swingmusic/folder/presentation/viewmodel/FoldersViewModel.kt b/feature/folder/src/main/java/com/android/swingmusic/folder/presentation/viewmodel/FoldersViewModel.kt index 7de7d7aa..9f099b9e 100644 --- a/feature/folder/src/main/java/com/android/swingmusic/folder/presentation/viewmodel/FoldersViewModel.kt +++ b/feature/folder/src/main/java/com/android/swingmusic/folder/presentation/viewmodel/FoldersViewModel.kt @@ -12,15 +12,16 @@ import com.android.swingmusic.core.domain.model.FoldersAndTracksRequest import com.android.swingmusic.folder.domain.FolderRepository import com.android.swingmusic.folder.presentation.event.FolderUiEvent import com.android.swingmusic.folder.presentation.state.FoldersAndTracksState +import com.android.swingmusic.player.domain.repository.PLayerRepository import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch -import timber.log.Timber import javax.inject.Inject @HiltViewModel class FoldersViewModel @Inject constructor( - private val folderRepository: FolderRepository + private val folderRepository: FolderRepository, + private val pLayerRepository: PLayerRepository ) : ViewModel() { val homeDir: Folder = Folder( path = "\$home", @@ -160,6 +161,69 @@ class FoldersViewModel @Inject constructor( resetUiToLoadingState() getFoldersAndTracks(_currentFolder.value.path) } + + is FolderUiEvent.ToggleTrackFavorite -> { + toggleTrackFavorite(event.trackHash, event.isFavorite) + } + } + } + + private fun toggleTrackFavorite(trackHash: String, isFavorite: Boolean) { + viewModelScope.launch { + // Optimistically update the UI + _foldersAndTracks.value = _foldersAndTracks.value.copy( + foldersAndTracks = _foldersAndTracks.value.foldersAndTracks.copy( + tracks = _foldersAndTracks.value.foldersAndTracks.tracks.map { track -> + if (track.trackHash == trackHash) { + track.copy(isFavorite = !isFavorite) + } else { + track + } + } + ) + ) + + val request = if (isFavorite) { + pLayerRepository.removeTrackFromFavorite(trackHash) + } else { + pLayerRepository.addTrackToFavorite(trackHash) + } + + request.collectLatest { + when (it) { + is Resource.Loading -> {} + + is Resource.Success -> { + _foldersAndTracks.value = _foldersAndTracks.value.copy( + foldersAndTracks = _foldersAndTracks.value.foldersAndTracks.copy( + tracks = _foldersAndTracks.value.foldersAndTracks.tracks.map { track -> + if (track.trackHash == trackHash) { + track.copy(isFavorite = it.data ?: false) + } else { + track + } + } + ) + ) + } + + is Resource.Error -> { + // Revert the optimistic updates in case of an error + _foldersAndTracks.value = _foldersAndTracks.value.copy( + foldersAndTracks = _foldersAndTracks.value.foldersAndTracks.copy( + tracks = _foldersAndTracks.value.foldersAndTracks.tracks.map { track -> + if (track.trackHash == trackHash) { + track.copy(isFavorite = isFavorite) + } else { + track + } + } + ) + ) + } + } + } + } } } diff --git a/feature/player/src/main/java/com/android/swingmusic/player/data/repository/DataPLayerRepository.kt b/feature/player/src/main/java/com/android/swingmusic/player/data/repository/DataPLayerRepository.kt index e77d3074..0de87d97 100644 --- a/feature/player/src/main/java/com/android/swingmusic/player/data/repository/DataPLayerRepository.kt +++ b/feature/player/src/main/java/com/android/swingmusic/player/data/repository/DataPLayerRepository.kt @@ -108,7 +108,7 @@ class DataPLayerRepository @Inject constructor( bearerToken = "Bearer $accessToken" ) - emit(Resource.Success(data = true)) + emit(Resource.Success(data = true)) // isFavorite = true } catch (e: HttpException) { emit(Resource.Error(message = "FAILED TO ADD TRACK TO FAVORITE")) @@ -132,7 +132,7 @@ class DataPLayerRepository @Inject constructor( toggleFavoriteRequest = ToggleFavoriteRequest(hash = trackHash, type = "track"), bearerToken = "Bearer $accessToken" ) - emit(Resource.Success(data = false)) + emit(Resource.Success(data = false)) // isFavorite = false } catch (e: HttpException) { emit(Resource.Error(message = "FAILED TO REMOVE TRACK FROM FAVORITE")) diff --git a/feature/player/src/main/java/com/android/swingmusic/player/presentation/screen/Queue.kt b/feature/player/src/main/java/com/android/swingmusic/player/presentation/screen/Queue.kt index 1fb6f37e..b310fba8 100644 --- a/feature/player/src/main/java/com/android/swingmusic/player/presentation/screen/Queue.kt +++ b/feature/player/src/main/java/com/android/swingmusic/player/presentation/screen/Queue.kt @@ -84,7 +84,7 @@ private fun Queue( playbackState: PlaybackState, baseUrl: String, onClickQueueSource: (source: QueueSource) -> Unit, - onToggleTrackFavorite: (isFavorite: Boolean, trackHash: String) -> Unit, + onToggleTrackFavorite: (trackHash: String, isFavorite: Boolean) -> Unit, onTogglePlayerState: () -> Unit, onClickQueueItem: (index: Int) -> Unit, onGetSheetAction: (track: Track, sheetAction: BottomSheetAction) -> Unit, @@ -98,6 +98,13 @@ private fun Queue( var showTrackBottomSheet by remember { mutableStateOf(false) } var clickedTrack: Track? by remember { mutableStateOf(null) } + LaunchedEffect(queue) { + clickedTrack?.let { track -> + val updatedTrack = queue.find { it.trackHash == track.trackHash } + clickedTrack = updatedTrack ?: track + } + } + // scroll past the playing track by one item to keep highlighted cards far apart at first LaunchedEffect(key1 = Unit) { if ((playingTrackIndex - 1) in queue.indices) { @@ -112,6 +119,7 @@ private fun Queue( scope = scope, sheetState = sheetState, clickedTrack = track, + isFavorite = track.isFavorite, baseUrl = baseUrl, bottomSheetItems = listOf( BottomSheetItemModel( @@ -154,8 +162,8 @@ private fun Queue( onChooseArtist = { hash -> onGotoArtist(hash) }, - onToggleTrackFavorite = { isFavorite, trackHash -> - onToggleTrackFavorite(isFavorite, trackHash) + onToggleTrackFavorite = { trackHash, isFavorite -> + onToggleTrackFavorite(trackHash, isFavorite) } ) } @@ -455,7 +463,7 @@ fun QueueScreen( }, onToggleTrackFavorite = { isFavorite, trackHash -> mediaControllerViewModel.onPlayerUiEvent( - PlayerUiEvent.OnToggleFavorite(isFavorite, trackHash) + PlayerUiEvent.OnToggleFavorite(trackHash, isFavorite) ) } ) diff --git a/feature/player/src/main/java/com/android/swingmusic/player/presentation/viewmodel/MediaControllerViewModel.kt b/feature/player/src/main/java/com/android/swingmusic/player/presentation/viewmodel/MediaControllerViewModel.kt index 0e899810..90bf9041 100644 --- a/feature/player/src/main/java/com/android/swingmusic/player/presentation/viewmodel/MediaControllerViewModel.kt +++ b/feature/player/src/main/java/com/android/swingmusic/player/presentation/viewmodel/MediaControllerViewModel.kt @@ -596,8 +596,6 @@ class MediaControllerViewModel @Inject constructor( } }.toMutableList() } - - else -> {} } } } diff --git a/uicomponent/src/main/java/com/android/swingmusic/uicomponent/presentation/component/CustomTrackBottomSheet.kt b/uicomponent/src/main/java/com/android/swingmusic/uicomponent/presentation/component/CustomTrackBottomSheet.kt index b926b22f..9bf14eb8 100644 --- a/uicomponent/src/main/java/com/android/swingmusic/uicomponent/presentation/component/CustomTrackBottomSheet.kt +++ b/uicomponent/src/main/java/com/android/swingmusic/uicomponent/presentation/component/CustomTrackBottomSheet.kt @@ -60,9 +60,10 @@ fun CustomTrackBottomSheet( sheetState: SheetState, clickedTrack: Track?, baseUrl: String, + isFavorite: Boolean = false, bottomSheetItems: List, currentArtisthash: String? = null, - onToggleTrackFavorite: (isFavorite: Boolean, trackHash: String) -> Unit, + onToggleTrackFavorite: (trackHash: String, isFavorite: Boolean) -> Unit, onHideBottomSheet: (show: Boolean) -> Unit, onClickSheetItem: (track: Track, sheetAction: BottomSheetAction) -> Unit, onChooseArtist: (hash: String) -> Unit @@ -85,26 +86,20 @@ fun CustomTrackBottomSheet( modifier = Modifier.offset(x = (-8).dp), contentAlignment = Alignment.CenterStart ) { - TrackItem( - track = track, + TrackItem(track = track, onClickTrackItem = {}, onClickMoreVert = {}, baseUrl = baseUrl ) Box( - modifier = Modifier.fillMaxWidth(), - contentAlignment = Alignment.CenterEnd + modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.CenterEnd ) { - IconButton( - modifier = Modifier - .clip(CircleShape), - onClick = { - onToggleTrackFavorite(track.isFavorite, track.trackHash) - }) { - val icon = - if (track.isFavorite) R.drawable.fav_filled - else R.drawable.fav_not_filled + IconButton(modifier = Modifier.clip(CircleShape), onClick = { + onToggleTrackFavorite(track.trackHash, track.isFavorite) + }) { + val icon = if (isFavorite) R.drawable.fav_filled + else R.drawable.fav_not_filled Icon( painter = painterResource(id = icon), contentDescription = "Favorite" @@ -118,8 +113,7 @@ fun CustomTrackBottomSheet( } } bottomSheetItems.forEach { model -> - BottomSheetItem( - label = model.label, + BottomSheetItem(label = model.label, enabled = model.enabled, baseUrl = baseUrl, sheetAction = model.sheetAction, @@ -154,8 +148,7 @@ fun CustomTrackBottomSheet( }, onDialogDismissRequest = { expand -> artistDialogExpanded = expand - } - ) + }) } Spacer(modifier = Modifier.height(48.dp)) @@ -178,21 +171,18 @@ fun BottomSheetItem( ) { val interactionSource = remember { MutableInteractionSource() } - Box( - modifier = Modifier - .fillMaxWidth() - .clickable(enabled = enabled) { - clickedTrack?.let { track -> - onClickSheetItem(track) - } + Box(modifier = Modifier + .fillMaxWidth() + .clickable(enabled = enabled) { + clickedTrack?.let { track -> + onClickSheetItem(track) } - .padding(all = 12.dp) - ) { + } + .padding(all = 12.dp)) { Row(verticalAlignment = Alignment.CenterVertically) { Icon( painter = iconPainter, - tint = if (!enabled) MaterialTheme.colorScheme.onSurface.copy(alpha = .30F) else - MaterialTheme.colorScheme.onSurface, + tint = if (!enabled) MaterialTheme.colorScheme.onSurface.copy(alpha = .30F) else MaterialTheme.colorScheme.onSurface, contentDescription = "Icon" ) @@ -200,20 +190,16 @@ fun BottomSheetItem( Text( text = label, - color = if (!enabled) MaterialTheme.colorScheme.onSurface.copy(alpha = .305F) else - MaterialTheme.colorScheme.onSurface + color = if (!enabled) MaterialTheme.colorScheme.onSurface.copy(alpha = .305F) else MaterialTheme.colorScheme.onSurface ) }.also { when (sheetAction) { is BottomSheetAction.OpenArtistsDialog -> { if (expandArtistDialog) { - Dialog( - properties = DialogProperties(decorFitsSystemWindows = true), - onDismissRequest = { onDialogDismissRequest(false) }) - { + Dialog(properties = DialogProperties(decorFitsSystemWindows = true), + onDismissRequest = { onDialogDismissRequest(false) }) { Surface( - shape = MaterialTheme.shapes.medium, - tonalElevation = 8.dp + shape = MaterialTheme.shapes.medium, tonalElevation = 8.dp ) { Column( modifier = Modifier @@ -241,19 +227,17 @@ fun BottomSheetItem( ) { onDialogDismissRequest(false) onChooseArtist(artist.artistHash) - }, - verticalAlignment = Alignment.CenterVertically + }, verticalAlignment = Alignment.CenterVertically ) { - AsyncImage( - modifier = Modifier - .padding(vertical = 8.dp) - .size(32.dp) - .clip(CircleShape) - .background( - MaterialTheme.colorScheme.inversePrimary.copy( - .5F - ) - ), + AsyncImage(modifier = Modifier + .padding(vertical = 8.dp) + .size(32.dp) + .clip(CircleShape) + .background( + MaterialTheme.colorScheme.inversePrimary.copy( + .5F + ) + ), model = ImageRequest.Builder(LocalContext.current) .data("${baseUrl}img/artist/small/${artist.artistHash}.webp") .build(), @@ -262,10 +246,8 @@ fun BottomSheetItem( error = painterResource(R.drawable.artist_fallback), contentScale = ContentScale.Crop, colorFilter = if (clickable) null else ColorMatrixColorFilter( - ColorMatrix().apply { setToSaturation(0f) } - ), - contentDescription = "Track Image" - ) + ColorMatrix().apply { setToSaturation(0f) }), + contentDescription = "Track Image") Spacer(modifier = Modifier.width(8.dp)) @@ -273,8 +255,9 @@ fun BottomSheetItem( text = artist.name, overflow = TextOverflow.Ellipsis, style = MaterialTheme.typography.bodyLarge, - color = if (clickable) MaterialTheme.colorScheme.onSurface else - MaterialTheme.colorScheme.onSurface.copy(alpha = .20F) + color = if (clickable) MaterialTheme.colorScheme.onSurface else MaterialTheme.colorScheme.onSurface.copy( + alpha = .20F + ) ) } }