fix Android swipe gesture edge cases

This commit is contained in:
2026-04-10 10:05:57 +02:00
parent ffed360cb9
commit 2553845100
3 changed files with 71 additions and 2 deletions
+1
View File
@@ -24,6 +24,7 @@ This is the canonical working plan and progress log for the project. Use this fi
- iOS project scaffolding now exists as `mobile/ios-app/HermesApp.xcodeproj` with a shared scheme and XCTest target.
- iOS sources and tests build and pass in Xcode on an iPhone simulator, and a standalone localization/error-mapping harness passes.
- Android local unit tests now cover localization, error mapping, and analytics batch conversion, and `./gradlew testDebugUnitTest` passes with the Android SDK installed.
- Android swipe-down gesture handling now uses cumulative drag distance, and edge-case tests cover upward drags, slow swipes, and per-gesture single-trigger behavior.
### Still Open
@@ -4,9 +4,40 @@ import androidx.compose.foundation.gestures.detectVerticalDragGestures
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.pointer.pointerInput
internal class HermesSwipeDownDetector(
private val threshold: Float = 32f,
) {
private var totalDrag = 0f
private var triggered = false
fun onDrag(dragAmount: Float): Boolean {
if (triggered) {
return false
}
totalDrag = (totalDrag + dragAmount).coerceAtLeast(0f)
if (totalDrag >= threshold) {
triggered = true
return true
}
return false
}
fun reset() {
totalDrag = 0f
triggered = false
}
}
fun Modifier.hermesSwipeDown(onSwipeDown: () -> Unit): Modifier = pointerInput(onSwipeDown) {
detectVerticalDragGestures { _, dragAmount ->
if (dragAmount > 32f) {
val detector = HermesSwipeDownDetector()
detectVerticalDragGestures(
onDragStart = { detector.reset() },
onDragEnd = { detector.reset() },
onDragCancel = { detector.reset() },
) { _, dragAmount ->
if (detector.onDrag(dragAmount)) {
onSwipeDown()
}
}
@@ -0,0 +1,37 @@
package com.hermes.app.core.gestures
import kotlin.test.Test
import kotlin.test.assertFalse
import kotlin.test.assertTrue
class HermesSwipeDownDetectorTest {
@Test
fun triggersAfterCumulativeDownwardDrag() {
val detector = HermesSwipeDownDetector(threshold = 32f)
assertFalse(detector.onDrag(10f))
assertFalse(detector.onDrag(10f))
assertTrue(detector.onDrag(12f))
}
@Test
fun doesNotTriggerForSmallOrUpwardDrags() {
val detector = HermesSwipeDownDetector(threshold = 32f)
assertFalse(detector.onDrag(20f))
assertFalse(detector.onDrag(-15f))
assertFalse(detector.onDrag(20f))
}
@Test
fun onlyTriggersOncePerGestureUntilReset() {
val detector = HermesSwipeDownDetector(threshold = 32f)
assertTrue(detector.onDrag(40f))
assertFalse(detector.onDrag(40f))
detector.reset()
assertTrue(detector.onDrag(40f))
}
}