Loading packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateContent.kt +4 −4 Original line number Diff line number Diff line Loading @@ -26,15 +26,15 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.launch internal fun CoroutineScope.animateContent( layoutState: MutableSceneTransitionLayoutStateImpl, transition: TransitionState.Transition, oneOffAnimation: OneOffAnimation, targetProgress: Float, startTransition: () -> Unit, finishTransition: () -> Unit, chain: Boolean = true, ) { // Start the transition. This will compute the TransformationSpec associated to [transition], // which we need to initialize the Animatable that will actually animate it. startTransition() layoutState.startTransition(transition, chain) // The transition now contains the transformation spec that we should use to instantiate the // Animatable. Loading @@ -59,7 +59,7 @@ internal fun CoroutineScope.animateContent( try { animatable.animateTo(targetProgress, animationSpec, initialVelocity) } finally { finishTransition() layoutState.finishTransition(transition) } } } Loading packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateOverlay.kt 0 → 100644 +144 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.compose.animation.scene import com.android.compose.animation.scene.content.state.TransitionState import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job /** Trigger a one-off transition to show or hide an overlay. */ internal fun CoroutineScope.showOrHideOverlay( layoutState: MutableSceneTransitionLayoutStateImpl, overlay: OverlayKey, fromOrToScene: SceneKey, isShowing: Boolean, transitionKey: TransitionKey?, replacedTransition: TransitionState.Transition.ShowOrHideOverlay?, reversed: Boolean, ): TransitionState.Transition.ShowOrHideOverlay { val targetProgress = if (reversed) 0f else 1f val (fromContent, toContent) = if (isShowing xor reversed) { fromOrToScene to overlay } else { overlay to fromOrToScene } val oneOffAnimation = OneOffAnimation() val transition = OneOffShowOrHideOverlayTransition( overlay = overlay, fromOrToScene = fromOrToScene, fromContent = fromContent, toContent = toContent, isEffectivelyShown = isShowing, key = transitionKey, replacedTransition = replacedTransition, oneOffAnimation = oneOffAnimation, ) animateContent( layoutState = layoutState, transition = transition, oneOffAnimation = oneOffAnimation, targetProgress = targetProgress, ) return transition } /** Trigger a one-off transition to replace an overlay by another one. */ internal fun CoroutineScope.replaceOverlay( layoutState: MutableSceneTransitionLayoutStateImpl, fromOverlay: OverlayKey, toOverlay: OverlayKey, transitionKey: TransitionKey?, replacedTransition: TransitionState.Transition.ReplaceOverlay?, reversed: Boolean, ): TransitionState.Transition.ReplaceOverlay { val targetProgress = if (reversed) 0f else 1f val effectivelyShownOverlay = if (reversed) fromOverlay else toOverlay val oneOffAnimation = OneOffAnimation() val transition = OneOffOverlayReplacingTransition( fromOverlay = fromOverlay, toOverlay = toOverlay, effectivelyShownOverlay = effectivelyShownOverlay, key = transitionKey, replacedTransition = replacedTransition, oneOffAnimation = oneOffAnimation, ) animateContent( layoutState = layoutState, transition = transition, oneOffAnimation = oneOffAnimation, targetProgress = targetProgress, ) return transition } private class OneOffShowOrHideOverlayTransition( overlay: OverlayKey, fromOrToScene: SceneKey, fromContent: ContentKey, toContent: ContentKey, override val isEffectivelyShown: Boolean, override val key: TransitionKey?, replacedTransition: TransitionState.Transition?, private val oneOffAnimation: OneOffAnimation, ) : TransitionState.Transition.ShowOrHideOverlay( overlay, fromOrToScene, fromContent, toContent, replacedTransition, ) { override val progress: Float get() = oneOffAnimation.progress override val progressVelocity: Float get() = oneOffAnimation.progressVelocity override val isInitiatedByUserInput: Boolean = false override val isUserInputOngoing: Boolean = false override fun finish(): Job = oneOffAnimation.finish() } private class OneOffOverlayReplacingTransition( fromOverlay: OverlayKey, toOverlay: OverlayKey, override val effectivelyShownOverlay: OverlayKey, override val key: TransitionKey?, replacedTransition: TransitionState.Transition?, private val oneOffAnimation: OneOffAnimation, ) : TransitionState.Transition.ReplaceOverlay(fromOverlay, toOverlay, replacedTransition) { override val progress: Float get() = oneOffAnimation.progress override val progressVelocity: Float get() = oneOffAnimation.progressVelocity override val isInitiatedByUserInput: Boolean = false override val isUserInputOngoing: Boolean = false override fun finish(): Job = oneOffAnimation.finish() } packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt +1 −1 Original line number Diff line number Diff line Loading @@ -412,7 +412,7 @@ private class AnimatedStateImpl<T, Delta>( if (canOverflow) transition.progress else transition.progress.fastCoerceIn(0f, 1f) } overscrollSpec.scene == transition.toContent -> 1f overscrollSpec.content == transition.toContent -> 1f else -> 0f } Loading packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt +2 −2 Original line number Diff line number Diff line Loading @@ -166,11 +166,11 @@ private fun CoroutineScope.animateToScene( } animateContent( layoutState = layoutState, transition = transition, oneOffAnimation = oneOffAnimation, targetProgress = targetProgress, startTransition = { layoutState.startTransition(transition, chain) }, finishTransition = { layoutState.finishTransition(transition) }, chain = chain, ) return transition Loading packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt +7 −6 Original line number Diff line number Diff line Loading @@ -310,9 +310,10 @@ internal class ElementNode( val transition = elementState as? TransitionState.Transition // If this element is not supposed to be laid out now because the other content of its // transition is overscrolling, then lay out the element normally and don't place it. val overscrollScene = transition?.currentOverscrollSpec?.scene // If this element is not supposed to be laid out now, either because it is not part of any // ongoing transition or the other content of its transition is overscrolling, then lay out // the element normally and don't place it. val overscrollScene = transition?.currentOverscrollSpec?.content val isOtherSceneOverscrolling = overscrollScene != null && overscrollScene != content.key if (isOtherSceneOverscrolling) { return doNotPlace(measurable, constraints) Loading Loading @@ -845,7 +846,7 @@ internal fun shouldPlaceOrComposeSharedElement( transition: TransitionState.Transition, ): Boolean { // If we are overscrolling, only place/compose the element in the overscrolling scene. val overscrollScene = transition.currentOverscrollSpec?.scene val overscrollScene = transition.currentOverscrollSpec?.content if (overscrollScene != null) { return content == overscrollScene } Loading Loading @@ -1184,7 +1185,7 @@ private inline fun <T> computeValue( val currentContent = currentContentState.content if (transition is TransitionState.HasOverscrollProperties) { val overscroll = transition.currentOverscrollSpec if (overscroll?.scene == currentContent) { if (overscroll?.content == currentContent) { val elementSpec = overscroll.transformationSpec.transformations(element.key, currentContent) val propertySpec = transformation(elementSpec) ?: return currentValue() Loading @@ -1210,7 +1211,7 @@ private inline fun <T> computeValue( // TODO(b/290184746): Make sure that we don't overflow transformations associated to a // range. val directionSign = if (transition.isUpOrLeft) -1 else 1 val isToContent = overscroll.scene == transition.toContent val isToContent = overscroll.content == transition.toContent val linearProgress = transition.progress.let { if (isToContent) it - 1f else it } val progressConverter = overscroll.progressConverter Loading Loading
packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateContent.kt +4 −4 Original line number Diff line number Diff line Loading @@ -26,15 +26,15 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.launch internal fun CoroutineScope.animateContent( layoutState: MutableSceneTransitionLayoutStateImpl, transition: TransitionState.Transition, oneOffAnimation: OneOffAnimation, targetProgress: Float, startTransition: () -> Unit, finishTransition: () -> Unit, chain: Boolean = true, ) { // Start the transition. This will compute the TransformationSpec associated to [transition], // which we need to initialize the Animatable that will actually animate it. startTransition() layoutState.startTransition(transition, chain) // The transition now contains the transformation spec that we should use to instantiate the // Animatable. Loading @@ -59,7 +59,7 @@ internal fun CoroutineScope.animateContent( try { animatable.animateTo(targetProgress, animationSpec, initialVelocity) } finally { finishTransition() layoutState.finishTransition(transition) } } } Loading
packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateOverlay.kt 0 → 100644 +144 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.compose.animation.scene import com.android.compose.animation.scene.content.state.TransitionState import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job /** Trigger a one-off transition to show or hide an overlay. */ internal fun CoroutineScope.showOrHideOverlay( layoutState: MutableSceneTransitionLayoutStateImpl, overlay: OverlayKey, fromOrToScene: SceneKey, isShowing: Boolean, transitionKey: TransitionKey?, replacedTransition: TransitionState.Transition.ShowOrHideOverlay?, reversed: Boolean, ): TransitionState.Transition.ShowOrHideOverlay { val targetProgress = if (reversed) 0f else 1f val (fromContent, toContent) = if (isShowing xor reversed) { fromOrToScene to overlay } else { overlay to fromOrToScene } val oneOffAnimation = OneOffAnimation() val transition = OneOffShowOrHideOverlayTransition( overlay = overlay, fromOrToScene = fromOrToScene, fromContent = fromContent, toContent = toContent, isEffectivelyShown = isShowing, key = transitionKey, replacedTransition = replacedTransition, oneOffAnimation = oneOffAnimation, ) animateContent( layoutState = layoutState, transition = transition, oneOffAnimation = oneOffAnimation, targetProgress = targetProgress, ) return transition } /** Trigger a one-off transition to replace an overlay by another one. */ internal fun CoroutineScope.replaceOverlay( layoutState: MutableSceneTransitionLayoutStateImpl, fromOverlay: OverlayKey, toOverlay: OverlayKey, transitionKey: TransitionKey?, replacedTransition: TransitionState.Transition.ReplaceOverlay?, reversed: Boolean, ): TransitionState.Transition.ReplaceOverlay { val targetProgress = if (reversed) 0f else 1f val effectivelyShownOverlay = if (reversed) fromOverlay else toOverlay val oneOffAnimation = OneOffAnimation() val transition = OneOffOverlayReplacingTransition( fromOverlay = fromOverlay, toOverlay = toOverlay, effectivelyShownOverlay = effectivelyShownOverlay, key = transitionKey, replacedTransition = replacedTransition, oneOffAnimation = oneOffAnimation, ) animateContent( layoutState = layoutState, transition = transition, oneOffAnimation = oneOffAnimation, targetProgress = targetProgress, ) return transition } private class OneOffShowOrHideOverlayTransition( overlay: OverlayKey, fromOrToScene: SceneKey, fromContent: ContentKey, toContent: ContentKey, override val isEffectivelyShown: Boolean, override val key: TransitionKey?, replacedTransition: TransitionState.Transition?, private val oneOffAnimation: OneOffAnimation, ) : TransitionState.Transition.ShowOrHideOverlay( overlay, fromOrToScene, fromContent, toContent, replacedTransition, ) { override val progress: Float get() = oneOffAnimation.progress override val progressVelocity: Float get() = oneOffAnimation.progressVelocity override val isInitiatedByUserInput: Boolean = false override val isUserInputOngoing: Boolean = false override fun finish(): Job = oneOffAnimation.finish() } private class OneOffOverlayReplacingTransition( fromOverlay: OverlayKey, toOverlay: OverlayKey, override val effectivelyShownOverlay: OverlayKey, override val key: TransitionKey?, replacedTransition: TransitionState.Transition?, private val oneOffAnimation: OneOffAnimation, ) : TransitionState.Transition.ReplaceOverlay(fromOverlay, toOverlay, replacedTransition) { override val progress: Float get() = oneOffAnimation.progress override val progressVelocity: Float get() = oneOffAnimation.progressVelocity override val isInitiatedByUserInput: Boolean = false override val isUserInputOngoing: Boolean = false override fun finish(): Job = oneOffAnimation.finish() }
packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt +1 −1 Original line number Diff line number Diff line Loading @@ -412,7 +412,7 @@ private class AnimatedStateImpl<T, Delta>( if (canOverflow) transition.progress else transition.progress.fastCoerceIn(0f, 1f) } overscrollSpec.scene == transition.toContent -> 1f overscrollSpec.content == transition.toContent -> 1f else -> 0f } Loading
packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt +2 −2 Original line number Diff line number Diff line Loading @@ -166,11 +166,11 @@ private fun CoroutineScope.animateToScene( } animateContent( layoutState = layoutState, transition = transition, oneOffAnimation = oneOffAnimation, targetProgress = targetProgress, startTransition = { layoutState.startTransition(transition, chain) }, finishTransition = { layoutState.finishTransition(transition) }, chain = chain, ) return transition Loading
packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt +7 −6 Original line number Diff line number Diff line Loading @@ -310,9 +310,10 @@ internal class ElementNode( val transition = elementState as? TransitionState.Transition // If this element is not supposed to be laid out now because the other content of its // transition is overscrolling, then lay out the element normally and don't place it. val overscrollScene = transition?.currentOverscrollSpec?.scene // If this element is not supposed to be laid out now, either because it is not part of any // ongoing transition or the other content of its transition is overscrolling, then lay out // the element normally and don't place it. val overscrollScene = transition?.currentOverscrollSpec?.content val isOtherSceneOverscrolling = overscrollScene != null && overscrollScene != content.key if (isOtherSceneOverscrolling) { return doNotPlace(measurable, constraints) Loading Loading @@ -845,7 +846,7 @@ internal fun shouldPlaceOrComposeSharedElement( transition: TransitionState.Transition, ): Boolean { // If we are overscrolling, only place/compose the element in the overscrolling scene. val overscrollScene = transition.currentOverscrollSpec?.scene val overscrollScene = transition.currentOverscrollSpec?.content if (overscrollScene != null) { return content == overscrollScene } Loading Loading @@ -1184,7 +1185,7 @@ private inline fun <T> computeValue( val currentContent = currentContentState.content if (transition is TransitionState.HasOverscrollProperties) { val overscroll = transition.currentOverscrollSpec if (overscroll?.scene == currentContent) { if (overscroll?.content == currentContent) { val elementSpec = overscroll.transformationSpec.transformations(element.key, currentContent) val propertySpec = transformation(elementSpec) ?: return currentValue() Loading @@ -1210,7 +1211,7 @@ private inline fun <T> computeValue( // TODO(b/290184746): Make sure that we don't overflow transformations associated to a // range. val directionSign = if (transition.isUpOrLeft) -1 else 1 val isToContent = overscroll.scene == transition.toContent val isToContent = overscroll.content == transition.toContent val linearProgress = transition.progress.let { if (isToContent) it - 1f else it } val progressConverter = overscroll.progressConverter Loading