Skip to main content

repose_ui/
anim_ext.rs

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        // restart animation to 1.0 each change (UI can layer content if desired)
62        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}