polyhorn_android/components/
image.rs

1use polyhorn_android_sys::{Bitmap, BitmapFactory, Env, Rect};
2use polyhorn_core::CommandBuffer;
3use polyhorn_ui::assets::ImageSource;
4use polyhorn_ui::geometry::{Dimension, Size};
5use polyhorn_ui::styles::ViewStyle;
6
7use crate::prelude::*;
8use crate::raw::{Builtin, Container, ContainerID, Environment, OpaqueContainer};
9use crate::{Key, Reference};
10
11impl Container for polyhorn_android_sys::ImageView {
12    fn mount(&mut self, child: &mut OpaqueContainer, environment: &mut Environment) {
13        if let Some(view) = child.container().to_view() {
14            polyhorn_android_sys::ImageView::to_view(self).add_view(environment.env(), &view)
15        }
16    }
17
18    fn unmount(&mut self) {}
19
20    fn to_view(&self) -> Option<polyhorn_android_sys::View> {
21        Some(polyhorn_android_sys::ImageView::to_view(self))
22    }
23}
24
25struct ConcreteImage {
26    image: Option<Bitmap>,
27    size: Size<f32>,
28}
29
30impl Component for Image {
31    fn render(&self, manager: &mut Manager) -> Element {
32        let view_ref: Reference<Option<ContainerID>> = use_reference!(manager, None);
33
34        let image_source = self.source.clone();
35        let tint_color = self.style.image.tint_color.clone();
36
37        let image = match image_source {
38            ImageSource::Asset(_) => todo!(),
39            ImageSource::Bytes(bytes) => {
40                let env = Env::current();
41                let bitmap = BitmapFactory::decode_byte_array(&env, &bytes).unwrap();
42                let size = Size::new(bitmap.width(&env) as f32, bitmap.height(&env) as f32);
43
44                ConcreteImage {
45                    image: Some(bitmap),
46                    size,
47                }
48            }
49            ImageSource::Placeholder(size) => ConcreteImage { image: None, size },
50        };
51
52        let width = Dimension::Points(image.size.width);
53        let height = Dimension::Points(image.size.height);
54
55        use_layout_effect!(manager, move |link, buffer| {
56            let id = match view_ref.apply(link, |id| id.to_owned()) {
57                Some(id) => id,
58                None => return,
59            };
60
61            buffer.mutate(&[id], move |containers, environment| {
62                let container = &mut containers[0];
63
64                let layout = match container.layout() {
65                    Some(layout) => layout.clone(),
66                    None => return,
67                };
68
69                let layout = layout.current();
70
71                if let Some(view) = container.downcast_mut::<polyhorn_android_sys::ImageView>() {
72                    if let Some(image) = image.image.as_ref() {
73                        if let Some(_) = tint_color {
74                            todo!();
75                        } else {
76                            view.set_image_bitmap(environment.env(), image);
77                        }
78                    }
79
80                    view.set_frame(
81                        environment.env(),
82                        Rect::new(
83                            environment.env(),
84                            layout.origin.x,
85                            layout.origin.y,
86                            layout.size.width,
87                            layout.size.height,
88                        ),
89                    );
90                }
91            });
92        });
93
94        Element::builtin(
95            Key::new(()),
96            Builtin::ImageView(ViewStyle {
97                size: Size { width, height },
98                ..Default::default()
99            }),
100            manager.children(),
101            Some(view_ref.weak(manager)),
102        )
103    }
104}