From 9139609cf35a85aa88ec1864f385af4a8acdcb4f Mon Sep 17 00:00:00 2001 From: vfsfitvnm Date: Fri, 1 Jul 2022 15:31:00 +0200 Subject: [PATCH] Show radio loading state --- .../vimusic/service/PlayerService.kt | 9 ++ .../vimusic/ui/views/CurrentPlaylistView.kt | 88 +++++++------------ .../vfsfitvnm/vimusic/utils/YoutubePlayer.kt | 15 +--- 3 files changed, 46 insertions(+), 66 deletions(-) diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/service/PlayerService.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/service/PlayerService.kt index 2d14abc..f007899 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/service/PlayerService.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/service/PlayerService.kt @@ -17,6 +17,9 @@ import android.support.v4.media.session.MediaSessionCompat import android.support.v4.media.session.PlaybackStateCompat import android.support.v4.media.session.PlaybackStateCompat.* import androidx.annotation.DrawableRes +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue import androidx.core.app.NotificationCompat import androidx.core.content.ContextCompat.startForegroundService import androidx.core.net.toUri @@ -541,6 +544,9 @@ class PlayerService : Service(), Player.Listener, PlaybackStatsListener.Callback private var radioJob: Job? = null + var isLoadingRadio by mutableStateOf(false) + private set + fun startSleepTimer(delayMillis: Long) { timerJob?.cancel() @@ -581,6 +587,7 @@ class PlayerService : Service(), Player.Listener, PlaybackStatsListener.Callback endpoint?.playlistSetVideoId, endpoint?.params ).let { + isLoadingRadio = true radioJob = coroutineScope.launch(Dispatchers.Main) { if (justAdd) { player.addMediaItems(it.process().drop(1)) @@ -588,11 +595,13 @@ class PlayerService : Service(), Player.Listener, PlaybackStatsListener.Callback player.forcePlayFromBeginning(it.process()) } radio = it + isLoadingRadio = false } } } fun stopRadio() { + isLoadingRadio = false radioJob?.cancel() radio = null } diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/CurrentPlaylistView.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/CurrentPlaylistView.kt index 151c011..dfd9b99 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/CurrentPlaylistView.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/CurrentPlaylistView.kt @@ -6,9 +6,7 @@ import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.foundation.Image import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.rememberLazyListState @@ -18,6 +16,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.hapticfeedback.HapticFeedbackType @@ -27,6 +26,8 @@ import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import androidx.media3.common.Player +import com.valentinilk.shimmer.ShimmerBounds +import com.valentinilk.shimmer.rememberShimmer import it.vfsfitvnm.reordering.rememberReorderingState import it.vfsfitvnm.reordering.verticalDragAfterLongPressToReorder import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder @@ -35,6 +36,7 @@ import it.vfsfitvnm.vimusic.enums.ThumbnailRoundness import it.vfsfitvnm.vimusic.ui.components.BottomSheetState import it.vfsfitvnm.vimusic.ui.components.MusicBars import it.vfsfitvnm.vimusic.ui.components.themed.QueuedMediaItemMenu +import it.vfsfitvnm.vimusic.ui.screens.SmallSongItemShimmer import it.vfsfitvnm.vimusic.ui.styling.LightColorPalette import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette import it.vfsfitvnm.vimusic.utils.PlayerState @@ -48,7 +50,7 @@ fun CurrentPlaylistView( onGlobalRouteEmitted: () -> Unit, modifier: Modifier = Modifier, ) { - val player = LocalPlayerServiceBinder.current?.player + val binder = LocalPlayerServiceBinder.current val hapticFeedback = LocalHapticFeedback.current val density = LocalDensity.current val colorPalette = LocalColorPalette.current @@ -88,13 +90,13 @@ fun CurrentPlaylistView( onClick = { if (isPlayingThisMediaItem) { if (isPaused) { - player?.play() + binder?.player?.play() } else { - player?.pause() + binder?.player?.pause() } } else { - player?.playWhenReady = true - player?.seekToDefaultPosition(index) + binder?.player?.playWhenReady = true + binder?.player?.seekToDefaultPosition(index) } }, menuContent = { @@ -113,7 +115,10 @@ fun CurrentPlaylistView( Box( contentAlignment = Alignment.Center, modifier = Modifier - .background(color = Color.Black.copy(alpha = 0.25f), shape = ThumbnailRoundness.shape) + .background( + color = Color.Black.copy(alpha = 0.25f), + shape = ThumbnailRoundness.shape + ) .size(54.dp) ) { if (isPaused) { @@ -146,56 +151,29 @@ fun CurrentPlaylistView( ) }, onDragEnd = { reachedIndex -> - player?.moveMediaItem(index, reachedIndex) + binder?.player?.moveMediaItem(index, reachedIndex) } ) ) } -// if (YoutubePlayer.Radio.isActive && player != null) { -// when (val nextContinuation = YoutubePlayer.Radio.nextContinuation) { -// is Outcome.Loading, is Outcome.Success<*> -> { -// if (nextContinuation is Outcome.Success<*>) { -// item { -// SideEffect { -// coroutineScope.launch { -// YoutubePlayer.Radio.process( -// playerState.mediaController, -// force = true -// ) -// } -// } -// } -// } -// -// items(count = 3, key = { it }) { index -> -// SmallSongItemShimmer( -// shimmer = shimmer, -// thumbnailSizeDp = 54.dp, -// modifier = Modifier -// .alpha(1f - index * 0.125f) -// .fillMaxWidth() -// .padding(vertical = 4.dp, horizontal = 16.dp) -// ) -// } -// } -// is Outcome.Error -> item { -// Error( -// error = nextContinuation -// ) -// } -// is Outcome.Recovered<*> -> item { -// Error( -// error = nextContinuation.error, -// onRetry = { -// coroutineScope.launch { -// YoutubePlayer.Radio.process(playerState.mediaController, force = true) -// } -// } -// ) -// } -// else -> {} -// } -// } + item { + if (binder?.isLoadingRadio == true) { + val shimmer = rememberShimmer(shimmerBounds = ShimmerBounds.Window) + + Column { + repeat(3) { index -> + SmallSongItemShimmer( + shimmer = shimmer, + thumbnailSizeDp = 54.dp, + modifier = Modifier + .alpha(1f - index * 0.125f) + .fillMaxWidth() + .padding(vertical = 4.dp, horizontal = 16.dp) + ) + } + } + } + } } } diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/YoutubePlayer.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/YoutubePlayer.kt index 81ab121..771d1e2 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/YoutubePlayer.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/YoutubePlayer.kt @@ -1,8 +1,6 @@ package it.vfsfitvnm.vimusic.utils -import androidx.compose.runtime.* import androidx.media3.common.MediaItem -import it.vfsfitvnm.youtubemusic.Outcome import it.vfsfitvnm.youtubemusic.YouTube import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @@ -13,13 +11,9 @@ data class YouTubeRadio( private val playlistSetVideoId: String? = null, private val parameters: String? = null ) { - var nextContinuation by mutableStateOf>(Outcome.Initial) + private var nextContinuation: String? = null suspend fun process(): List { - val token = nextContinuation.valueOrNull - - nextContinuation = Outcome.Loading - var mediaItems: List? = null nextContinuation = withContext(Dispatchers.IO) { @@ -28,13 +22,12 @@ data class YouTubeRadio( playlistId = playlistId, params = parameters, playlistSetVideoId = playlistSetVideoId, - continuation = token + continuation = nextContinuation ) }.map { nextResult -> mediaItems = nextResult.items?.map(YouTube.Item.Song::asMediaItem) - - nextResult.continuation?.takeUnless { token == nextResult.continuation } - }.recoverWith(token) + nextResult.continuation?.takeUnless { nextContinuation == nextResult.continuation } + }.recoverWith(nextContinuation).valueOrNull return mediaItems ?: emptyList() }