Tweak shuffle queue button UI
This commit is contained in:
@@ -11,6 +11,7 @@ import androidx.compose.foundation.ScrollState
|
|||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.BoxScope
|
import androidx.compose.foundation.layout.BoxScope
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
import androidx.compose.foundation.layout.WindowInsetsSides
|
import androidx.compose.foundation.layout.WindowInsetsSides
|
||||||
import androidx.compose.foundation.layout.asPaddingValues
|
import androidx.compose.foundation.layout.asPaddingValues
|
||||||
import androidx.compose.foundation.layout.only
|
import androidx.compose.foundation.layout.only
|
||||||
@@ -38,6 +39,7 @@ fun BoxScope.FloatingActionsContainerWithScrollToTop(
|
|||||||
visible: Boolean = true,
|
visible: Boolean = true,
|
||||||
iconId: Int? = null,
|
iconId: Int? = null,
|
||||||
onClick: (() -> Unit)? = null,
|
onClick: (() -> Unit)? = null,
|
||||||
|
windowInsets: WindowInsets = LocalPlayerAwareWindowInsets.current
|
||||||
) {
|
) {
|
||||||
val transitionState = remember {
|
val transitionState = remember {
|
||||||
MutableTransitionState<ScrollingInfo?>(ScrollingInfo())
|
MutableTransitionState<ScrollingInfo?>(ScrollingInfo())
|
||||||
@@ -48,6 +50,7 @@ fun BoxScope.FloatingActionsContainerWithScrollToTop(
|
|||||||
onScrollToTop = lazyGridState::smoothScrollToTop,
|
onScrollToTop = lazyGridState::smoothScrollToTop,
|
||||||
iconId = iconId,
|
iconId = iconId,
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
|
windowInsets = windowInsets,
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -60,6 +63,7 @@ fun BoxScope.FloatingActionsContainerWithScrollToTop(
|
|||||||
visible: Boolean = true,
|
visible: Boolean = true,
|
||||||
iconId: Int? = null,
|
iconId: Int? = null,
|
||||||
onClick: (() -> Unit)? = null,
|
onClick: (() -> Unit)? = null,
|
||||||
|
windowInsets: WindowInsets = LocalPlayerAwareWindowInsets.current
|
||||||
) {
|
) {
|
||||||
val transitionState = remember {
|
val transitionState = remember {
|
||||||
MutableTransitionState<ScrollingInfo?>(ScrollingInfo())
|
MutableTransitionState<ScrollingInfo?>(ScrollingInfo())
|
||||||
@@ -70,6 +74,7 @@ fun BoxScope.FloatingActionsContainerWithScrollToTop(
|
|||||||
onScrollToTop = lazyListState::smoothScrollToTop,
|
onScrollToTop = lazyListState::smoothScrollToTop,
|
||||||
iconId = iconId,
|
iconId = iconId,
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
|
windowInsets = windowInsets,
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -82,6 +87,7 @@ fun BoxScope.FloatingActionsContainerWithScrollToTop(
|
|||||||
visible: Boolean = true,
|
visible: Boolean = true,
|
||||||
iconId: Int? = null,
|
iconId: Int? = null,
|
||||||
onClick: (() -> Unit)? = null,
|
onClick: (() -> Unit)? = null,
|
||||||
|
windowInsets: WindowInsets = LocalPlayerAwareWindowInsets.current
|
||||||
) {
|
) {
|
||||||
val transitionState = remember {
|
val transitionState = remember {
|
||||||
MutableTransitionState<ScrollingInfo?>(ScrollingInfo())
|
MutableTransitionState<ScrollingInfo?>(ScrollingInfo())
|
||||||
@@ -91,6 +97,7 @@ fun BoxScope.FloatingActionsContainerWithScrollToTop(
|
|||||||
transitionState = transitionState,
|
transitionState = transitionState,
|
||||||
iconId = iconId,
|
iconId = iconId,
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
|
windowInsets = windowInsets,
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -99,13 +106,13 @@ fun BoxScope.FloatingActionsContainerWithScrollToTop(
|
|||||||
@Composable
|
@Composable
|
||||||
fun BoxScope.FloatingActions(
|
fun BoxScope.FloatingActions(
|
||||||
transitionState: MutableTransitionState<ScrollingInfo?>,
|
transitionState: MutableTransitionState<ScrollingInfo?>,
|
||||||
|
windowInsets: WindowInsets,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
onScrollToTop: (suspend () -> Unit)? = null,
|
onScrollToTop: (suspend () -> Unit)? = null,
|
||||||
iconId: Int? = null,
|
iconId: Int? = null,
|
||||||
onClick: (() -> Unit)? = null,
|
onClick: (() -> Unit)? = null
|
||||||
) {
|
) {
|
||||||
val transition = updateTransition(transitionState, "")
|
val transition = updateTransition(transitionState, "")
|
||||||
val windowInsets = LocalPlayerAwareWindowInsets.current
|
|
||||||
|
|
||||||
val bottomPaddingValues = windowInsets.only(WindowInsetsSides.Bottom).asPaddingValues()
|
val bottomPaddingValues = windowInsets.only(WindowInsetsSides.Bottom).asPaddingValues()
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ import it.vfsfitvnm.vimusic.ui.components.BottomSheet
|
|||||||
import it.vfsfitvnm.vimusic.ui.components.BottomSheetState
|
import it.vfsfitvnm.vimusic.ui.components.BottomSheetState
|
||||||
import it.vfsfitvnm.vimusic.ui.components.LocalMenuState
|
import it.vfsfitvnm.vimusic.ui.components.LocalMenuState
|
||||||
import it.vfsfitvnm.vimusic.ui.components.MusicBars
|
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.IconButton
|
||||||
import it.vfsfitvnm.vimusic.ui.components.themed.QueuedMediaItemMenu
|
import it.vfsfitvnm.vimusic.ui.components.themed.QueuedMediaItemMenu
|
||||||
import it.vfsfitvnm.vimusic.ui.items.SongItem
|
import it.vfsfitvnm.vimusic.ui.items.SongItem
|
||||||
@@ -125,134 +126,150 @@ fun Queue(
|
|||||||
extraItemCount = 0
|
extraItemCount = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
val rippleIndication = rememberRipple(bounded = false)
|
val rippleIndication = rememberRipple(bounded = false)
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
ReorderingLazyColumn(
|
Box(
|
||||||
reorderingState = reorderingState,
|
|
||||||
contentPadding = windowInsets
|
|
||||||
.only(WindowInsetsSides.Horizontal + WindowInsetsSides.Top).asPaddingValues(),
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(colorPalette.background0)
|
|
||||||
.fillMaxSize()
|
|
||||||
.nestedScroll(remember {
|
|
||||||
layoutState.nestedScrollConnection(reorderingState.lazyListState.firstVisibleItemIndex == 0 && reorderingState.lazyListState.firstVisibleItemScrollOffset == 0)
|
|
||||||
})
|
|
||||||
.background(colorPalette.background1)
|
.background(colorPalette.background1)
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
) {
|
) {
|
||||||
items(
|
ReorderingLazyColumn(
|
||||||
items = windows,
|
reorderingState = reorderingState,
|
||||||
key = { it.uid.hashCode() }
|
contentPadding = windowInsets
|
||||||
) { window ->
|
.only(WindowInsetsSides.Horizontal + WindowInsetsSides.Top).asPaddingValues(),
|
||||||
val isPlayingThisMediaItem = mediaItemIndex == window.firstPeriodIndex
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
modifier = Modifier
|
||||||
|
.nestedScroll(remember {
|
||||||
|
layoutState.nestedScrollConnection(reorderingState.lazyListState.firstVisibleItemIndex == 0 && reorderingState.lazyListState.firstVisibleItemScrollOffset == 0)
|
||||||
|
})
|
||||||
|
|
||||||
SongItem(
|
) {
|
||||||
song = window.mediaItem,
|
items(
|
||||||
thumbnailSizePx = thumbnailSizePx,
|
items = windows,
|
||||||
thumbnailSizeDp = thumbnailSizeDp,
|
key = { it.uid.hashCode() }
|
||||||
onThumbnailContent = {
|
) { window ->
|
||||||
androidx.compose.animation.AnimatedVisibility(
|
val isPlayingThisMediaItem = mediaItemIndex == window.firstPeriodIndex
|
||||||
visible = isPlayingThisMediaItem,
|
|
||||||
enter = fadeIn(),
|
SongItem(
|
||||||
exit = fadeOut(),
|
song = window.mediaItem,
|
||||||
) {
|
thumbnailSizePx = thumbnailSizePx,
|
||||||
Box(
|
thumbnailSizeDp = thumbnailSizeDp,
|
||||||
contentAlignment = Alignment.Center,
|
onThumbnailContent = {
|
||||||
modifier = Modifier
|
androidx.compose.animation.AnimatedVisibility(
|
||||||
.background(
|
visible = isPlayingThisMediaItem,
|
||||||
color = Color.Black.copy(alpha = 0.25f),
|
enter = fadeIn(),
|
||||||
shape = thumbnailShape
|
exit = fadeOut(),
|
||||||
)
|
|
||||||
.size(Dimensions.thumbnails.song)
|
|
||||||
) {
|
) {
|
||||||
if (shouldBePlaying) {
|
Box(
|
||||||
MusicBars(
|
contentAlignment = Alignment.Center,
|
||||||
color = colorPalette.onOverlay,
|
modifier = Modifier
|
||||||
modifier = Modifier
|
.background(
|
||||||
.height(24.dp)
|
color = Color.Black.copy(alpha = 0.25f),
|
||||||
)
|
shape = thumbnailShape
|
||||||
} else {
|
)
|
||||||
Image(
|
.size(Dimensions.thumbnails.song)
|
||||||
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) {
|
|
||||||
if (shouldBePlaying) {
|
if (shouldBePlaying) {
|
||||||
binder.player.pause()
|
MusicBars(
|
||||||
|
color = colorPalette.onOverlay,
|
||||||
|
modifier = Modifier
|
||||||
|
.height(24.dp)
|
||||||
|
)
|
||||||
} else {
|
} 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)
|
trailingContent = {
|
||||||
.draggedItem(
|
IconButton(
|
||||||
reorderingState = reorderingState,
|
icon = R.drawable.reorder,
|
||||||
index = window.firstPeriodIndex
|
color = colorPalette.textDisabled,
|
||||||
)
|
indication = rippleIndication,
|
||||||
)
|
onClick = {},
|
||||||
}
|
|
||||||
|
|
||||||
item {
|
|
||||||
if (binder.isLoadingRadio) {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.shimmer()
|
|
||||||
) {
|
|
||||||
repeat(3) { index ->
|
|
||||||
SongItemPlaceholder(
|
|
||||||
thumbnailSizeDp = Dimensions.thumbnails.song,
|
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.alpha(1f - index * 0.125f)
|
.reorder(
|
||||||
.fillMaxWidth()
|
reorderingState = reorderingState,
|
||||||
.padding(vertical = 4.dp, horizontal = 16.dp)
|
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(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.clickable(onClick = layoutState::collapseSoft)
|
.clickable(onClick = layoutState::collapseSoft)
|
||||||
@@ -282,22 +299,6 @@ fun Queue(
|
|||||||
.align(Alignment.Center)
|
.align(Alignment.Center)
|
||||||
.size(18.dp)
|
.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)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user