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

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

Merge "Ensure that movable elements are composed even when not in a transition" into main

parents de7b2e27 e9407837
Loading
Loading
Loading
Loading
+4 −14
Original line number Diff line number Diff line
@@ -350,8 +350,7 @@ internal class ElementNode(
            val placeInThisContent =
                elementContentWhenIdle(
                    layoutImpl,
                    currentState.currentScene,
                    currentState.currentOverlays,
                    currentState,
                    isInContent = { it in element.stateByContent },
                ) == content.key

@@ -639,20 +638,11 @@ internal inline fun elementState(

internal inline fun elementContentWhenIdle(
    layoutImpl: SceneTransitionLayoutImpl,
    idle: TransitionState.Idle,
    isInContent: (ContentKey) -> Boolean,
): ContentKey {
    val currentScene = idle.currentScene
    val overlays = idle.currentOverlays
    return elementContentWhenIdle(layoutImpl, currentScene, overlays, isInContent)
}

private inline fun elementContentWhenIdle(
    layoutImpl: SceneTransitionLayoutImpl,
    currentScene: SceneKey,
    overlays: Set<OverlayKey>,
    currentState: TransitionState,
    isInContent: (ContentKey) -> Boolean,
): ContentKey {
    val currentScene = currentState.currentScene
    val overlays = currentState.currentOverlays
    if (overlays.isEmpty()) {
        return currentScene
    }
+4 −2
Original line number Diff line number Diff line
@@ -188,7 +188,9 @@ private fun shouldComposeMovableElement(
    return when (
        val elementState = movableElementState(element, layoutImpl.state.transitionStates)
    ) {
        null -> false
        null ->
            movableElementContentWhenIdle(layoutImpl, element, layoutImpl.state.transitionState) ==
                content
        is TransitionState.Idle ->
            movableElementContentWhenIdle(layoutImpl, element, elementState) == content
        is TransitionState.Transition -> {
@@ -217,7 +219,7 @@ private fun movableElementState(
private fun movableElementContentWhenIdle(
    layoutImpl: SceneTransitionLayoutImpl,
    element: MovableElementKey,
    elementState: TransitionState.Idle,
    elementState: TransitionState,
): ContentKey {
    val contents = element.contentPicker.contents
    return elementContentWhenIdle(layoutImpl, elementState, isInContent = { contents.contains(it) })
+37 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsNotDisplayed
import androidx.compose.ui.test.assertPositionInRootIsEqualTo
import androidx.compose.ui.test.hasParent
import androidx.compose.ui.test.hasTestTag
import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onAllNodesWithText
@@ -404,4 +405,40 @@ class MovableElementTest {
        rule.waitForIdle()
        rule.onNodeWithTag(fooParentInOverlayTag).assertSizeIsEqualTo(fooSize)
    }

    @Test
    fun movableElementInOverlayShouldBeComposed() {
        val fooKey = MovableElementKey("foo", contents = setOf(OverlayA))
        val fooContentTag = "fooContentTag"

        @Composable
        fun ContentScope.MovableFoo(modifier: Modifier = Modifier) {
            MovableElement(fooKey, modifier) {
                content { Box(Modifier.testTag(fooContentTag).size(100.dp)) }
            }
        }

        val state =
            rule.runOnUiThread {
                MutableSceneTransitionLayoutState(
                    initialScene = SceneA,
                    initialOverlays = setOf(OverlayA),
                )
            }

        val scope =
            rule.setContentAndCreateMainScope {
                SceneTransitionLayout(state) {
                    scene(SceneA) { Box(Modifier.fillMaxSize()) }
                    overlay(OverlayA) { MovableFoo() }
                    overlay(OverlayB) { Box(Modifier.size(50.dp)) }
                }
            }

        rule.onNode(hasTestTag(fooContentTag)).assertIsDisplayed().assertSizeIsEqualTo(100.dp)

        // Show overlay B. This shouldn't have any impact on Foo that should still be composed in A.
        scope.launch { state.startTransition(transition(SceneA, OverlayB)) }
        rule.onNode(hasTestTag(fooContentTag)).assertIsDisplayed().assertSizeIsEqualTo(100.dp)
    }
}