mirror of
https://github.com/LiveFastEatTrashRaccoon/RaccoonForLemmy.git
synced 2025-02-09 12:48:42 +01:00
chore: update SwipeableCard sensitivity
This commit is contained in:
parent
d41923b86a
commit
df7b4632b7
@ -2,32 +2,48 @@ package com.github.diegoberaldin.raccoonforlemmy.core.commonui.components
|
||||
|
||||
import androidx.compose.animation.animateColorAsState
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.gestures.Orientation
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.DismissDirection
|
||||
import androidx.compose.material.DismissState
|
||||
import androidx.compose.material.DismissValue
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.FixedThreshold
|
||||
import androidx.compose.material.FractionalThreshold
|
||||
import androidx.compose.material.SwipeToDismiss
|
||||
import androidx.compose.material.ResistanceConfig
|
||||
import androidx.compose.material.SwipeableDefaults
|
||||
import androidx.compose.material.ThresholdConfig
|
||||
import androidx.compose.material.rememberDismissState
|
||||
import androidx.compose.material.swipeable
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.snapshotFlow
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.onGloballyPositioned
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.toSize
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
@ -47,15 +63,18 @@ fun SwipeableCard(
|
||||
) {
|
||||
if (enabled) {
|
||||
var width by remember { mutableStateOf(0f) }
|
||||
val dismissToEndCallback by rememberUpdatedState(onDismissToEnd)
|
||||
val dismissToStartCallback by rememberUpdatedState(onDismissToStart)
|
||||
val gestureBeginCallback by rememberUpdatedState(onGestureBegin)
|
||||
val dismissState = rememberDismissState(
|
||||
confirmStateChange = {
|
||||
when (it) {
|
||||
DismissValue.DismissedToEnd -> {
|
||||
onDismissToEnd?.invoke()
|
||||
dismissToEndCallback?.invoke()
|
||||
}
|
||||
|
||||
DismissValue.DismissedToStart -> {
|
||||
onDismissToStart?.invoke()
|
||||
dismissToStartCallback?.invoke()
|
||||
}
|
||||
|
||||
else -> Unit
|
||||
@ -66,19 +85,20 @@ fun SwipeableCard(
|
||||
|
||||
val threshold = 0.15f
|
||||
LaunchedEffect(dismissState) {
|
||||
snapshotFlow { dismissState.offset.value }.map {
|
||||
snapshotFlow { dismissState.offset.value }.map { offset ->
|
||||
when {
|
||||
it > width * threshold -> DismissDirection.StartToEnd
|
||||
it < -width * threshold -> DismissDirection.EndToStart
|
||||
offset > width * threshold -> DismissDirection.StartToEnd
|
||||
offset < -width * threshold -> DismissDirection.EndToStart
|
||||
else -> null
|
||||
}
|
||||
}.stateIn(this).onEach { willDismissDirection ->
|
||||
if (willDismissDirection != null) {
|
||||
onGestureBegin?.invoke()
|
||||
gestureBeginCallback?.invoke()
|
||||
}
|
||||
}.launchIn(this)
|
||||
}
|
||||
SwipeToDismiss(
|
||||
|
||||
SwipeToDismiss2(
|
||||
modifier = modifier.onGloballyPositioned {
|
||||
width = it.size.toSize().width
|
||||
},
|
||||
@ -89,7 +109,7 @@ fun SwipeableCard(
|
||||
},
|
||||
background = {
|
||||
val direction =
|
||||
dismissState.dismissDirection ?: return@SwipeToDismiss
|
||||
dismissState.dismissDirection ?: DismissDirection.StartToEnd
|
||||
val bgColor by animateColorAsState(
|
||||
backgroundColor(dismissState.targetValue),
|
||||
)
|
||||
@ -114,3 +134,80 @@ fun SwipeableCard(
|
||||
content()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Copied from androidx.material.SwipeToDismiss with different ResistanceConfig and velocity threshold.
|
||||
*/
|
||||
@Composable
|
||||
@ExperimentalMaterialApi
|
||||
private fun SwipeToDismiss2(
|
||||
state: DismissState,
|
||||
modifier: Modifier = Modifier,
|
||||
directions: Set<DismissDirection> = setOf(
|
||||
DismissDirection.EndToStart,
|
||||
DismissDirection.StartToEnd
|
||||
),
|
||||
dismissThresholds: (DismissDirection) -> ThresholdConfig = {
|
||||
FixedThreshold(DISMISS_THRESHOLD)
|
||||
},
|
||||
background: @Composable RowScope.() -> Unit,
|
||||
dismissContent: @Composable RowScope.() -> Unit,
|
||||
) = BoxWithConstraints(modifier) {
|
||||
val width = constraints.maxWidth.toFloat()
|
||||
val isRtl = LocalLayoutDirection.current == LayoutDirection.Rtl
|
||||
|
||||
val anchors = mutableMapOf(0f to DismissValue.Default)
|
||||
if (DismissDirection.StartToEnd in directions) anchors += width to DismissValue.DismissedToEnd
|
||||
if (DismissDirection.EndToStart in directions) anchors += -width to DismissValue.DismissedToStart
|
||||
|
||||
val thresholds = { from: DismissValue, to: DismissValue ->
|
||||
dismissThresholds(getDismissDirection(from, to)!!)
|
||||
}
|
||||
Box(
|
||||
Modifier.swipeable(
|
||||
state = state,
|
||||
anchors = anchors,
|
||||
thresholds = thresholds,
|
||||
orientation = Orientation.Horizontal,
|
||||
enabled = state.currentValue == DismissValue.Default,
|
||||
reverseDirection = isRtl,
|
||||
resistance = ResistanceConfig(
|
||||
basis = width,
|
||||
factorAtMin = SwipeableDefaults.StiffResistanceFactor,
|
||||
factorAtMax = SwipeableDefaults.StiffResistanceFactor
|
||||
),
|
||||
velocityThreshold = Dp.Infinity
|
||||
)
|
||||
) {
|
||||
Row(
|
||||
content = background,
|
||||
modifier = Modifier.matchParentSize()
|
||||
)
|
||||
Row(
|
||||
content = dismissContent,
|
||||
modifier = Modifier.offset { IntOffset(state.offset.value.roundToInt(), 0) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getDismissDirection(from: DismissValue, to: DismissValue): DismissDirection? {
|
||||
return when {
|
||||
// settled at the default state
|
||||
from == to && from == DismissValue.Default -> null
|
||||
// has been dismissed to the end
|
||||
from == to && from == DismissValue.DismissedToEnd -> DismissDirection.StartToEnd
|
||||
// has been dismissed to the start
|
||||
from == to && from == DismissValue.DismissedToStart -> DismissDirection.EndToStart
|
||||
// is currently being dismissed to the end
|
||||
from == DismissValue.Default && to == DismissValue.DismissedToEnd -> DismissDirection.StartToEnd
|
||||
// is currently being dismissed to the start
|
||||
from == DismissValue.Default && to == DismissValue.DismissedToStart -> DismissDirection.EndToStart
|
||||
// has been dismissed to the end but is now animated back to default
|
||||
from == DismissValue.DismissedToEnd && to == DismissValue.Default -> DismissDirection.StartToEnd
|
||||
// has been dismissed to the start but is now animated back to default
|
||||
from == DismissValue.DismissedToStart && to == DismissValue.Default -> DismissDirection.EndToStart
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private val DISMISS_THRESHOLD = 56.dp
|
||||
|
Loading…
x
Reference in New Issue
Block a user