Showing
5 changed files
with
86 additions
and
40 deletions
| @@ -3,28 +3,38 @@ use web_sys::{HtmlInputElement, ImageBitmap, HtmlCanvasElement, CanvasRenderingC | @@ -3,28 +3,38 @@ use web_sys::{HtmlInputElement, ImageBitmap, HtmlCanvasElement, CanvasRenderingC | ||
| 3 | 3 | ||
| 4 | use super::upload::Upload; | 4 | use super::upload::Upload; |
| 5 | 5 | ||
| 6 | +#[derive(Clone, Debug)] | ||
| 7 | +pub(super) enum UploadLogic { | ||
| 8 | + Add(DomEvent), | ||
| 9 | + Remove(usize), | ||
| 10 | +} | ||
| 11 | + | ||
| 6 | pub(super) async fn upload_preview_logic( mut rx_canvas :broadcast::Receiver<Dom> | 12 | pub(super) async fn upload_preview_logic( mut rx_canvas :broadcast::Receiver<Dom> |
| 7 | - , upload :Upload ) { | ||
| 8 | - while let Some(dom) = rx_canvas.next().await { | ||
| 9 | - match dom.inner_read() { | ||
| 10 | - Either::Left(c) => { | ||
| 11 | - let canvas = c.to_owned().dyn_into::<HtmlCanvasElement>().unwrap(); | ||
| 12 | - let context = canvas | ||
| 13 | - . get_context("2d").unwrap().unwrap() | ||
| 14 | - . dyn_into::<CanvasRenderingContext2d>().unwrap(); | ||
| 15 | - context | ||
| 16 | - . draw_image_with_image_bitmap_and_dw_and_dh( | ||
| 17 | - &upload.bitmap() | ||
| 18 | - , 0.0, 0.0 | ||
| 19 | - , canvas.width() as f64, canvas.height() as f64 ) | ||
| 20 | - . unwrap(); | ||
| 21 | - }, | ||
| 22 | - _ => (), | 13 | + , mut rx_click :broadcast::Receiver<DomEvent> |
| 14 | + , upload :Upload ) { | ||
| 15 | + if let Some(dom) = rx_canvas.next().await { | ||
| 16 | + if let Either::Left(c) = dom.inner_read() { | ||
| 17 | + let canvas = c.to_owned().dyn_into::<HtmlCanvasElement>().unwrap(); | ||
| 18 | + let context = canvas | ||
| 19 | + . get_context("2d").unwrap().unwrap() | ||
| 20 | + . dyn_into::<CanvasRenderingContext2d>().unwrap(); | ||
| 21 | + context | ||
| 22 | + . draw_image_with_image_bitmap_and_dw_and_dh( | ||
| 23 | + &upload.bitmap() | ||
| 24 | + , 0.0, 0.0 | ||
| 25 | + , canvas.width() as f64, canvas.height() as f64 ) | ||
| 26 | + . unwrap(); | ||
| 23 | } | 27 | } |
| 24 | } | 28 | } |
| 29 | + | ||
| 30 | + while let Some(event) = rx_click.next().await { | ||
| 31 | + upload.tx_logic . try_broadcast(UploadLogic::Remove(upload.id)) | ||
| 32 | + . unwrap(); | ||
| 33 | + } | ||
| 25 | } | 34 | } |
| 26 | 35 | ||
| 27 | -pub(super) async fn upload_logic( mut rx_logic: broadcast::Receiver<DomEvent> | 36 | +pub(super) async fn upload_logic( mut rx_logic :broadcast::Receiver<UploadLogic> |
| 37 | + , tx_logic :broadcast::Sender<UploadLogic> | ||
| 28 | , tx_previews: mpmc::Sender<ListPatch<ViewBuilder<Dom>>> | 38 | , tx_previews: mpmc::Sender<ListPatch<ViewBuilder<Dom>>> |
| 29 | ) { | 39 | ) { |
| 30 | let mut uploads: ListPatchModel<Upload> = ListPatchModel::new(); | 40 | let mut uploads: ListPatchModel<Upload> = ListPatchModel::new(); |
| @@ -37,20 +47,39 @@ pub(super) async fn upload_logic( mut rx_logic: broadcast::Receiver<DomEvent> | @@ -37,20 +47,39 @@ pub(super) async fn upload_logic( mut rx_logic: broadcast::Receiver<DomEvent> | ||
| 37 | } | 47 | } |
| 38 | })); | 48 | })); |
| 39 | 49 | ||
| 50 | + let mut next_id = 0; | ||
| 51 | + | ||
| 40 | while let Some(msg) = rx_logic.next().await { | 52 | while let Some(msg) = rx_logic.next().await { |
| 41 | - match msg.clone_inner() { | ||
| 42 | - Either::Left(val) => { | ||
| 43 | - let filelist = val.dyn_into::<Event>().unwrap() | ||
| 44 | - . target().unwrap() | ||
| 45 | - . dyn_into::<HtmlInputElement>().unwrap() | ||
| 46 | - . files().unwrap(); | ||
| 47 | - | ||
| 48 | - for index in 0..filelist.length() { | ||
| 49 | - let file = filelist.item(index).unwrap(); | ||
| 50 | - uploads.list_patch_push(Upload::new(file).await); | 53 | + match msg { |
| 54 | + UploadLogic::Add(event) => | ||
| 55 | + if let Either::Left(inner) = event.clone_inner() { | ||
| 56 | + let filelist = inner.dyn_into::<Event>().unwrap() | ||
| 57 | + . target().unwrap() | ||
| 58 | + . dyn_into::<HtmlInputElement>().unwrap() | ||
| 59 | + . files().unwrap(); | ||
| 60 | + | ||
| 61 | + for index in 0..filelist.length() { | ||
| 62 | + let file = filelist.item(index).unwrap(); | ||
| 63 | + let tx_logic = tx_logic.clone(); | ||
| 64 | + uploads.list_patch_push( Upload::new(next_id, file, tx_logic) | ||
| 65 | + . await); | ||
| 66 | + next_id += 1; | ||
| 67 | + } | ||
| 68 | + }, | ||
| 69 | + UploadLogic::Remove(id) => { | ||
| 70 | + let mut found = None; | ||
| 71 | + | ||
| 72 | + for (upload, index) in uploads.read().await.iter().zip(0..) { | ||
| 73 | + if upload.id == id { | ||
| 74 | + found = Some(index); | ||
| 75 | + break; | ||
| 76 | + } | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | + if let Some(index) = found { | ||
| 80 | + uploads.list_patch_remove(index).unwrap(); | ||
| 51 | } | 81 | } |
| 52 | }, | 82 | }, |
| 53 | - _ => (), | ||
| 54 | } | 83 | } |
| 55 | } | 84 | } |
| 56 | } | 85 | } |
| @@ -10,8 +10,8 @@ pub(crate) async fn new() -> Component<Dom> { | @@ -10,8 +10,8 @@ pub(crate) async fn new() -> Component<Dom> { | ||
| 10 | let (tx_logic, rx_logic) = broadcast::bounded(1); | 10 | let (tx_logic, rx_logic) = broadcast::bounded(1); |
| 11 | let (tx_previews, rx_previews) = mpmc::bounded(1); | 11 | let (tx_previews, rx_previews) = mpmc::bounded(1); |
| 12 | 12 | ||
| 13 | - let view = upload_view(tx_logic, rx_previews); | ||
| 14 | - let logic = upload_logic(rx_logic, tx_previews); | 13 | + let view = upload_view(tx_logic.clone(), rx_previews); |
| 14 | + let logic = upload_logic(rx_logic, tx_logic, tx_previews); | ||
| 15 | 15 | ||
| 16 | Component::from(view).with_logic(logic) | 16 | Component::from(view).with_logic(logic) |
| 17 | } | 17 | } |
| 1 | use mogwai::{prelude::*, utils::window}; | 1 | use mogwai::{prelude::*, utils::window}; |
| 2 | use web_sys::{File, ImageBitmap, ReadableStream}; | 2 | use web_sys::{File, ImageBitmap, ReadableStream}; |
| 3 | 3 | ||
| 4 | -use super::{view::upload_preview_view, logic::upload_preview_logic}; | 4 | +use super::{view::upload_preview_view, logic::{upload_preview_logic, UploadLogic}}; |
| 5 | 5 | ||
| 6 | #[derive(Clone, Debug)] | 6 | #[derive(Clone, Debug)] |
| 7 | pub(super) struct Upload { | 7 | pub(super) struct Upload { |
| 8 | - file :File, | ||
| 9 | - bitmap :ImageBitmap, | 8 | + pub(super) id :usize, |
| 9 | + file :File, | ||
| 10 | + bitmap :ImageBitmap, | ||
| 11 | + pub(super) tx_logic :broadcast::Sender<UploadLogic>, | ||
| 10 | } | 12 | } |
| 11 | 13 | ||
| 12 | impl Upload { | 14 | impl Upload { |
| 13 | - pub(super) async fn new(file :File) -> Upload { | 15 | + pub(super) async fn new( id :usize |
| 16 | + , file :File | ||
| 17 | + , tx_logic :broadcast::Sender<UploadLogic> | ||
| 18 | + ) -> Upload { | ||
| 14 | let bitmap = window() | 19 | let bitmap = window() |
| 15 | . create_image_bitmap_with_blob(&file.clone().into()) | 20 | . create_image_bitmap_with_blob(&file.clone().into()) |
| 16 | . unwrap(); | 21 | . unwrap(); |
| @@ -18,7 +23,7 @@ impl Upload { | @@ -18,7 +23,7 @@ impl Upload { | ||
| 18 | . await.unwrap() | 23 | . await.unwrap() |
| 19 | . dyn_into::<ImageBitmap>().unwrap(); | 24 | . dyn_into::<ImageBitmap>().unwrap(); |
| 20 | 25 | ||
| 21 | - Self { file, bitmap } | 26 | + Self { id, file, bitmap, tx_logic } |
| 22 | } | 27 | } |
| 23 | 28 | ||
| 24 | pub(super) fn mime_type(&self) -> String { | 29 | pub(super) fn mime_type(&self) -> String { |
| @@ -37,13 +42,15 @@ impl Upload { | @@ -37,13 +42,15 @@ impl Upload { | ||
| 37 | impl From<Upload> for Component<Dom> { | 42 | impl From<Upload> for Component<Dom> { |
| 38 | fn from(upload: Upload) -> Self { | 43 | fn from(upload: Upload) -> Self { |
| 39 | let (tx_canvas, rx_canvas) = broadcast::bounded(1); | 44 | let (tx_canvas, rx_canvas) = broadcast::bounded(1); |
| 45 | + let (tx_click, rx_click) = broadcast::bounded(1); | ||
| 40 | 46 | ||
| 41 | let view = upload_preview_view( tx_canvas | 47 | let view = upload_preview_view( tx_canvas |
| 48 | + , tx_click | ||
| 42 | , upload.file.name() | 49 | , upload.file.name() |
| 43 | , upload.file.size() | 50 | , upload.file.size() |
| 44 | , upload.file.type_() | 51 | , upload.file.type_() |
| 45 | , upload.file.last_modified() ); | 52 | , upload.file.last_modified() ); |
| 46 | - let logic = upload_preview_logic(rx_canvas, upload); | 53 | + let logic = upload_preview_logic(rx_canvas, rx_click, upload); |
| 47 | 54 | ||
| 48 | Component::from(view).with_logic(logic) | 55 | Component::from(view).with_logic(logic) |
| 49 | } | 56 | } |
| 1 | use mogwai::prelude::*; | 1 | use mogwai::prelude::*; |
| 2 | 2 | ||
| 3 | +use crate::component::upload::logic::UploadLogic; | ||
| 4 | + | ||
| 3 | pub(super) fn upload_preview_view( tx_canvas :broadcast::Sender<Dom> | 5 | pub(super) fn upload_preview_view( tx_canvas :broadcast::Sender<Dom> |
| 6 | + , tx_click :broadcast::Sender<DomEvent> | ||
| 4 | , filename :String | 7 | , filename :String |
| 5 | , size :f64 | 8 | , size :f64 |
| 6 | , mime_type :String | 9 | , mime_type :String |
| 7 | - , mtime :f64 ) -> ViewBuilder<Dom> { | 10 | + , mtime :f64 |
| 11 | + ) -> ViewBuilder<Dom> { | ||
| 8 | let post_build = move |dom: &mut Dom| { | 12 | let post_build = move |dom: &mut Dom| { |
| 9 | tx_canvas.try_broadcast(dom.clone()).unwrap(); | 13 | tx_canvas.try_broadcast(dom.clone()).unwrap(); |
| 10 | }; | 14 | }; |
| 11 | 15 | ||
| 12 | builder! { | 16 | builder! { |
| 13 | - <li style:display="flex"> | 17 | + <li style:display="flex" |
| 18 | + on:click=tx_click.sink()> | ||
| 14 | <canvas width="75px" | 19 | <canvas width="75px" |
| 15 | height="75px" | 20 | height="75px" |
| 16 | post:build=post_build /> | 21 | post:build=post_build /> |
| @@ -24,9 +29,13 @@ pub(super) fn upload_preview_view( tx_canvas :broadcast::Sender<Dom> | @@ -24,9 +29,13 @@ pub(super) fn upload_preview_view( tx_canvas :broadcast::Sender<Dom> | ||
| 24 | } | 29 | } |
| 25 | } | 30 | } |
| 26 | 31 | ||
| 27 | -pub(super) fn upload_view( tx_logic: broadcast::Sender<DomEvent> | 32 | +pub(super) fn upload_view( tx_logic: broadcast::Sender<UploadLogic> |
| 28 | , rx_previews: mpmc::Receiver<ListPatch<ViewBuilder<Dom>>> | 33 | , rx_previews: mpmc::Receiver<ListPatch<ViewBuilder<Dom>>> |
| 29 | ) -> ViewBuilder<Dom> { | 34 | ) -> ViewBuilder<Dom> { |
| 35 | + let on_change_filter = tx_logic | ||
| 36 | + . sink() | ||
| 37 | + . contra_map(|e| UploadLogic::Add(e)); | ||
| 38 | + | ||
| 30 | // <div class="spin"></div> | 39 | // <div class="spin"></div> |
| 31 | builder! { | 40 | builder! { |
| 32 | <div class="upload"> | 41 | <div class="upload"> |
| @@ -34,7 +43,7 @@ pub(super) fn upload_view( tx_logic: broadcast::Sender<DomEvent> | @@ -34,7 +43,7 @@ pub(super) fn upload_view( tx_logic: broadcast::Sender<DomEvent> | ||
| 34 | <input type="file" | 43 | <input type="file" |
| 35 | multiple="multiple" | 44 | multiple="multiple" |
| 36 | accept="image/*" | 45 | accept="image/*" |
| 37 | - on:change=tx_logic.sink() /> | 46 | + on:change=on_change_filter /> |
| 38 | <button>"Upload"</button> | 47 | <button>"Upload"</button> |
| 39 | </div> | 48 | </div> |
| 40 | <ul patch:children=rx_previews> | 49 | <ul patch:children=rx_previews> |
Please
register
or
login
to post a comment