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

Commit 2fadf24f authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add NestedDraggable.shouldConsumeNestedPreScroll()" into main

parents 5d42182b 6b7574f3
Loading
Loading
Loading
Loading
+44 −20
Original line number Diff line number Diff line
@@ -95,10 +95,20 @@ interface NestedDraggable {
     * nested scrollable.
     *
     * This is called whenever a nested scrollable does not consume some scroll amount. If this
     * returns `true`, then [onDragStarted] will be called and this draggable will have priority and
     * returns `true`, then [onDragStarted] will be called, this draggable will have priority and
     * consume all future events during preScroll until the nested scroll is finished.
     */
    fun shouldConsumeNestedScroll(sign: Float): Boolean
    fun shouldConsumeNestedPostScroll(sign: Float): Boolean = true

    /**
     * Whether this draggable should consume any scroll amount with the given [sign] *before* it can
     * be consumed by a nested scrollable.
     *
     * This is called before a nested scrollable is able to consume that scroll amount. If this
     * returns `true`, then [onDragStarted] will be called, this draggable will have priority and
     * consume all future scroll events during preScroll until the nested scroll is finished.
     */
    fun shouldConsumeNestedPreScroll(sign: Float): Boolean = false

    interface Controller {
        /**
@@ -540,6 +550,14 @@ private class NestedDraggableNode(
    }

    override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
        val sign = available.toFloat().sign
        maybeCreateNewController(
            sign = sign,
            condition = {
                source == NestedScrollSource.UserInput &&
                    draggable.shouldConsumeNestedPreScroll(sign)
            },
        )
        val controller = nestedScrollController ?: return Offset.Zero
        return scrollWithOverscroll(controller, available)
    }
@@ -560,19 +578,29 @@ private class NestedDraggableNode(
        }

        val sign = offset.sign
        maybeCreateNewController(
            sign,
            condition = { draggable.shouldConsumeNestedPostScroll(sign) },
        )
        val controller = nestedScrollController ?: return Offset.Zero
        return scrollWithOverscroll(controller, available)
    }

    private fun maybeCreateNewController(sign: Float, condition: () -> Boolean) {
        if (
            nestedDragsEnabled &&
                nestedScrollController == null &&
                // TODO(b/388231324): Remove this.
                !lastEventWasScrollWheel &&
                draggable.shouldConsumeNestedScroll(sign) &&
                lastFirstDown != null
            !nestedDragsEnabled ||
                nestedScrollController != null ||
                lastEventWasScrollWheel ||
                lastFirstDown == null ||
                !condition()
        ) {
            val startedPosition = checkNotNull(lastFirstDown)
            return
        }

        // TODO(b/382665591): Ensure that there is at least one pointer down.
        val pointersDownCount = pointersDown.size.coerceAtLeast(1)
        val pointerType = pointersDown.entries.firstOrNull()?.value
        val startedPosition = checkNotNull(lastFirstDown)
        nestedScrollController =
            NestedScrollController(
                overscrollEffect,
@@ -580,10 +608,6 @@ private class NestedDraggableNode(
            )
    }

        val controller = nestedScrollController ?: return Offset.Zero
        return scrollWithOverscroll(controller, available)
    }

    private fun scrollWithOverscroll(controller: NestedScrollController, offset: Offset): Offset {
        return scrollWithOverscroll(offset) {
            controller.controller.onDrag(it.toFloat()).toOffset()
+37 −3
Original line number Diff line number Diff line
@@ -971,6 +971,35 @@ class NestedDraggableTest(override val orientation: Orientation) : OrientationAw
        assertThat(availableToEffectPostFling).isWithin(1f).of(100f)
    }

    @Test
    fun consumeNestedPreScroll() {
        var consumeNestedPreScroll by mutableStateOf(false)
        val draggable = TestDraggable(shouldConsumeNestedPreScroll = { consumeNestedPreScroll })

        val touchSlop =
            rule.setContentWithTouchSlop {
                Box(
                    Modifier.fillMaxSize()
                        .nestedDraggable(draggable, orientation)
                        // Always consume everything so that the only way to start the drag is to
                        // intercept preScroll events.
                        .scrollable(rememberScrollableState { it }, orientation)
                )
            }

        rule.onRoot().performTouchInput {
            down(center)
            moveBy((touchSlop + 1f).toOffset())
        }

        assertThat(draggable.onDragStartedCalled).isFalse()

        consumeNestedPreScroll = true
        rule.onRoot().performTouchInput { moveBy(1f.toOffset()) }

        assertThat(draggable.onDragStartedCalled).isTrue()
    }

    private fun ComposeContentTestRule.setContentWithTouchSlop(
        content: @Composable () -> Unit
    ): Float {
@@ -996,7 +1025,8 @@ class NestedDraggableTest(override val orientation: Orientation) : OrientationAw
            { velocity, _ ->
                velocity
            },
        private val shouldConsumeNestedScroll: (Float) -> Boolean = { true },
        private val shouldConsumeNestedPostScroll: (Float) -> Boolean = { true },
        private val shouldConsumeNestedPreScroll: (Float) -> Boolean = { false },
    ) : NestedDraggable {
        var shouldStartDrag = true
        var onDragStartedCalled = false
@@ -1042,8 +1072,12 @@ class NestedDraggableTest(override val orientation: Orientation) : OrientationAw
            }
        }

        override fun shouldConsumeNestedScroll(sign: Float): Boolean {
            return shouldConsumeNestedScroll.invoke(sign)
        override fun shouldConsumeNestedPostScroll(sign: Float): Boolean {
            return shouldConsumeNestedPostScroll.invoke(sign)
        }

        override fun shouldConsumeNestedPreScroll(sign: Float): Boolean {
            return shouldConsumeNestedPreScroll.invoke(sign)
        }
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -68,7 +68,7 @@ internal class DraggableHandler(
        return layoutImpl.swipeDetector.detectSwipe(change)
    }

    override fun shouldConsumeNestedScroll(sign: Float): Boolean {
    override fun shouldConsumeNestedPostScroll(sign: Float): Boolean {
        return this.enabled()
    }