polyhorn-android 0.4.0

Polyhorn for Android.
Documentation
use polyhorn_android_sys::{Bitmap, BitmapFactory, Env, Rect};
use polyhorn_core::CommandBuffer;
use polyhorn_ui::assets::ImageSource;
use polyhorn_ui::geometry::{Dimension, Size};
use polyhorn_ui::styles::ViewStyle;

use crate::prelude::*;
use crate::raw::{Builtin, Container, ContainerID, Environment, OpaqueContainer};
use crate::{Key, Reference};

impl Container for polyhorn_android_sys::ImageView {
    fn mount(&mut self, child: &mut OpaqueContainer, environment: &mut Environment) {
        if let Some(view) = child.container().to_view() {
            polyhorn_android_sys::ImageView::to_view(self).add_view(environment.env(), &view)
        }
    }

    fn unmount(&mut self) {}

    fn to_view(&self) -> Option<polyhorn_android_sys::View> {
        Some(polyhorn_android_sys::ImageView::to_view(self))
    }
}

struct ConcreteImage {
    image: Option<Bitmap>,
    size: Size<f32>,
}

impl Component for Image {
    fn render(&self, manager: &mut Manager) -> Element {
        let view_ref: Reference<Option<ContainerID>> = use_reference!(manager, None);

        let image_source = self.source.clone();
        let tint_color = self.style.image.tint_color.clone();

        let image = match image_source {
            ImageSource::Asset(_) => todo!(),
            ImageSource::Bytes(bytes) => {
                let env = Env::current();
                let bitmap = BitmapFactory::decode_byte_array(&env, &bytes).unwrap();
                let size = Size::new(bitmap.width(&env) as f32, bitmap.height(&env) as f32);

                ConcreteImage {
                    image: Some(bitmap),
                    size,
                }
            }
            ImageSource::Placeholder(size) => ConcreteImage { image: None, size },
        };

        let width = Dimension::Points(image.size.width);
        let height = Dimension::Points(image.size.height);

        use_layout_effect!(manager, move |link, buffer| {
            let id = match view_ref.apply(link, |id| id.to_owned()) {
                Some(id) => id,
                None => return,
            };

            buffer.mutate(&[id], move |containers, environment| {
                let container = &mut containers[0];

                let layout = match container.layout() {
                    Some(layout) => layout.clone(),
                    None => return,
                };

                let layout = layout.current();

                if let Some(view) = container.downcast_mut::<polyhorn_android_sys::ImageView>() {
                    if let Some(image) = image.image.as_ref() {
                        if let Some(_) = tint_color {
                            todo!();
                        } else {
                            view.set_image_bitmap(environment.env(), image);
                        }
                    }

                    view.set_frame(
                        environment.env(),
                        Rect::new(
                            environment.env(),
                            layout.origin.x,
                            layout.origin.y,
                            layout.size.width,
                            layout.size.height,
                        ),
                    );
                }
            });
        });

        Element::builtin(
            Key::new(()),
            Builtin::ImageView(ViewStyle {
                size: Size { width, height },
                ..Default::default()
            }),
            manager.children(),
            Some(view_ref.weak(manager)),
        )
    }
}