JetBrains / compose-multiplatform

Compose Multiplatform, a modern UI framework for Kotlin that makes building performant and beautiful user interfaces easy and enjoyable.
https://jetbrains.com/lp/compose-multiplatform
Apache License 2.0
15.24k stars 1.11k forks source link

PointerInputChange onDrag events always emit ID of 0 on desktop #4882

Closed Flipstream-pinball closed 4 weeks ago

Flipstream-pinball commented 4 weeks ago

Describe the bug Using a custom pointerInput handler, the detectDragGestures function onDrag event always generates a PointerInputChange id value of 0 on Desktop/JDK

Affected platforms

Versions

To Reproduce Steps to reproduce the behavior:

  1. Add a pointerInput modifier to a composable on desktop/JVM:
    @Composable
    fun BugReproduction() {
      Scaffold {
          Box(
              modifier = Modifier
                  .fillMaxSize()
                  .pointerInput(Unit) {
                      detectDragGestures(
                          onDrag = { change: PointerInputChange, _: Offset ->
                              Logger.v { "Drag: ${change.id.value}" }
                          }
                      )
                  }
          )
          {
              // Box content
          }
      }
    }
  2. Click and hold/drag anywhere on the box area
  3. Note that the change.id.value is 0
  4. Release the button and click+drag again
  5. Note that the change.id.value is still 0

Expected behavior Compose should generate non-zero/unique change ID values similar to the behavior on Android.

MatkovIvan commented 4 weeks ago

Compose should generate non-zero/unique change ID values similar to the behavior on Android.

Why? Could you please explain your use case? It doesn't seem as a bug for me.

This ID is unique in case of touch but not for mouse even on Android (to test this try to drag with bluetooth mouse connected to real device).

Flipstream-pinball commented 4 weeks ago

Why? Could you please explain your use case? It doesn't seem as a bug for me.

Thank you for the additional information. To clarify, I'm writing a 3rd party client application that needs to support three button activation options:

The parent Box composable sets up a MutableStateFlow for the PointerInputChange onDrag ID's Long value that is passed to button composables within the Box that subscribe to the flow. In the case of single drag-press, the Button remembers the last ID to limit clicks to one per PointerInputChange ID.

I originally initialized the ID flow with a value of 0 which worked beautifully on Android and compose. Migrating to multiplatform, PointerInputChange always emitting a matching value of 0 meant buttons set to single drag-press always ignored drag events on desktop.

I've worked around the behavior by changing the ID flow to support null values, and added an additional drag end event handler to emit a null value to the MutableStateFlow. It works, although altering the flows to allow null values feels like an anti-pattern.

This ID is unique in case of touch but not for mouse even on Android (to test this try to drag with bluetooth mouse connected to real device).

The PointerInputChange documentation doesn't mention that IDs are unique for touch events only, which is why I believed this was a defect.

However, it sounds like this is expected behavior, and I suspect my "single drag-press" use case may be rare.

MatkovIvan commented 4 weeks ago

I see, thanks for clarification.

From that mentioned docs:

id The unique id of the pointer associated with this PointerInputChange.

"unique id of the pointer" - so mouse is a single pointer with id 0. Clicking the button doesn't create a new pointer, but starting the touch does. So, I believe that current behaviour matches documentation.

Closing as it's expected behaviour and you already found workaround.