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

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

Merge "feat(MM): Make MotionSpec declarative and state-driven (2/3)" into main

parents 7fd1322d 30211835
Loading
Loading
Loading
Loading
+32 −14
Original line number Diff line number Diff line
@@ -17,6 +17,10 @@
package com.android.compose.gesture

import androidx.compose.foundation.gestures.Orientation
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.input.pointer.PointerType
@@ -106,11 +110,34 @@ private class OverscrollToDismissNode(
    private val gestureContext =
        DistanceGestureContext(0f, InputDirection.Max, directionChangeSlop = 1f)

    private var dragState: DragState by mutableStateOf(DragState.Idle)

    enum class DragState {
        Idle,
        Dragging,
        Dismissed,
    }

    private val spec = derivedStateOf {
        with(motionBuilderContext) {
            when (dragState) {
                DragState.Idle -> fixedSpatialValueSpec(0f, SnapBackSpring)
                DragState.Dragging -> spatialMotionSpec { after(0f, MagneticDetach()) }
                DragState.Dismissed ->
                    fixedSpatialValueSpec(
                        contentBoxWidth.toFloat(),
                        SnapBackSpring,
                        listOf(isDismissedState with true),
                    )
            }
        }
    }

    private val motionValue =
        MotionValue(
            gestureContext::dragOffset,
            gestureContext,
            motionBuilderContext.fixedSpatialValueSpec(0f),
            input = { gestureContext.dragOffset },
            gestureContext = gestureContext,
            spec = spec::value,
        )

    private var delegateNode =
@@ -161,7 +188,7 @@ private class OverscrollToDismissNode(
    ): NestedDraggable.Controller {
        overscrollSign = sign
        gestureContext.reset(dragOffset = motionValue.output, direction = InputDirection.Max)
        motionValue.spec = motionBuilderContext.spatialMotionSpec { after(0f, MagneticDetach()) }
        dragState = DragState.Dragging

        return this
    }
@@ -187,16 +214,7 @@ private class OverscrollToDismissNode(
                currentState == MagneticDetach.State.Attached ||
                    (currentState == MagneticDetach.State.Detached && isFlingInOppositeDirection)

            motionValue.spec =
                if (settleAttached) {
                    motionBuilderContext.fixedSpatialValueSpec(0f, SnapBackSpring)
                } else {
                    motionBuilderContext.fixedSpatialValueSpec(
                        contentBoxWidth.toFloat(),
                        SnapBackSpring,
                        listOf(isDismissedState with true),
                    )
                }
            dragState = if (settleAttached) DragState.Idle else DragState.Dismissed
        }
        return velocity
    }
+21 −9
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.compose.animation.scene.mechanics

import androidx.annotation.VisibleForTesting
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.mutableFloatStateOf
import com.android.compose.animation.scene.ContentKey
import com.android.compose.animation.scene.ElementKey
@@ -51,11 +52,13 @@ internal class TransitionScopedMechanicsAdapter(
    private val computeInput: MotionValueInput = { progress, _, _ -> progress },
    private val stableThreshold: Float = MotionValue.StableThresholdEffect,
    private val label: String? = null,
    private val createSpec: SpecFactory,
    private val getSpec: SpecFactory,
) {

    private val input = mutableFloatStateOf(0f)
    private var motionValue: MotionValue? = null
    private var transformationContent: ContentKey? = null
    private var transformationElement: ElementKey? = null

    fun PropertyTransformationScope.update(
        content: ContentKey,
@@ -68,23 +71,32 @@ internal class TransitionScopedMechanicsAdapter(
        var motionValue = motionValue

        if (motionValue == null) {
            transformationContent = content
            transformationElement = element
            motionValue =
                MotionValue(
                    input::floatValue,
                    input = { input.floatValue },
                    gestureContext =
                        transition.gestureContext
                            ?: ProvidedGestureContext(
                                0f,
                                appearDirection(content, element, transition),
                            ),
                    createSpec(content, element),
                    stableThreshold = stableThreshold,
                    spec = derivedStateOf { getSpec(content, element) }::value,
                    label = label,
                    stableThreshold = stableThreshold,
                )

            this@TransitionScopedMechanicsAdapter.motionValue = motionValue

            transitionScope.launch {
                motionValue.keepRunningWhile { !transition.isProgressStable || !isStable }
            }
        } else {
            check(content == transformationContent && element == transformationElement) {
                "update received ($content, $element), " +
                    "instead of ($transformationContent, $transformationElement)"
            }
        }

        return motionValue.output
+1 −1
Original line number Diff line number Diff line
@@ -447,7 +447,7 @@ class TransitionScopedMechanicsAdapterTest {
        override val property = PropertyTransformation.Property.Offset

        val motionValue =
            TransitionScopedMechanicsAdapter(createSpec = specFactory, stableThreshold = 1f)
            TransitionScopedMechanicsAdapter(getSpec = specFactory, stableThreshold = 1f)

        override fun PropertyTransformationScope.transform(
            content: ContentKey,