Skip to main content

freya_components/
loader.rs

1use freya_animation::prelude::*;
2use freya_core::prelude::*;
3use torin::size::Size;
4
5use crate::{
6    define_theme,
7    get_theme,
8};
9
10define_theme! {
11    %[component]
12    pub CircularLoader {
13        %[fields]
14        primary_color: Color,
15        inversed_color: Color,
16    }
17}
18
19/// Circular loader component.
20///
21/// # Example
22///
23/// ```rust
24/// # use freya::prelude::*;
25/// fn app() -> impl IntoElement {
26///     CircularLoader::new()
27/// }
28///
29/// # use freya_testing::prelude::*;
30/// # launch_doc(|| {
31/// #   rect().spacing(8.).center().expanded().child(app())
32/// # }, "./images/gallery_circular_loader.png").render();
33/// ```
34///
35/// # Preview
36/// ![Circular Loader Preview][circular_loader]
37#[cfg_attr(feature = "docs",
38    doc = embed_doc_image::embed_image!("circular_loader", "images/gallery_circular_loader.png")
39)]
40#[derive(PartialEq)]
41pub struct CircularLoader {
42    pub(crate) theme: Option<CircularLoaderThemePartial>,
43    size: f32,
44    key: DiffKey,
45}
46
47impl KeyExt for CircularLoader {
48    fn write_key(&mut self) -> &mut DiffKey {
49        &mut self.key
50    }
51}
52
53impl Default for CircularLoader {
54    fn default() -> Self {
55        Self::new()
56    }
57}
58
59impl CircularLoader {
60    pub fn new() -> Self {
61        Self {
62            size: 32.,
63            theme: None,
64            key: DiffKey::None,
65        }
66    }
67
68    pub fn size(mut self, size: f32) -> Self {
69        self.size = size;
70        self
71    }
72}
73
74impl Component for CircularLoader {
75    fn render(&self) -> impl IntoElement {
76        let theme = get_theme!(
77            &self.theme,
78            CircularLoaderThemePreference,
79            "circular_loader"
80        );
81
82        let animation = use_animation(|conf| {
83            conf.on_creation(OnCreation::Run);
84            conf.on_finish(OnFinish::restart());
85            AnimNum::new(0.0, 360.0).time(650)
86        });
87
88        svg(Bytes::from_static(
89            r#"<svg viewBox="0 0 600 600" xmlns="http://www.w3.org/2000/svg">
90                <circle class="spin" cx="300" cy="300" fill="none"
91                r="250" stroke-width="64" stroke="{color}"
92                stroke-dasharray="256 1400"
93                stroke-linecap="round" />
94            </svg>"#
95                .as_bytes(),
96        ))
97        .a11y_focusable(true)
98        .a11y_role(AccessibilityRole::ProgressIndicator)
99        .width(Size::px(self.size))
100        .height(Size::px(self.size))
101        .stroke(theme.primary_color)
102        .rotate(animation.get().value())
103    }
104
105    fn render_key(&self) -> DiffKey {
106        self.key.clone().or(self.default_key())
107    }
108}