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

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

Merge "Expose ElementKey.currentAlpha() in ContentScope" into main

parents 47ca0de2 593cfcf1
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -692,7 +692,7 @@ internal class ElementNode(
}

/** The [TransitionState] that we should consider for [element]. */
private fun elementState(
internal fun elementState(
    layoutImpl: SceneTransitionLayoutImpl,
    element: Element,
    transitionStates: List<List<TransitionState>>,
@@ -1127,7 +1127,7 @@ private fun isElementOpaque(
 * [isElementOpaque] is checked during placement and we don't want to read the transition progress
 * in that phase.
 */
private fun elementAlpha(
internal fun elementAlpha(
    layoutImpl: SceneTransitionLayoutImpl,
    element: Element,
    transition: TransitionState.Transition?,
+9 −0
Original line number Diff line number Diff line
@@ -312,6 +312,15 @@ interface BaseContentScope : ElementStateScope {
    fun Modifier.disableSwipesWhenScrolling(
        bounds: NestedScrollableBound = NestedScrollableBound.Any
    ): Modifier

    /**
     * Return the alpha of [this] element in this content, given the current transition state and
     * transition transformations (e.g. fade).
     *
     * Important: This should *not* be read during composition and should instead be read during
     * layout, drawing or in a LaunchedEffect.
     */
    fun ElementKey.currentAlpha(): Float?
}

@Stable
+14 −0
Original line number Diff line number Diff line
@@ -76,8 +76,12 @@ import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
import com.android.compose.animation.scene.ValueKey
import com.android.compose.animation.scene.animateSharedValueAsState
import com.android.compose.animation.scene.content.state.TransitionState
import com.android.compose.animation.scene.effect.GestureEffect
import com.android.compose.animation.scene.element
import com.android.compose.animation.scene.elementAlpha
import com.android.compose.animation.scene.elementState
import com.android.compose.animation.scene.getAllNestedTransitionStates
import com.android.compose.animation.scene.modifiers.noResizeDuringTransitions
import com.android.compose.gesture.NestedScrollControlState
import com.android.compose.gesture.NestedScrollableBound
@@ -422,6 +426,16 @@ internal class ContentScopeImpl(
                it.fromContent == content || it.toContent == content
            }
    }

    override fun ElementKey.currentAlpha(): Float? {
        val element = layoutImpl.elements[this] ?: return null
        val stateInContent = element.stateByContent[contentKey] ?: return null
        val elementState =
            elementState(layoutImpl, element, getAllNestedTransitionStates(layoutImpl))
                ?: return null
        val transition = elementState as? TransitionState.Transition
        return elementAlpha(layoutImpl, element, transition, stateInContent)
    }
}

/** A [LifecycleOwner] that follows its [parentLifecycle] but is capped at [maxLifecycleState]. */
+53 −0
Original line number Diff line number Diff line
@@ -24,11 +24,13 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.platform.LocalViewConfiguration
@@ -380,4 +382,55 @@ class ContentTest {
        assertThat(nestedMiddle.ancestors).containsExactly(outerState)
        assertThat(nestedInner.ancestors).containsExactly(outerState, middleState).inOrder()
    }

    @Test
    fun currentElementAlpha() {
        var lastAlpha: Float? = null

        val state =
            rule.runOnUiThread {
                MutableSceneTransitionLayoutStateForTests(
                    SceneA,
                    transitions =
                        transitions { from(SceneA, to = SceneB) { fade(TestElements.Foo) } },
                )
            }
        val scope =
            rule.setContentAndCreateMainScope {
                SceneTransitionLayout(state) {
                    scene(SceneA) {}
                    scene(SceneB) {
                        LaunchedEffect(Unit) {
                            snapshotFlow { TestElements.Foo.currentAlpha() }
                                .collect { lastAlpha = it }
                        }

                        Box(Modifier.element(TestElements.Foo).fillMaxSize())
                    }
                }
            }

        assertThat(lastAlpha).isNull()

        var progress by mutableStateOf(0f)
        scope.launch { state.startTransition(transition(SceneA, SceneB, progress = { progress })) }
        rule.waitForIdle()
        assertThat(lastAlpha).isWithin(0.01f).of(0f)

        progress = 0.25f
        rule.waitForIdle()
        assertThat(lastAlpha).isWithin(0.01f).of(0.25f)

        progress = 0.5f
        rule.waitForIdle()
        assertThat(lastAlpha).isWithin(0.01f).of(0.5f)

        progress = 0.75f
        rule.waitForIdle()
        assertThat(lastAlpha).isWithin(0.01f).of(0.75f)

        progress = 1f
        rule.waitForIdle()
        assertThat(lastAlpha).isWithin(0.01f).of(1f)
    }
}