1use std::{
2 ops::Deref,
3 time::{
4 Duration,
5 Instant,
6 },
7};
8
9use async_io::Timer;
10use freya_core::prelude::*;
11
12#[derive(Default, PartialEq, Clone, Debug)]
13pub struct AnimConfiguration {
14 on_finish: OnFinish,
15 on_creation: OnCreation,
16 on_change: OnChange,
17}
18
19impl AnimConfiguration {
20 pub fn on_finish(&mut self, on_finish: OnFinish) -> &mut Self {
21 self.on_finish = on_finish;
22 self
23 }
24
25 pub fn on_creation(&mut self, on_creation: OnCreation) -> &mut Self {
26 self.on_creation = on_creation;
27 self
28 }
29
30 pub fn on_change(&mut self, on_change: OnChange) -> &mut Self {
31 self.on_change = on_change;
32 self
33 }
34}
35
36#[derive(Clone, Copy, PartialEq)]
38pub enum AnimDirection {
39 Forward,
40 Reverse,
41}
42
43impl AnimDirection {
44 pub fn toggle(&mut self) {
45 match self {
46 Self::Forward => *self = Self::Reverse,
47 Self::Reverse => *self = Self::Forward,
48 }
49 }
50}
51
52#[derive(PartialEq, Clone, Copy, Default, Debug)]
56pub enum OnFinish {
57 #[default]
59 Nothing,
60 Reverse {
62 delay: Duration,
64 },
65 Restart {
67 delay: Duration,
69 },
70}
71
72impl OnFinish {
73 pub fn nothing() -> Self {
75 Self::Nothing
76 }
77
78 pub fn reverse() -> Self {
80 Self::Reverse {
81 delay: Duration::ZERO,
82 }
83 }
84
85 pub fn reverse_with_delay(delay: Duration) -> Self {
87 Self::Reverse { delay }
88 }
89
90 pub fn restart() -> Self {
92 Self::Restart {
93 delay: Duration::ZERO,
94 }
95 }
96
97 pub fn restart_with_delay(delay: Duration) -> Self {
99 Self::Restart { delay }
100 }
101}
102
103#[derive(PartialEq, Clone, Copy, Default, Debug)]
107pub enum OnCreation {
108 #[default]
110 Nothing,
111 Run,
113 Finish,
115}
116
117#[derive(PartialEq, Clone, Copy, Default, Debug)]
121pub enum OnChange {
122 #[default]
124 Reset,
125 Finish,
127 Rerun,
129 Nothing,
131}
132
133pub trait ReadAnimatedValue: Clone + 'static {
134 type Output;
135 fn value(&self) -> Self::Output;
136}
137
138pub trait AnimatedValue: Clone + Default + 'static {
139 fn prepare(&mut self, direction: AnimDirection);
140
141 fn is_finished(&self, index: u128, direction: AnimDirection) -> bool;
142
143 fn advance(&mut self, index: u128, direction: AnimDirection);
144
145 fn finish(&mut self, direction: AnimDirection);
146
147 fn into_reversed(self) -> Self;
148}
149
150#[derive(Default, Clone, Copy, PartialEq, Eq)]
151pub enum Ease {
152 In,
153 #[default]
154 Out,
155 InOut,
156}
157
158#[derive(Clone, PartialEq)]
160pub struct UseAnimation<Animated: AnimatedValue> {
161 pub(crate) animated_value: State<Animated>,
162 pub(crate) config: State<AnimConfiguration>,
163 pub(crate) is_running: State<bool>,
164 pub(crate) has_run_yet: State<bool>,
165 pub(crate) task: State<Option<TaskHandle>>,
166 pub(crate) last_direction: State<AnimDirection>,
167}
168impl<T: AnimatedValue> Copy for UseAnimation<T> {}
169
170impl<Animated: AnimatedValue> Deref for UseAnimation<Animated> {
171 type Target = State<Animated>;
172 fn deref(&self) -> &Self::Target {
173 &self.animated_value
174 }
175}
176
177impl<Animated: AnimatedValue> UseAnimation<Animated> {
178 pub fn get(&self) -> ReadRef<'static, Animated> {
180 self.animated_value.read()
181 }
182
183 pub fn start(&mut self) {
185 self.run(AnimDirection::Forward)
186 }
187
188 pub fn reverse(&mut self) {
190 self.run(AnimDirection::Reverse)
191 }
192
193 pub fn reset(&mut self) {
195 if let Some(task) = self.task.write().take() {
196 task.cancel();
197 }
198
199 self.animated_value
200 .write()
201 .prepare(*self.last_direction.peek());
202
203 *self.has_run_yet.write() = true;
204 }
205
206 pub fn finish(&mut self) {
208 if let Some(task) = self.task.write().take() {
209 task.cancel();
210 }
211
212 self.animated_value
213 .write()
214 .finish(*self.last_direction.peek());
215
216 *self.has_run_yet.write() = true;
217 }
218
219 pub fn is_running(&self) -> State<bool> {
220 self.is_running
221 }
222
223 pub fn has_run_yet(&self) -> State<bool> {
224 self.has_run_yet
225 }
226
227 pub fn run(&self, mut direction: AnimDirection) {
229 let mut is_running = self.is_running;
230 let mut has_run_yet = self.has_run_yet;
231 let mut task = self.task;
232 let mut last_direction = self.last_direction;
233
234 let on_finish = self.config.peek().on_finish;
235 let mut animated_value = self.animated_value;
236
237 last_direction.set(direction);
238
239 if let Some(task) = task.write().take() {
241 task.cancel();
242 }
243
244 let peek_has_run_yet = *self.has_run_yet.peek();
245
246 let mut ticker = RenderingTicker::get();
247 let platform = Platform::get();
248 let animation_clock = AnimationClock::get();
249
250 let animation_task = spawn(async move {
251 platform.send(UserEvent::RequestRedraw);
252
253 let mut index = 0u128;
254 let mut prev_frame = Instant::now();
255
256 animated_value.write().prepare(direction);
258
259 if !peek_has_run_yet {
260 *has_run_yet.write() = true;
261 }
262 is_running.set(true);
263
264 loop {
265 ticker.tick().await;
267
268 platform.send(UserEvent::RequestRedraw);
270
271 let elapsed = animation_clock.correct_elapsed_duration(prev_frame.elapsed());
272
273 index += elapsed.as_millis();
274
275 let is_finished = {
276 let mut animated_value = animated_value.write();
277 let is_finished = animated_value.is_finished(index, direction);
278 animated_value.advance(index, direction);
280
281 is_finished
282 };
283
284 if is_finished {
285 let delay = match on_finish {
286 OnFinish::Reverse { delay } => {
287 direction.toggle();
289 delay
290 }
291 OnFinish::Restart { delay } => delay,
292 OnFinish::Nothing => {
293 break;
295 }
296 };
297
298 if !delay.is_zero() {
299 Timer::after(delay).await;
300 }
301
302 index = 0;
303
304 animated_value.write().prepare(direction);
306 }
307
308 prev_frame = Instant::now();
309 }
310
311 is_running.set(false);
312 task.write().take();
313 });
314
315 task.write().replace(animation_task);
317 }
318}
319pub fn use_animation<Animated: AnimatedValue>(
415 mut run: impl 'static + FnMut(&mut AnimConfiguration) -> Animated,
416) -> UseAnimation<Animated> {
417 use_hook(|| {
418 let mut config = State::create(AnimConfiguration::default());
419 let mut animated_value = State::create(Animated::default());
420 let is_running = State::create(false);
421 let has_run_yet = State::create(false);
422 let task = State::create(None);
423 let last_direction = State::create(AnimDirection::Forward);
424
425 let mut animation = UseAnimation {
426 animated_value,
427 config,
428 is_running,
429 has_run_yet,
430 task,
431 last_direction,
432 };
433
434 Effect::create_sync(move || {
435 let mut anim_conf = AnimConfiguration::default();
436 animated_value.set(run(&mut anim_conf));
437 *config.write() = anim_conf;
438 });
439
440 Effect::create_sync_with_gen(move |current_gen| match config.read().on_change {
441 OnChange::Finish if current_gen > 0 => {
442 animation.finish();
443 }
444 OnChange::Rerun if current_gen > 0 => {
445 let last_direction = *animation.last_direction.peek();
446 animation.run(last_direction);
447 }
448 OnChange::Reset if current_gen > 0 => {
449 animation.reset();
450 }
451 _ => {}
452 });
453
454 match config.peek().on_creation {
455 OnCreation::Run => {
456 animation.run(AnimDirection::Forward);
457 }
458 OnCreation::Finish => {
459 animation.finish();
460 }
461 _ => {}
462 }
463
464 animation
465 })
466}
467
468pub fn use_animation_with_dependencies<Animated: AnimatedValue, D: 'static + Clone + PartialEq>(
485 dependencies: &D,
486 mut run: impl 'static + FnMut(&mut AnimConfiguration, &D) -> Animated,
487) -> UseAnimation<Animated> {
488 let dependencies = use_reactive(dependencies);
489 use_hook(|| {
490 let mut config = State::create(AnimConfiguration::default());
491 let mut animated_value = State::create(Animated::default());
492 let is_running = State::create(false);
493 let has_run_yet = State::create(false);
494 let task = State::create(None);
495 let last_direction = State::create(AnimDirection::Forward);
496
497 let mut animation = UseAnimation {
498 animated_value,
499 config,
500 is_running,
501 has_run_yet,
502 task,
503 last_direction,
504 };
505
506 Effect::create_sync(move || {
507 let dependencies = dependencies.read();
508 let mut anim_conf = AnimConfiguration::default();
509 animated_value.set(run(&mut anim_conf, &dependencies));
510 *config.write() = anim_conf;
511 });
512
513 Effect::create_sync_with_gen(move |current_gen| match config.read().on_change {
514 OnChange::Finish if current_gen > 0 => {
515 animation.finish();
516 }
517 OnChange::Rerun if current_gen > 0 => {
518 let last_direction = *animation.last_direction.peek();
519 animation.run(last_direction);
520 }
521 OnChange::Reset if current_gen > 0 => {
522 animation.reset();
523 }
524 _ => {}
525 });
526
527 match config.peek().on_creation {
528 OnCreation::Run => {
529 animation.run(AnimDirection::Forward);
530 }
531 OnCreation::Finish => {
532 animation.finish();
533 }
534 _ => {}
535 }
536
537 animation
538 })
539}
540
541macro_rules! impl_tuple_call {
542 ($(($($type:ident),*)),*) => {
543 $(
544 impl<$($type,)*> AnimatedValue for ($($type,)*)
545 where
546 $($type: AnimatedValue,)*
547 {
548 fn prepare(&mut self, direction: AnimDirection) {
549 #[allow(non_snake_case)]
550 let ($($type,)*) = self;
551 $(
552 $type.prepare(direction);
553 )*
554 }
555
556 fn is_finished(&self, index: u128, direction: AnimDirection) -> bool {
557 #[allow(non_snake_case)]
558 let ($($type,)*) = self;
559 $(
560 if !$type.is_finished(index, direction) {
561 return false;
562 }
563 )*
564 true
565 }
566
567 fn advance(&mut self, index: u128, direction: AnimDirection) {
568 #[allow(non_snake_case)]
569 let ($($type,)*) = self;
570 $(
571 $type.advance(index, direction);
572 )*
573 }
574
575 fn finish(&mut self, direction: AnimDirection) {
576 #[allow(non_snake_case)]
577 let ($($type,)*) = self;
578 $(
579 $type.finish(direction);
580 )*
581 }
582
583 fn into_reversed(self) -> Self {
584 #[allow(non_snake_case)]
585 let ($($type,)*) = self;
586 (
587 $(
588 $type.into_reversed(),
589 )*
590 )
591 }
592 }
593 impl<$($type,)*> ReadAnimatedValue for ($($type,)*)
594 where
595 $($type: ReadAnimatedValue,)*
596 {
597 type Output = (
598 $(
599 <$type as ReadAnimatedValue>::Output,
600 )*
601 );
602 fn value(&self) -> Self::Output {
603 #[allow(non_snake_case)]
604 let ($($type,)*) = self;
605 (
606 $(
607 $type.value(),
608 )*
609 )
610 }
611 }
612 )*
613 };
614}
615
616impl_tuple_call!(
617 (T1),
618 (T1, T2),
619 (T1, T2, T3),
620 (T1, T2, T3, T4),
621 (T1, T2, T3, T4, T5),
622 (T1, T2, T3, T4, T5, T6),
623 (T1, T2, T3, T4, T5, T6, T7),
624 (T1, T2, T3, T4, T5, T6, T7, T8),
625 (T1, T2, T3, T4, T5, T6, T7, T8, T9),
626 (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10),
627 (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11),
628 (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12)
629);