logic.rs 4.8 KB
use mogwai::prelude::*;
use web_sys::{HtmlInputElement, HtmlCanvasElement, CanvasRenderingContext2d};

use crate::api::upload::UploadApi;

use super::upload::Upload;

#[derive(Clone, Debug)]
pub(super) enum UploadLogic {
    Add(DomEvent),
    Remove(usize),
    Upload,
}

pub(super) async fn upload_preview_logic( mut rx_canvas :broadcast::Receiver<Dom>
                                        , mut rx_click  :broadcast::Receiver<DomEvent>
                                        ,     upload    :Upload ) {
    if let Some(dom) = rx_canvas.next().await {
        if let Either::Left(c) = dom.inner_read() {
            let canvas = c.to_owned().dyn_into::<HtmlCanvasElement>().unwrap();
            let context = canvas
                        . get_context("2d").unwrap().unwrap()
                        . dyn_into::<CanvasRenderingContext2d>().unwrap();
            let image_width = upload.bitmap().width() as f64;
            let image_height = upload.bitmap().height() as f64;
            let canvas_width = canvas.width() as f64;
            let canvas_height = canvas.height() as f64;

            /* scale with aspect ratio */
            let (ox, oy, width, height) = if image_width > image_height {
                let f = canvas_width / image_width;
                let dest_height = image_height * f;
                let o_y = (canvas_height - dest_height) / 2.0;
                (0.0, o_y, canvas_width, dest_height)
            } else {
                let f = canvas_height / image_height;
                let dest_width = image_width * f;
                let o_x = (canvas_width - dest_width) / 2.0;
                (o_x, 0.0, dest_width, canvas_height)
            };

            context
                . draw_image_with_image_bitmap_and_dw_and_dh(
                      &upload.bitmap()
                    , ox, oy, width, height )
                . unwrap();
        }
    }

    while let Some(_) = rx_click.next().await {
        upload.tx_logic . try_broadcast(UploadLogic::Remove(upload.id))
                        . unwrap();
    }
}

pub(super) async fn upload_logic( mut rx_logic :broadcast::Receiver<UploadLogic>
                                , tx_logic     :broadcast::Sender<UploadLogic>
                                , tx_previews: mpmc::Sender<ListPatch<ViewBuilder<Dom>>>
                                ) {
    let mut uploads: ListPatchModel<Upload> = ListPatchModel::new();
    let api = UploadApi::new().await.unwrap();

    mogwai::spawn(uploads.stream().for_each(move |patch| {
        let patch = patch.map(|u| u.into());
        let tx_previews = tx_previews.clone();
        async move {
            tx_previews.send(patch).await.unwrap();
        }
    }));

    let mut next_id = 0;

    while let Some(msg) = rx_logic.next().await {
        match msg {
            UploadLogic::Add(event) =>
                if let Either::Left(inner) = event.clone_inner() {
                    let filelist = inner.dyn_into::<Event>().unwrap()
                                 . target().unwrap()
                                 . dyn_into::<HtmlInputElement>().unwrap()
                                 . files().unwrap();

                    for index in 0..filelist.length() {
                        let file = filelist.item(index).unwrap();
                        let tx_logic = tx_logic.clone();
                        uploads.list_patch_push( Upload::new(next_id, file, tx_logic)
                                               . await);
                        next_id += 1;
                    }
                },
            UploadLogic::Remove(id) => {
                let mut found = None;

                for (upload, index) in uploads.read().await.iter().zip(0..) {
                    if upload.id == id {
                        found = Some(index);
                        break;
                    }
                }

                if let Some(index) = found {
                    uploads.list_patch_remove(index).unwrap();
                }
            },
            UploadLogic::Upload => {
                let mut remove_ids = vec![];

                for upload in uploads.read().await.iter() {
                    match api.store(upload).await {
                        Ok(_) => remove_ids.push(upload.id),
                        Err(e) => log::error!("{:?}", e),
                    }
                }

                for id in remove_ids.iter() {
                    let mut found = None;

                    for (upload, index) in uploads.read().await.iter().zip(0..) {
                        if upload.id == *id {
                            found = Some(index);
                            break;
                        }
                    }

                    if let Some(index) = found {
                        uploads.list_patch_remove(index).unwrap();
                    }
                }
            }
        }
    }
}