Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modifier.draggable onDragStopped not called. #3310

Closed
elijah-semyonov opened this issue Jul 4, 2023 · 3 comments · Fixed by JetBrains/compose-multiplatform-core#623
Closed
Labels
bug Something isn't working submitted

Comments

@elijah-semyonov
Copy link
Contributor

elijah-semyonov commented Jul 4, 2023

Describe the bug
If a user drags his finger to the right part of the screen until the finger leaves the screen during scrolling content, onDragStopped lambda is not called.

Affected platforms
Select one of the platforms below:

  • iOS

Versions
jb-main 864ab80ff12dc70377d2f28d0a9bfbafd402ea44

Expected behavior
It must be called.

Notes
Not reproducible on Android.

@elijah-semyonov elijah-semyonov added bug Something isn't working submitted labels Jul 4, 2023
@elijah-semyonov
Copy link
Contributor Author

elijah-semyonov commented Jul 4, 2023

Investigation part 1

Call of this lambda is happening after dispatching DragStopped event. On Android is DragStopped event is consumed (in Draggable.kt:251) when finger leaves screen on any side(left, top, bottom, right) of the screen, on iOS - any side except right one. The expected sequence of events will be called normal, and a buggy one - buggy.

Events are created using result of awaitDownAndSlop
Normal sequence is:
processDragStart - n x dragBy - processDragStop

Buggy sequence is processDragStart - n x dragBy - freeze (no touches are processed, takes approx 0.5s before it can cancel) - processDragCancel on touch after freeze

On buggy sequence awaitDrag suspends and doesn't return until next drag sequence, on normal one it exits when touches end/leave screen. (implementation bug or touches generation logic bug?)

Inside closure passed to onDragOrUp at AwaitPointerEventScope.awaitDrag:
On normal sequence: event.changedToUpIgnoreConsumed() is always true, except the last one.
On buggy sequence: event.changedToUpIgnoreConsumed() is always true.

This method has a simple implementation of: fun PointerInputChange.changedToUpIgnoreConsumed() = previousPressed && !pressed

On buggy sequence last received event.pressed is true, on normal one it's false (how is that property calculated, was it miscalculated, or was it intercepted before reaching this closure?)

Events source data is correct and sent at ComposeLayer.jsNative.kt:68 onPointerEvent

PointerInputChange event with relevant pressed is sourced from within AwaitPointerEventScope.drag

@elijah-semyonov
Copy link
Contributor Author

elijah-semyonov commented Jul 5, 2023

Investigation part 2

Investigating absence of event with pressed equal to true from within AwaitPointerEventScope.drag.

On normal sequence:

UP UITouch sent
awaitDragOrUp returned something
awaitDragOrUp returned something
awaitDrag finished
DragStopped

On buggy sequence:

UP UITouch sent
-- nothing until 0.5s lag and next drag gesture --
awaitDragOrUp returned null
awaitDrag finished
DragCancelled

awaitDragOrUp doesn't receive data for end of the touch.
Inside that method suspension happens only at once place (DragGestureDetector.kt:617):
val event = awaitPointerEvent()

It means that the implementation of AwaitPointerEventScope doesn't forward it to us.
The implementation of AwaitPointerEventScope is provided by awaitPointerEventScope of PointerInputScope
The implementation of PointerInputScope is provided by Modifier.pointerInput. It's SuspendingPointerInputFilter
The implementation of AwaitPointerEventScope provided within is SuspendingPointerInputFilter.PointerEventHandlerCoroutine

@elijah-semyonov
Copy link
Contributor Author

Resolution

Event is not sent in ComposeScene.processRelease because pressOwner is null due to logical error and hoveredOwner is also null, because the touch is slightly outside the bounds of window due to floating-point multiplication error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working submitted
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant