Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 71c06b71 authored by Omar Miatello's avatar Omar Miatello Committed by Android (Google) Code Review
Browse files

Merge "Support for multiple gestures at once" into main

parents aca5839b e0b825dd
Loading
Loading
Loading
Loading
+19 −2
Original line number Diff line number Diff line
@@ -157,6 +157,8 @@ class SceneGestureHandler(
     */
    private val positionalThreshold = with(layoutImpl.density) { 56.dp.toPx() }

    internal var gestureWithPriority: Any? = null

    internal fun onDragStarted() {
        if (isDrivingTransition) {
            // This [transition] was already driving the animation: simply take over it.
@@ -525,17 +527,23 @@ private class SceneDraggableHandler(
    private val gestureHandler: SceneGestureHandler,
) : DraggableHandler {
    override suspend fun onDragStarted(coroutineScope: CoroutineScope, startedPosition: Offset) {
        gestureHandler.gestureWithPriority = this
        gestureHandler.onDragStarted()
    }

    override fun onDelta(pixels: Float) {
        if (gestureHandler.gestureWithPriority == this) {
            gestureHandler.onDrag(delta = pixels)
        }
    }

    override suspend fun onDragStopped(coroutineScope: CoroutineScope, velocity: Float) {
        if (gestureHandler.gestureWithPriority == this) {
            gestureHandler.gestureWithPriority = null
            gestureHandler.onDragStopped(velocity = velocity, canChangeScene = true)
        }
    }
}

@VisibleForTesting
class SceneNestedScrollHandler(
@@ -615,10 +623,15 @@ class SceneNestedScrollHandler(
            },
            canContinueScroll = { priorityScene == gestureHandler.swipeTransitionToScene.key },
            onStart = {
                gestureHandler.gestureWithPriority = this
                priorityScene = nextScene
                gestureHandler.onDragStarted()
            },
            onScroll = { offsetAvailable ->
                if (gestureHandler.gestureWithPriority != this) {
                    return@PriorityNestedScrollConnection Offset.Zero
                }

                val amount = offsetAvailable.toAmount()

                // TODO(b/297842071) We should handle the overscroll or slow drag if the gesture is
@@ -628,6 +641,10 @@ class SceneNestedScrollHandler(
                amount.toOffset()
            },
            onStop = { velocityAvailable ->
                if (gestureHandler.gestureWithPriority != this) {
                    return@PriorityNestedScrollConnection Velocity.Zero
                }

                priorityScene = null

                gestureHandler.onDragStopped(
+48 −0
Original line number Diff line number Diff line
@@ -312,4 +312,52 @@ class SceneGestureHandlerTest {
        advanceUntilIdle()
        assertScene(currentScene = SceneA, isIdle = true)
    }

    @Test
    fun beforeDraggableStart_drag_shouldBeIgnored() = runGestureTest {
        draggable.onDelta(deltaInPixels10)
        assertScene(currentScene = SceneA, isIdle = true)
    }
    @Test
    fun beforeDraggableStart_stop_shouldBeIgnored() = runGestureTest {
        draggable.onDragStopped(coroutineScope, velocityThreshold)
        assertScene(currentScene = SceneA, isIdle = true)
    }

    @Test
    fun beforeNestedScrollStart_stop_shouldBeIgnored() = runGestureTest {
        nestedScroll.onPreFling(Velocity(0f, velocityThreshold))
        assertScene(currentScene = SceneA, isIdle = true)
    }

    @Test
    fun startNestedScrollWhileDragging() = runGestureTest {
        draggable.onDragStarted(coroutineScope, Offset.Zero)
        assertScene(currentScene = SceneA, isIdle = false)
        val transition = transitionState as Transition

        draggable.onDelta(deltaInPixels10)
        assertThat(transition.progress).isEqualTo(0.1f)

        // now we can intercept the scroll events
        nestedScrollEvents(available = offsetY10)
        assertThat(transition.progress).isEqualTo(0.2f)

        // this should be ignored, we are scrolling now!
        draggable.onDragStopped(coroutineScope, velocityThreshold)
        assertScene(currentScene = SceneA, isIdle = false)

        nestedScrollEvents(available = offsetY10)
        assertThat(transition.progress).isEqualTo(0.3f)

        nestedScrollEvents(available = offsetY10)
        assertThat(transition.progress).isEqualTo(0.4f)

        nestedScroll.onPreFling(available = Velocity(0f, velocityThreshold))
        assertScene(currentScene = SceneC, isIdle = false)

        // wait for the stop animation
        advanceUntilIdle()
        assertScene(currentScene = SceneC, isIdle = true)
    }
}