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

Commit 2ebb6622 authored by Jordan Demeulenaere's avatar Jordan Demeulenaere Committed by Android (Google) Code Review
Browse files

Merge changes I91a27f82,I62688e42 into main

* changes:
  Introduce CustomPropertyTransformation
  Remove Transformation.reversed()
parents f2aecfd2 a97625ec
Loading
Loading
Loading
Loading
+66 −10
Original line number Diff line number Diff line
@@ -50,6 +50,8 @@ import androidx.compose.ui.util.fastForEachReversed
import androidx.compose.ui.util.lerp
import com.android.compose.animation.scene.content.Content
import com.android.compose.animation.scene.content.state.TransitionState
import com.android.compose.animation.scene.transformation.CustomPropertyTransformation
import com.android.compose.animation.scene.transformation.InterpolatedPropertyTransformation
import com.android.compose.animation.scene.transformation.PropertyTransformation
import com.android.compose.animation.scene.transformation.SharedElementTransformation
import com.android.compose.animation.scene.transformation.TransformationWithRange
@@ -1308,7 +1310,14 @@ private inline fun <T> computeValue(
                checkNotNull(if (currentContent == toContent) toState else fromState)
            val idleValue = contentValue(overscrollState)
            val targetValue =
                with(propertySpec.transformation) {
                with(
                    propertySpec.transformation.requireInterpolatedTransformation(
                        element,
                        transition,
                    ) {
                        "Custom transformations in overscroll specs should not be possible"
                    }
                ) {
                    layoutImpl.propertyTransformationScope.transform(
                        currentContent,
                        element.key,
@@ -1390,7 +1399,7 @@ private inline fun <T> computeValue(
    // fromContent or toContent during interruptions.
    val content = contentState.content

    val transformation =
    val transformationWithRange =
        transformation(transition.transformationSpec.transformations(element.key, content))

    val previewTransformation =
@@ -1403,7 +1412,14 @@ private inline fun <T> computeValue(
        val idleValue = contentValue(contentState)
        val isEntering = content == toContent
        val previewTargetValue =
            with(previewTransformation.transformation) {
            with(
                previewTransformation.transformation.requireInterpolatedTransformation(
                    element,
                    transition,
                ) {
                    "Custom transformations in preview specs should not be possible"
                }
            ) {
                layoutImpl.propertyTransformationScope.transform(
                    content,
                    element.key,
@@ -1413,8 +1429,15 @@ private inline fun <T> computeValue(
            }

        val targetValueOrNull =
            transformation?.let { transformation ->
                with(transformation.transformation) {
            transformationWithRange?.let { transformation ->
                with(
                    transformation.transformation.requireInterpolatedTransformation(
                        element,
                        transition,
                    ) {
                        "Custom transformations are not allowed for properties with a preview"
                    }
                ) {
                    layoutImpl.propertyTransformationScope.transform(
                        content,
                        element.key,
@@ -1461,7 +1484,7 @@ private inline fun <T> computeValue(
            lerp(
                lerp(previewTargetValue, targetValueOrNull ?: idleValue, previewRangeProgress),
                idleValue,
                transformation?.range?.progress(transition.progress) ?: transition.progress,
                transformationWithRange?.range?.progress(transition.progress) ?: transition.progress,
            )
        } else {
            if (targetValueOrNull == null) {
@@ -1474,22 +1497,39 @@ private inline fun <T> computeValue(
                lerp(
                    lerp(idleValue, previewTargetValue, previewRangeProgress),
                    targetValueOrNull,
                    transformation.range?.progress(transition.progress) ?: transition.progress,
                    transformationWithRange.range?.progress(transition.progress)
                        ?: transition.progress,
                )
            }
        }
    }

    if (transformation == null) {
    if (transformationWithRange == null) {
        // If there is no transformation explicitly associated to this element value, let's use
        // the value given by the system (like the current position and size given by the layout
        // pass).
        return currentValue()
    }

    val transformation = transformationWithRange.transformation
    when (transformation) {
        is CustomPropertyTransformation ->
            return with(transformation) {
                layoutImpl.propertyTransformationScope.transform(
                    content,
                    element.key,
                    transition,
                    transition.coroutineScope,
                )
            }
        is InterpolatedPropertyTransformation -> {
            /* continue */
        }
    }

    val idleValue = contentValue(contentState)
    val targetValue =
        with(transformation.transformation) {
        with(transformation) {
            layoutImpl.propertyTransformationScope.transform(
                content,
                element.key,
@@ -1506,7 +1546,7 @@ private inline fun <T> computeValue(

    val progress = transition.progress
    // TODO(b/290184746): Make sure that we don't overflow transformations associated to a range.
    val rangeProgress = transformation.range?.progress(progress) ?: progress
    val rangeProgress = transformationWithRange.range?.progress(progress) ?: progress

    // Interpolate between the value at rest and the value before entering/after leaving.
    val isEntering =
@@ -1523,6 +1563,22 @@ private inline fun <T> computeValue(
    }
}

private inline fun <T> PropertyTransformation<T>.requireInterpolatedTransformation(
    element: Element,
    transition: TransitionState.Transition,
    errorMessage: () -> String,
): InterpolatedPropertyTransformation<T> {
    return when (this) {
        is InterpolatedPropertyTransformation -> this
        is CustomPropertyTransformation -> {
            val elem = element.key.debugName
            val fromContent = transition.fromContent
            val toContent = transition.toContent
            error("${errorMessage()} (element=$elem fromContent=$fromContent toContent=$toContent)")
        }
    }
}

private inline fun <T> interpolateSharedElement(
    transition: TransitionState.Transition,
    contentValue: (Element.State) -> T,
+4 −3
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import kotlin.math.absoluteValue
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch

/**
@@ -466,9 +467,9 @@ internal class MutableSceneTransitionLayoutStateImpl(
            return
        }

        // Make sure that this transition settles in case it was force finished, for instance by
        // calling snapToScene().
        transition.freezeAndAnimateToCurrentState()
        // Make sure that this transition is cancelled in case it was force finished, for instance
        // if snapToScene() is called.
        transition.coroutineScope.cancel()

        val transitionStates = this.transitionStates
        if (!transitionStates.contains(transition)) {
+16 −17
Original line number Diff line number Diff line
@@ -26,18 +26,18 @@ import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.util.fastForEach
import com.android.compose.animation.scene.content.state.TransitionState
import com.android.compose.animation.scene.transformation.AnchoredSize
import com.android.compose.animation.scene.transformation.AnchoredTranslate
import com.android.compose.animation.scene.transformation.DrawScale
import com.android.compose.animation.scene.transformation.EdgeTranslate
import com.android.compose.animation.scene.transformation.Fade
import com.android.compose.animation.scene.transformation.OverscrollTranslate
import com.android.compose.animation.scene.transformation.CustomAlphaTransformation
import com.android.compose.animation.scene.transformation.CustomOffsetTransformation
import com.android.compose.animation.scene.transformation.CustomScaleTransformation
import com.android.compose.animation.scene.transformation.CustomSizeTransformation
import com.android.compose.animation.scene.transformation.InterpolatedAlphaTransformation
import com.android.compose.animation.scene.transformation.InterpolatedOffsetTransformation
import com.android.compose.animation.scene.transformation.InterpolatedScaleTransformation
import com.android.compose.animation.scene.transformation.InterpolatedSizeTransformation
import com.android.compose.animation.scene.transformation.PropertyTransformation
import com.android.compose.animation.scene.transformation.ScaleSize
import com.android.compose.animation.scene.transformation.SharedElementTransformation
import com.android.compose.animation.scene.transformation.Transformation
import com.android.compose.animation.scene.transformation.TransformationWithRange
import com.android.compose.animation.scene.transformation.Translate

/** The transitions configuration of a [SceneTransitionLayout]. */
class SceneTransitions
@@ -359,35 +359,34 @@ internal class TransformationSpecImpl(
                        transformationWithRange
                            as TransformationWithRange<SharedElementTransformation>
                }
                is Translate,
                is OverscrollTranslate,
                is EdgeTranslate,
                is AnchoredTranslate -> {
                is InterpolatedOffsetTransformation,
                is CustomOffsetTransformation -> {
                    throwIfNotNull(offset, element, name = "offset")
                    offset =
                        transformationWithRange
                            as TransformationWithRange<PropertyTransformation<Offset>>
                }
                is ScaleSize,
                is AnchoredSize -> {
                is InterpolatedSizeTransformation,
                is CustomSizeTransformation -> {
                    throwIfNotNull(size, element, name = "size")
                    size =
                        transformationWithRange
                            as TransformationWithRange<PropertyTransformation<IntSize>>
                }
                is DrawScale -> {
                is InterpolatedScaleTransformation,
                is CustomScaleTransformation -> {
                    throwIfNotNull(drawScale, element, name = "drawScale")
                    drawScale =
                        transformationWithRange
                            as TransformationWithRange<PropertyTransformation<Scale>>
                }
                is Fade -> {
                is InterpolatedAlphaTransformation,
                is CustomAlphaTransformation -> {
                    throwIfNotNull(alpha, element, name = "alpha")
                    alpha =
                        transformationWithRange
                            as TransformationWithRange<PropertyTransformation<Float>>
                }
                else -> error("Unknown transformation: $transformation")
            }
        }

+11 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.android.compose.animation.scene.content.state.TransitionState
import com.android.compose.animation.scene.transformation.CustomPropertyTransformation
import kotlin.math.tanh

/** Define the [transitions][SceneTransitions] to be used with a [SceneTransitionLayout]. */
@@ -527,6 +528,16 @@ interface PropertyTransformationBuilder {
        anchorWidth: Boolean = true,
        anchorHeight: Boolean = true,
    )

    /**
     * Apply a [CustomPropertyTransformation] to one or more elements.
     *
     * @see com.android.compose.animation.scene.transformation.CustomSizeTransformation
     * @see com.android.compose.animation.scene.transformation.CustomOffsetTransformation
     * @see com.android.compose.animation.scene.transformation.CustomAlphaTransformation
     * @see com.android.compose.animation.scene.transformation.CustomScaleTransformation
     */
    fun transformation(transformation: CustomPropertyTransformation<*>)
}

/** This converter lets you change a linear progress into a function of your choice. */
+16 −10
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import androidx.compose.ui.unit.Dp
import com.android.compose.animation.scene.content.state.TransitionState
import com.android.compose.animation.scene.transformation.AnchoredSize
import com.android.compose.animation.scene.transformation.AnchoredTranslate
import com.android.compose.animation.scene.transformation.CustomPropertyTransformation
import com.android.compose.animation.scene.transformation.DrawScale
import com.android.compose.animation.scene.transformation.EdgeTranslate
import com.android.compose.animation.scene.transformation.Fade
@@ -173,7 +174,7 @@ internal abstract class BaseTransitionBuilderImpl : BaseTransitionBuilder {
        range = null
    }

    protected fun transformation(transformation: Transformation) {
    protected fun addTransformation(transformation: Transformation) {
        val transformationWithRange = TransformationWithRange(transformation, range)
        transformations.add(
            if (reversed) {
@@ -185,11 +186,11 @@ internal abstract class BaseTransitionBuilderImpl : BaseTransitionBuilder {
    }

    override fun fade(matcher: ElementMatcher) {
        transformation(Fade(matcher))
        addTransformation(Fade(matcher))
    }

    override fun translate(matcher: ElementMatcher, x: Dp, y: Dp) {
        transformation(Translate(matcher, x, y))
        addTransformation(Translate(matcher, x, y))
    }

    override fun translate(
@@ -197,19 +198,19 @@ internal abstract class BaseTransitionBuilderImpl : BaseTransitionBuilder {
        edge: Edge,
        startsOutsideLayoutBounds: Boolean,
    ) {
        transformation(EdgeTranslate(matcher, edge, startsOutsideLayoutBounds))
        addTransformation(EdgeTranslate(matcher, edge, startsOutsideLayoutBounds))
    }

    override fun anchoredTranslate(matcher: ElementMatcher, anchor: ElementKey) {
        transformation(AnchoredTranslate(matcher, anchor))
        addTransformation(AnchoredTranslate(matcher, anchor))
    }

    override fun scaleSize(matcher: ElementMatcher, width: Float, height: Float) {
        transformation(ScaleSize(matcher, width, height))
        addTransformation(ScaleSize(matcher, width, height))
    }

    override fun scaleDraw(matcher: ElementMatcher, scaleX: Float, scaleY: Float, pivot: Offset) {
        transformation(DrawScale(matcher, scaleX, scaleY, pivot))
        addTransformation(DrawScale(matcher, scaleX, scaleY, pivot))
    }

    override fun anchoredSize(
@@ -218,7 +219,12 @@ internal abstract class BaseTransitionBuilderImpl : BaseTransitionBuilder {
        anchorWidth: Boolean,
        anchorHeight: Boolean,
    ) {
        transformation(AnchoredSize(matcher, anchor, anchorWidth, anchorHeight))
        addTransformation(AnchoredSize(matcher, anchor, anchorWidth, anchorHeight))
    }

    override fun transformation(transformation: CustomPropertyTransformation<*>) {
        check(range == null) { "Custom transformations can not be applied inside a range" }
        addTransformation(transformation)
    }
}

@@ -257,7 +263,7 @@ internal class TransitionBuilderImpl(override val transition: TransitionState.Tr
                "(${transition.toContent.debugName})"
        }

        transformation(SharedElementTransformation(matcher, enabled, elevateInContent))
        addTransformation(SharedElementTransformation(matcher, enabled, elevateInContent))
    }

    override fun timestampRange(
@@ -288,6 +294,6 @@ internal open class OverscrollBuilderImpl : BaseTransitionBuilderImpl(), Overscr
        x: OverscrollScope.() -> Float,
        y: OverscrollScope.() -> Float,
    ) {
        transformation(OverscrollTranslate(matcher, x, y))
        addTransformation(OverscrollTranslate(matcher, x, y))
    }
}
Loading