diff --git a/examples/filedragdrop.rs b/examples/filedragdrop.rs new file mode 100644 index 000000000..a36b64ddb --- /dev/null +++ b/examples/filedragdrop.rs @@ -0,0 +1,18 @@ +use dioxus::prelude::*; + +fn main() { + dioxus::desktop::launch_with_props(app, (), |c| { + c.with_file_drop_handler(|w, e| { + println!("{:?}", e); + false + }) + }); +} + +fn app(cx: Scope) -> Element { + cx.render(rsx!( + div { + h1 { "drag an file here" } + } + )) +} diff --git a/examples/manual_edits.rs b/examples/manual_edits.rs deleted file mode 100644 index c6486919a..000000000 --- a/examples/manual_edits.rs +++ /dev/null @@ -1,39 +0,0 @@ -/* -Example: Manual Edits - -It's possible to manually provide a stream of DomEdits to a Dioxus Renderer. All renderers are designed to accept a stream -of DomEdits that abstract over a stack machine. This allows the VirtualDOM to exist entirely separately from the RealDOM, -though features like NodeRefs and NativeEvents might not work properly everywhere. -*/ - -use dioxus::core::*; -use dioxus::prelude::*; - -fn main() { - use DomEdit::*; - - let edits = vec![ - // create a container and push it onto the stack - CreateElement { - tag: "div", - root: 0, - }, - // create an element and push it onto the stack - CreateElement { tag: "h1", root: 2 }, - // create a text node and push it onto the stack - CreateTextNode { - text: "hello world", - root: 3, - }, - // append the text node to the h1 element - AppendChildren { many: 1 }, - // append the h1 element to the container - AppendChildren { many: 1 }, - // append the container to the default render element ("dioxusroot" if used with default config) - AppendChildren { many: 1 }, - ]; - - let app: Component = |cx| cx.render(rsx!(div { "some app" })); - - dioxus_desktop::launch_with_props(app, (), |c| c.with_edits(edits)); -} diff --git a/packages/desktop/src/cfg.rs b/packages/desktop/src/cfg.rs index 60e3ff887..ad85cfc0f 100644 --- a/packages/desktop/src/cfg.rs +++ b/packages/desktop/src/cfg.rs @@ -1,19 +1,29 @@ -use dioxus_core::DomEdit; use wry::{ - application::{event_loop::EventLoop, window::WindowBuilder}, - webview::WebView, + application::{ + event_loop::EventLoop, + window::{Window, WindowBuilder}, + }, + http::{Request as HttpRequest, Response as HttpResponse}, + webview::{FileDropEvent, WebView}, + Result as WryResult, }; pub(crate) type DynEventHandlerFn = dyn Fn(&mut EventLoop<()>, &mut WebView); -pub struct DesktopConfig<'a> { +pub struct DesktopConfig { pub window: WindowBuilder, - pub(crate) manual_edits: Option>>, + pub file_drop_handler: Option bool>>, + pub protocos: Vec, pub(crate) pre_rendered: Option, pub(crate) event_handler: Option>, } -impl<'a> DesktopConfig<'a> { +pub type WryProtocl = ( + String, + Box WryResult + 'static>, +); + +impl DesktopConfig { /// Initializes a new `WindowBuilder` with default values. #[inline] pub fn new() -> Self { @@ -21,16 +31,12 @@ impl<'a> DesktopConfig<'a> { Self { event_handler: None, window, + protocos: Vec::new(), + file_drop_handler: None, pre_rendered: None, - manual_edits: None, } } - pub fn with_edits(&mut self, edits: Vec>) -> &mut Self { - self.manual_edits = Some(edits); - self - } - pub fn with_prerendered(&mut self, content: String) -> &mut Self { self.pre_rendered = Some(content); self @@ -56,9 +62,25 @@ impl<'a> DesktopConfig<'a> { self.event_handler = Some(Box::new(handler)); self } + + pub fn with_file_drop_handler( + &mut self, + handler: impl Fn(&Window, FileDropEvent) -> bool + 'static, + ) -> &mut Self { + self.file_drop_handler = Some(Box::new(handler)); + self + } + + pub fn with_custom_protocol(mut self, name: String, handler: F) -> Self + where + F: Fn(&HttpRequest) -> WryResult + 'static, + { + self.protocos.push((name, Box::new(handler))); + self + } } -impl<'a> Default for DesktopConfig<'a> { +impl Default for DesktopConfig { fn default() -> Self { Self::new() } diff --git a/packages/desktop/src/index.html b/packages/desktop/src/index.html index 5228818bd..a67432e98 100644 --- a/packages/desktop/src/index.html +++ b/packages/desktop/src/index.html @@ -15,4 +15,4 @@ - \ No newline at end of file + diff --git a/packages/desktop/src/lib.rs b/packages/desktop/src/lib.rs index 62270290e..0b6044761 100644 --- a/packages/desktop/src/lib.rs +++ b/packages/desktop/src/lib.rs @@ -116,7 +116,7 @@ pub fn launch(root: Component) { /// ``` pub fn launch_cfg( root: Component, - config_builder: impl for<'a, 'b> FnOnce(&'b mut DesktopConfig<'a>) -> &'b mut DesktopConfig<'a>, + config_builder: impl FnOnce(&mut DesktopConfig) -> &mut DesktopConfig, ) { launch_with_props(root, (), config_builder) } @@ -147,7 +147,7 @@ pub fn launch_cfg( pub fn launch_with_props( root: Component

, props: P, - builder: impl for<'a, 'b> FnOnce(&'b mut DesktopConfig<'a>) -> &'b mut DesktopConfig<'a>, + builder: impl FnOnce(&mut DesktopConfig) -> &mut DesktopConfig, ) { let mut cfg = DesktopConfig::new(); builder(&mut cfg); @@ -170,9 +170,11 @@ pub fn launch_with_props( let (is_ready, sender) = (desktop.is_ready.clone(), desktop.sender.clone()); let proxy = proxy.clone(); - let webview = WebViewBuilder::new(window) + let file_handler = cfg.file_drop_handler.take(); + + let mut webview = WebViewBuilder::new(window) .unwrap() - .with_url("wry://index.html/") + .with_url("dioxus://index.html/") .unwrap() .with_rpc_handler(move |_window: &Window, req: RpcRequest| { match req.method.as_str() { @@ -189,26 +191,37 @@ pub fn launch_with_props( } None }) - .with_custom_protocol("wry".into(), move |request| { - // Any content that that uses the `wry://` scheme will be shuttled through this handler as a "special case" + .with_custom_protocol("dioxus".into(), move |request| { + // Any content that that uses the `dioxus://` scheme will be shuttled through this handler as a "special case" // For now, we only serve two pieces of content which get included as bytes into the final binary. - let path = request.uri().replace("wry://", ""); - let (data, meta) = match path.as_str() { - "index.html" | "index.html/" | "/index.html" => { - (include_bytes!("./index.html").to_vec(), "text/html") - } - "index.html/index.js" => { - (include_bytes!("./index.js").to_vec(), "text/javascript") - } - _ => (include_bytes!("./index.html").to_vec(), "text/html"), - }; + let path = request.uri().replace("dioxus://", ""); - wry::http::ResponseBuilder::new().mimetype(meta).body(data) + if path.trim_end_matches('/') == "index.html" { + wry::http::ResponseBuilder::new() + .mimetype("text/html") + .body(include_bytes!("./index.html").to_vec()) + } else if path.trim_end_matches('/') == "index.html/index.js" { + wry::http::ResponseBuilder::new() + .mimetype("text/javascript") + .body(include_bytes!("./index.js").to_vec()) + } else { + wry::http::ResponseBuilder::new() + .status(wry::http::status::StatusCode::NOT_FOUND) + .body(format!("Not found: {}", path).as_bytes().to_vec()) + } }) - .build() - .unwrap(); + .with_file_drop_handler(move |window, evet| { + if let Some(handler) = file_handler.as_ref() { + return handler(window, evet); + } + false + }); - desktop.webviews.insert(window_id, webview); + for (name, handler) in cfg.protocos.drain(..) { + webview = webview.with_custom_protocol(name, handler) + } + + desktop.webviews.insert(window_id, webview.build().unwrap()); } Event::WindowEvent {