Fix buggy BottomSheet nested scroll connection
Thanks, Albert Chang!
This commit is contained in:
parent
23dcce88ab
commit
ae6babb452
5 changed files with 58 additions and 78 deletions
|
@ -38,7 +38,6 @@ import androidx.compose.ui.unit.Dp
|
|||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.Velocity
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
|
@ -72,36 +71,7 @@ fun BottomSheet(
|
|||
onDragEnd = {
|
||||
val velocity = -velocityTracker.calculateVelocity().y
|
||||
velocityTracker.resetTracking()
|
||||
|
||||
if (velocity > 250) {
|
||||
state.expand()
|
||||
} else if (velocity < -250) {
|
||||
if (state.value < state.collapsedBound && onDismiss != null) {
|
||||
state.dismiss()
|
||||
onDismiss.invoke()
|
||||
} else {
|
||||
state.collapse()
|
||||
}
|
||||
} else {
|
||||
val l0 = state.dismissedBound
|
||||
val l1 = (state.collapsedBound - state.dismissedBound) / 2
|
||||
val l2 = (state.expandedBound - state.collapsedBound) / 2
|
||||
val l3 = state.expandedBound
|
||||
|
||||
when (state.value) {
|
||||
in l0..l1 -> {
|
||||
if (onDismiss != null) {
|
||||
state.dismiss()
|
||||
onDismiss.invoke()
|
||||
} else {
|
||||
state.collapse()
|
||||
}
|
||||
}
|
||||
in l1..l2 -> state.collapse()
|
||||
in l2..l3 -> state.expand()
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
state.performFling(velocity, onDismiss)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -173,11 +143,11 @@ class BottomSheetState(
|
|||
}
|
||||
}
|
||||
|
||||
fun collapse() {
|
||||
private fun collapse() {
|
||||
collapse(SpringSpec())
|
||||
}
|
||||
|
||||
fun expand() {
|
||||
private fun expand() {
|
||||
expand(SpringSpec())
|
||||
}
|
||||
|
||||
|
@ -202,21 +172,53 @@ class BottomSheetState(
|
|||
}
|
||||
}
|
||||
|
||||
fun nestedScrollConnection(initialIsTopReached: Boolean = true): NestedScrollConnection {
|
||||
return object : NestedScrollConnection {
|
||||
var isTopReached = initialIsTopReached
|
||||
fun performFling(velocity: Float, onDismiss: (() -> Unit)?) {
|
||||
if (velocity > 250) {
|
||||
expand()
|
||||
} else if (velocity < -250) {
|
||||
if (value < collapsedBound && onDismiss != null) {
|
||||
dismiss()
|
||||
onDismiss.invoke()
|
||||
} else {
|
||||
collapse()
|
||||
}
|
||||
} else {
|
||||
val l0 = dismissedBound
|
||||
val l1 = (collapsedBound - dismissedBound) / 2
|
||||
val l2 = (expandedBound - collapsedBound) / 2
|
||||
val l3 = expandedBound
|
||||
|
||||
when (value) {
|
||||
in l0..l1 -> {
|
||||
if (onDismiss != null) {
|
||||
dismiss()
|
||||
onDismiss.invoke()
|
||||
} else {
|
||||
collapse()
|
||||
}
|
||||
}
|
||||
in l1..l2 -> collapse()
|
||||
in l2..l3 -> expand()
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val preUpPostDownNestedScrollConnection
|
||||
get() = object : NestedScrollConnection {
|
||||
var isTopReached = false
|
||||
|
||||
override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
|
||||
if (isExpanded && available.y < 0) {
|
||||
isTopReached = false
|
||||
}
|
||||
|
||||
if (isTopReached) {
|
||||
return if (isTopReached && available.y < 0 && source == NestedScrollSource.Drag) {
|
||||
dispatchRawDelta(available.y)
|
||||
return available
|
||||
available
|
||||
} else {
|
||||
Offset.Zero
|
||||
}
|
||||
|
||||
return Offset.Zero
|
||||
}
|
||||
|
||||
override fun onPostScroll(
|
||||
|
@ -228,44 +230,30 @@ class BottomSheetState(
|
|||
isTopReached = consumed.y == 0f && available.y > 0
|
||||
}
|
||||
|
||||
return Offset.Zero
|
||||
return if (isTopReached && source == NestedScrollSource.Drag) {
|
||||
dispatchRawDelta(available.y)
|
||||
available
|
||||
} else {
|
||||
Offset.Zero
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun onPreFling(available: Velocity): Velocity {
|
||||
if (isTopReached) {
|
||||
return if (isTopReached) {
|
||||
val velocity = -available.y
|
||||
coroutineScope {
|
||||
if (velocity > 250) {
|
||||
expand()
|
||||
} else if (velocity < -250) {
|
||||
collapse()
|
||||
} else {
|
||||
val l0 = dismissedBound
|
||||
val l1 = (collapsedBound - dismissedBound) / 2
|
||||
val l2 = (expandedBound - collapsedBound) / 2
|
||||
val l3 = expandedBound
|
||||
performFling(velocity, null)
|
||||
|
||||
when (value) {
|
||||
in l0..l1 -> collapse()
|
||||
in l1..l2 -> collapse()
|
||||
in l2..l3 -> expand()
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return available
|
||||
available
|
||||
} else {
|
||||
Velocity.Zero
|
||||
}
|
||||
|
||||
return Velocity.Zero
|
||||
}
|
||||
|
||||
override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity {
|
||||
isTopReached = false
|
||||
return super.onPostFling(consumed, available)
|
||||
return Velocity.Zero
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const val expandedAnchor = 2
|
||||
|
|
|
@ -37,8 +37,6 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
|
@ -53,9 +51,9 @@ import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder
|
|||
import it.vfsfitvnm.vimusic.R
|
||||
import it.vfsfitvnm.vimusic.query
|
||||
import it.vfsfitvnm.vimusic.ui.components.LocalMenuState
|
||||
import it.vfsfitvnm.vimusic.ui.components.ShimmerHost
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.Menu
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.MenuEntry
|
||||
import it.vfsfitvnm.vimusic.ui.components.ShimmerHost
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.TextFieldDialog
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.TextPlaceholder
|
||||
import it.vfsfitvnm.vimusic.ui.styling.DefaultDarkColorPalette
|
||||
|
@ -89,7 +87,6 @@ fun Lyrics(
|
|||
mediaMetadataProvider: () -> MediaMetadata,
|
||||
durationProvider: () -> Long,
|
||||
onLyricsUpdate: (Boolean, String, String) -> Unit,
|
||||
nestedScrollConnectionProvider: () -> NestedScrollConnection,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
AnimatedVisibility(
|
||||
|
@ -274,7 +271,6 @@ fun Lyrics(
|
|||
text = lyrics,
|
||||
style = typography.xs.center.medium.color(PureBlackColorPalette.text),
|
||||
modifier = Modifier
|
||||
.nestedScroll(remember { nestedScrollConnectionProvider() })
|
||||
.verticalFadingEdge()
|
||||
.verticalScroll(rememberScrollState())
|
||||
.fillMaxWidth()
|
||||
|
|
|
@ -36,6 +36,7 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.drawBehind
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
|
@ -239,8 +240,8 @@ fun Player(
|
|||
onShowLyrics = { isShowingLyrics = it },
|
||||
isShowingStatsForNerds = isShowingStatsForNerds,
|
||||
onShowStatsForNerds = { isShowingStatsForNerds = it },
|
||||
nestedScrollConnectionProvider = layoutState::nestedScrollConnection,
|
||||
modifier = modifier
|
||||
.nestedScroll(layoutState.preUpPostDownNestedScrollConnection)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -140,9 +140,7 @@ fun Queue(
|
|||
.only(WindowInsetsSides.Horizontal + WindowInsetsSides.Top).asPaddingValues(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier
|
||||
.nestedScroll(remember {
|
||||
layoutState.nestedScrollConnection(reorderingState.lazyListState.firstVisibleItemIndex == 0 && reorderingState.lazyListState.firstVisibleItemScrollOffset == 0)
|
||||
})
|
||||
.nestedScroll(layoutState.preUpPostDownNestedScrollConnection)
|
||||
|
||||
) {
|
||||
items(
|
||||
|
|
|
@ -21,7 +21,6 @@ import androidx.compose.runtime.remember
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
@ -48,7 +47,6 @@ fun Thumbnail(
|
|||
onShowLyrics: (Boolean) -> Unit,
|
||||
isShowingStatsForNerds: Boolean,
|
||||
onShowStatsForNerds: (Boolean) -> Unit,
|
||||
nestedScrollConnectionProvider: () -> NestedScrollConnection,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val binder = LocalPlayerServiceBinder.current
|
||||
|
@ -145,7 +143,6 @@ fun Thumbnail(
|
|||
size = thumbnailSizeDp,
|
||||
mediaMetadataProvider = mediaItem::mediaMetadata,
|
||||
durationProvider = player::getDuration,
|
||||
nestedScrollConnectionProvider = nestedScrollConnectionProvider,
|
||||
)
|
||||
|
||||
StatsForNerds(
|
||||
|
|
Loading…
Reference in a new issue