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

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

Merge "Don't share elements when the shared animation is disabled" into main

parents 7b281c63 de8d634c
Loading
Loading
Loading
Loading
+23 −8
Original line number Diff line number Diff line
@@ -828,15 +828,21 @@ private fun shouldPlaceElement(

    // Don't place the element in this content if this content is not part of the current element
    // transition.
    if (content != transition.fromContent && content != transition.toContent) {
    val isReplacingOverlay = transition is TransitionState.Transition.ReplaceOverlay
    if (
        content != transition.fromContent &&
            content != transition.toContent &&
            (!isReplacingOverlay || content != transition.currentScene)
    ) {
        return false
    }

    // Place the element if it is not shared.
    if (
        transition.fromContent !in element.stateByContent ||
            transition.toContent !in element.stateByContent
    ) {
    var copies = 0
    if (transition.fromContent in element.stateByContent) copies++
    if (transition.toContent in element.stateByContent) copies++
    if (isReplacingOverlay && transition.currentScene in element.stateByContent) copies++
    if (copies <= 1) {
        return true
    }

@@ -1269,9 +1275,10 @@ private inline fun <T> computeValue(

    // If we are replacing an overlay and the element is both in a single overlay and in the current
    // scene, interpolate the state of the element using the current scene as the other scene.
    var currentSceneState: Element.State? = null
    if (!isSharedElement && transition is TransitionState.Transition.ReplaceOverlay) {
        val currentSceneState = element.stateByContent[transition.currentScene]
        if (currentSceneState != null) {
        currentSceneState = element.stateByContent[transition.currentScene]
        if (currentSceneState != null && isSharedElementEnabled(element.key, transition)) {
            return interpolateSharedElement(
                transition = transition,
                contentValue = contentValue,
@@ -1290,6 +1297,8 @@ private inline fun <T> computeValue(
            when {
                isSharedElement && currentContent == fromContent -> fromState
                isSharedElement -> toState
                currentSceneState != null && currentContent == transition.currentScene ->
                    currentSceneState
                else -> fromState ?: toState
            }
        )
@@ -1409,7 +1418,13 @@ private inline fun <T> computeValue(
    val rangeProgress = transformation.range?.progress(progress) ?: progress

    // Interpolate between the value at rest and the value before entering/after leaving.
    val isEntering = content == toContent
    val isEntering =
        when {
            content == toContent -> true
            content == fromContent -> false
            content == transition.currentScene -> toState == null
            else -> content == toContent
        }
    return if (isEntering) {
        lerp(targetValue, idleValue, rangeProgress)
    } else {
+79 −0
Original line number Diff line number Diff line
@@ -653,6 +653,85 @@ class OverlayTest {
        }
    }

    @Test
    fun replaceAnimation_elementInCurrentSceneAndOneOverlay_sharedElementDisabled() {
        rule.testReplaceOverlayTransition(
            currentSceneContent = {
                Box(Modifier.size(width = 180.dp, height = 120.dp)) {
                    Foo(width = 60.dp, height = 40.dp)
                }
            },
            fromContent = {},
            fromAlignment = Alignment.TopStart,
            toContent = { Foo(width = 100.dp, height = 80.dp) },
            transition = {
                // 4 frames of animation
                spec = tween(4 * 16, easing = LinearEasing)

                // Scale Foo to/from size 0 in each content instead of sharing it.
                sharedElement(TestElements.Foo, enabled = false)
                scaleSize(TestElements.Foo, width = 0f, height = 0f)
            },
        ) {
            before {
                rule
                    .onNode(isElement(TestElements.Foo, content = SceneA))
                    .assertSizeIsEqualTo(60.dp, 40.dp)
                    .assertPositionInRootIsEqualTo(0.dp, 0.dp)
                rule.onNode(isElement(TestElements.Foo, content = OverlayA)).assertDoesNotExist()
                rule.onNode(isElement(TestElements.Foo, content = OverlayB)).assertDoesNotExist()
            }

            at(16) {
                rule
                    .onNode(isElement(TestElements.Foo, content = SceneA))
                    .assertSizeIsEqualTo(45.dp, 30.dp)
                    .assertPositionInRootIsEqualTo(0.dp, 0.dp)
                rule.onNode(isElement(TestElements.Foo, content = OverlayA)).assertDoesNotExist()
                rule
                    .onNode(isElement(TestElements.Foo, content = OverlayB))
                    .assertSizeIsEqualTo(25.dp, 20.dp)
                    .assertPositionInRootIsEqualTo(((180 - 25) / 2f).dp, ((120 - 20) / 2f).dp)
            }

            at(32) {
                rule
                    .onNode(isElement(TestElements.Foo, content = SceneA))
                    .assertSizeIsEqualTo(30.dp, 20.dp)
                    .assertPositionInRootIsEqualTo(0.dp, 0.dp)
                rule.onNode(isElement(TestElements.Foo, content = OverlayA)).assertDoesNotExist()
                rule
                    .onNode(isElement(TestElements.Foo, content = OverlayB))
                    .assertSizeIsEqualTo(50.dp, 40.dp)
                    .assertPositionInRootIsEqualTo(((180 - 50) / 2f).dp, ((120 - 40) / 2f).dp)
            }

            at(48) {
                rule
                    .onNode(isElement(TestElements.Foo, content = SceneA))
                    .assertSizeIsEqualTo(15.dp, 10.dp)
                    .assertPositionInRootIsEqualTo(0.dp, 0.dp)
                rule.onNode(isElement(TestElements.Foo, content = OverlayA)).assertDoesNotExist()
                rule
                    .onNode(isElement(TestElements.Foo, content = OverlayB))
                    .assertSizeIsEqualTo(75.dp, 60.dp)
                    .assertPositionInRootIsEqualTo(((180 - 75) / 2f).dp, ((120 - 60) / 2f).dp)
            }

            after {
                rule
                    .onNode(isElement(TestElements.Foo, content = SceneA))
                    .assertExists()
                    .assertIsNotDisplayed()
                rule.onNode(isElement(TestElements.Foo, content = OverlayA)).assertDoesNotExist()
                rule
                    .onNode(isElement(TestElements.Foo, content = OverlayB))
                    .assertSizeIsEqualTo(100.dp, 80.dp)
                    .assertPositionInRootIsEqualTo(40.dp, 20.dp)
            }
        }
    }

    @Test
    fun overscrollingOverlay_movableElementNotInOverlay() {
        val state =