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 f76ae84..0aeb440 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 @@ -22,8 +22,8 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import it.vfsfitvnm.vimusic.LocalPlayerAwarePaddingValues import it.vfsfitvnm.vimusic.R -import it.vfsfitvnm.vimusic.utils.isScrollingDown -import it.vfsfitvnm.vimusic.utils.isScrollingDownToIsFar +import it.vfsfitvnm.vimusic.utils.ScrollingInfo +import it.vfsfitvnm.vimusic.utils.scrollingInfo import it.vfsfitvnm.vimusic.utils.smoothScrollToTop import kotlinx.coroutines.launch @@ -32,12 +32,13 @@ import kotlinx.coroutines.launch fun BoxScope.FloatingActionsContainerWithScrollToTop( lazyGridState: LazyGridState, modifier: Modifier = Modifier, + visible: Boolean = true, iconId: Int? = null, onClick: (() -> Unit)? = null, ) { val transitionState = remember { - MutableTransitionState(false to false) - }.apply { targetState = lazyGridState.isScrollingDownToIsFar() } + MutableTransitionState(ScrollingInfo()) + }.apply { targetState = if (visible) lazyGridState.scrollingInfo() else null } FloatingActions( transitionState = transitionState, @@ -53,12 +54,13 @@ fun BoxScope.FloatingActionsContainerWithScrollToTop( fun BoxScope.FloatingActionsContainerWithScrollToTop( lazyListState: LazyListState, modifier: Modifier = Modifier, + visible: Boolean = true, iconId: Int? = null, onClick: (() -> Unit)? = null, ) { val transitionState = remember { - MutableTransitionState(false to false) - }.apply { targetState = lazyListState.isScrollingDownToIsFar() } + MutableTransitionState(ScrollingInfo()) + }.apply { targetState = if (visible) lazyListState.scrollingInfo() else null } FloatingActions( transitionState = transitionState, @@ -74,12 +76,13 @@ fun BoxScope.FloatingActionsContainerWithScrollToTop( fun BoxScope.FloatingActionsContainerWithScrollToTop( scrollState: ScrollState, modifier: Modifier = Modifier, + visible: Boolean = true, iconId: Int? = null, onClick: (() -> Unit)? = null, ) { val transitionState = remember { - MutableTransitionState(false to false) - }.apply { targetState = scrollState.isScrollingDown() to false } + MutableTransitionState(ScrollingInfo()) + }.apply { targetState = if (visible) scrollState.scrollingInfo() else null } FloatingActions( transitionState = transitionState, @@ -92,13 +95,13 @@ fun BoxScope.FloatingActionsContainerWithScrollToTop( @ExperimentalAnimationApi @Composable fun BoxScope.FloatingActions( - transitionState: MutableTransitionState>, + transitionState: MutableTransitionState, modifier: Modifier = Modifier, onScrollToTop: (suspend () -> Unit)? = null, iconId: Int? = null, onClick: (() -> Unit)? = null, ) { - val transition = updateTransition(transitionState, "FloatingActionsContainer") + val transition = updateTransition(transitionState, "") Row( horizontalArrangement = Arrangement.spacedBy(16.dp), @@ -110,7 +113,7 @@ fun BoxScope.FloatingActions( ) { onScrollToTop?.let { transition.AnimatedVisibility( - visible = { it.first && it.second }, + visible = { it?.isScrollingDown == false && it.isFar }, enter = slideInVertically(tween(500, if (iconId == null) 0 else 100)) { it }, exit = slideOutVertically(tween(500, 0)) { it }, ) { @@ -122,6 +125,7 @@ fun BoxScope.FloatingActions( onScrollToTop() } }, + enabled = transition.targetState?.isScrollingDown == false && transition.targetState?.isFar == true, iconId = R.drawable.chevron_up, modifier = Modifier .padding(bottom = 16.dp) @@ -132,13 +136,14 @@ fun BoxScope.FloatingActions( iconId?.let { onClick?.let { transition.AnimatedVisibility( - visible = { it.first }, + visible = { it?.isScrollingDown == false }, enter = slideInVertically(tween(500, 0)) { it }, exit = slideOutVertically(tween(500, 100)) { it }, ) { PrimaryButton( iconId = iconId, onClick = onClick, + enabled = transition.targetState?.isScrollingDown == false, modifier = Modifier .padding(bottom = 16.dp) ) diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/PrimaryButton.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/PrimaryButton.kt index 6a832cf..294b520 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/PrimaryButton.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/PrimaryButton.kt @@ -21,14 +21,14 @@ fun PrimaryButton( onClick: () -> Unit, @DrawableRes iconId: Int, modifier: Modifier = Modifier, - isEnabled: Boolean = true, + enabled: Boolean = true, ) { val (colorPalette) = LocalAppearance.current Box( modifier = modifier .clip(RoundedCornerShape(16.dp)) - .clickable(enabled = isEnabled, onClick = onClick) + .clickable(enabled = enabled, onClick = onClick) .background(colorPalette.background2) .size(62.dp) ) { diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/SecondaryButton.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/SecondaryButton.kt index 9ceffc6..894b7e7 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/SecondaryButton.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/themed/SecondaryButton.kt @@ -21,14 +21,14 @@ fun SecondaryButton( onClick: () -> Unit, @DrawableRes iconId: Int, modifier: Modifier = Modifier, - isEnabled: Boolean = true, + enabled: Boolean = true, ) { val (colorPalette) = LocalAppearance.current Box( modifier = modifier .clip(CircleShape) - .clickable(enabled = isEnabled, onClick = onClick) + .clickable(enabled = enabled, onClick = onClick) .background(colorPalette.background2) .size(48.dp) ) { diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/localplaylist/LocalPlaylistSongs.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/localplaylist/LocalPlaylistSongs.kt index cc623e9..cb69255 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/localplaylist/LocalPlaylistSongs.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/localplaylist/LocalPlaylistSongs.kt @@ -277,6 +277,7 @@ fun LocalPlaylistSongs( FloatingActionsContainerWithScrollToTop( lazyListState = lazyListState, iconId = R.drawable.shuffle, + visible = !reorderingState.isDragging, onClick = { playlistWithSongs?.songs?.let { songs -> if (songs.isNotEmpty()) { diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/LazyGridState.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/LazyGridState.kt deleted file mode 100644 index 59fa682..0000000 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/LazyGridState.kt +++ /dev/null @@ -1,40 +0,0 @@ -package it.vfsfitvnm.vimusic.utils - -import androidx.compose.foundation.lazy.grid.LazyGridState -import androidx.compose.runtime.Composable -import androidx.compose.runtime.derivedStateOf -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue - -suspend fun LazyGridState.smoothScrollToTop() { - if (firstVisibleItemIndex > layoutInfo.visibleItemsInfo.size) { - scrollToItem(layoutInfo.visibleItemsInfo.size) - } - animateScrollToItem(0) -} - -@Composable -fun LazyGridState.isScrollingDownToIsFar(): Pair { - var previousIndex by remember(this) { - mutableStateOf(firstVisibleItemIndex) - } - - var previousScrollOffset by remember(this) { - mutableStateOf(firstVisibleItemScrollOffset) - } - - return remember(this) { - derivedStateOf { - if (previousIndex != firstVisibleItemIndex) { - previousIndex > firstVisibleItemIndex - } else { - previousScrollOffset >= firstVisibleItemScrollOffset - }.also { - previousIndex = firstVisibleItemIndex - previousScrollOffset = firstVisibleItemScrollOffset - } to (firstVisibleItemIndex > layoutInfo.visibleItemsInfo.size) - } - }.value -} diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/LazyListState.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/LazyListState.kt deleted file mode 100644 index 9163459..0000000 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/LazyListState.kt +++ /dev/null @@ -1,40 +0,0 @@ -package it.vfsfitvnm.vimusic.utils - -import androidx.compose.foundation.lazy.LazyListState -import androidx.compose.runtime.Composable -import androidx.compose.runtime.derivedStateOf -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue - -suspend fun LazyListState.smoothScrollToTop() { - if (firstVisibleItemIndex > layoutInfo.visibleItemsInfo.size) { - scrollToItem(layoutInfo.visibleItemsInfo.size) - } - animateScrollToItem(0) -} - -@Composable -fun LazyListState.isScrollingDownToIsFar(): Pair { - var previousIndex by remember(this) { - mutableStateOf(firstVisibleItemIndex) - } - - var previousScrollOffset by remember(this) { - mutableStateOf(firstVisibleItemScrollOffset) - } - - return remember(this) { - derivedStateOf { - if (previousIndex != firstVisibleItemIndex) { - previousIndex > firstVisibleItemIndex - } else { - previousScrollOffset >= firstVisibleItemScrollOffset - }.also { - previousIndex = firstVisibleItemIndex - previousScrollOffset = firstVisibleItemScrollOffset - } to (firstVisibleItemIndex > layoutInfo.visibleItemsInfo.size) - } - }.value -} diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/ScrollState.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/ScrollState.kt deleted file mode 100644 index cd3bdeb..0000000 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/ScrollState.kt +++ /dev/null @@ -1,24 +0,0 @@ -package it.vfsfitvnm.vimusic.utils - -import androidx.compose.foundation.ScrollState -import androidx.compose.runtime.Composable -import androidx.compose.runtime.derivedStateOf -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue - -@Composable -fun ScrollState.isScrollingDown(): Boolean { - var previousValue by remember(this) { - mutableStateOf(value) - } - - return remember(this) { - derivedStateOf { - (previousValue >= value).also { - previousValue = value - } - } - }.value -} diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/ScrollingInfo.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/ScrollingInfo.kt new file mode 100644 index 0000000..6d0f521 --- /dev/null +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/ScrollingInfo.kt @@ -0,0 +1,93 @@ +package it.vfsfitvnm.vimusic.utils + +import androidx.compose.foundation.ScrollState +import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.foundation.lazy.grid.LazyGridState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue + +data class ScrollingInfo( + val isScrollingDown: Boolean = false, + val isFar: Boolean = false +) { + fun and(condition: Boolean) = +// copy(isScrollingDown = isScrollingDown && condition, isFar = isFar && condition) + if (condition) this else copy(isScrollingDown = !isScrollingDown, isFar = !isFar) +} + +@Composable +fun LazyListState.scrollingInfo(): ScrollingInfo { + var previousIndex by remember(this) { + mutableStateOf(firstVisibleItemIndex) + } + + var previousScrollOffset by remember(this) { + mutableStateOf(firstVisibleItemScrollOffset) + } + + return remember(this) { + derivedStateOf { + val isScrollingDown = if (previousIndex == firstVisibleItemIndex) { + firstVisibleItemScrollOffset > previousScrollOffset + } else { + firstVisibleItemIndex > previousIndex + } + + val isFar = firstVisibleItemIndex > layoutInfo.visibleItemsInfo.size + + previousIndex = firstVisibleItemIndex + previousScrollOffset = firstVisibleItemScrollOffset + + ScrollingInfo(isScrollingDown, isFar) + } + }.value +} + +@Composable +fun LazyGridState.scrollingInfo(): ScrollingInfo { + var previousIndex by remember(this) { + mutableStateOf(firstVisibleItemIndex) + } + + var previousScrollOffset by remember(this) { + mutableStateOf(firstVisibleItemScrollOffset) + } + + return remember(this) { + derivedStateOf { + val isScrollingDown = if (previousIndex == firstVisibleItemIndex) { + firstVisibleItemScrollOffset > previousScrollOffset + } else { + firstVisibleItemIndex > previousIndex + } + + val isFar = firstVisibleItemIndex > layoutInfo.visibleItemsInfo.size + + previousIndex = firstVisibleItemIndex + previousScrollOffset = firstVisibleItemScrollOffset + + ScrollingInfo(isScrollingDown, isFar) + } + }.value +} + +@Composable +fun ScrollState.scrollingInfo(): ScrollingInfo { + var previousValue by remember(this) { + mutableStateOf(value) + } + + return remember(this) { + derivedStateOf { + val isScrollingDown = value > previousValue + + previousValue = value + + ScrollingInfo(isScrollingDown, false) + } + }.value +} diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/SmoothScrollToTop.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/SmoothScrollToTop.kt new file mode 100644 index 0000000..02a75ff --- /dev/null +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/SmoothScrollToTop.kt @@ -0,0 +1,24 @@ +package it.vfsfitvnm.vimusic.utils + +import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.foundation.lazy.grid.LazyGridState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue + +suspend fun LazyGridState.smoothScrollToTop() { + if (firstVisibleItemIndex > layoutInfo.visibleItemsInfo.size) { + scrollToItem(layoutInfo.visibleItemsInfo.size) + } + animateScrollToItem(0) +} + +suspend fun LazyListState.smoothScrollToTop() { + if (firstVisibleItemIndex > layoutInfo.visibleItemsInfo.size) { + scrollToItem(layoutInfo.visibleItemsInfo.size) + } + animateScrollToItem(0) +} diff --git a/compose-reordering/src/main/kotlin/it/vfsfitvnm/reordering/ReorderingState.kt b/compose-reordering/src/main/kotlin/it/vfsfitvnm/reordering/ReorderingState.kt index 67d6208..d2b45f4 100644 --- a/compose-reordering/src/main/kotlin/it/vfsfitvnm/reordering/ReorderingState.kt +++ b/compose-reordering/src/main/kotlin/it/vfsfitvnm/reordering/ReorderingState.kt @@ -52,6 +52,9 @@ class ReorderingState( internal var indexesToAnimate = mutableStateMapOf>() private var animatablesPool: AnimatablesPool? = null + val isDragging: Boolean + get() = draggingIndex != -1 + fun onDragStart(index: Int) { overscrolled = 0 itemInfo = lazyListState.layoutInfo.visibleItemsInfo.find {