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 direction(&self) -> ReadRef<'static, AnimDirection> {
185 self.last_direction.read()
186 }
187
188 pub fn start(&mut self) {
190 self.run(AnimDirection::Forward)
191 }
192
193 pub fn reverse(&mut self) {
195 self.run(AnimDirection::Reverse)
196 }
197
198 pub fn reset(&mut self) {
200 if let Some(task) = self.task.write().take() {
201 task.cancel();
202 }
203
204 self.animated_value
205 .write()
206 .prepare(*self.last_direction.peek());
207
208 *self.has_run_yet.write() = true;
209 }
210
211 pub fn finish(&mut self) {
213 if let Some(task) = self.task.write().take() {
214 task.cancel();
215 }
216
217 self.animated_value
218 .write()
219 .finish(*self.last_direction.peek());
220
221 *self.has_run_yet.write() = true;
222 }
223
224 pub fn is_running(&self) -> State<bool> {
225 self.is_running
226 }
227
228 pub fn has_run_yet(&self) -> State<bool> {
229 self.has_run_yet
230 }
231
232 pub fn run(&self, mut direction: AnimDirection) {
234 let mut is_running = self.is_running;
235 let mut has_run_yet = self.has_run_yet;
236 let mut task = self.task;
237 let mut last_direction = self.last_direction;
238
239 let on_finish = self.config.peek().on_finish;
240 let mut animated_value = self.animated_value;
241
242 last_direction.set(direction);
243
244 if let Some(task) = task.write().take() {
246 task.cancel();
247 }
248
249 let peek_has_run_yet = *self.has_run_yet.peek();
250
251 let mut ticker = RenderingTicker::get();
252 let platform = Platform::get();
253 let animation_clock = AnimationClock::get();
254
255 let animation_task = spawn(async move {
256 platform.send(UserEvent::RequestRedraw);
257
258 let mut index = 0u128;
259 let mut prev_frame = Instant::now();
260
261 animated_value.write().prepare(direction);
263
264 if !peek_has_run_yet {
265 *has_run_yet.write() = true;
266 }
267 is_running.set(true);
268
269 loop {
270 ticker.tick().await;
272
273 platform.send(UserEvent::RequestRedraw);
275
276 let elapsed = animation_clock.correct_elapsed_duration(prev_frame.elapsed());
277
278 index += elapsed.as_millis();
279
280 let is_finished = {
281 let mut animated_value = animated_value.write();
282 let is_finished = animated_value.is_finished(index, direction);
283 animated_value.advance(index, direction);
285
286 is_finished
287 };
288
289 if is_finished {
290 let delay = match on_finish {
291 OnFinish::Reverse { delay } => {
292 direction.toggle();
294 delay
295 }
296 OnFinish::Restart { delay } => delay,
297 OnFinish::Nothing => {
298 break;
300 }
301 };
302
303 if !delay.is_zero() {
304 Timer::after(delay).await;
305 }
306
307 index = 0;
308
309 animated_value.write().prepare(direction);
311 }
312
313 prev_frame = Instant::now();
314 }
315
316 is_running.set(false);
317 task.write().take();
318 });
319
320 task.write().replace(animation_task);
322 }
323}
324pub fn use_animation<Animated: AnimatedValue>(
420 mut run: impl 'static + FnMut(&mut AnimConfiguration) -> Animated,
421) -> UseAnimation<Animated> {
422 use_hook(|| {
423 let mut config = State::create(AnimConfiguration::default());
424 let mut animated_value = State::create(Animated::default());
425 let is_running = State::create(false);
426 let has_run_yet = State::create(false);
427 let task = State::create(None);
428 let last_direction = State::create(AnimDirection::Forward);
429
430 let mut animation = UseAnimation {
431 animated_value,
432 config,
433 is_running,
434 has_run_yet,
435 task,
436 last_direction,
437 };
438
439 Effect::create_sync(move || {
440 let mut anim_conf = AnimConfiguration::default();
441 animated_value.set(run(&mut anim_conf));
442 *config.write() = anim_conf;
443 });
444
445 Effect::create_sync_with_gen(move |current_gen| match config.read().on_change {
446 OnChange::Finish if current_gen > 0 => {
447 animation.finish();
448 }
449 OnChange::Rerun if current_gen > 0 => {
450 let last_direction = *animation.last_direction.peek();
451 animation.run(last_direction);
452 }
453 OnChange::Reset if current_gen > 0 => {
454 animation.reset();
455 }
456 _ => {}
457 });
458
459 match config.peek().on_creation {
460 OnCreation::Run => {
461 animation.run(AnimDirection::Forward);
462 }
463 OnCreation::Finish => {
464 animation.finish();
465 }
466 _ => {}
467 }
468
469 animation
470 })
471}
472
473pub fn use_animation_with_dependencies<Animated: AnimatedValue, D: 'static + Clone + PartialEq>(
490 dependencies: &D,
491 mut run: impl 'static + FnMut(&mut AnimConfiguration, &D) -> Animated,
492) -> UseAnimation<Animated> {
493 let dependencies = use_reactive(dependencies);
494 use_hook(|| {
495 let mut config = State::create(AnimConfiguration::default());
496 let mut animated_value = State::create(Animated::default());
497 let is_running = State::create(false);
498 let has_run_yet = State::create(false);
499 let task = State::create(None);
500 let last_direction = State::create(AnimDirection::Forward);
501
502 let mut animation = UseAnimation {
503 animated_value,
504 config,
505 is_running,
506 has_run_yet,
507 task,
508 last_direction,
509 };
510
511 Effect::create_sync(move || {
512 let dependencies = dependencies.read();
513 let mut anim_conf = AnimConfiguration::default();
514 animated_value.set(run(&mut anim_conf, &dependencies));
515 *config.write() = anim_conf;
516 });
517
518 Effect::create_sync_with_gen(move |current_gen| match config.read().on_change {
519 OnChange::Finish if current_gen > 0 => {
520 animation.finish();
521 }
522 OnChange::Rerun if current_gen > 0 => {
523 let last_direction = *animation.last_direction.peek();
524 animation.run(last_direction);
525 }
526 OnChange::Reset if current_gen > 0 => {
527 animation.reset();
528 }
529 _ => {}
530 });
531
532 match config.peek().on_creation {
533 OnCreation::Run => {
534 animation.run(AnimDirection::Forward);
535 }
536 OnCreation::Finish => {
537 animation.finish();
538 }
539 _ => {}
540 }
541
542 animation
543 })
544}
545
546macro_rules! impl_tuple_call {
547 ($(($($type:ident),*)),*) => {
548 $(
549 impl<$($type,)*> AnimatedValue for ($($type,)*)
550 where
551 $($type: AnimatedValue,)*
552 {
553 fn prepare(&mut self, direction: AnimDirection) {
554 #[allow(non_snake_case)]
555 let ($($type,)*) = self;
556 $(
557 $type.prepare(direction);
558 )*
559 }
560
561 fn is_finished(&self, index: u128, direction: AnimDirection) -> bool {
562 #[allow(non_snake_case)]
563 let ($($type,)*) = self;
564 $(
565 if !$type.is_finished(index, direction) {
566 return false;
567 }
568 )*
569 true
570 }
571
572 fn advance(&mut self, index: u128, direction: AnimDirection) {
573 #[allow(non_snake_case)]
574 let ($($type,)*) = self;
575 $(
576 $type.advance(index, direction);
577 )*
578 }
579
580 fn finish(&mut self, direction: AnimDirection) {
581 #[allow(non_snake_case)]
582 let ($($type,)*) = self;
583 $(
584 $type.finish(direction);
585 )*
586 }
587
588 fn into_reversed(self) -> Self {
589 #[allow(non_snake_case)]
590 let ($($type,)*) = self;
591 (
592 $(
593 $type.into_reversed(),
594 )*
595 )
596 }
597 }
598 impl<$($type,)*> ReadAnimatedValue for ($($type,)*)
599 where
600 $($type: ReadAnimatedValue,)*
601 {
602 type Output = (
603 $(
604 <$type as ReadAnimatedValue>::Output,
605 )*
606 );
607 fn value(&self) -> Self::Output {
608 #[allow(non_snake_case)]
609 let ($($type,)*) = self;
610 (
611 $(
612 $type.value(),
613 )*
614 )
615 }
616 }
617 )*
618 };
619}
620
621impl_tuple_call!(
622 (T1),
623 (T1, T2),
624 (T1, T2, T3),
625 (T1, T2, T3, T4),
626 (T1, T2, T3, T4, T5),
627 (T1, T2, T3, T4, T5, T6),
628 (T1, T2, T3, T4, T5, T6, T7),
629 (T1, T2, T3, T4, T5, T6, T7, T8),
630 (T1, T2, T3, T4, T5, T6, T7, T8, T9),
631 (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10),
632 (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11),
633 (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12)
634);