fix: refine swipe-back thresholds for improved navigation responsiveness
This commit is contained in:
@@ -23,12 +23,15 @@ import kotlinx.coroutines.launch
|
||||
// Telegram's CubicBezierInterpolator(0.25, 0.1, 0.25, 1.0)
|
||||
private val TelegramEasing = CubicBezierEasing(0.25f, 0.1f, 0.25f, 1.0f)
|
||||
|
||||
// Swipe-back thresholds (Telegram-like)
|
||||
private const val COMPLETION_THRESHOLD = 0.2f // 20% of screen width — very easy to complete
|
||||
private const val FLING_VELOCITY_THRESHOLD = 150f // px/s — very sensitive to flings
|
||||
// Swipe-back thresholds tuned for ultra-light navigation.
|
||||
private const val COMPLETION_THRESHOLD = 0.05f // 5% of screen width
|
||||
private const val FLING_VELOCITY_THRESHOLD = 35f // px/s
|
||||
private const val ANIMATION_DURATION_ENTER = 300
|
||||
private const val ANIMATION_DURATION_EXIT = 200
|
||||
private const val EDGE_ZONE_DP = 200
|
||||
private const val EDGE_ZONE_DP = 320
|
||||
private const val EDGE_ZONE_WIDTH_FRACTION = 0.85f
|
||||
private const val TOUCH_SLOP_FACTOR = 0.35f
|
||||
private const val HORIZONTAL_DOMINANCE_RATIO = 1.05f
|
||||
|
||||
/**
|
||||
* Telegram-style swipe back container (optimized)
|
||||
@@ -40,7 +43,7 @@ private const val EDGE_ZONE_DP = 200
|
||||
* - Smooth Telegram-style bezier animation
|
||||
* - Scrim (dimming) on background
|
||||
* - Shadow on left edge during swipe
|
||||
* - Threshold: 50% of width OR 600px/s fling velocity
|
||||
* - Low completion threshold for comfortable one-handed back swipe
|
||||
*/
|
||||
@Composable
|
||||
fun SwipeBackContainer(
|
||||
@@ -60,6 +63,7 @@ fun SwipeBackContainer(
|
||||
val configuration = LocalConfiguration.current
|
||||
val screenWidthPx = with(density) { configuration.screenWidthDp.dp.toPx() }
|
||||
val edgeZonePx = with(density) { EDGE_ZONE_DP.dp.toPx() }
|
||||
val effectiveEdgeZonePx = maxOf(edgeZonePx, screenWidthPx * EDGE_ZONE_WIDTH_FRACTION)
|
||||
|
||||
// Animation state for swipe (used only for swipe animations, not during drag)
|
||||
val offsetAnimatable = remember { Animatable(0f) }
|
||||
@@ -148,7 +152,9 @@ fun SwipeBackContainer(
|
||||
if (swipeEnabled && !isAnimatingIn && !isAnimatingOut) {
|
||||
Modifier.pointerInput(Unit) {
|
||||
val velocityTracker = VelocityTracker()
|
||||
val touchSlop = viewConfiguration.touchSlop
|
||||
val touchSlop =
|
||||
viewConfiguration.touchSlop *
|
||||
TOUCH_SLOP_FACTOR
|
||||
|
||||
awaitEachGesture {
|
||||
val down =
|
||||
@@ -157,7 +163,7 @@ fun SwipeBackContainer(
|
||||
)
|
||||
|
||||
// Edge-only detection
|
||||
if (down.position.x > edgeZonePx) {
|
||||
if (down.position.x > effectiveEdgeZonePx) {
|
||||
return@awaitEachGesture
|
||||
}
|
||||
|
||||
@@ -205,7 +211,8 @@ fun SwipeBackContainer(
|
||||
) >
|
||||
kotlin.math.abs(
|
||||
totalDragY
|
||||
) * 1.5f
|
||||
) *
|
||||
HORIZONTAL_DOMINANCE_RATIO
|
||||
) {
|
||||
passedSlop = true
|
||||
startedSwipe = true
|
||||
@@ -255,15 +262,15 @@ fun SwipeBackContainer(
|
||||
dragOffset / screenWidthPx
|
||||
|
||||
val shouldComplete =
|
||||
currentProgress >
|
||||
0.5f || // Past 50% — always
|
||||
// complete
|
||||
velocity >
|
||||
FLING_VELOCITY_THRESHOLD || // Fast fling right
|
||||
(currentProgress >
|
||||
COMPLETION_THRESHOLD &&
|
||||
currentProgress >=
|
||||
COMPLETION_THRESHOLD ||
|
||||
velocity >
|
||||
FLING_VELOCITY_THRESHOLD || // Fast fling right
|
||||
(currentProgress >=
|
||||
COMPLETION_THRESHOLD *
|
||||
0.5f &&
|
||||
velocity >
|
||||
-FLING_VELOCITY_THRESHOLD) // 20%+ and not flinging back
|
||||
-FLING_VELOCITY_THRESHOLD * 4f) // Complete by default once swipe starts unless user strongly throws back
|
||||
|
||||
scope.launch {
|
||||
offsetAnimatable.snapTo(dragOffset)
|
||||
|
||||
Reference in New Issue
Block a user