Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion android/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ plugins {

dependencies {
implementation(project(":reorderable"))
implementation("androidx.compose.runtime:runtime:1.8.1")
implementation("androidx.compose.runtime:runtime:1.8.2")
implementation("androidx.compose.material3:material3:1.3.2")
implementation("androidx.activity:activity-compose:1.10.1")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.9.0")
Expand Down
4 changes: 2 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ plugins {
}

ext {
extra["compileSdkVersion"] = 35
extra["compileSdkVersion"] = 36
extra["minSdkVersion"] = 21
extra["targetSdkVersion"] = 35
extra["targetSdkVersion"] = 36
}

allprojects {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
*/
package org.burnoutcrew.reorderable

import androidx.compose.foundation.gestures.awaitEachGesture
import androidx.compose.foundation.gestures.awaitFirstDown
import androidx.compose.foundation.gestures.awaitLongPressOrCancellation
import androidx.compose.foundation.gestures.forEachGesture
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
Expand All @@ -25,20 +27,18 @@ import androidx.compose.ui.input.pointer.pointerInput
fun Modifier.detectReorder(state: ReorderableState<*>) =
this.then(
Modifier.pointerInput(Unit) {
forEachGesture {
awaitPointerEventScope {
val down = awaitFirstDown(requireUnconsumed = false)
var drag: PointerInputChange?
var overSlop = Offset.Zero
do {
drag = awaitPointerSlopOrCancellation(down.id, down.type) { change, over ->
change.consume()
overSlop = over
}
} while (drag != null && !drag.isConsumed)
if (drag != null) {
state.interactions.trySend(StartDrag(down.id, overSlop))
awaitEachGesture {
val down = awaitFirstDown(requireUnconsumed = false)
var drag: PointerInputChange?
var overSlop = Offset.Zero
do {
drag = awaitPointerSlopOrCancellation(down.id, down.type) { change, over ->
change.consume()
overSlop = over
}
} while (drag != null && !drag.isConsumed)
if (drag != null) {
state.interactions.trySend(StartDrag(down.id, overSlop))
}
}
}
Expand All @@ -48,11 +48,9 @@ fun Modifier.detectReorder(state: ReorderableState<*>) =
fun Modifier.detectReorderAfterLongPress(state: ReorderableState<*>) =
this.then(
Modifier.pointerInput(Unit) {
forEachGesture {
val down = awaitPointerEventScope {
awaitFirstDown(requireUnconsumed = false)
}
awaitLongPressOrCancellation(down)?.also {
awaitEachGesture {
val down = awaitFirstDown(requireUnconsumed = false)
awaitLongPressOrCancellation(down.id).also {
state.interactions.trySend(StartDrag(down.id))
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,60 +88,6 @@ internal suspend fun AwaitPointerEventScope.awaitPointerSlopOrCancellation(
}
}

internal 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.fastAll { it.changedToUpIgnoreConsumed() }) {
// All pointers are up
finished = true
}

if (
event.changes.fastAny {
it.isConsumed || 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.fastAny { it.isConsumed }) {
finished = true
}
if (!event.isPointerUp(currentDown.id)) {
longPress = event.changes.fastFirstOrNull { it.id == currentDown.id }
} else {
val newPressed = event.changes.fastFirstOrNull { 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
}
}

private fun PointerEvent.isPointerUp(pointerId: PointerId): Boolean =
changes.fastFirstOrNull { it.id == pointerId }?.pressed != true

Expand Down