1use std::cell::RefCell;
2
3use crate::{Box, ViewExt, navigation::Transition};
4use repose_core::*;
5
6use crate::anim::animate_f32;
7
8pub fn AnimatedVisibility(
9 key: impl Into<String>,
10 visible: bool,
11 _enter: EnterTransition,
12 _exit: ExitTransition,
13 content: View,
14) -> View {
15 let key = key.into();
16 let alpha = animate_f32(
17 format!("visibility_alpha:{key}"),
18 if visible { 1.0 } else { 0.0 },
19 AnimationSpec::default(),
20 );
21
22 let scale = animate_f32(
23 format!("visibility_scale:{key}"),
24 if visible { 1.0 } else { 0.8 },
25 AnimationSpec::default(),
26 );
27
28 if alpha > 0.01 {
29 Box(Modifier::new().alpha(alpha).scale(scale)).child(content)
30 } else {
31 Box(Modifier::new())
32 }
33}
34
35pub enum EnterTransition {
36 FadeIn,
37 SlideIn,
38 ScaleIn,
39 ExpandIn,
40}
41
42pub enum ExitTransition {
43 FadeOut,
44 SlideOut,
45 ScaleOut,
46 ShrinkOut,
47}
48
49pub fn Crossfade<T: PartialEq + Clone + 'static>(
50 key: impl Into<String>,
51 target: T,
52 content: impl Fn(T) -> View + 'static,
53) -> View {
54 let key = key.into();
55 let prev = remember_with_key(format!("crossfade_prev:{key}"), || {
56 RefCell::new(target.clone())
57 });
58
59 let alpha = if *prev.borrow() != target {
60 prev.replace(target.clone());
61 animate_f32(format!("crossfade_alpha:{key}"), 1.0, AnimationSpec::fast())
63 } else {
64 1.0
65 };
66
67 Box(Modifier::new().alpha(alpha)).child(content(target))
68}
69
70pub fn AnimatedContent(key: String, transition: Option<Transition>, content: View) -> View {
71 match transition {
72 Some(Transition::Push { .. }) => {
73 let offset = animate_f32(format!("push_{key}"), 0.0, AnimationSpec::default());
74 Box(Modifier::new().translate(offset, 0.0)).child(content)
75 }
76 Some(Transition::Pop { .. }) => {
77 let offset = animate_f32(format!("pop_{key}"), 0.0, AnimationSpec::default());
78 Box(Modifier::new().translate(-offset, 0.0)).child(content)
79 }
80 _ => content,
81 }
82}