Travis Griggs
10/10/2023, 7:28 PMTravis Griggs
10/10/2023, 7:29 PMsuspend fun AwaitPointerEventScope.awaitTwoDown(
requireUnconsumed: Boolean = true,
pass: PointerEventPass = PointerEventPass.Main,
): Pair<PointerInputChange, PointerInputChange> {
awaitFirstDown(requireUnconsumed, pass)
var event: PointerEvent
do {
event = awaitPointerEvent(pass)
} while (!(event.changes.size == 2 && event.changes.any { change -> !(requireUnconsumed && change.isConsumed) && change.pressed && change.previousPressed } && event.changes.any { change -> !(requireUnconsumed && change.isConsumed) && change.pressed && !change.previousPressed }))
return event.changes[0] to event.changes[1]
}
suspend fun PointerInputScope.detectTwoTouch(
onPinchStart: BinaryAction<Offset, Offset> = { _, _ -> },
onPinchMove: BinaryAction<Offset, Offset> = { _, _ -> },
onPinchEnd: BinaryAction<Offset, Offset> = { _, _ -> },
onPinchCancel: NullaryAction = { },
onTwoTap: BinaryAction<Offset, Offset> = { _, _ -> }
) {
val pinchThreshold = 20f
awaitEachGesture {
val (start1, start2) = awaitTwoDown()
val startPoints = listOf(start1.position, start2.position)
var endPoints = mutableListOf<Offset>()
var inPinch = false
var canceled = false
do {
val event = awaitPointerEvent()
when (event.type) {
PointerEventType.Press -> {
canceled = true // this means a 3rd tap came down
}
PointerEventType.Move -> {
val dragPoints = event.changes.map { change -> change.position }
if (dragPoints.size == 2) {
if (NOT(inPinch)) {
val maxTouchSlop = (startPoints.zip(dragPoints) { s, d -> (s - d).r }).max()
if (maxTouchSlop > pinchThreshold) {
onPinchStart(start1.position, start2.position)
inPinch = true
}
}
if (inPinch) {
onPinchMove(dragPoints[0], dragPoints[1])
}
}
}
PointerEventType.Release -> {
endPoints += event.changes.filter { change -> change.changedToUpIgnoreConsumed() }
.map { change -> change.position }
}
}
} while (!canceled && event.changes.any { change -> change.pressed })
if (canceled) {
if (inPinch) {
onPinchCancel()
}
} else {
if (inPinch) {
onPinchEnd(endPoints[0], endPoints[1])
} else {
onTwoTap(endPoints[0], endPoints[1])
}
}
}
}