Loading packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt +2 −2 Original line number Diff line number Diff line Loading @@ -387,11 +387,11 @@ internal class MutableSceneTransitionLayoutStateImpl( transition.transformationSpec = transitions .transitionSpec(fromContent, toContent, key = transition.key) .transformationSpec() .transformationSpec(transition) transition.previewTransformationSpec = transitions .transitionSpec(fromContent, toContent, key = transition.key) .previewTransformationSpec() .previewTransformationSpec(transition) if (orientation != null) { transition.updateOverscrollSpecs( fromSpec = transitions.overscrollSpec(fromContent, orientation), Loading packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt +22 −13 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import androidx.compose.foundation.gestures.Orientation 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 Loading Loading @@ -191,20 +192,21 @@ interface TransitionSpec { fun reversed(): TransitionSpec /** * The [TransformationSpec] associated to this [TransitionSpec]. * The [TransformationSpec] associated to this [TransitionSpec] for the given [transition]. * * Note that this is called once whenever a transition associated to this [TransitionSpec] is * started. */ fun transformationSpec(): TransformationSpec fun transformationSpec(transition: TransitionState.Transition): TransformationSpec /** * The preview [TransformationSpec] associated to this [TransitionSpec]. * The preview [TransformationSpec] associated to this [TransitionSpec] for the given * [transition]. * * Note that this is called once whenever a transition associated to this [TransitionSpec] is * started. */ fun previewTransformationSpec(): TransformationSpec? fun previewTransformationSpec(transition: TransitionState.Transition): TransformationSpec? } interface TransformationSpec { Loading Loading @@ -241,7 +243,7 @@ interface TransformationSpec { distance = null, transformations = emptyList(), ) internal val EmptyProvider = { Empty } internal val EmptyProvider = { _: TransitionState.Transition -> Empty } } } Loading @@ -249,9 +251,13 @@ internal class TransitionSpecImpl( override val key: TransitionKey?, override val from: ContentKey?, override val to: ContentKey?, private val previewTransformationSpec: (() -> TransformationSpecImpl)? = null, private val reversePreviewTransformationSpec: (() -> TransformationSpecImpl)? = null, private val transformationSpec: () -> TransformationSpecImpl, private val previewTransformationSpec: ((TransitionState.Transition) -> TransformationSpecImpl)? = null, private val reversePreviewTransformationSpec: ((TransitionState.Transition) -> TransformationSpecImpl)? = null, private val transformationSpec: (TransitionState.Transition) -> TransformationSpecImpl, ) : TransitionSpec { override fun reversed(): TransitionSpecImpl { return TransitionSpecImpl( Loading @@ -260,8 +266,8 @@ internal class TransitionSpecImpl( to = from, previewTransformationSpec = reversePreviewTransformationSpec, reversePreviewTransformationSpec = previewTransformationSpec, transformationSpec = { val reverse = transformationSpec.invoke() transformationSpec = { transition -> val reverse = transformationSpec.invoke(transition) TransformationSpecImpl( progressSpec = reverse.progressSpec, swipeSpec = reverse.swipeSpec, Loading @@ -272,10 +278,13 @@ internal class TransitionSpecImpl( ) } override fun transformationSpec(): TransformationSpecImpl = this.transformationSpec.invoke() override fun transformationSpec( transition: TransitionState.Transition ): TransformationSpecImpl = transformationSpec.invoke(transition) override fun previewTransformationSpec(): TransformationSpecImpl? = previewTransformationSpec?.invoke() override fun previewTransformationSpec( transition: TransitionState.Transition ): TransformationSpecImpl? = previewTransformationSpec?.invoke(transition) } /** The definition of the overscroll behavior of the [content]. */ Loading packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt +3 −0 Original line number Diff line number Diff line Loading @@ -156,6 +156,9 @@ interface BaseTransitionBuilder : PropertyTransformationBuilder { @TransitionDsl interface TransitionBuilder : BaseTransitionBuilder { /** The [TransitionState.Transition] for which we currently compute the transformations. */ val transition: TransitionState.Transition /** * The [AnimationSpec] used to animate the associated transition progress from `0` to `1` when * the transition is triggered (i.e. it is not gesture-based). Loading packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt +12 −9 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import androidx.compose.animation.core.spring import androidx.compose.foundation.gestures.Orientation import androidx.compose.ui.geometry.Offset 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.DrawScale Loading Loading @@ -128,8 +129,11 @@ private class SceneTransitionsBuilderImpl : SceneTransitionsBuilder { reversePreview: (TransitionBuilder.() -> Unit)?, builder: TransitionBuilder.() -> Unit, ): TransitionSpec { fun transformationSpec(builder: TransitionBuilder.() -> Unit): TransformationSpecImpl { val impl = TransitionBuilderImpl().apply(builder) fun transformationSpec( transition: TransitionState.Transition, builder: TransitionBuilder.() -> Unit, ): TransformationSpecImpl { val impl = TransitionBuilderImpl(transition).apply(builder) return TransformationSpecImpl( progressSpec = impl.spec, swipeSpec = impl.swipeSpec, Loading @@ -138,17 +142,15 @@ private class SceneTransitionsBuilderImpl : SceneTransitionsBuilder { ) } val previewTransformationSpec = preview?.let { { transformationSpec(it) } } val reversePreviewTransformationSpec = reversePreview?.let { { transformationSpec(it) } } val transformationSpec = { transformationSpec(builder) } val spec = TransitionSpecImpl( key, from, to, previewTransformationSpec, reversePreviewTransformationSpec, transformationSpec, previewTransformationSpec = preview?.let { { t -> transformationSpec(t, it) } }, reversePreviewTransformationSpec = reversePreview?.let { { t -> transformationSpec(t, it) } }, transformationSpec = { t -> transformationSpec(t, builder) }, ) transitionSpecs.add(spec) return spec Loading Loading @@ -227,7 +229,8 @@ internal abstract class BaseTransitionBuilderImpl : BaseTransitionBuilder { } } internal class TransitionBuilderImpl : BaseTransitionBuilderImpl(), TransitionBuilder { internal class TransitionBuilderImpl(override val transition: TransitionState.Transition) : BaseTransitionBuilderImpl(), TransitionBuilder { override var spec: AnimationSpec<Float> = spring(stiffness = Spring.StiffnessLow) override var swipeSpec: SpringSpec<Float>? = null override var distance: UserActionDistance? = null Loading packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt +63 −48 Original line number Diff line number Diff line Loading @@ -23,11 +23,17 @@ import androidx.compose.animation.core.spring import androidx.compose.animation.core.tween import androidx.compose.foundation.gestures.Orientation import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.compose.animation.scene.TestScenes.SceneA import com.android.compose.animation.scene.TestScenes.SceneB import com.android.compose.animation.scene.TestScenes.SceneC import com.android.compose.animation.scene.content.state.TransitionState import com.android.compose.animation.scene.transformation.OverscrollTranslate import com.android.compose.animation.scene.transformation.Transformation import com.android.compose.animation.scene.transformation.TransformationRange import com.android.compose.test.transition import com.google.common.truth.Correspondence import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.test.runTest import org.junit.Assert.assertThrows import org.junit.Test import org.junit.runner.RunWith Loading @@ -43,9 +49,9 @@ class TransitionDslTest { @Test fun manyTransitions() { val transitions = transitions { from(TestScenes.SceneA, to = TestScenes.SceneB) from(TestScenes.SceneB, to = TestScenes.SceneC) from(TestScenes.SceneC, to = TestScenes.SceneA) from(SceneA, to = SceneB) from(SceneB, to = SceneC) from(SceneC, to = SceneA) } assertThat(transitions.transitionSpecs).hasSize(3) } Loading @@ -53,9 +59,9 @@ class TransitionDslTest { @Test fun toFromBuilders() { val transitions = transitions { from(TestScenes.SceneA, to = TestScenes.SceneB) from(TestScenes.SceneB) to(TestScenes.SceneC) from(SceneA, to = SceneB) from(SceneB) to(SceneC) } assertThat(transitions.transitionSpecs) Loading @@ -65,38 +71,34 @@ class TransitionDslTest { "has (from, to) equal to", ) ) .containsExactly( TestScenes.SceneA to TestScenes.SceneB, TestScenes.SceneB to null, null to TestScenes.SceneC, ) .containsExactly(SceneA to SceneB, SceneB to null, null to SceneC) } private fun aToB() = transition(SceneA, SceneB) @Test fun defaultTransitionSpec() { val transitions = transitions { from(TestScenes.SceneA, to = TestScenes.SceneB) } val transformationSpec = transitions.transitionSpecs.single().transformationSpec() val transitions = transitions { from(SceneA, to = SceneB) } val transformationSpec = transitions.transitionSpecs.single().transformationSpec(aToB()) assertThat(transformationSpec.progressSpec).isInstanceOf(SpringSpec::class.java) } @Test fun customTransitionSpec() { val transitions = transitions { from(TestScenes.SceneA, to = TestScenes.SceneB) { spec = tween(durationMillis = 42) } from(SceneA, to = SceneB) { spec = tween(durationMillis = 42) } } val transformationSpec = transitions.transitionSpecs.single().transformationSpec() val transformationSpec = transitions.transitionSpecs.single().transformationSpec(aToB()) assertThat(transformationSpec.progressSpec).isInstanceOf(TweenSpec::class.java) assertThat((transformationSpec.progressSpec as TweenSpec).durationMillis).isEqualTo(42) } @Test fun defaultRange() { val transitions = transitions { from(TestScenes.SceneA, to = TestScenes.SceneB) { fade(TestElements.Foo) } } val transitions = transitions { from(SceneA, to = SceneB) { fade(TestElements.Foo) } } val transformations = transitions.transitionSpecs.single().transformationSpec().transformations transitions.transitionSpecs.single().transformationSpec(aToB()).transformations assertThat(transformations.size).isEqualTo(1) assertThat(transformations.single().range).isEqualTo(null) } Loading @@ -104,7 +106,7 @@ class TransitionDslTest { @Test fun fractionRange() { val transitions = transitions { from(TestScenes.SceneA, to = TestScenes.SceneB) { from(SceneA, to = SceneB) { fractionRange(start = 0.1f, end = 0.8f) { fade(TestElements.Foo) } fractionRange(start = 0.2f) { fade(TestElements.Foo) } fractionRange(end = 0.9f) { fade(TestElements.Foo) } Loading @@ -119,7 +121,7 @@ class TransitionDslTest { } val transformations = transitions.transitionSpecs.single().transformationSpec().transformations transitions.transitionSpecs.single().transformationSpec(aToB()).transformations assertThat(transformations) .comparingElementsUsing(TRANSFORMATION_RANGE) .containsExactly( Loading @@ -133,7 +135,7 @@ class TransitionDslTest { @Test fun timestampRange() { val transitions = transitions { from(TestScenes.SceneA, to = TestScenes.SceneB) { from(SceneA, to = SceneB) { spec = tween(500) timestampRange(startMillis = 100, endMillis = 300) { fade(TestElements.Foo) } Loading @@ -150,7 +152,7 @@ class TransitionDslTest { } val transformations = transitions.transitionSpecs.single().transformationSpec().transformations transitions.transitionSpecs.single().transformationSpec(aToB()).transformations assertThat(transformations) .comparingElementsUsing(TRANSFORMATION_RANGE) .containsExactly( Loading @@ -168,7 +170,7 @@ class TransitionDslTest { @Test fun reversed() { val transitions = transitions { from(TestScenes.SceneA, to = TestScenes.SceneB) { from(SceneA, to = SceneB) { spec = tween(500) reversed { fractionRange(start = 0.1f, end = 0.8f) { fade(TestElements.Foo) } Loading @@ -178,7 +180,7 @@ class TransitionDslTest { } val transformations = transitions.transitionSpecs.single().transformationSpec().transformations transitions.transitionSpecs.single().transformationSpec(aToB()).transformations assertThat(transformations) .comparingElementsUsing(TRANSFORMATION_RANGE) .containsExactly( Loading @@ -191,8 +193,8 @@ class TransitionDslTest { fun defaultReversed() { val transitions = transitions { from( TestScenes.SceneA, to = TestScenes.SceneB, SceneA, to = SceneB, preview = { fractionRange(start = 0.1f, end = 0.8f) { fade(TestElements.Foo) } }, reversePreview = { fractionRange(start = 0.5f, end = 0.6f) { fade(TestElements.Foo) } Loading @@ -206,10 +208,9 @@ class TransitionDslTest { // Fetch the transition from B to A, which will automatically reverse the transition from A // to B we defined. val transitionSpec = transitions.transitionSpec(from = TestScenes.SceneB, to = TestScenes.SceneA, key = null) val transitionSpec = transitions.transitionSpec(from = SceneB, to = SceneA, key = null) val transformations = transitionSpec.transformationSpec().transformations val transformations = transitionSpec.transformationSpec(aToB()).transformations assertThat(transformations) .comparingElementsUsing(TRANSFORMATION_RANGE) Loading @@ -218,7 +219,8 @@ class TransitionDslTest { TransformationRange(start = 1f - 300 / 500f, end = 1f - 100 / 500f), ) val previewTransformations = transitionSpec.previewTransformationSpec()?.transformations val previewTransformations = transitionSpec.previewTransformationSpec(aToB())?.transformations assertThat(previewTransformations) .comparingElementsUsing(TRANSFORMATION_RANGE) Loading @@ -229,8 +231,8 @@ class TransitionDslTest { fun defaultPredictiveBack() { val transitions = transitions { from( TestScenes.SceneA, to = TestScenes.SceneB, SceneA, to = SceneB, preview = { fractionRange(start = 0.1f, end = 0.8f) { fade(TestElements.Foo) } }, ) { spec = tween(500) Loading @@ -243,12 +245,12 @@ class TransitionDslTest { // transition despite it not having the PredictiveBack key set. val transitionSpec = transitions.transitionSpec( from = TestScenes.SceneA, to = TestScenes.SceneB, from = SceneA, to = SceneB, key = TransitionKey.PredictiveBack, ) val transformations = transitionSpec.transformationSpec().transformations val transformations = transitionSpec.transformationSpec(aToB()).transformations assertThat(transformations) .comparingElementsUsing(TRANSFORMATION_RANGE) Loading @@ -257,7 +259,8 @@ class TransitionDslTest { TransformationRange(start = 100 / 500f, end = 300 / 500f), ) val previewTransformations = transitionSpec.previewTransformationSpec()?.transformations val previewTransformations = transitionSpec.previewTransformationSpec(aToB())?.transformations assertThat(previewTransformations) .comparingElementsUsing(TRANSFORMATION_RANGE) Loading @@ -271,10 +274,10 @@ class TransitionDslTest { val transitions = transitions { defaultSwipeSpec = defaultSpec from(TestScenes.SceneA, to = TestScenes.SceneB) { from(SceneA, to = SceneB) { // Default swipe spec. } from(TestScenes.SceneA, to = TestScenes.SceneC) { swipeSpec = specFromAToC } from(SceneA, to = SceneC) { swipeSpec = specFromAToC } } assertThat(transitions.defaultSwipeSpec).isSameInstanceAs(defaultSpec) Loading @@ -282,8 +285,8 @@ class TransitionDslTest { // A => B does not have a custom spec. assertThat( transitions .transitionSpec(from = TestScenes.SceneA, to = TestScenes.SceneB, key = null) .transformationSpec() .transitionSpec(from = SceneA, to = SceneB, key = null) .transformationSpec(aToB()) .swipeSpec ) .isNull() Loading @@ -291,8 +294,8 @@ class TransitionDslTest { // A => C has a custom swipe spec. assertThat( transitions .transitionSpec(from = TestScenes.SceneA, to = TestScenes.SceneC, key = null) .transformationSpec() .transitionSpec(from = SceneA, to = SceneC, key = null) .transformationSpec(transition(from = SceneA, to = SceneC)) .swipeSpec ) .isSameInstanceAs(specFromAToC) Loading @@ -301,7 +304,7 @@ class TransitionDslTest { @Test fun overscrollSpec() { val transitions = transitions { overscroll(TestScenes.SceneA, Orientation.Vertical) { overscroll(SceneA, Orientation.Vertical) { translate(TestElements.Bar, x = { 1f }, y = { 2f }) } } Loading @@ -313,9 +316,7 @@ class TransitionDslTest { @Test fun overscrollSpec_for_overscrollDisabled() { val transitions = transitions { overscrollDisabled(TestScenes.SceneA, Orientation.Vertical) } val transitions = transitions { overscrollDisabled(SceneA, Orientation.Vertical) } val overscrollSpec = transitions.overscrollSpecs.single() assertThat(overscrollSpec.transformationSpec.transformations).isEmpty() } Loading @@ -323,8 +324,22 @@ class TransitionDslTest { @Test fun overscrollSpec_throwIfTransformationsIsEmpty() { assertThrows(IllegalStateException::class.java) { transitions { overscroll(TestScenes.SceneA, Orientation.Vertical) {} } transitions { overscroll(SceneA, Orientation.Vertical) {} } } } @Test fun transitionIsPassedToBuilder() = runTest { var transitionPassedToBuilder: TransitionState.Transition? = null val state = MutableSceneTransitionLayoutState( SceneA, transitions { from(SceneA, to = SceneB) { transitionPassedToBuilder = transition } }, ) val transition = aToB() state.startTransitionImmediately(animationScope = backgroundScope, transition) assertThat(transitionPassedToBuilder).isSameInstanceAs(transition) } companion object { Loading Loading
packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt +2 −2 Original line number Diff line number Diff line Loading @@ -387,11 +387,11 @@ internal class MutableSceneTransitionLayoutStateImpl( transition.transformationSpec = transitions .transitionSpec(fromContent, toContent, key = transition.key) .transformationSpec() .transformationSpec(transition) transition.previewTransformationSpec = transitions .transitionSpec(fromContent, toContent, key = transition.key) .previewTransformationSpec() .previewTransformationSpec(transition) if (orientation != null) { transition.updateOverscrollSpecs( fromSpec = transitions.overscrollSpec(fromContent, orientation), Loading
packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt +22 −13 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import androidx.compose.foundation.gestures.Orientation 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 Loading Loading @@ -191,20 +192,21 @@ interface TransitionSpec { fun reversed(): TransitionSpec /** * The [TransformationSpec] associated to this [TransitionSpec]. * The [TransformationSpec] associated to this [TransitionSpec] for the given [transition]. * * Note that this is called once whenever a transition associated to this [TransitionSpec] is * started. */ fun transformationSpec(): TransformationSpec fun transformationSpec(transition: TransitionState.Transition): TransformationSpec /** * The preview [TransformationSpec] associated to this [TransitionSpec]. * The preview [TransformationSpec] associated to this [TransitionSpec] for the given * [transition]. * * Note that this is called once whenever a transition associated to this [TransitionSpec] is * started. */ fun previewTransformationSpec(): TransformationSpec? fun previewTransformationSpec(transition: TransitionState.Transition): TransformationSpec? } interface TransformationSpec { Loading Loading @@ -241,7 +243,7 @@ interface TransformationSpec { distance = null, transformations = emptyList(), ) internal val EmptyProvider = { Empty } internal val EmptyProvider = { _: TransitionState.Transition -> Empty } } } Loading @@ -249,9 +251,13 @@ internal class TransitionSpecImpl( override val key: TransitionKey?, override val from: ContentKey?, override val to: ContentKey?, private val previewTransformationSpec: (() -> TransformationSpecImpl)? = null, private val reversePreviewTransformationSpec: (() -> TransformationSpecImpl)? = null, private val transformationSpec: () -> TransformationSpecImpl, private val previewTransformationSpec: ((TransitionState.Transition) -> TransformationSpecImpl)? = null, private val reversePreviewTransformationSpec: ((TransitionState.Transition) -> TransformationSpecImpl)? = null, private val transformationSpec: (TransitionState.Transition) -> TransformationSpecImpl, ) : TransitionSpec { override fun reversed(): TransitionSpecImpl { return TransitionSpecImpl( Loading @@ -260,8 +266,8 @@ internal class TransitionSpecImpl( to = from, previewTransformationSpec = reversePreviewTransformationSpec, reversePreviewTransformationSpec = previewTransformationSpec, transformationSpec = { val reverse = transformationSpec.invoke() transformationSpec = { transition -> val reverse = transformationSpec.invoke(transition) TransformationSpecImpl( progressSpec = reverse.progressSpec, swipeSpec = reverse.swipeSpec, Loading @@ -272,10 +278,13 @@ internal class TransitionSpecImpl( ) } override fun transformationSpec(): TransformationSpecImpl = this.transformationSpec.invoke() override fun transformationSpec( transition: TransitionState.Transition ): TransformationSpecImpl = transformationSpec.invoke(transition) override fun previewTransformationSpec(): TransformationSpecImpl? = previewTransformationSpec?.invoke() override fun previewTransformationSpec( transition: TransitionState.Transition ): TransformationSpecImpl? = previewTransformationSpec?.invoke(transition) } /** The definition of the overscroll behavior of the [content]. */ Loading
packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt +3 −0 Original line number Diff line number Diff line Loading @@ -156,6 +156,9 @@ interface BaseTransitionBuilder : PropertyTransformationBuilder { @TransitionDsl interface TransitionBuilder : BaseTransitionBuilder { /** The [TransitionState.Transition] for which we currently compute the transformations. */ val transition: TransitionState.Transition /** * The [AnimationSpec] used to animate the associated transition progress from `0` to `1` when * the transition is triggered (i.e. it is not gesture-based). Loading
packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt +12 −9 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import androidx.compose.animation.core.spring import androidx.compose.foundation.gestures.Orientation import androidx.compose.ui.geometry.Offset 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.DrawScale Loading Loading @@ -128,8 +129,11 @@ private class SceneTransitionsBuilderImpl : SceneTransitionsBuilder { reversePreview: (TransitionBuilder.() -> Unit)?, builder: TransitionBuilder.() -> Unit, ): TransitionSpec { fun transformationSpec(builder: TransitionBuilder.() -> Unit): TransformationSpecImpl { val impl = TransitionBuilderImpl().apply(builder) fun transformationSpec( transition: TransitionState.Transition, builder: TransitionBuilder.() -> Unit, ): TransformationSpecImpl { val impl = TransitionBuilderImpl(transition).apply(builder) return TransformationSpecImpl( progressSpec = impl.spec, swipeSpec = impl.swipeSpec, Loading @@ -138,17 +142,15 @@ private class SceneTransitionsBuilderImpl : SceneTransitionsBuilder { ) } val previewTransformationSpec = preview?.let { { transformationSpec(it) } } val reversePreviewTransformationSpec = reversePreview?.let { { transformationSpec(it) } } val transformationSpec = { transformationSpec(builder) } val spec = TransitionSpecImpl( key, from, to, previewTransformationSpec, reversePreviewTransformationSpec, transformationSpec, previewTransformationSpec = preview?.let { { t -> transformationSpec(t, it) } }, reversePreviewTransformationSpec = reversePreview?.let { { t -> transformationSpec(t, it) } }, transformationSpec = { t -> transformationSpec(t, builder) }, ) transitionSpecs.add(spec) return spec Loading Loading @@ -227,7 +229,8 @@ internal abstract class BaseTransitionBuilderImpl : BaseTransitionBuilder { } } internal class TransitionBuilderImpl : BaseTransitionBuilderImpl(), TransitionBuilder { internal class TransitionBuilderImpl(override val transition: TransitionState.Transition) : BaseTransitionBuilderImpl(), TransitionBuilder { override var spec: AnimationSpec<Float> = spring(stiffness = Spring.StiffnessLow) override var swipeSpec: SpringSpec<Float>? = null override var distance: UserActionDistance? = null Loading
packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt +63 −48 Original line number Diff line number Diff line Loading @@ -23,11 +23,17 @@ import androidx.compose.animation.core.spring import androidx.compose.animation.core.tween import androidx.compose.foundation.gestures.Orientation import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.compose.animation.scene.TestScenes.SceneA import com.android.compose.animation.scene.TestScenes.SceneB import com.android.compose.animation.scene.TestScenes.SceneC import com.android.compose.animation.scene.content.state.TransitionState import com.android.compose.animation.scene.transformation.OverscrollTranslate import com.android.compose.animation.scene.transformation.Transformation import com.android.compose.animation.scene.transformation.TransformationRange import com.android.compose.test.transition import com.google.common.truth.Correspondence import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.test.runTest import org.junit.Assert.assertThrows import org.junit.Test import org.junit.runner.RunWith Loading @@ -43,9 +49,9 @@ class TransitionDslTest { @Test fun manyTransitions() { val transitions = transitions { from(TestScenes.SceneA, to = TestScenes.SceneB) from(TestScenes.SceneB, to = TestScenes.SceneC) from(TestScenes.SceneC, to = TestScenes.SceneA) from(SceneA, to = SceneB) from(SceneB, to = SceneC) from(SceneC, to = SceneA) } assertThat(transitions.transitionSpecs).hasSize(3) } Loading @@ -53,9 +59,9 @@ class TransitionDslTest { @Test fun toFromBuilders() { val transitions = transitions { from(TestScenes.SceneA, to = TestScenes.SceneB) from(TestScenes.SceneB) to(TestScenes.SceneC) from(SceneA, to = SceneB) from(SceneB) to(SceneC) } assertThat(transitions.transitionSpecs) Loading @@ -65,38 +71,34 @@ class TransitionDslTest { "has (from, to) equal to", ) ) .containsExactly( TestScenes.SceneA to TestScenes.SceneB, TestScenes.SceneB to null, null to TestScenes.SceneC, ) .containsExactly(SceneA to SceneB, SceneB to null, null to SceneC) } private fun aToB() = transition(SceneA, SceneB) @Test fun defaultTransitionSpec() { val transitions = transitions { from(TestScenes.SceneA, to = TestScenes.SceneB) } val transformationSpec = transitions.transitionSpecs.single().transformationSpec() val transitions = transitions { from(SceneA, to = SceneB) } val transformationSpec = transitions.transitionSpecs.single().transformationSpec(aToB()) assertThat(transformationSpec.progressSpec).isInstanceOf(SpringSpec::class.java) } @Test fun customTransitionSpec() { val transitions = transitions { from(TestScenes.SceneA, to = TestScenes.SceneB) { spec = tween(durationMillis = 42) } from(SceneA, to = SceneB) { spec = tween(durationMillis = 42) } } val transformationSpec = transitions.transitionSpecs.single().transformationSpec() val transformationSpec = transitions.transitionSpecs.single().transformationSpec(aToB()) assertThat(transformationSpec.progressSpec).isInstanceOf(TweenSpec::class.java) assertThat((transformationSpec.progressSpec as TweenSpec).durationMillis).isEqualTo(42) } @Test fun defaultRange() { val transitions = transitions { from(TestScenes.SceneA, to = TestScenes.SceneB) { fade(TestElements.Foo) } } val transitions = transitions { from(SceneA, to = SceneB) { fade(TestElements.Foo) } } val transformations = transitions.transitionSpecs.single().transformationSpec().transformations transitions.transitionSpecs.single().transformationSpec(aToB()).transformations assertThat(transformations.size).isEqualTo(1) assertThat(transformations.single().range).isEqualTo(null) } Loading @@ -104,7 +106,7 @@ class TransitionDslTest { @Test fun fractionRange() { val transitions = transitions { from(TestScenes.SceneA, to = TestScenes.SceneB) { from(SceneA, to = SceneB) { fractionRange(start = 0.1f, end = 0.8f) { fade(TestElements.Foo) } fractionRange(start = 0.2f) { fade(TestElements.Foo) } fractionRange(end = 0.9f) { fade(TestElements.Foo) } Loading @@ -119,7 +121,7 @@ class TransitionDslTest { } val transformations = transitions.transitionSpecs.single().transformationSpec().transformations transitions.transitionSpecs.single().transformationSpec(aToB()).transformations assertThat(transformations) .comparingElementsUsing(TRANSFORMATION_RANGE) .containsExactly( Loading @@ -133,7 +135,7 @@ class TransitionDslTest { @Test fun timestampRange() { val transitions = transitions { from(TestScenes.SceneA, to = TestScenes.SceneB) { from(SceneA, to = SceneB) { spec = tween(500) timestampRange(startMillis = 100, endMillis = 300) { fade(TestElements.Foo) } Loading @@ -150,7 +152,7 @@ class TransitionDslTest { } val transformations = transitions.transitionSpecs.single().transformationSpec().transformations transitions.transitionSpecs.single().transformationSpec(aToB()).transformations assertThat(transformations) .comparingElementsUsing(TRANSFORMATION_RANGE) .containsExactly( Loading @@ -168,7 +170,7 @@ class TransitionDslTest { @Test fun reversed() { val transitions = transitions { from(TestScenes.SceneA, to = TestScenes.SceneB) { from(SceneA, to = SceneB) { spec = tween(500) reversed { fractionRange(start = 0.1f, end = 0.8f) { fade(TestElements.Foo) } Loading @@ -178,7 +180,7 @@ class TransitionDslTest { } val transformations = transitions.transitionSpecs.single().transformationSpec().transformations transitions.transitionSpecs.single().transformationSpec(aToB()).transformations assertThat(transformations) .comparingElementsUsing(TRANSFORMATION_RANGE) .containsExactly( Loading @@ -191,8 +193,8 @@ class TransitionDslTest { fun defaultReversed() { val transitions = transitions { from( TestScenes.SceneA, to = TestScenes.SceneB, SceneA, to = SceneB, preview = { fractionRange(start = 0.1f, end = 0.8f) { fade(TestElements.Foo) } }, reversePreview = { fractionRange(start = 0.5f, end = 0.6f) { fade(TestElements.Foo) } Loading @@ -206,10 +208,9 @@ class TransitionDslTest { // Fetch the transition from B to A, which will automatically reverse the transition from A // to B we defined. val transitionSpec = transitions.transitionSpec(from = TestScenes.SceneB, to = TestScenes.SceneA, key = null) val transitionSpec = transitions.transitionSpec(from = SceneB, to = SceneA, key = null) val transformations = transitionSpec.transformationSpec().transformations val transformations = transitionSpec.transformationSpec(aToB()).transformations assertThat(transformations) .comparingElementsUsing(TRANSFORMATION_RANGE) Loading @@ -218,7 +219,8 @@ class TransitionDslTest { TransformationRange(start = 1f - 300 / 500f, end = 1f - 100 / 500f), ) val previewTransformations = transitionSpec.previewTransformationSpec()?.transformations val previewTransformations = transitionSpec.previewTransformationSpec(aToB())?.transformations assertThat(previewTransformations) .comparingElementsUsing(TRANSFORMATION_RANGE) Loading @@ -229,8 +231,8 @@ class TransitionDslTest { fun defaultPredictiveBack() { val transitions = transitions { from( TestScenes.SceneA, to = TestScenes.SceneB, SceneA, to = SceneB, preview = { fractionRange(start = 0.1f, end = 0.8f) { fade(TestElements.Foo) } }, ) { spec = tween(500) Loading @@ -243,12 +245,12 @@ class TransitionDslTest { // transition despite it not having the PredictiveBack key set. val transitionSpec = transitions.transitionSpec( from = TestScenes.SceneA, to = TestScenes.SceneB, from = SceneA, to = SceneB, key = TransitionKey.PredictiveBack, ) val transformations = transitionSpec.transformationSpec().transformations val transformations = transitionSpec.transformationSpec(aToB()).transformations assertThat(transformations) .comparingElementsUsing(TRANSFORMATION_RANGE) Loading @@ -257,7 +259,8 @@ class TransitionDslTest { TransformationRange(start = 100 / 500f, end = 300 / 500f), ) val previewTransformations = transitionSpec.previewTransformationSpec()?.transformations val previewTransformations = transitionSpec.previewTransformationSpec(aToB())?.transformations assertThat(previewTransformations) .comparingElementsUsing(TRANSFORMATION_RANGE) Loading @@ -271,10 +274,10 @@ class TransitionDslTest { val transitions = transitions { defaultSwipeSpec = defaultSpec from(TestScenes.SceneA, to = TestScenes.SceneB) { from(SceneA, to = SceneB) { // Default swipe spec. } from(TestScenes.SceneA, to = TestScenes.SceneC) { swipeSpec = specFromAToC } from(SceneA, to = SceneC) { swipeSpec = specFromAToC } } assertThat(transitions.defaultSwipeSpec).isSameInstanceAs(defaultSpec) Loading @@ -282,8 +285,8 @@ class TransitionDslTest { // A => B does not have a custom spec. assertThat( transitions .transitionSpec(from = TestScenes.SceneA, to = TestScenes.SceneB, key = null) .transformationSpec() .transitionSpec(from = SceneA, to = SceneB, key = null) .transformationSpec(aToB()) .swipeSpec ) .isNull() Loading @@ -291,8 +294,8 @@ class TransitionDslTest { // A => C has a custom swipe spec. assertThat( transitions .transitionSpec(from = TestScenes.SceneA, to = TestScenes.SceneC, key = null) .transformationSpec() .transitionSpec(from = SceneA, to = SceneC, key = null) .transformationSpec(transition(from = SceneA, to = SceneC)) .swipeSpec ) .isSameInstanceAs(specFromAToC) Loading @@ -301,7 +304,7 @@ class TransitionDslTest { @Test fun overscrollSpec() { val transitions = transitions { overscroll(TestScenes.SceneA, Orientation.Vertical) { overscroll(SceneA, Orientation.Vertical) { translate(TestElements.Bar, x = { 1f }, y = { 2f }) } } Loading @@ -313,9 +316,7 @@ class TransitionDslTest { @Test fun overscrollSpec_for_overscrollDisabled() { val transitions = transitions { overscrollDisabled(TestScenes.SceneA, Orientation.Vertical) } val transitions = transitions { overscrollDisabled(SceneA, Orientation.Vertical) } val overscrollSpec = transitions.overscrollSpecs.single() assertThat(overscrollSpec.transformationSpec.transformations).isEmpty() } Loading @@ -323,8 +324,22 @@ class TransitionDslTest { @Test fun overscrollSpec_throwIfTransformationsIsEmpty() { assertThrows(IllegalStateException::class.java) { transitions { overscroll(TestScenes.SceneA, Orientation.Vertical) {} } transitions { overscroll(SceneA, Orientation.Vertical) {} } } } @Test fun transitionIsPassedToBuilder() = runTest { var transitionPassedToBuilder: TransitionState.Transition? = null val state = MutableSceneTransitionLayoutState( SceneA, transitions { from(SceneA, to = SceneB) { transitionPassedToBuilder = transition } }, ) val transition = aToB() state.startTransitionImmediately(animationScope = backgroundScope, transition) assertThat(transitionPassedToBuilder).isSameInstanceAs(transition) } companion object { Loading