diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/FloatingActionsContainer.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/FloatingActionsContainer.kt index 04ab6b2..8b0b57c 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/FloatingActionsContainer.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/FloatingActionsContainer.kt @@ -11,6 +11,7 @@ import androidx.compose.foundation.ScrollState import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.BoxScope import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.only @@ -38,6 +39,7 @@ fun BoxScope.FloatingActionsContainerWithScrollToTop( visible: Boolean = true, iconId: Int? = null, onClick: (() -> Unit)? = null, + windowInsets: WindowInsets = LocalPlayerAwareWindowInsets.current ) { val transitionState = remember { MutableTransitionState(ScrollingInfo()) @@ -48,6 +50,7 @@ fun BoxScope.FloatingActionsContainerWithScrollToTop( onScrollToTop = lazyGridState::smoothScrollToTop, iconId = iconId, onClick = onClick, + windowInsets = windowInsets, modifier = modifier ) } @@ -60,6 +63,7 @@ fun BoxScope.FloatingActionsContainerWithScrollToTop( visible: Boolean = true, iconId: Int? = null, onClick: (() -> Unit)? = null, + windowInsets: WindowInsets = LocalPlayerAwareWindowInsets.current ) { val transitionState = remember { MutableTransitionState(ScrollingInfo()) @@ -70,6 +74,7 @@ fun BoxScope.FloatingActionsContainerWithScrollToTop( onScrollToTop = lazyListState::smoothScrollToTop, iconId = iconId, onClick = onClick, + windowInsets = windowInsets, modifier = modifier ) } @@ -82,6 +87,7 @@ fun BoxScope.FloatingActionsContainerWithScrollToTop( visible: Boolean = true, iconId: Int? = null, onClick: (() -> Unit)? = null, + windowInsets: WindowInsets = LocalPlayerAwareWindowInsets.current ) { val transitionState = remember { MutableTransitionState(ScrollingInfo()) @@ -91,6 +97,7 @@ fun BoxScope.FloatingActionsContainerWithScrollToTop( transitionState = transitionState, iconId = iconId, onClick = onClick, + windowInsets = windowInsets, modifier = modifier ) } @@ -99,13 +106,13 @@ fun BoxScope.FloatingActionsContainerWithScrollToTop( @Composable fun BoxScope.FloatingActions( transitionState: MutableTransitionState, + windowInsets: WindowInsets, modifier: Modifier = Modifier, onScrollToTop: (suspend () -> Unit)? = null, iconId: Int? = null, - onClick: (() -> Unit)? = null, + onClick: (() -> Unit)? = null ) { val transition = updateTransition(transitionState, "") - val windowInsets = LocalPlayerAwareWindowInsets.current val bottomPaddingValues = windowInsets.only(WindowInsetsSides.Bottom).asPaddingValues() diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/player/Queue.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/player/Queue.kt index c8a189b..dce39f2 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/player/Queue.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/player/Queue.kt @@ -50,6 +50,7 @@ import it.vfsfitvnm.vimusic.ui.components.BottomSheet import it.vfsfitvnm.vimusic.ui.components.BottomSheetState import it.vfsfitvnm.vimusic.ui.components.LocalMenuState import it.vfsfitvnm.vimusic.ui.components.MusicBars +import it.vfsfitvnm.vimusic.ui.components.themed.FloatingActionsContainerWithScrollToTop import it.vfsfitvnm.vimusic.ui.components.themed.IconButton import it.vfsfitvnm.vimusic.ui.components.themed.QueuedMediaItemMenu import it.vfsfitvnm.vimusic.ui.items.SongItem @@ -125,134 +126,150 @@ fun Queue( extraItemCount = 0 ) - - val rippleIndication = rememberRipple(bounded = false) Column { - ReorderingLazyColumn( - reorderingState = reorderingState, - contentPadding = windowInsets - .only(WindowInsetsSides.Horizontal + WindowInsetsSides.Top).asPaddingValues(), - horizontalAlignment = Alignment.CenterHorizontally, + Box( modifier = Modifier - .background(colorPalette.background0) - .fillMaxSize() - .nestedScroll(remember { - layoutState.nestedScrollConnection(reorderingState.lazyListState.firstVisibleItemIndex == 0 && reorderingState.lazyListState.firstVisibleItemScrollOffset == 0) - }) .background(colorPalette.background1) .weight(1f) ) { - items( - items = windows, - key = { it.uid.hashCode() } - ) { window -> - val isPlayingThisMediaItem = mediaItemIndex == window.firstPeriodIndex + ReorderingLazyColumn( + reorderingState = reorderingState, + contentPadding = windowInsets + .only(WindowInsetsSides.Horizontal + WindowInsetsSides.Top).asPaddingValues(), + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier + .nestedScroll(remember { + layoutState.nestedScrollConnection(reorderingState.lazyListState.firstVisibleItemIndex == 0 && reorderingState.lazyListState.firstVisibleItemScrollOffset == 0) + }) - SongItem( - song = window.mediaItem, - thumbnailSizePx = thumbnailSizePx, - thumbnailSizeDp = thumbnailSizeDp, - onThumbnailContent = { - androidx.compose.animation.AnimatedVisibility( - visible = isPlayingThisMediaItem, - enter = fadeIn(), - exit = fadeOut(), - ) { - Box( - contentAlignment = Alignment.Center, - modifier = Modifier - .background( - color = Color.Black.copy(alpha = 0.25f), - shape = thumbnailShape - ) - .size(Dimensions.thumbnails.song) + ) { + items( + items = windows, + key = { it.uid.hashCode() } + ) { window -> + val isPlayingThisMediaItem = mediaItemIndex == window.firstPeriodIndex + + SongItem( + song = window.mediaItem, + thumbnailSizePx = thumbnailSizePx, + thumbnailSizeDp = thumbnailSizeDp, + onThumbnailContent = { + androidx.compose.animation.AnimatedVisibility( + visible = isPlayingThisMediaItem, + enter = fadeIn(), + exit = fadeOut(), ) { - if (shouldBePlaying) { - MusicBars( - color = colorPalette.onOverlay, - modifier = Modifier - .height(24.dp) - ) - } else { - Image( - painter = painterResource(R.drawable.play), - contentDescription = null, - colorFilter = ColorFilter.tint(colorPalette.onOverlay), - modifier = Modifier - .size(24.dp) - ) - } - } - } - }, - trailingContent = { - IconButton( - icon = R.drawable.reorder, - color = colorPalette.textDisabled, - indication = rippleIndication, - onClick = {}, - modifier = Modifier - .reorder( - reorderingState = reorderingState, - index = window.firstPeriodIndex - ) - .size(18.dp) - ) - }, - modifier = Modifier - .combinedClickable( - onLongClick = { - menuState.display { - QueuedMediaItemMenu( - mediaItem = window.mediaItem, - indexInQueue = if (isPlayingThisMediaItem) null else window.firstPeriodIndex, - onDismiss = menuState::hide - ) - } - }, - onClick = { - if (isPlayingThisMediaItem) { + Box( + contentAlignment = Alignment.Center, + modifier = Modifier + .background( + color = Color.Black.copy(alpha = 0.25f), + shape = thumbnailShape + ) + .size(Dimensions.thumbnails.song) + ) { if (shouldBePlaying) { - binder.player.pause() + MusicBars( + color = colorPalette.onOverlay, + modifier = Modifier + .height(24.dp) + ) } else { - binder.player.play() + Image( + painter = painterResource(R.drawable.play), + contentDescription = null, + colorFilter = ColorFilter.tint(colorPalette.onOverlay), + modifier = Modifier + .size(24.dp) + ) } - } else { - binder.player.playWhenReady = true - binder.player.seekToDefaultPosition(window.firstPeriodIndex) } } - ) - .animateItemPlacement(reorderingState = reorderingState) - .draggedItem( - reorderingState = reorderingState, - index = window.firstPeriodIndex - ) - ) - } - - item { - if (binder.isLoadingRadio) { - Column( - modifier = Modifier - .shimmer() - ) { - repeat(3) { index -> - SongItemPlaceholder( - thumbnailSizeDp = Dimensions.thumbnails.song, + }, + trailingContent = { + IconButton( + icon = R.drawable.reorder, + color = colorPalette.textDisabled, + indication = rippleIndication, + onClick = {}, modifier = Modifier - .alpha(1f - index * 0.125f) - .fillMaxWidth() - .padding(vertical = 4.dp, horizontal = 16.dp) + .reorder( + reorderingState = reorderingState, + index = window.firstPeriodIndex + ) + .size(18.dp) ) + }, + modifier = Modifier + .combinedClickable( + onLongClick = { + menuState.display { + QueuedMediaItemMenu( + mediaItem = window.mediaItem, + indexInQueue = if (isPlayingThisMediaItem) null else window.firstPeriodIndex, + onDismiss = menuState::hide + ) + } + }, + onClick = { + if (isPlayingThisMediaItem) { + if (shouldBePlaying) { + binder.player.pause() + } else { + binder.player.play() + } + } else { + binder.player.playWhenReady = true + binder.player.seekToDefaultPosition(window.firstPeriodIndex) + } + } + ) + .animateItemPlacement(reorderingState = reorderingState) + .draggedItem( + reorderingState = reorderingState, + index = window.firstPeriodIndex + ) + ) + } + + item { + if (binder.isLoadingRadio) { + Column( + modifier = Modifier + .shimmer() + ) { + repeat(3) { index -> + SongItemPlaceholder( + thumbnailSizeDp = Dimensions.thumbnails.song, + modifier = Modifier + .alpha(1f - index * 0.125f) + .fillMaxWidth() + .padding(vertical = 4.dp, horizontal = 16.dp) + ) + } } } } } + + FloatingActionsContainerWithScrollToTop( + lazyListState = reorderingState.lazyListState, + iconId = R.drawable.shuffle, + visible = !reorderingState.isDragging, + windowInsets = windowInsets.only(WindowInsetsSides.Horizontal), + onClick = { + reorderingState.coroutineScope.launch { + reorderingState.lazyListState.smoothScrollToTop() + }.invokeOnCompletion { + binder.player.shuffleQueue() + } + } + ) } + Box( modifier = Modifier .clickable(onClick = layoutState::collapseSoft) @@ -282,22 +299,6 @@ fun Queue( .align(Alignment.Center) .size(18.dp) ) - - IconButton( - icon = R.drawable.shuffle, - color = colorPalette.text, - onClick = { - reorderingState.coroutineScope.launch { - reorderingState.lazyListState.smoothScrollToTop() - }.invokeOnCompletion { - binder.player.shuffleQueue() - } - }, - modifier = Modifier - .padding(horizontal = 4.dp, vertical = 8.dp) - .size(20.dp) - .align(Alignment.CenterEnd) - ) } } }