Pārlūkot izejas kodu

Merge pull request #1074 from kaid/directory-selection-dialog

Add directory support for file input.
Jonathan Kelley 1 gadu atpakaļ
vecāks
revīzija
41c4b57984

+ 21 - 6
examples/file_upload.rs

@@ -1,32 +1,47 @@
 #![allow(non_snake_case)]
 use dioxus::prelude::*;
+use tokio::time::sleep;
 
 fn main() {
     dioxus_desktop::launch(App);
 }
 
 fn App(cx: Scope) -> Element {
+    let enable_directory_upload = use_state(cx, || false);
     let files_uploaded: &UseRef<Vec<String>> = use_ref(cx, Vec::new);
 
     cx.render(rsx! {
+        label {
+            input {
+                r#type: "checkbox",
+                checked: "{enable_directory_upload}",
+                oninput: move |evt| {
+                    enable_directory_upload.set(evt.value.parse().unwrap());
+                },
+            },
+            "Enable directory upload"
+        }
+
         input {
             r#type: "file",
-            accept: ".txt, .rs",
+            accept: ".txt,.rs",
             multiple: true,
+            directory: **enable_directory_upload,
             onchange: |evt| {
                 to_owned![files_uploaded];
                 async move {
                     if let Some(file_engine) = &evt.files {
                         let files = file_engine.files();
-                        for file_name in &files {
-                            if let Some(file) = file_engine.read_file_to_string(file_name).await{
-                                files_uploaded.write().push(file);
-                            }
+                        for file_name in files {
+                            sleep(std::time::Duration::from_secs(1)).await;
+                            files_uploaded.write().push(file_name);
                         }
                     }
                 }
             },
-        }
+        },
+
+        div { "progress: {files_uploaded.read().len()}" },
 
         ul {
             for file in files_uploaded.read().iter() {

+ 43 - 23
packages/desktop/src/file_upload.rs

@@ -8,36 +8,24 @@ pub(crate) struct FileDialogRequest {
     #[serde(default)]
     accept: Option<String>,
     multiple: bool,
+    directory: bool,
     pub event: String,
     pub target: usize,
     pub bubbles: bool,
 }
 
-#[cfg(not(any(
-    target_os = "windows",
-    target_os = "macos",
-    target_os = "linux",
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "netbsd",
-    target_os = "openbsd"
-)))]
-pub(crate) fn get_file_event(_request: &FileDialogRequest) -> Vec<PathBuf> {
-    vec![]
+fn get_file_event_for_folder(request: &FileDialogRequest, dialog: rfd::FileDialog) -> Vec<PathBuf> {
+    if request.multiple {
+        dialog.pick_folders().into_iter().flatten().collect()
+    } else {
+        dialog.pick_folder().into_iter().collect()
+    }
 }
 
-#[cfg(any(
-    target_os = "windows",
-    target_os = "macos",
-    target_os = "linux",
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "netbsd",
-    target_os = "openbsd"
-))]
-pub(crate) fn get_file_event(request: &FileDialogRequest) -> Vec<PathBuf> {
-    let mut dialog = rfd::FileDialog::new();
-
+fn get_file_event_for_file(
+    request: &FileDialogRequest,
+    mut dialog: rfd::FileDialog,
+) -> Vec<PathBuf> {
     let filters: Vec<_> = request
         .accept
         .as_deref()
@@ -62,6 +50,38 @@ pub(crate) fn get_file_event(request: &FileDialogRequest) -> Vec<PathBuf> {
     files
 }
 
+#[cfg(not(any(
+target_os = "windows",
+target_os = "macos",
+target_os = "linux",
+target_os = "dragonfly",
+target_os = "freebsd",
+target_os = "netbsd",
+target_os = "openbsd"
+)))]
+pub(crate) fn get_file_event(_request: &FileDialogRequest) -> Vec<PathBuf> {
+    vec![]
+}
+
+#[cfg(any(
+target_os = "windows",
+target_os = "macos",
+target_os = "linux",
+target_os = "dragonfly",
+target_os = "freebsd",
+target_os = "netbsd",
+target_os = "openbsd"
+))]
+pub(crate) fn get_file_event(request: &FileDialogRequest) -> Vec<PathBuf> {
+    let dialog = rfd::FileDialog::new();
+
+    if request.directory {
+        get_file_event_for_folder(request, dialog)
+    } else {
+        get_file_event_for_file(request, dialog)
+    }
+}
+
 enum Filters {
     Extension(String),
     Mime(String),

+ 1 - 1
packages/desktop/src/protocol.rs

@@ -24,7 +24,7 @@ fn module_loader(root_name: &str) -> String {
             let target_id = find_real_id(target);
             if (target_id !== null) {
               const send = (event_name) => {
-                const message = serializeIpcMessage("file_diolog", { accept: target.getAttribute("accept"), multiple: target.hasAttribute("multiple"), target: parseInt(target_id), bubbles: event_bubbles(event_name), event: event_name });
+                const message = serializeIpcMessage("file_diolog", { accept: target.getAttribute("accept"), directory: target.getAttribute("webkitdirectory") === "true", multiple: target.hasAttribute("multiple"), target: parseInt(target_id), bubbles: event_bubbles(event_name), event: event_name });
                 window.ipc.postMessage(message);
               };
               send("change&input");

+ 1 - 0
packages/html/src/elements.rs

@@ -1098,6 +1098,7 @@ builder_constructors! {
         autofocus: Bool DEFAULT,
         capture: String DEFAULT,
         checked: Bool DEFAULT,
+        directory: Bool "webkitdirectory",
         disabled: Bool DEFAULT,
         form: Id DEFAULT,
         formaction: Uri DEFAULT,

+ 1 - 0
packages/interpreter/src/common.js

@@ -25,6 +25,7 @@ const bool_attrs = {
   reversed: true,
   selected: true,
   truespeed: true,
+  webkitdirectory: true,
 };
 
 export function setAttributeInner(node, field, value, ns) {

+ 1 - 0
packages/interpreter/src/sledgehammer_bindings.rs

@@ -163,6 +163,7 @@ mod js {
         reversed: true,
         selected: true,
         truespeed: true,
+        webkitdirectory: true,
       };
       function truthy(val) {
         return val === "true" || val === true;