From bc765335125b4980cb925aeba8c61395fc9c03ba Mon Sep 17 00:00:00 2001 From: vfsfitvnm Date: Fri, 22 Jul 2022 10:26:12 +0200 Subject: [PATCH] Make PlayerBottomSheet composable smart recompose --- .../vimusic/ui/views/CurrentPlaylistView.kt | 73 +++++++++---------- .../vimusic/ui/views/PlayerBottomSheet.kt | 2 - .../vfsfitvnm/vimusic/ui/views/PlayerView.kt | 2 - .../it/vfsfitvnm/vimusic/utils/Player.kt | 5 ++ .../it/vfsfitvnm/vimusic/utils/PlayerState.kt | 38 ++++++++++ 5 files changed, 77 insertions(+), 43 deletions(-) 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 d66ba80..cba2bb1 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 @@ -10,12 +10,11 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.text.BasicText import androidx.compose.material.ripple.rememberRipple import androidx.compose.runtime.Composable -import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Alignment @@ -30,7 +29,6 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll 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.shimmer import it.vfsfitvnm.reordering.rememberReorderingState import it.vfsfitvnm.reordering.verticalDragAfterLongPressToReorder @@ -45,16 +43,11 @@ import it.vfsfitvnm.vimusic.ui.styling.Dimensions import it.vfsfitvnm.vimusic.ui.styling.LightColorPalette import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance import it.vfsfitvnm.vimusic.ui.styling.px -import it.vfsfitvnm.vimusic.utils.PlayerState -import it.vfsfitvnm.vimusic.utils.medium -import it.vfsfitvnm.vimusic.utils.secondary -import it.vfsfitvnm.vimusic.utils.semiBold - +import it.vfsfitvnm.vimusic.utils.* @ExperimentalAnimationApi @Composable fun CurrentPlaylistView( - playerState: PlayerState?, layoutState: BottomSheetState, onGlobalRouteEmitted: () -> Unit, modifier: Modifier = Modifier, @@ -63,16 +56,18 @@ fun CurrentPlaylistView( val hapticFeedback = LocalHapticFeedback.current val (colorPalette, typography) = LocalAppearance.current + binder?.player ?: return + val thumbnailSize = Dimensions.thumbnails.song.px - val isPaused by derivedStateOf { - playerState?.playbackState == Player.STATE_ENDED || playerState?.playWhenReady == false - } + val mediaItemIndex by rememberMediaItemIndex(binder.player) + val windows by rememberWindows(binder.player) + val shouldBePlaying by rememberShouldBePlaying(binder.player) val lazyListState = - rememberLazyListState(initialFirstVisibleItemIndex = playerState?.mediaItemIndex ?: 0) + rememberLazyListState(initialFirstVisibleItemIndex = mediaItemIndex) - val reorderingState = rememberReorderingState(playerState?.mediaItems ?: emptyList()) + val reorderingState = rememberReorderingState(windows) Box { LazyColumn( @@ -84,32 +79,31 @@ fun CurrentPlaylistView( layoutState.nestedScrollConnection(lazyListState.firstVisibleItemIndex == 0 && lazyListState.firstVisibleItemScrollOffset == 0) }) ) { - itemsIndexed( - items = playerState?.mediaItems ?: emptyList() - ) { index, mediaItem -> - val isPlayingThisMediaItem by derivedStateOf { - playerState?.mediaItemIndex == index - } + items( + items = windows, + key = { it.uid.hashCode() } + ) { window -> + val isPlayingThisMediaItem = mediaItemIndex == window.firstPeriodIndex SongItem( - mediaItem = mediaItem, + mediaItem = window.mediaItem, thumbnailSize = thumbnailSize, onClick = { if (isPlayingThisMediaItem) { - if (isPaused) { - binder?.player?.play() + if (shouldBePlaying) { + binder.player.pause() } else { - binder?.player?.pause() + binder.player.play() } } else { - binder?.player?.playWhenReady = true - binder?.player?.seekToDefaultPosition(index) + binder.player.playWhenReady = true + binder.player.seekToDefaultPosition(window.firstPeriodIndex) } }, menuContent = { QueuedMediaItemMenu( - mediaItem = mediaItem, - indexInQueue = if (isPlayingThisMediaItem) null else index, + mediaItem = window.mediaItem, + indexInQueue = if (isPlayingThisMediaItem) null else window.firstPeriodIndex, onGlobalRouteEmitted = onGlobalRouteEmitted ) }, @@ -128,7 +122,13 @@ fun CurrentPlaylistView( ) .size(Dimensions.thumbnails.song) ) { - if (isPaused) { + if (shouldBePlaying) { + MusicBars( + color = LightColorPalette.background, + modifier = Modifier + .height(24.dp) + ) + } else { Image( painter = painterResource(R.drawable.play), contentDescription = null, @@ -136,12 +136,6 @@ fun CurrentPlaylistView( modifier = Modifier .size(24.dp) ) - } else { - MusicBars( - color = LightColorPalette.background, - modifier = Modifier - .height(24.dp) - ) } } } @@ -159,23 +153,24 @@ fun CurrentPlaylistView( }, backgroundColor = colorPalette.background, modifier = Modifier +// .animateItemPlacement() .verticalDragAfterLongPressToReorder( reorderingState = reorderingState, - index = index, + index = window.firstPeriodIndex, onDragStart = { hapticFeedback.performHapticFeedback( HapticFeedbackType.LongPress ) }, onDragEnd = { reachedIndex -> - binder?.player?.moveMediaItem(index, reachedIndex) + binder.player.moveMediaItem(window.firstPeriodIndex, reachedIndex) } ) ) } item { - if (binder?.isLoadingRadio == true) { + if (binder.isLoadingRadio) { Column( modifier = Modifier .shimmer() @@ -226,7 +221,7 @@ fun CurrentPlaylistView( modifier = Modifier ) BasicText( - text = "${playerState?.mediaItems?.size ?: 0} songs", + text = "${windows.size} songs", style = typography.xxs.semiBold.secondary, modifier = Modifier ) diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/PlayerBottomSheet.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/PlayerBottomSheet.kt index 097d998..f7348a9 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/PlayerBottomSheet.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/PlayerBottomSheet.kt @@ -22,7 +22,6 @@ import it.vfsfitvnm.vimusic.utils.PlayerState @ExperimentalAnimationApi @Composable fun PlayerBottomSheet( - playerState: PlayerState?, layoutState: BottomSheetState, onShowLyrics: () -> Unit, onShowStatsForNerds: () -> Unit, @@ -101,7 +100,6 @@ fun PlayerBottomSheet( } ) { CurrentPlaylistView( - playerState = playerState, layoutState = layoutState, onGlobalRouteEmitted = onGlobalRouteEmitted, modifier = Modifier diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/PlayerView.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/PlayerView.kt index 02cf64a..6d8244e 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/PlayerView.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/PlayerView.kt @@ -311,7 +311,6 @@ fun PlayerView( } PlayerBottomSheet( - playerState = playerState, layoutState = rememberBottomSheetState(64.dp, layoutState.upperBound), onShowLyrics = { isShowingStatsForNerds = false @@ -441,7 +440,6 @@ private fun Thumbnail( } } - @Composable private fun Lyrics( mediaId: String, diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/Player.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/Player.kt index af076cc..de8189e 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/Player.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/Player.kt @@ -10,6 +10,11 @@ val Timeline.mediaItems: List getWindow(index, Timeline.Window()).mediaItem } +val Timeline.windows: List + get() = (0 until windowCount).map { index -> + getWindow(index, Timeline.Window()) + } + val Player.shouldBePlaying: Boolean get() = !(playbackState == Player.STATE_ENDED || !playWhenReady) diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/PlayerState.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/PlayerState.kt index b4339f0..557b182 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/PlayerState.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/PlayerState.kt @@ -154,6 +154,44 @@ fun rememberMediaItemIndex(player: Player): State { return mediaItemIndexState } +@Composable +fun rememberWindows(player: Player): State> { + val windowsState = remember(player) { + mutableStateOf(player.currentTimeline.windows) + } + + DisposableEffect(player) { + player.listener(object : Player.Listener { + override fun onTimelineChanged(timeline: Timeline, reason: Int) { + windowsState.value = timeline.windows + } + }) + } + + return windowsState +} + +@Composable +fun rememberShouldBePlaying(player: Player): State { + val state = remember(player) { + mutableStateOf(!(player.playbackState == Player.STATE_ENDED || !player.playWhenReady)) + } + + DisposableEffect(player) { + player.listener(object : Player.Listener { + override fun onPlayWhenReadyChanged(playWhenReady: Boolean, reason: Int) { + state.value = !(player.playbackState == Player.STATE_ENDED || !playWhenReady) + } + + override fun onPlaybackStateChanged(playbackState: Int) { + state.value = !(playbackState == Player.STATE_ENDED || !player.playWhenReady) + } + }) + } + + return state +} + @Composable fun rememberVolume(player: Player): State { val volumeState = remember(player) {