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