feat: get desktop working with just creation

This commit is contained in:
Jonathan Kelley committed 2022-11-15 18:32:48 -08:00
1 parent 8caabb97d8
commit e8ae830cf2
16 files changed
+1301 -329

No files matched your search

+2 -2
View File
@@ -27,7 +27,7 @@ type DropHandler = Box<dyn Fn(&Window, FileDropEvent) -> bool>;
pub(crate) type WryProtocol = (
String,
Box<dyn Fn(&HttpRequest) -> WryResult<HttpResponse> + 'static>,
Box<dyn Fn(&HttpRequest<Vec<u8>>) -> WryResult<HttpResponse<Vec<u8>>> + 'static>,
);
impl Config {
@@ -96,7 +96,7 @@ impl Config {
/// Set a custom protocol
pub fn with_custom_protocol<F>(mut self, name: String, handler: F) -> Self
where
F: Fn(&HttpRequest) -> WryResult<HttpResponse> + 'static,
F: Fn(&HttpRequest<Vec<u8>>) -> WryResult<HttpResponse<Vec<u8>>> + 'static,
{
self.protocols.push((name, Box::new(handler)));
self
+27 -18
View File
@@ -40,24 +40,23 @@ impl DesktopController {
.unwrap();
runtime.block_on(async move {
println!("starting vdom");
let mut dom = VirtualDom::new_with_props(root, props);
let window_context = DesktopContext::new(desktop_context_proxy);
dom.base_scope().provide_context(window_context);
// // allow other proccesses to send the new rsx text to the @dioxusin ipc channel and recieve erros on the @dioxusout channel
// #[cfg(any(feature = "hot-reload", debug_assertions))]
// crate::hot_reload::init(&dom);
let edits = dom.rebuild();
let mut queue = edit_queue.lock().unwrap();
queue.push(serde_json::to_string(&edits.template_mutations).unwrap());
queue.push(serde_json::to_string(&edits.edits).unwrap());
// Make sure the window is ready for any new updates
proxy.send_event(UserWindowEvent::Update).unwrap();
{
let mut queue = edit_queue.lock().unwrap();
queue.push(serde_json::to_string(&edits.template_mutations).unwrap());
queue.push(serde_json::to_string(&edits.edits).unwrap());
proxy.send_event(UserWindowEvent::Update).unwrap();
drop(queue);
}
loop {
// todo: add the channel of the event loop in
@@ -71,14 +70,18 @@ impl DesktopController {
))
.await;
let mut queue = edit_queue.lock().unwrap();
{
let mut queue = edit_queue.lock().unwrap();
for edit in muts.template_mutations {
queue.push(serde_json::to_string(&edit).unwrap());
}
for edit in muts.template_mutations {
queue.push(serde_json::to_string(&edit).unwrap());
}
for edit in muts.edits {
queue.push(serde_json::to_string(&edit).unwrap());
for edit in muts.edits {
queue.push(serde_json::to_string(&edit).unwrap());
}
drop(queue);
}
let _ = proxy.send_event(UserWindowEvent::Update);
@@ -104,10 +107,16 @@ impl DesktopController {
pub(super) fn try_load_ready_webviews(&mut self) {
if self.is_ready.load(std::sync::atomic::Ordering::Relaxed) {
let mut queue = self.pending_edits.lock().unwrap();
let mut new_queue = Vec::new();
{
let mut queue = self.pending_edits.lock().unwrap();
std::mem::swap(&mut new_queue, &mut *queue);
}
let (_id, view) = self.webviews.iter_mut().next().unwrap();
for edit in queue.drain(..) {
for edit in new_queue.drain(..) {
view.evaluate_script(&format!("window.interpreter.handleEdits({})", edit))
.unwrap();
}
+11 -7
View File
@@ -1,3 +1,5 @@
use std::rc::Rc;
use crate::controller::DesktopController;
use dioxus_core::ScopeState;
use wry::application::event_loop::ControlFlow;
@@ -15,6 +17,13 @@ pub fn use_window(cx: &ScopeState) -> &DesktopContext {
.unwrap()
}
/// Get a closure that executes any JavaScript in the WebView context.
pub fn use_eval(cx: &ScopeState) -> &Rc<dyn Fn(String)> {
let desktop = use_window(cx).clone();
&*cx.use_hook(|| Rc::new(move |script| desktop.eval(script)) as Rc<dyn Fn(String)>)
}
/// An imperative interface to the current window.
///
/// To get a handle to the current window, use the [`use_window`] hook.
@@ -176,6 +185,8 @@ pub(super) fn handler(
let webview = desktop.webviews.values().next().unwrap();
let window = webview.window();
println!("user_event: {:?}", user_event);
match user_event {
Update => desktop.try_load_ready_webviews(),
CloseWindow => *control_flow = ControlFlow::Exit,
@@ -227,10 +238,3 @@ pub(super) fn handler(
}
}
}
/// Get a closure that executes any JavaScript in the WebView context.
pub fn use_eval<S: std::string::ToString>(cx: &ScopeState) -> &dyn Fn(S) {
let desktop = use_window(cx).clone();
cx.use_hook(|| move |script| desktop.eval(script))
}
+10 -2
View File
@@ -105,19 +105,20 @@ pub fn launch_with_props<P: 'static + Send>(root: Component<P>, props: P, mut cf
// We assume that if the icon is None, then the user just didnt set it
if cfg.window.window.window_icon.is_none() {
cfg.window.window.window_icon = Some(
cfg.window = cfg.window.with_window_icon(Some(
tao::window::Icon::from_rgba(
include_bytes!("./assets/default_icon.bin").to_vec(),
460,
460,
)
.expect("image parse failed"),
);
));
}
event_loop.run(move |window_event, event_loop, control_flow| {
*control_flow = ControlFlow::Wait;
// println!("window event: {:?}", window_event);
match window_event {
Event::NewEvents(StartCause::Init) => {
let builder = cfg.window.clone();
@@ -151,6 +152,7 @@ pub fn launch_with_props<P: 'static + Send>(root: Component<P>, props: P, mut cf
}
"initialize" => {
is_ready.store(true, std::sync::atomic::Ordering::Relaxed);
println!("initializing...");
let _ = proxy.send_event(UserWindowEvent::Update);
}
"browser_open" => {
@@ -179,6 +181,12 @@ pub fn launch_with_props<P: 'static + Send>(root: Component<P>, props: P, mut cf
index_file.clone(),
)
})
// passing edits via the custom protocol is faster than using eval, maybe?
.with_custom_protocol(String::from("edits"), move |r| {
//
// Ok(Response::body())
todo!()
})
.with_file_drop_handler(move |window, evet| {
file_handler
.as_ref()
+23 -15
View File
@@ -1,6 +1,6 @@
use std::path::{Path, PathBuf};
use wry::{
http::{status::StatusCode, Request, Response, ResponseBuilder},
http::{status::StatusCode, Request, Response},
Result,
};
@@ -13,14 +13,14 @@ const MODULE_LOADER: &str = r#"
"#;
pub(super) fn desktop_handler(
request: &Request,
request: &Request<Vec<u8>>,
asset_root: Option<PathBuf>,
custom_head: Option<String>,
custom_index: Option<String>,
) -> Result<Response> {
) -> Result<Response<Vec<u8>>> {
// Any content 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("dioxus://", "");
let path = request.uri().to_string().replace("dioxus://", "");
// all assets should be called from index.html
let trimmed = path.trim_start_matches("index.html/");
@@ -32,7 +32,10 @@ pub(super) fn desktop_handler(
let rendered = custom_index
.replace("</body>", &format!("{}</body>", MODULE_LOADER))
.into_bytes();
ResponseBuilder::new().mimetype("text/html").body(rendered)
Response::builder()
.header("Content-Type", "text/html")
.body(rendered)
.map_err(From::from)
} else {
// Otherwise, we'll serve the default index.html and apply a custom head if that's specified.
let mut template = include_str!("./index.html").to_string();
@@ -41,14 +44,16 @@ pub(super) fn desktop_handler(
}
template = template.replace("<!-- MODULE LOADER -->", MODULE_LOADER);
ResponseBuilder::new()
.mimetype("text/html")
Response::builder()
.header("Content-Type", "text/html")
.body(template.into_bytes())
.map_err(From::from)
}
} else if trimmed == "index.js" {
ResponseBuilder::new()
.mimetype("text/javascript")
Response::builder()
.header("Content-Type", "text/javascript")
.body(dioxus_interpreter_js::INTERPRETER_JS.as_bytes().to_vec())
.map_err(From::from)
} else {
let asset_root = asset_root
.unwrap_or_else(|| get_asset_root().unwrap_or_else(|| Path::new(".").to_path_buf()))
@@ -57,20 +62,23 @@ pub(super) fn desktop_handler(
let asset = asset_root.join(trimmed).canonicalize()?;
if !asset.starts_with(asset_root) {
return ResponseBuilder::new()
return Response::builder()
.status(StatusCode::FORBIDDEN)
.body(String::from("Forbidden").into_bytes());
.body(String::from("Forbidden").into_bytes())
.map_err(From::from);
}
if !asset.exists() {
return ResponseBuilder::new()
return Response::builder()
.status(StatusCode::NOT_FOUND)
.body(String::from("Not Found").into_bytes());
.body(String::from("Not Found").into_bytes())
.map_err(From::from);
}
ResponseBuilder::new()
.mimetype(get_mime_from_path(trimmed)?)
Response::builder()
.header("Content-Type", get_mime_from_path(trimmed)?)
.body(std::fs::read(asset)?)
.map_err(From::from)
}
}