1 /*
2  * Copyright 2020 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 androidx.compose.animation.core
18 
19 import androidx.compose.runtime.State
20 import androidx.compose.runtime.getValue
21 import androidx.compose.runtime.mutableStateOf
22 import androidx.compose.runtime.setValue
23 
24 /**
25  * [AnimationState] contains the necessary information to indicate the state of an animation. Once
26  * an [AnimationState] is constructed, it can only be updated/mutated by animations. If there's a
27  * need to mutate some of the fields of an [AnimationState], consider using [copy] functions.
28  *
29  * @param typeConverter [TwoWayConverter] to convert type [T] from and to [AnimationVector]
30  * @param initialValue initial value of the [AnimationState]
31  * @param initialVelocityVector initial velocity of the [AnimationState], null (i.e. no velocity) by
32  *   default.
33  * @param lastFrameTimeNanos last frame time of the animation, [AnimationConstants.UnspecifiedTime]
34  *   by default
35  * @param finishedTimeNanos the time that the animation finished successfully,
36  *   [AnimationConstants.UnspecifiedTime] until then
37  * @param isRunning whether the [AnimationState] is currently being updated by an animation. False
38  *   by default
39  */
40 public class AnimationState<T, V : AnimationVector>(
41     public val typeConverter: TwoWayConverter<T, V>,
42     initialValue: T,
43     initialVelocityVector: V? = null,
44     lastFrameTimeNanos: Long = AnimationConstants.UnspecifiedTime,
45     finishedTimeNanos: Long = AnimationConstants.UnspecifiedTime,
46     isRunning: Boolean = false
47 ) : State<T> {
48     /** Current value of the [AnimationState]. */
49     override var value: T by mutableStateOf(initialValue)
50         internal set
51 
52     /** Current velocity vector of the [AnimationState]. */
53     public var velocityVector: V =
54         initialVelocityVector?.copy() ?: typeConverter.createZeroVectorFrom(initialValue)
55         internal set
56 
57     /**
58      * Last frame time of the animation.
59      *
60      * If the animation has never started, this will be [AnimationConstants.UnspecifiedTime], unless
61      * specified otherwise in the [AnimationState] constructor. [lastFrameTimeNanos] is the frame
62      * time when the animation is last updated, in the [System.nanoTime] timebase. It is also used
63      * for starting a sequential animation in [AnimationState.animateTo]. This allows the sequential
64      * animation to set its start time to when the previous animation is interrupted or finished.
65      */
66     @get:Suppress("MethodNameUnits")
67     public var lastFrameTimeNanos: Long = lastFrameTimeNanos
68         internal set
69 
70     /**
71      * The time when the animation finished successfully in the [System.nanoTime] timebase.
72      *
73      * If the animation has never finished (i.e. currently running, interrupted, or never started),
74      * this will be [AnimationConstants.UnspecifiedTime], unless specified otherwise in
75      * [AnimationState] constructor.
76      */
77     @get:Suppress("MethodNameUnits")
78     public var finishedTimeNanos: Long = finishedTimeNanos
79         internal set
80 
81     /** Indicates whether the animation is currently running. */
82     public var isRunning: Boolean = isRunning
83         internal set
84 
85     /** Velocity of type [T], converted from [velocityVector]. */
86     public val velocity: T
87         get() = typeConverter.convertFromVector(velocityVector)
88 
toStringnull89     override fun toString(): String {
90         return "AnimationState(" +
91             "value=$value, " +
92             "velocity=$velocity, " +
93             "isRunning=$isRunning, " +
94             "lastFrameTimeNanos=$lastFrameTimeNanos, " +
95             "finishedTimeNanos=$finishedTimeNanos" +
96             ")"
97     }
98 }
99 
100 /**
101  * Indicates whether the given [AnimationState] is for an animation that has finished, indicated by
102  * [AnimationState.finishedTimeNanos] having a specified value.
103  */
104 public val AnimationState<*, *>.isFinished: Boolean
105     get() = finishedTimeNanos != AnimationConstants.UnspecifiedTime
106 
107 /**
108  * [AnimationScope] provides all the animation related info specific to an animation run. An
109  * [AnimationScope] will be accessible during an animation.
110  *
111  * @see [AnimationState.animateTo]
112  */
113 public class AnimationScope<T, V : AnimationVector>
114 internal constructor(
115     initialValue: T,
116     /** [TwoWayConverter] to convert type [T] from and to [AnimationVector]. */
117     public val typeConverter: TwoWayConverter<T, V>,
118     initialVelocityVector: V,
119     lastFrameTimeNanos: Long,
120     /** Target value of the animation. */
121     public val targetValue: T,
122     /** Start time of the animation in the [System.nanoTime] timebase. */
123     @get:Suppress("MethodNameUnits") public val startTimeNanos: Long,
124     isRunning: Boolean,
125     private val onCancel: () -> Unit
126 ) {
127     // Externally immutable fields
128     /** Current value of the [AnimationScope]. */
129     public var value: T by mutableStateOf(initialValue)
130         internal set
131 
132     /** Current velocity vector of the [AnimationScope]. */
133     public var velocityVector: V = initialVelocityVector.copy()
134         internal set
135 
136     /**
137      * Last frame time of the animation.
138      *
139      * If the animation has never started, this will be [AnimationConstants.UnspecifiedTime], unless
140      * specified otherwise in the [AnimationState] constructor. [lastFrameTimeNanos] is the frame
141      * time when the animation is last updated, in the [System.nanoTime] timebase. It is also used
142      * for starting a sequential animation in [AnimationState.animateTo]. This allows the sequential
143      * animation to set its start time to when the previous animation is interrupted or finished.
144      */
145     @get:Suppress("MethodNameUnits")
146     public var lastFrameTimeNanos: Long = lastFrameTimeNanos
147         internal set
148 
149     /**
150      * The time when the animation finished successfully in the [System.nanoTime] timebase.
151      *
152      * If the animation has never finished (i.e. currently running, interrupted, or never started),
153      * this will be [AnimationConstants.UnspecifiedTime], unless specified otherwise in
154      * [AnimationState] constructor.
155      */
156     @get:Suppress("MethodNameUnits")
157     public var finishedTimeNanos: Long = AnimationConstants.UnspecifiedTime
158         internal set
159 
160     /** Indicates whether the animation is currently running. */
161     public var isRunning: Boolean by mutableStateOf(isRunning)
162         internal set
163 
164     /** Velocity of type [T], converted from [velocityVector]. */
165     public val velocity: T
166         get() = typeConverter.convertFromVector(velocityVector)
167 
168     /**
169      * Cancels the animation that this [AnimationScope] corresponds to. The scope will not be
170      * updated any more after [cancelAnimation] is called.
171      */
cancelAnimationnull172     public fun cancelAnimation() {
173         isRunning = false
174         onCancel()
175     }
176 
177     /**
178      * Creates an [AnimationState] that populates all the fields in [AnimationState] from
179      * [AnimationScope].
180      */
toAnimationStatenull181     public fun toAnimationState(): AnimationState<T, V> =
182         AnimationState(
183             typeConverter,
184             value,
185             velocityVector,
186             lastFrameTimeNanos,
187             finishedTimeNanos,
188             isRunning
189         )
190 }
191 
192 /**
193  * Creates a new [AnimationState] from a given [AnimationState]. This function allows some of the
194  * fields to be different in the new [AnimationState].
195  *
196  * @param value value of the [AnimationState], using the value of the given [AnimationState] by
197  *   default
198  * @param velocityVector velocity of the [AnimationState], using the velocity of the given
199  *   [AnimationState] by default.
200  * @param lastFrameTimeNanos last frame time of the animation, same as the given [AnimationState] by
201  *   default
202  * @param finishedTimeNanos the time that the animation finished successfully,
203  *   [AnimationConstants.UnspecifiedTime] until then. Default value is the same as the given
204  *   [AnimationState].
205  * @param isRunning whether the [AnimationState] is currently being updated by an animation. Same as
206  *   the given [AnimationState] by default
207  * @return A new [AnimationState] instance copied from the given instance, with some fields
208  *   optionally altered
209  */
210 public fun <T, V : AnimationVector> AnimationState<T, V>.copy(
211     value: T = this.value,
212     velocityVector: V? = this.velocityVector.copy(),
213     lastFrameTimeNanos: Long = this.lastFrameTimeNanos,
214     finishedTimeNanos: Long = this.finishedTimeNanos,
215     isRunning: Boolean = this.isRunning
216 ): AnimationState<T, V> =
217     AnimationState(
218         this.typeConverter,
219         value,
220         velocityVector,
221         lastFrameTimeNanos,
222         finishedTimeNanos,
223         isRunning
224     )
225 
226 /**
227  * Creates a new [AnimationState] of Float [value] type from a given [AnimationState] of the same
228  * type. This function allows some of the fields to be different in the new [AnimationState].
229  *
230  * @param value value of the [AnimationState], using the value of the given [AnimationState] by
231  *   default
232  * @param velocity velocity of the [AnimationState], using the velocity of the given
233  *   [AnimationState] by default.
234  * @param lastFrameTimeNanos last frame time of the animation, same as the given [AnimationState] by
235  *   default
236  * @param finishedTimeNanos the time that the animation finished successfully, same as the given
237  *   [AnimationState] by default.
238  * @param isRunning whether the [AnimationState] is currently being updated by an animation. Same as
239  *   the given [AnimationState] by default
240  * @return A new [AnimationState] instance copied from the given instance, with some fields
241  *   optionally altered
242  */
243 public fun AnimationState<Float, AnimationVector1D>.copy(
244     value: Float = this.value,
245     velocity: Float = this.velocityVector.value,
246     lastFrameTimeNanos: Long = this.lastFrameTimeNanos,
247     finishedTimeNanos: Long = this.finishedTimeNanos,
248     isRunning: Boolean = this.isRunning
249 ): AnimationState<Float, AnimationVector1D> =
250     AnimationState(
251         this.typeConverter,
252         value,
253         AnimationVector(velocity),
254         lastFrameTimeNanos,
255         finishedTimeNanos,
256         isRunning
257     )
258 
259 /**
260  * Factory method for creating an [AnimationState] for Float [initialValue].
261  *
262  * @param initialValue initial value of the [AnimationState]
263  * @param initialVelocity initial velocity of the [AnimationState], 0 (i.e. no velocity) by default
264  * @param lastFrameTimeNanos last frame time of the animation, [AnimationConstants.UnspecifiedTime]
265  *   by default
266  * @param finishedTimeNanos the time that the animation finished successfully,
267  *   [AnimationConstants.UnspecifiedTime] by default.
268  * @param isRunning whether the [AnimationState] is currently being updated by an animation. False
269  *   by default
270  * @return A new [AnimationState] instance
271  */
272 public fun AnimationState(
273     initialValue: Float,
274     initialVelocity: Float = 0f,
275     lastFrameTimeNanos: Long = AnimationConstants.UnspecifiedTime,
276     finishedTimeNanos: Long = AnimationConstants.UnspecifiedTime,
277     isRunning: Boolean = false
278 ): AnimationState<Float, AnimationVector1D> {
279     return AnimationState(
280         Float.VectorConverter,
281         initialValue,
282         AnimationVector(initialVelocity),
283         lastFrameTimeNanos,
284         finishedTimeNanos,
285         isRunning
286     )
287 }
288 
289 /**
290  * Factory method for creating an [AnimationState] with an [initialValue] and an [initialVelocity].
291  *
292  * @param typeConverter [TwoWayConverter] to convert type [T] from and to [AnimationVector]
293  * @param initialValue initial value of the [AnimationState]
294  * @param initialVelocity initial velocity of the [AnimationState]
295  * @param lastFrameTimeNanos last frame time of the animation, [AnimationConstants.UnspecifiedTime]
296  *   by default
297  * @param finishedTimeNanos the time that the animation finished successfully,
298  *   [AnimationConstants.UnspecifiedTime] by default.
299  * @param isRunning whether the [AnimationState] is currently being updated by an animation. False
300  *   by default
301  * @return A new [AnimationState] instance
302  */
AnimationStatenull303 public fun <T, V : AnimationVector> AnimationState(
304     typeConverter: TwoWayConverter<T, V>,
305     initialValue: T,
306     initialVelocity: T,
307     lastFrameTimeNanos: Long = AnimationConstants.UnspecifiedTime,
308     finishedTimeNanos: Long = AnimationConstants.UnspecifiedTime,
309     isRunning: Boolean = false
310 ): AnimationState<T, V> {
311     return AnimationState(
312         typeConverter,
313         initialValue,
314         typeConverter.convertToVector(initialVelocity),
315         lastFrameTimeNanos,
316         finishedTimeNanos,
317         isRunning
318     )
319 }
320 
321 /**
322  * Creates an AnimationVector with all the values set to 0 using the provided [TwoWayConverter] and
323  * the [value].
324  *
325  * @return a new AnimationVector instance of type [V].
326  */
createZeroVectorFromnull327 public fun <T, V : AnimationVector> TwoWayConverter<T, V>.createZeroVectorFrom(value: T): V =
328     convertToVector(value).also { it.reset() }
329