Programmistich
07/26/2022, 3:44 PMcombinedClickable()
have onClick/onDouble/onLong but dont have onHoldLandry Norris
07/26/2022, 3:45 PMLandry Norris
07/26/2022, 3:46 PMfun Modifier.longPress(onClick: () -> Unit, onLongPressStart: () -> Unit, onLongPressEnd: () -> Unit) =
pointerInput(Unit) {
forEachGesture {
val down = awaitPointerEventScope {
awaitFirstDown(requireUnconsumed = false)
}
val change = awaitLongPressOrCancellation(down)
val wasLongPress = (change == down)
if(!wasLongPress) {
onClick()
return@forEachGesture
}
//was a long press
println("Long press")
onLongPressStart()
awaitPointerEventScope { waitForUpOrCancellation() }
println("Long press ending")
onLongPressEnd()
}
}
//Copied from internal function in Compose Source Code
suspend fun PointerInputScope.awaitLongPressOrCancellation(
initialDown: PointerInputChange
): PointerInputChange? {
var longPress: PointerInputChange? = null
var currentDown = initialDown
val longPressTimeout = viewConfiguration.longPressTimeoutMillis
return try {
// wait for first tap up or long press
withTimeout(longPressTimeout) {
awaitPointerEventScope {
var finished = false
while (!finished) {
val event = awaitPointerEvent(PointerEventPass.Main)
if (event.changes.all { it.changedToUpIgnoreConsumed() }) {
// All pointers are up
finished = true
}
if (
event.changes.any {
it.consumed.downChange || it.isOutOfBounds(size, extendedTouchPadding)
}
) {
finished = true // Canceled
}
// Check for cancel by position consumption. We can look on the Final pass of
// the existing pointer event because it comes after the Main pass we checked
// above.
val consumeCheck = awaitPointerEvent(PointerEventPass.Final)
if (consumeCheck.changes.any { it.positionChangeConsumed() }) {
finished = true
}
if (event.changes.firstOrNull { it.id == currentDown.id }?.pressed == true) {
longPress = event.changes.firstOrNull { it.id == currentDown.id }
} else {
val newPressed = event.changes.firstOrNull { it.pressed }
if (newPressed != null) {
currentDown = newPressed
longPress = currentDown
} else {
// should technically never happen as we checked it above
finished = true
}
}
}
}
}
null
} catch (_: TimeoutCancellationException) {
longPress ?: initialDown
}
}