diff --git a/client/src/component/uploader.rs b/client/src/component/uploader.rs index 6e4f807..cc098c7 100644 --- a/client/src/component/uploader.rs +++ b/client/src/component/uploader.rs @@ -1,11 +1,20 @@ +use serde_wasm_bindgen::from_value; use wasm_bindgen_futures::{spawn_local, JsFuture}; use web_sys::{console, Event, HtmlInputElement}; use wasm_bindgen::{closure::Closure, JsCast, JsValue}; -use yew::{ html, prelude::function_component, use_callback, use_context, use_state, Callback, Html, Properties}; +use yew::{ html, prelude::function_component, use_callback, use_context, use_memo, use_state, Callback, Html, Properties}; use js_sys::{Promise, JSON::stringify_with_replacer_and_space}; +use serde_json::{Value}; +use serde::{Deserialize}; use crate::constants::app::AppContext; +#[derive(Deserialize, PartialEq, Clone)] +pub struct Progress { + percent: Value, + total: Value +} + #[derive(Properties, PartialEq)] pub struct UploaderProps { pub on_upload_start: Callback<()>, @@ -20,6 +29,15 @@ pub fn uploader(props: &UploaderProps) -> Html { // state let upload_result = use_state(|| None); let is_uploading = use_state(|| false); + let progress = use_state(|| 0f64); + let percentage = use_memo(progress.clone(), |progress| { + let progress = *progress.clone(); + format!("{:.1}%", progress * 100.0f64) + }); + let circle_style = use_memo(progress.clone(), |progress| { + let progress = *progress.clone(); + format!("--percentage: {:.1};", progress * 100.0f64) + }); // callbacks let upload_start = use_callback( (props.on_upload_start.clone(), is_uploading.clone()), @@ -36,29 +54,53 @@ pub fn uploader(props: &UploaderProps) -> Html { } ); - let on_upload = use_callback(upload_end.clone(), move |e: Event, upload_cb| { - upload_start.emit(()); - let upload_cb = upload_cb.clone(); - let result = cos_upload.call1(&JsValue::NULL, e.as_ref()).unwrap(); - let promise = Promise::from(result); - let closure = Closure::once(Box::new(move |value: JsValue| { - console::log_1(&value); - upload_cb.emit(Some(value)); - }) as Box); - let promise = promise.then(&closure); - closure.forget(); - let future = JsFuture::from(promise); - spawn_local(async { - match future.await { - Ok(_res) => {}, - Err(err) => console::error_1(&err), - }; - }); - }); + let on_upload = use_callback( + (upload_end.clone(), progress.clone()), + move |e: Event, (upload_cb, progress_state)| { + upload_start.emit(()); + + let progress_state = progress_state.clone(); + let closure = Closure::wrap(Box::new(move |payload: JsValue| { + console::log_2(&JsValue::from_str("received"), &payload); + let payload_value: Progress = from_value(payload).unwrap(); + let percent = payload_value.percent.as_f64().unwrap(); + progress_state.set(percent) + }) as Box); + // invoke upload + let result = cos_upload.call2( + &JsValue::NULL, + e.as_ref(), + closure.as_ref().unchecked_ref() + ).unwrap(); + + closure.forget(); + + // promise.then + let promise = Promise::from(result); + let upload_cb = upload_cb.clone(); + let closure = Closure::once(Box::new(move |value: JsValue| { + console::log_1(&value); + upload_cb.emit(Some(value)); + }) as Box); + let promise = promise.then(&closure); + closure.forget(); + + // spawn promise future + let future = JsFuture::from(promise); + spawn_local(async { + match future.await { + Ok(_res) => {}, + Err(err) => console::error_1(&err), + }; + }); + }, + ); html! { -
+
+ + {if let Some(data) = upload_result.as_ref() { let upload_text = stringify_with_replacer_and_space(&data, &JsValue::NULL, &JsValue::from_f64(4.0)).unwrap(); html! {
@@ -66,7 +108,32 @@ pub fn uploader(props: &UploaderProps) -> Html {
{upload_text.as_string().unwrap_or_default()}
} } else if *is_uploading { - html! {
{ "Uploading..." }
} + html! { +
+ + ::clone(&*circle_style.clone())} + /> + +
+
+
{{ percentage }}
+
+
+
+ } } else { html! {