1 /*
2 * Copyright (C) 2024 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package com.android.compose.test
18
19 import androidx.compose.foundation.gestures.Orientation
20 import com.android.compose.animation.scene.ContentKey
21 import com.android.compose.animation.scene.SceneKey
22 import com.android.compose.animation.scene.SceneTransitionLayoutImpl
23 import com.android.compose.animation.scene.content.state.TransitionState
24 import com.android.compose.animation.scene.content.state.TransitionState.Transition
25 import kotlinx.coroutines.CompletableDeferred
26
27 /** A [Transition.ChangeScene] for tests that will be finished once [finish] is called. */
28 abstract class TestSceneTransition(
29 fromScene: SceneKey,
30 toScene: SceneKey,
31 replacedTransition: Transition?,
32 ) : Transition.ChangeScene(fromScene, toScene, replacedTransition) {
33 private val finishCompletable = CompletableDeferred<Unit>()
34
runnull35 override suspend fun run() {
36 finishCompletable.await()
37 }
38
39 /** Finish this transition. */
finishnull40 fun finish() {
41 finishCompletable.complete(Unit)
42 }
43 }
44
45 /** A utility to easily create a [TestSceneTransition] in tests. */
transitionnull46 fun transition(
47 from: SceneKey,
48 to: SceneKey,
49 current: () -> SceneKey = { to },
<lambda>null50 progress: () -> Float = { 0f },
<lambda>null51 progressVelocity: () -> Float = { 0f },
<lambda>null52 previewProgress: () -> Float = { 0f },
<lambda>null53 previewProgressVelocity: () -> Float = { 0f },
<lambda>null54 isInPreviewStage: () -> Boolean = { false },
<lambda>null55 interruptionProgress: () -> Float = { 0f },
56 isInitiatedByUserInput: Boolean = false,
57 isUserInputOngoing: Boolean = false,
58 isUpOrLeft: Boolean = false,
59 bouncingContent: ContentKey? = null,
60 orientation: Orientation = Orientation.Horizontal,
61 onFreezeAndAnimate: ((TestSceneTransition) -> Unit)? = null,
62 replacedTransition: Transition? = null,
63 ): TestSceneTransition {
64 return object :
65 TestSceneTransition(from, to, replacedTransition), TransitionState.HasOverscrollProperties {
66 override val currentScene: SceneKey
67 get() = current()
68
69 override val progress: Float
70 get() = progress()
71
72 override val progressVelocity: Float
73 get() = progressVelocity()
74
75 override val previewProgress: Float
76 get() = previewProgress()
77
78 override val previewProgressVelocity: Float
79 get() = previewProgressVelocity()
80
81 override val isInPreviewStage: Boolean
82 get() = isInPreviewStage()
83
84 override val isInitiatedByUserInput: Boolean = isInitiatedByUserInput
85 override val isUserInputOngoing: Boolean = isUserInputOngoing
86 override val isUpOrLeft: Boolean = isUpOrLeft
87 override val bouncingContent: ContentKey? = bouncingContent
88 override val orientation: Orientation = orientation
89 override val absoluteDistance = 0f
90
freezeAndAnimateToCurrentStatenull91 override fun freezeAndAnimateToCurrentState() {
92 if (onFreezeAndAnimate != null) {
93 onFreezeAndAnimate(this)
94 } else {
95 finish()
96 }
97 }
98
interruptionProgressnull99 override fun interruptionProgress(layoutImpl: SceneTransitionLayoutImpl): Float {
100 return interruptionProgress()
101 }
102 }
103 }
104