Skip to main content

freya_camera/
camera_viewer.rs

1//! [`CameraViewer`] component.
2
3use freya_core::{
4    elements::image::*,
5    prelude::*,
6};
7
8use crate::{
9    camera::CameraError,
10    use_camera::Camera,
11};
12
13/// Renders the latest frame produced by a [`Camera`].
14///
15/// # Example
16///
17/// ```rust, no_run
18/// use freya::{
19///     camera::*,
20///     prelude::*,
21/// };
22///
23/// fn app() -> impl IntoElement {
24///     let camera = use_camera(CameraConfig::default);
25///     CameraViewer::new(camera)
26/// }
27/// ```
28#[derive(PartialEq)]
29pub struct CameraViewer {
30    camera: Camera,
31
32    layout: LayoutData,
33    image_data: ImageData,
34    accessibility: AccessibilityData,
35    effect: EffectData,
36    corner_radius: Option<CornerRadius>,
37
38    children: Vec<Element>,
39    loading_placeholder: Option<Element>,
40    error_renderer: Option<Callback<CameraError, Element>>,
41
42    key: DiffKey,
43}
44
45impl CameraViewer {
46    pub fn new(camera: Camera) -> Self {
47        Self {
48            camera,
49            layout: LayoutData::default(),
50            image_data: ImageData::default(),
51            accessibility: AccessibilityData::default(),
52            effect: EffectData::default(),
53            corner_radius: None,
54            children: Vec::new(),
55            loading_placeholder: None,
56            error_renderer: None,
57            key: DiffKey::None,
58        }
59    }
60
61    pub fn corner_radius(mut self, corner_radius: impl Into<CornerRadius>) -> Self {
62        self.corner_radius = Some(corner_radius.into());
63        self
64    }
65
66    /// Custom element rendered while the camera has not yet produced a frame.
67    pub fn loading_placeholder(mut self, placeholder: impl Into<Element>) -> Self {
68        self.loading_placeholder = Some(placeholder.into());
69        self
70    }
71
72    /// Custom element rendered when the camera fails before producing any frame.
73    pub fn error_renderer(mut self, renderer: impl Into<Callback<CameraError, Element>>) -> Self {
74        self.error_renderer = Some(renderer.into());
75        self
76    }
77}
78
79impl KeyExt for CameraViewer {
80    fn write_key(&mut self) -> &mut DiffKey {
81        &mut self.key
82    }
83}
84
85impl LayoutExt for CameraViewer {
86    fn get_layout(&mut self) -> &mut LayoutData {
87        &mut self.layout
88    }
89}
90
91impl ContainerExt for CameraViewer {}
92impl ContainerWithContentExt for CameraViewer {}
93
94impl ImageExt for CameraViewer {
95    fn get_image_data(&mut self) -> &mut ImageData {
96        &mut self.image_data
97    }
98}
99
100impl AccessibilityExt for CameraViewer {
101    fn get_accessibility_data(&mut self) -> &mut AccessibilityData {
102        &mut self.accessibility
103    }
104}
105
106impl ChildrenExt for CameraViewer {
107    fn get_children(&mut self) -> &mut Vec<Element> {
108        &mut self.children
109    }
110}
111
112impl EffectExt for CameraViewer {
113    fn get_effect(&mut self) -> &mut EffectData {
114        &mut self.effect
115    }
116}
117
118impl Component for CameraViewer {
119    fn render(&self) -> impl IntoElement {
120        if let Some(holder) = self.camera.frame.read().clone() {
121            return image(holder)
122                .accessibility(self.accessibility.clone())
123                .a11y_role(AccessibilityRole::Image)
124                .a11y_focusable(true)
125                .layout(self.layout.clone())
126                .image_data(self.image_data.clone())
127                .effect(self.effect.clone())
128                .children(self.children.clone())
129                .map(self.corner_radius, |img, corner_radius| {
130                    img.corner_radius(corner_radius)
131                })
132                .into_element();
133        }
134
135        if let Some(renderer) = &self.error_renderer
136            && let Some(err) = self.camera.error.read().clone()
137        {
138            return renderer.call(err);
139        }
140
141        rect()
142            .layout(self.layout.clone())
143            .center()
144            .map(self.loading_placeholder.clone(), |r, placeholder| {
145                r.child(placeholder)
146            })
147            .into_element()
148    }
149
150    fn render_key(&self) -> DiffKey {
151        self.key.clone().or(self.default_key())
152    }
153}