• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.animation.scene
18 
19 import com.android.compose.animation.scene.content.state.TransitionState
20 import com.android.mechanics.GestureContext
21 import kotlinx.coroutines.CoroutineScope
22 
23 /** Trigger a one-off transition to show or hide an overlay. */
showOrHideOverlaynull24 internal fun CoroutineScope.showOrHideOverlay(
25     layoutState: MutableSceneTransitionLayoutStateImpl,
26     overlay: OverlayKey,
27     fromOrToScene: SceneKey,
28     isShowing: Boolean,
29     transitionKey: TransitionKey?,
30     replacedTransition: TransitionState.Transition.ShowOrHideOverlay?,
31     reversed: Boolean,
32 ): TransitionState.Transition.ShowOrHideOverlay {
33     val targetProgress = if (reversed) 0f else 1f
34     val (fromContent, toContent) =
35         if (isShowing xor reversed) {
36             fromOrToScene to overlay
37         } else {
38             overlay to fromOrToScene
39         }
40 
41     val oneOffAnimation = OneOffAnimation()
42     val transition =
43         OneOffShowOrHideOverlayTransition(
44             overlay = overlay,
45             fromOrToScene = fromOrToScene,
46             fromContent = fromContent,
47             toContent = toContent,
48             isEffectivelyShown = isShowing,
49             key = transitionKey,
50             replacedTransition = replacedTransition,
51             oneOffAnimation = oneOffAnimation,
52         )
53 
54     animateContent(
55         layoutState = layoutState,
56         transition = transition,
57         oneOffAnimation = oneOffAnimation,
58         targetProgress = targetProgress,
59     )
60 
61     return transition
62 }
63 
64 /** Trigger a one-off transition to replace an overlay by another one. */
replaceOverlaynull65 internal fun CoroutineScope.replaceOverlay(
66     layoutState: MutableSceneTransitionLayoutStateImpl,
67     fromOverlay: OverlayKey,
68     toOverlay: OverlayKey,
69     transitionKey: TransitionKey?,
70     replacedTransition: TransitionState.Transition.ReplaceOverlay?,
71     reversed: Boolean,
72 ): TransitionState.Transition.ReplaceOverlay {
73     val targetProgress = if (reversed) 0f else 1f
74     val effectivelyShownOverlay = if (reversed) fromOverlay else toOverlay
75 
76     val oneOffAnimation = OneOffAnimation()
77     val transition =
78         OneOffOverlayReplacingTransition(
79             fromOverlay = fromOverlay,
80             toOverlay = toOverlay,
81             effectivelyShownOverlay = effectivelyShownOverlay,
82             key = transitionKey,
83             replacedTransition = replacedTransition,
84             oneOffAnimation = oneOffAnimation,
85         )
86 
87     animateContent(
88         layoutState = layoutState,
89         transition = transition,
90         oneOffAnimation = oneOffAnimation,
91         targetProgress = targetProgress,
92     )
93 
94     return transition
95 }
96 
97 private class OneOffShowOrHideOverlayTransition(
98     overlay: OverlayKey,
99     fromOrToScene: SceneKey,
100     fromContent: ContentKey,
101     toContent: ContentKey,
102     override val isEffectivelyShown: Boolean,
103     override val key: TransitionKey?,
104     replacedTransition: TransitionState.Transition?,
105     private val oneOffAnimation: OneOffAnimation,
106 ) :
107     TransitionState.Transition.ShowOrHideOverlay(
108         overlay,
109         fromOrToScene,
110         fromContent,
111         toContent,
112         replacedTransition,
113     ) {
114     override val progress: Float
115         get() = oneOffAnimation.progress
116 
117     override val progressVelocity: Float
118         get() = oneOffAnimation.progressVelocity
119 
120     override val isInitiatedByUserInput: Boolean = false
121     override val isUserInputOngoing: Boolean = false
122     override val gestureContext: GestureContext? = null
123 
runnull124     override suspend fun run() {
125         oneOffAnimation.run()
126     }
127 
freezeAndAnimateToCurrentStatenull128     override fun freezeAndAnimateToCurrentState() {
129         oneOffAnimation.freezeAndAnimateToCurrentState()
130     }
131 }
132 
133 private class OneOffOverlayReplacingTransition(
134     fromOverlay: OverlayKey,
135     toOverlay: OverlayKey,
136     override val effectivelyShownOverlay: OverlayKey,
137     override val key: TransitionKey?,
138     replacedTransition: TransitionState.Transition?,
139     private val oneOffAnimation: OneOffAnimation,
140 ) : TransitionState.Transition.ReplaceOverlay(fromOverlay, toOverlay, replacedTransition) {
141     override val progress: Float
142         get() = oneOffAnimation.progress
143 
144     override val progressVelocity: Float
145         get() = oneOffAnimation.progressVelocity
146 
147     override val isInitiatedByUserInput: Boolean = false
148     override val isUserInputOngoing: Boolean = false
149     override val gestureContext: GestureContext? = null
150 
runnull151     override suspend fun run() {
152         oneOffAnimation.run()
153     }
154 
freezeAndAnimateToCurrentStatenull155     override fun freezeAndAnimateToCurrentState() {
156         oneOffAnimation.freezeAndAnimateToCurrentState()
157     }
158 }
159