Skip to content

Commit

Permalink
File upload - simplify a bit with gloo::file::FileList::from (#3685)
Browse files Browse the repository at this point in the history
* simplify a little with gloo::file::FileList::from

* a little less repetition

* trim the web_sys feature flags a bit

* drop the clone

* more golf

* fmt

---------

Co-authored-by: Elina <[email protected]>
  • Loading branch information
knzai and ranile authored Oct 12, 2024
1 parent 4978b99 commit 8788a4f
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 51 deletions.
2 changes: 1 addition & 1 deletion examples/file_upload/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ gloo = "0.11"

[dependencies.web-sys]
version = "0.3"
features = ["File", "DragEvent", "DataTransfer"]
features = ["DataTransfer"]
79 changes: 29 additions & 50 deletions examples/file_upload/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,19 @@ use std::collections::HashMap;
use base64::engine::general_purpose::STANDARD;
use base64::Engine;
use gloo::file::callbacks::FileReader;
use gloo::file::File;
use web_sys::{DragEvent, Event, FileList, HtmlInputElement};
use web_sys::{DragEvent, Event, HtmlInputElement};
use yew::html::TargetCast;
use yew::{html, Callback, Component, Context, Html};

struct FileDetails {
pub struct FileDetails {
name: String,
file_type: String,
data: Vec<u8>,
}

pub enum Msg {
Loaded(String, String, Vec<u8>),
Files(Vec<File>),
Loaded(FileDetails),
Files(Option<web_sys::FileList>),
}

pub struct App {
Expand All @@ -38,40 +37,38 @@ impl Component for App {

fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
match msg {
Msg::Loaded(file_name, file_type, data) => {
self.files.push(FileDetails {
data,
file_type,
name: file_name.clone(),
});
self.readers.remove(&file_name);
Msg::Loaded(file) => {
self.readers.remove(&file.name);
self.files.push(file);
true
}
Msg::Files(files) => {
for file in files.into_iter() {
let file_name = file.name();
for file in gloo::file::FileList::from(files.expect("files")).iter() {
let link = ctx.link().clone();
let name = file.name().clone();
let file_type = file.raw_mime_type();

let task = {
let link = ctx.link().clone();
let file_name = file_name.clone();

gloo::file::callbacks::read_as_bytes(&file, move |res| {
link.send_message(Msg::Loaded(
file_name,
gloo::file::callbacks::read_as_bytes(file, move |res| {
link.send_message(Msg::Loaded(FileDetails {
data: res.expect("failed to read file"),
file_type,
res.expect("failed to read file"),
))
name,
}))
})
};
self.readers.insert(file_name, task);
self.readers.insert(file.name(), task);
}
true
}
}
}

fn view(&self, ctx: &Context<Self>) -> Html {
let noop_drag = Callback::from(|e: DragEvent| {
e.prevent_default();
});

html! {
<div id="wrapper">
<p id="title">{ "Upload Your Files To The Cloud" }</p>
Expand All @@ -80,15 +77,10 @@ impl Component for App {
id="drop-container"
ondrop={ctx.link().callback(|event: DragEvent| {
event.prevent_default();
let files = event.data_transfer().unwrap().files();
Self::upload_files(files)
})}
ondragover={Callback::from(|event: DragEvent| {
event.prevent_default();
})}
ondragenter={Callback::from(|event: DragEvent| {
event.prevent_default();
Msg::Files(event.data_transfer().unwrap().files())
})}
ondragover={&noop_drag}
ondragenter={&noop_drag}
>
<i class="fa fa-cloud-upload"></i>
<p>{"Drop your images here or click to select"}</p>
Expand All @@ -101,7 +93,7 @@ impl Component for App {
multiple={true}
onchange={ctx.link().callback(move |e: Event| {
let input: HtmlInputElement = e.target_unchecked_into();
Self::upload_files(input.files())
Msg::Files(input.files())
})}
/>
<div id="preview-area">
Expand All @@ -114,37 +106,24 @@ impl Component for App {

impl App {
fn view_file(file: &FileDetails) -> Html {
let file_type = file.file_type.to_string();
let src = format!("data:{};base64,{}", file_type, STANDARD.encode(&file.data));
html! {
<div class="preview-tile">
<p class="preview-name">{ format!("{}", file.name) }</p>
<p class="preview-name">{ &file.name }</p>
<div class="preview-media">
if file.file_type.contains("image") {
<img src={format!("data:{};base64,{}", file.file_type, STANDARD.encode(&file.data))} />
<img src={src} />
} else if file.file_type.contains("video") {
<video controls={true}>
<source src={format!("data:{};base64,{}", file.file_type, STANDARD.encode(&file.data))} type={file.file_type.clone()}/>
<source src={src} type={ file_type }/>
</video>
}
</div>
</div>
}
}

fn upload_files(files: Option<FileList>) -> Msg {
let mut result = Vec::new();

if let Some(files) = files {
let files = js_sys::try_iter(&files)
.unwrap()
.unwrap()
.map(|v| web_sys::File::from(v.unwrap()))
.map(File::from);
result.extend(files);
}
Msg::Files(result)
}
}

fn main() {
yew::Renderer::<App>::new().render();
}

1 comment on commit 8788a4f

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yew master branch benchmarks (Lower is better)

Benchmark suite Current: 8788a4f Previous: 4978b99 Ratio
yew-hooks-v0.21.0-keyed 01_run1k 194.5 186.1 1.05
yew-hooks-v0.21.0-keyed 02_replace1k 221.1 211.3 1.05
yew-hooks-v0.21.0-keyed 03_update10th1k_x16 96.3 86.3 1.12
yew-hooks-v0.21.0-keyed 04_select1k 42.9 38.1 1.13
yew-hooks-v0.21.0-keyed 05_swap1k 115.9 97.6 1.19
yew-hooks-v0.21.0-keyed 06_remove-one-1k 81.4 76 1.07
yew-hooks-v0.21.0-keyed 07_create10k 2201.2 2171 1.01
yew-hooks-v0.21.0-keyed 08_create1k-after1k_x2 224.9 211.9 1.06
yew-hooks-v0.21.0-keyed 09_clear1k_x8 89.7 82.5 1.09
yew-hooks-v0.21.0-keyed 21_ready-memory 2.1515684127807617 2.1226301193237305 1.01
yew-hooks-v0.21.0-keyed 22_run-memory 6.310305595397949 6.260809898376465 1.01
yew-hooks-v0.21.0-keyed 23_update5-memory 6.610221862792969 6.571136474609375 1.01
yew-hooks-v0.21.0-keyed 25_run-clear-memory 5.131223678588867 5.14837646484375 1.00
yew-hooks-v0.21.0-keyed 26_run-10k-memory 42.7772216796875 42.82802867889404 1.00
yew-hooks-v0.21.0-keyed 41_size-uncompressed 168 168 1
yew-hooks-v0.21.0-keyed 42_size-compressed 54.6 54.6 1
yew-hooks-v0.21.0-keyed 43_first-paint 433.9 440.2 0.99
yew-v0.21.0-keyed 01_run1k 190.5 188.6 1.01
yew-v0.21.0-keyed 02_replace1k 216.1 209.4 1.03
yew-v0.21.0-keyed 03_update10th1k_x16 68.3 64.6 1.06
yew-v0.21.0-keyed 04_select1k 15.9 14.8 1.07
yew-v0.21.0-keyed 05_swap1k 75.3 73.3 1.03
yew-v0.21.0-keyed 06_remove-one-1k 64.4 63.5 1.01
yew-v0.21.0-keyed 07_create10k 2188.4 2153.4 1.02
yew-v0.21.0-keyed 08_create1k-after1k_x2 218.2 205.6 1.06
yew-v0.21.0-keyed 09_clear1k_x8 88.4 82.7 1.07
yew-v0.21.0-keyed 21_ready-memory 2.1397790908813477 2.1184768676757812 1.01
yew-v0.21.0-keyed 22_run-memory 6.247590065002441 6.225220680236816 1.00
yew-v0.21.0-keyed 23_update5-memory 6.338171005249023 6.371580123901367 0.99
yew-v0.21.0-keyed 25_run-clear-memory 4.97933292388916 4.891103744506836 1.02
yew-v0.21.0-keyed 26_run-10k-memory 41.577165603637695 41.544267654418945 1.00
yew-v0.21.0-keyed 41_size-uncompressed 166 166 1
yew-v0.21.0-keyed 42_size-compressed 54.4 54.4 1
yew-v0.21.0-keyed 43_first-paint 424.9 433 0.98

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.