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