Merge "Return all descendant animations in getAnimatedProperties" into androidx-main
diff --git a/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/animation/PreviewAnimationClockTest.kt b/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/animation/PreviewAnimationClockTest.kt
index b0c394f..2b06bd8 100644
--- a/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/animation/PreviewAnimationClockTest.kt
+++ b/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/animation/PreviewAnimationClockTest.kt
@@ -20,10 +20,13 @@
import androidx.compose.animation.EnterExitState
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.animateColor
+import androidx.compose.animation.core.ExperimentalTransitionApi
import androidx.compose.animation.core.InternalAnimationApi
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.Transition
+import androidx.compose.animation.core.animateDp
import androidx.compose.animation.core.animateFloat
+import androidx.compose.animation.core.createChildTransition
import androidx.compose.animation.core.tween
import androidx.compose.animation.core.updateTransition
import androidx.compose.animation.fadeIn
@@ -41,6 +44,7 @@
import androidx.test.filters.MediumTest
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
+import org.junit.Assert.assertNotNull
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Rule
@@ -95,7 +99,7 @@
assertEquals(72f, rotation.value as Float, eps)
animatedProperties = testClock.getAnimatedProperties(offsetAnimation!!)
- val offset = animatedProperties.single()
+ val offset = animatedProperties.single { it.label == "myOffset" }
// We're animating from O1 (0) to O2 (100). There is a transition of 800ms defined for
// the offset, and we set the clock to 25% of this time.
assertEquals(25f, offset.value as Float, eps)
@@ -122,6 +126,24 @@
}
@Test
+ fun getAnimatedPropertiesReturnsAllDescendantAnimations() {
+ var transitionAnimation: ComposeAnimation? = null
+
+ composeRule.setContent {
+ transitionAnimation = setUpOffsetScenario()
+ }
+ composeRule.waitForIdle()
+
+ val animatedProperties = testClock.getAnimatedProperties(transitionAnimation!!)
+ // getAnimatedProperties should return all the transition animations as well as the
+ // animations of all descendant transitions
+ assertNotNull(animatedProperties.single { it.label == "myOffset" })
+ assertNotNull(animatedProperties.single { it.label == "child1 scale" })
+ assertNotNull(animatedProperties.single { it.label == "child2 color" })
+ assertNotNull(animatedProperties.single { it.label == "grandchild" })
+ }
+
+ @Test
fun getAnimatedPropertiesReturnsChildAnimations() {
var animatedVisibility: ComposeAnimation? = null
@@ -357,6 +379,9 @@
}
// Sets up a transition animation scenario, going from from Offset.O1 to Offset.O2.
+ // The main transition in this scenario also has 2 child animations. One of them has a child
+ // animation of its own.
+ @OptIn(ExperimentalTransitionApi::class)
@Suppress("UNCHECKED_CAST")
@Composable
private fun setUpOffsetScenario(): ComposeAnimation {
@@ -373,6 +398,21 @@
}
}
+ val child1 = transition.createChildTransition { it == Offset.O1 }
+ child1.animateFloat(label = "child1 scale") { pressed ->
+ if (pressed) 1f else 3f
+ }
+
+ child1.createChildTransition { it }
+ .animateDp(label = "grandchild") { parentState ->
+ if (parentState) 1.dp else 3.dp
+ }
+
+ transition.createChildTransition { it }
+ .animateColor(label = "child2 color") { state ->
+ if (state == Offset.O1) Color.Red else Color.Blue
+ }
+
testClock.trackTransition(transition as Transition<Any>)
val animation = testClock.trackedTransitions.single { it.states.contains(Offset.O1) }
testClock.updateFromAndToStates(animation, Offset.O1, Offset.O2)
diff --git a/compose/ui/ui-tooling/src/androidMain/kotlin/androidx/compose/ui/tooling/animation/PreviewAnimationClock.kt b/compose/ui/ui-tooling/src/androidMain/kotlin/androidx/compose/ui/tooling/animation/PreviewAnimationClock.kt
index 950f573..03aaf36 100644
--- a/compose/ui/ui-tooling/src/androidMain/kotlin/androidx/compose/ui/tooling/animation/PreviewAnimationClock.kt
+++ b/compose/ui/ui-tooling/src/androidMain/kotlin/androidx/compose/ui/tooling/animation/PreviewAnimationClock.kt
@@ -231,16 +231,13 @@
if (trackedTransitions.contains(animation)) {
val transition = (animation as TransitionComposeAnimation).animationObject
// In case the transition have child transitions, make sure to return their
- // animations as well.
- // TODO(b/187962923): support indirect descendants, e.g. grandchildren animations.
- val animations =
- transition.animations + transition.transitions.flatMap { it.animations }
- return animations.mapNotNull {
+ // descendant animations as well.
+ return transition.allAnimations().mapNotNull {
ComposeAnimatedProperty(it.label, it.value ?: return@mapNotNull null)
}
} else if (trackedAnimatedVisibility.contains(animation)) {
(animation as AnimatedVisibilityComposeAnimation).childTransition?.let { child ->
- return child.animations.mapNotNull {
+ return child.allAnimations().mapNotNull {
ComposeAnimatedProperty(it.label, it.value ?: return@mapNotNull null)
}
}
@@ -293,4 +290,13 @@
private fun AnimatedVisibilityState.toCurrentTargetPair() =
if (this == AnimatedVisibilityState.Enter) false to true else true to false
+
+ /**
+ * Return all the animations of a [Transition], as well as all the animations of its every
+ * descendant [Transition]s.
+ */
+ private fun Transition<*>.allAnimations(): List<Transition<*>.TransitionAnimationState<*, *>> {
+ val descendantAnimations = transitions.flatMap { it.allAnimations() }
+ return animations + descendantAnimations
+ }
}