polyhorn-ios 0.3.0

Polyhorn for iOS.
Documentation
use polyhorn_core::CommandBuffer;
use polyhorn_ios_sys::coregraphics::CGRect;
use polyhorn_ios_sys::polykit::{PLYImageView, PLYView};
use polyhorn_ios_sys::uikit::UIImage;
use polyhorn_ui::assets::{Asset, ImageSource};
use polyhorn_ui::geometry::{Dimension, Size};
use polyhorn_ui::styles::ViewStyle;

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

impl Container for PLYImageView {
    fn mount(&mut self, child: &mut OpaqueContainer) {
        if let Some(view) = child.container().to_view() {
            PLYImageView::to_view(self).add_subview(&view)
        }
    }

    fn unmount(&mut self) {
        PLYImageView::to_view(self).remove_from_superview();
    }

    fn to_view(&self) -> Option<PLYView> {
        Some(PLYImageView::to_view(self))
    }
}

struct ConcreteImage {
    image: Option<UIImage>,
    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(asset) => {
                let path = asset.package().to_owned() + "/" + asset.name();
                let image = UIImage::with_name(&path).unwrap();
                let size = Size::new(image.size().width as f32, image.size().height as f32);

                ConcreteImage {
                    image: Some(image),
                    size,
                }
            }
            ImageSource::Placeholder(size) => ConcreteImage { image: None, size },
            _ => unimplemented!("Image sources backed by buffers are not yet implemented."),
        };

        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, _| {
                let container = &mut containers[0];

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

                if let Some(view) = container.downcast_mut::<PLYImageView>() {
                    if let Some(image) = image.image.as_ref() {
                        view.set_image(image);
                    }

                    if let Some(tint_color) = tint_color {
                        view.set_tint_color(&tint_color.convert());
                    }

                    view.to_view().set_layout(move || {
                        let current = layout.current();

                        CGRect::new(
                            current.origin.x as _,
                            current.origin.y as _,
                            current.size.width as _,
                            current.size.height as _,
                        )
                    });
                }
            });
        });

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