This commit is contained in:
Matthew Ryan Dillon 2021-12-07 21:20:33 -07:00
parent 89e36d7eb0
commit 78153e8bf4
3 changed files with 50 additions and 34 deletions

View file

@ -1,17 +0,0 @@
mod utils;
// use wasm_bindgen::prelude::*;
//
// #[cfg(feature = "wee_alloc")]
// #[global_allocator]
// static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
//
// #[wasm_bindgen]
// pub fn merge(files: js_sys::Array) -> wasm_bindgen::JsValue {
// utils::set_panic_hook();
// let files: Vec<String> = utils::translate_js_to_rust(files);
// let merged: gpx::Gpx = utils::join_gpx_files(files);
// let out_vec: Vec<u8> = utils::write_gpx_to_buffer(merged);
//
// JsValue::from_str(&String::from_utf8(out_vec).unwrap())
// }

View file

@ -9,7 +9,7 @@ use super::utils;
pub enum Msg { pub enum Msg {
FileLoaded(String, String), FileLoaded(String, String),
Files(Vec<File>), StartLoad(Vec<File>),
FilesLoaded, FilesLoaded,
Reset, Reset,
} }
@ -18,6 +18,9 @@ pub struct Loader {
readers: HashMap<String, FileReader>, readers: HashMap<String, FileReader>,
files: Vec<String>, files: Vec<String>,
count: usize, count: usize,
is_loading: bool,
// This field is to handle resetting the native HTML widget's state on error
field_value: &'static str,
} }
impl Component for Loader { impl Component for Loader {
@ -29,6 +32,8 @@ impl Component for Loader {
readers: HashMap::default(), readers: HashMap::default(),
files: vec![], files: vec![],
count: 0, count: 0,
is_loading: false,
field_value: "",
} }
} }
@ -43,8 +48,15 @@ impl Component for Loader {
true true
} }
Msg::Files(files) => { Msg::StartLoad(files) => {
self.count = files.len(); self.count = files.len();
if self.count < 2 {
utils::alert("must load two or more files");
ctx.link().send_message(Msg::Reset);
return true;
}
self.is_loading = true;
for file in files.into_iter() { for file in files.into_iter() {
let file_name = file.name(); let file_name = file.name();
let task = { let task = {
@ -64,7 +76,14 @@ impl Component for Loader {
} }
Msg::FilesLoaded => { Msg::FilesLoaded => {
let merged = utils::merge(&self.files); let merged = match utils::merge(&self.files) {
Ok(result) => result,
Err(err) => {
utils::alert(&err.to_string());
ctx.link().send_message(Msg::Reset);
return true
}
};
let window = web_sys::window().expect("no global `window` exists"); let window = web_sys::window().expect("no global `window` exists");
let document = window.document().expect("should have a document on window"); let document = window.document().expect("should have a document on window");
@ -75,6 +94,8 @@ impl Component for Loader {
anchor_element.set_attribute("href", &url).unwrap(); anchor_element.set_attribute("href", &url).unwrap();
anchor_element.set_attribute("download", "merged.gpx").unwrap(); anchor_element.set_attribute("download", "merged.gpx").unwrap();
self.is_loading = false;
let event = MouseEvent::new("click").unwrap(); let event = MouseEvent::new("click").unwrap();
anchor_element.dispatch_event(&event).unwrap(); anchor_element.dispatch_event(&event).unwrap();
@ -85,6 +106,8 @@ impl Component for Loader {
self.readers = HashMap::default(); self.readers = HashMap::default();
self.files = vec![]; self.files = vec![];
self.count = 0; self.count = 0;
self.is_loading = false;
self.field_value = "";
true true
} }
} }
@ -93,8 +116,10 @@ impl Component for Loader {
fn view(&self, ctx: &Context<Self>) -> Html { fn view(&self, ctx: &Context<Self>) -> Html {
let link = ctx.link(); let link = ctx.link();
html! { html! {
<> if self.is_loading {
<input type="file" multiple=true onchange={link.callback(move |e: Event| { <span>{"loading..."}</span>
} else {
<input type="file" value={self.field_value} multiple=true onchange={link.callback(move |e: Event| {
let mut result = Vec::new(); let mut result = Vec::new();
let input: HtmlInputElement = e.target_unchecked_into(); let input: HtmlInputElement = e.target_unchecked_into();
@ -106,10 +131,10 @@ impl Component for Loader {
.map(File::from); .map(File::from);
result.extend(files); result.extend(files);
} }
Msg::Files(result) Msg::StartLoad(result)
})} })}
/> />
</> }
} }
} }
} }

View file

@ -1,12 +1,14 @@
use std::error::Error;
use web_sys::Blob; use web_sys::Blob;
use wasm_bindgen::prelude::*;
fn join_gpx_files(files: &Vec<String>) -> gpx::Gpx { fn join_gpx_files(files: &Vec<String>) -> Result<gpx::Gpx, Box<dyn Error>> {
let mut merged_gpx: gpx::Gpx = Default::default(); let mut merged_gpx: gpx::Gpx = Default::default();
let mut merged_track: gpx::Track = gpx::Track::new(); let mut merged_track: gpx::Track = gpx::Track::new();
for file in files.iter() { for file in files.iter() {
let buffer = std::io::BufReader::new(file.as_bytes()); let buffer = std::io::BufReader::new(file.as_bytes());
let mut parsed_gpx: gpx::Gpx = gpx::read(buffer).expect("invalid gpx"); let mut parsed_gpx: gpx::Gpx = gpx::read(buffer)?;
// consolidate all track segements into one single track. // consolidate all track segements into one single track.
for track in parsed_gpx.tracks { for track in parsed_gpx.tracks {
@ -36,22 +38,28 @@ fn join_gpx_files(files: &Vec<String>) -> gpx::Gpx {
merged_gpx.metadata = Some(metadata); merged_gpx.metadata = Some(metadata);
merged_gpx.version = gpx::GpxVersion::Gpx11; merged_gpx.version = gpx::GpxVersion::Gpx11;
merged_gpx Ok(merged_gpx)
} }
fn write_gpx_to_buffer(gpx: gpx::Gpx) -> js_sys::Array { fn write_gpx_to_buffer(gpx: gpx::Gpx) -> Result<js_sys::Array, Box<dyn Error>> {
let mut buffer = Vec::new(); let mut buffer = Vec::new();
gpx::write(&gpx, &mut buffer).unwrap(); gpx::write(&gpx, &mut buffer)?;
let uint8arr = js_sys::Uint8Array::new(&unsafe { js_sys::Uint8Array::view(&buffer) }.into()); let uint8arr = js_sys::Uint8Array::new(&unsafe { js_sys::Uint8Array::view(&buffer) }.into());
let array = js_sys::Array::new(); let array = js_sys::Array::new();
array.push(&uint8arr.buffer()); array.push(&uint8arr.buffer());
array Ok(array)
} }
pub fn merge(files: &Vec<String>) -> Blob { pub fn merge(files: &Vec<String>) -> Result<Blob, Box<dyn Error>> {
let merged: gpx::Gpx = join_gpx_files(files); let merged: gpx::Gpx = join_gpx_files(files)?;
let out_vec = write_gpx_to_buffer(merged); let out_vec = write_gpx_to_buffer(merged)?;
let result = Blob::new_with_u8_array_sequence(&out_vec).map_err(|e| e.as_string().unwrap() )?;
Blob::new_with_u8_array_sequence(&out_vec).unwrap() Ok(result)
}
#[wasm_bindgen]
extern {
pub fn alert(s: &str);
} }