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

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

Merge changes I283074e5,I401dd8c5 into main

* changes:
  Update description for NestedScrollBehavior.DuringTransitionBetweenScenes
  Migrate nestedScrollToScene to the new Modifier Node API
parents 47d1356e 339674af
Loading
Loading
Loading
Loading
+99 −16
Original line number Diff line number Diff line
@@ -17,11 +17,13 @@
package com.android.compose.animation.scene

import androidx.compose.foundation.gestures.Orientation
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.input.nestedscroll.nestedScrollModifierNode
import androidx.compose.ui.node.DelegatableNode
import androidx.compose.ui.node.DelegatingNode
import androidx.compose.ui.node.ModifierNodeElement
import androidx.compose.ui.platform.InspectorInfo
import com.android.compose.nestedscroll.PriorityNestedScrollConnection

/**
 * Defines the behavior of the [SceneTransitionLayout] when a scrollable component is scrolled.
@@ -32,8 +34,9 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll
 */
enum class NestedScrollBehavior(val canStartOnPostFling: Boolean) {
    /**
     * During scene transitions, scroll events are consumed by the [SceneTransitionLayout] instead
     * of the scrollable component.
     * During scene transitions, if we are within
     * [SceneTransitionLayoutImpl.transitionInterceptionThreshold], the [SceneTransitionLayout]
     * consumes scroll events instead of the scrollable component.
     */
    DuringTransitionBetweenScenes(canStartOnPostFling = false),

@@ -72,21 +75,101 @@ internal fun Modifier.nestedScrollToScene(
    orientation: Orientation,
    startBehavior: NestedScrollBehavior,
    endBehavior: NestedScrollBehavior,
): Modifier = composed {
    val connection =
        remember(layoutImpl, orientation, startBehavior, endBehavior) {
) =
    this then
        NestedScrollToSceneElement(
            layoutImpl = layoutImpl,
            orientation = orientation,
            startBehavior = startBehavior,
            endBehavior = endBehavior,
        )

private data class NestedScrollToSceneElement(
    private val layoutImpl: SceneTransitionLayoutImpl,
    private val orientation: Orientation,
    private val startBehavior: NestedScrollBehavior,
    private val endBehavior: NestedScrollBehavior,
) : ModifierNodeElement<NestedScrollToSceneNode>() {
    override fun create() =
        NestedScrollToSceneNode(
            layoutImpl = layoutImpl,
            orientation = orientation,
            startBehavior = startBehavior,
            endBehavior = endBehavior,
        )

    override fun update(node: NestedScrollToSceneNode) {
        node.update(
            layoutImpl = layoutImpl,
            orientation = orientation,
            startBehavior = startBehavior,
            endBehavior = endBehavior,
        )
    }

    override fun InspectorInfo.inspectableProperties() {
        name = "nestedScrollToScene"
        properties["layoutImpl"] = layoutImpl
        properties["orientation"] = orientation
        properties["startBehavior"] = startBehavior
        properties["endBehavior"] = endBehavior
    }
}

private class NestedScrollToSceneNode(
    layoutImpl: SceneTransitionLayoutImpl,
    orientation: Orientation,
    startBehavior: NestedScrollBehavior,
    endBehavior: NestedScrollBehavior,
) : DelegatingNode() {
    private var priorityNestedScrollConnection: PriorityNestedScrollConnection =
        scenePriorityNestedScrollConnection(
            layoutImpl = layoutImpl,
            orientation = orientation,
            startBehavior = startBehavior,
                endBehavior = endBehavior
            endBehavior = endBehavior,
        )

    private var nestedScrollNode: DelegatableNode =
        nestedScrollModifierNode(
            connection = priorityNestedScrollConnection,
            dispatcher = null,
        )

    override fun onAttach() {
        delegate(nestedScrollNode)
    }

    override fun onDetach() {
        // Make sure we reset the scroll connection when this modifier is removed from composition
    DisposableEffect(connection) { onDispose { connection.reset() } }
        priorityNestedScrollConnection.reset()
    }

    fun update(
        layoutImpl: SceneTransitionLayoutImpl,
        orientation: Orientation,
        startBehavior: NestedScrollBehavior,
        endBehavior: NestedScrollBehavior,
    ) {
        // Clean up the old nested scroll connection
        priorityNestedScrollConnection.reset()
        undelegate(nestedScrollNode)

    nestedScroll(connection = connection)
        // Create a new nested scroll connection
        priorityNestedScrollConnection =
            scenePriorityNestedScrollConnection(
                layoutImpl = layoutImpl,
                orientation = orientation,
                startBehavior = startBehavior,
                endBehavior = endBehavior,
            )
        nestedScrollNode =
            nestedScrollModifierNode(
                connection = priorityNestedScrollConnection,
                dispatcher = null,
            )
        delegate(nestedScrollNode)
    }
}

private fun scenePriorityNestedScrollConnection(