clippy, and don't hash invisible files for ts generation

This commit is contained in:
Jonathan Kelley committed 2024-03-05 22:38:38 -08:00
1 parent 39d6580eca
commit 4b2e426958
27 files changed
+173 -936

No files matched your search

+38 -32
View File
@@ -3,12 +3,11 @@ use crate::{
element::DesktopElement,
event_handlers::WindowEventHandlers,
file_upload::{DesktopFileDragEvent, DesktopFileUploadForm, FileDialogRequest},
ipc::{EventData, IpcMessage, UserWindowEvent},
ipc::{IpcMessage, UserWindowEvent},
query::QueryResult,
shortcut::{GlobalHotKeyEvent, ShortcutRegistry},
webview::WebviewInstance,
};
use crossbeam_channel::Receiver;
use dioxus_core::ElementId;
use dioxus_core::VirtualDom;
use dioxus_html::{native_bind::NativeFileEngine, HasFileData, HtmlEvent, PlatformEventData};
@@ -50,7 +49,6 @@ pub(crate) struct SharedContext {
pub(crate) event_handlers: WindowEventHandlers,
pub(crate) pending_webviews: RefCell<Vec<WebviewInstance>>,
pub(crate) shortcut_manager: ShortcutRegistry,
pub(crate) global_hotkey_channel: Receiver<GlobalHotKeyEvent>,
pub(crate) proxy: EventLoopProxy<UserWindowEvent>,
pub(crate) target: EventLoopWindowTarget<UserWindowEvent>,
}
@@ -70,7 +68,6 @@ impl App {
event_handlers: WindowEventHandlers::default(),
pending_webviews: Default::default(),
shortcut_manager: ShortcutRegistry::new(),
global_hotkey_channel: GlobalHotKeyEvent::receiver().clone(),
proxy: event_loop.create_proxy(),
target: event_loop.clone(),
}),
@@ -79,6 +76,9 @@ impl App {
// Set the event converter
dioxus_html::set_event_converter(Box::new(crate::events::SerializedHtmlEventConverter));
// Wire up the global hotkey handler
app.set_global_hotkey_handler();
// Allow hotreloading to work - but only in debug mode
#[cfg(all(feature = "hot-reload", debug_assertions))]
app.connect_hotreload();
@@ -88,14 +88,13 @@ impl App {
pub fn tick(&mut self, window_event: &Event<'_, UserWindowEvent>) {
self.control_flow = ControlFlow::Wait;
self.shared
.event_handlers
.apply_event(window_event, &self.shared.target);
}
if let Ok(event) = self.shared.global_hotkey_channel.try_recv() {
self.shared.shortcut_manager.call_handlers(event);
}
pub fn handle_global_hotkey(&self, event: GlobalHotKeyEvent) {
self.shared.shortcut_manager.call_handlers(event);
}
#[cfg(all(feature = "hot-reload", debug_assertions))]
@@ -103,10 +102,7 @@ impl App {
dioxus_hot_reload::connect({
let proxy = self.shared.proxy.clone();
move |template| {
let _ = proxy.send_event(UserWindowEvent(
EventData::HotReloadEvent(template),
unsafe { WindowId::dummy() },
));
let _ = proxy.send_event(UserWindowEvent::HotReloadEvent(template));
}
});
}
@@ -115,10 +111,7 @@ impl App {
for handler in self.shared.pending_webviews.borrow_mut().drain(..) {
let id = handler.desktop_context.window.id();
self.webviews.insert(id, handler);
_ = self
.shared
.proxy
.send_event(UserWindowEvent(EventData::Poll, id));
_ = self.shared.proxy.send_event(UserWindowEvent::Poll(id));
}
}
@@ -168,11 +161,6 @@ impl App {
let id = webview.desktop_context.window.id();
self.webviews.insert(id, webview);
_ = self
.shared
.proxy
.send_event(UserWindowEvent(EventData::Poll, id));
}
pub fn handle_browser_open(&mut self, msg: IpcMessage) {
@@ -186,19 +174,29 @@ impl App {
}
}
/// The webview is finally loaded
///
/// Let's rebuild it and then start polling it
pub fn handle_initialize_msg(&mut self, id: WindowId) {
let view = self.webviews.get_mut(&id).unwrap();
view.dom
.rebuild(&mut *view.desktop_context.mutation_state.borrow_mut());
view.desktop_context.send_edits();
view.desktop_context
.window
.set_visible(self.is_visible_before_start);
_ = self.shared.proxy.send_event(UserWindowEvent::Poll(id));
}
/// Todo: maybe we should poll the virtualdom asking if it has any final actions to apply before closing the webview
///
/// Technically you can handle this with the use_window_event hook
pub fn handle_close_msg(&mut self, id: WindowId) {
self.webviews.remove(&id);
if self.webviews.is_empty() {
self.control_flow = ControlFlow::Exit
}
@@ -244,16 +242,14 @@ impl App {
if drag.files().is_some() {
let file_event = recent_file.current().unwrap();
let paths = match file_event {
wry::FileDropEvent::Hovered { paths, position } => paths,
wry::FileDropEvent::Dropped { paths, position } => paths,
wry::FileDropEvent::Hovered { paths, .. } => paths,
wry::FileDropEvent::Dropped { paths, .. } => paths,
_ => vec![],
};
let files = Arc::new(NativeFileEngine::new(paths));
let event = DesktopFileDragEvent {
Rc::new(PlatformEventData::new(Box::new(DesktopFileDragEvent {
mouse: drag.mouse.clone(),
files,
};
Rc::new(PlatformEventData::new(Box::new(event)))
files: Arc::new(NativeFileEngine::new(paths)),
})))
} else {
data.into_any()
}
@@ -282,8 +278,6 @@ impl App {
}
}
pub fn handle_file_drag(&mut self, msg: IpcMessage, window: WindowId) {}
pub fn handle_file_dialog_msg(&mut self, msg: IpcMessage, window: WindowId) {
let Ok(file_dialog) = serde_json::from_value::<FileDialogRequest>(msg.params()) else {
return;
@@ -327,6 +321,19 @@ impl App {
view.poll_vdom();
}
fn set_global_hotkey_handler(&self) {
let receiver = self.shared.proxy.clone();
// The event loop becomes the hotkey receiver
// This means we don't need to poll the receiver on every tick - we just get the events as they come in
// This is a bit more efficient than the previous implementation, but if someone else sets a handler, the
// receiver will become inert.
global_hotkey::GlobalHotKeyEvent::set_event_handler(Some(move |t| {
// todo: should we unset the event handler when the app shuts down?
_ = receiver.send_event(UserWindowEvent::GlobalHotKeyEvent(t));
}));
}
}
/// Different hide implementations per platform
@@ -336,7 +343,6 @@ pub fn hide_app_window(window: &wry::WebView) {
{
use tao::platform::windows::WindowExtWindows;
window.set_visible(false);
// window.set_skip_taskbar(true);
}
#[cfg(target_os = "linux")]
+2 -10
View File
@@ -1,11 +1,7 @@
use std::borrow::Cow;
use std::path::PathBuf;
use tao::window::{Icon, WindowBuilder, WindowId};
use wry::{
http::{Request as HttpRequest, Response as HttpResponse},
FileDropEvent,
};
use tao::window::{Icon, WindowBuilder};
use wry::http::{Request as HttpRequest, Response as HttpResponse};
/// The behaviour of the application when the last window is closed.
#[derive(Copy, Clone, Eq, PartialEq)]
@@ -21,7 +17,6 @@ pub enum WindowCloseBehaviour {
/// The configuration for the desktop application.
pub struct Config {
pub(crate) window: WindowBuilder,
pub(crate) file_drop_handler: Option<DropHandler>,
pub(crate) protocols: Vec<WryProtocol>,
pub(crate) pre_rendered: Option<String>,
pub(crate) disable_context_menu: bool,
@@ -35,8 +30,6 @@ pub struct Config {
pub(crate) enable_default_menu_bar: bool,
}
type DropHandler = Box<dyn Fn(WindowId, FileDropEvent) -> bool>;
pub(crate) type WryProtocol = (
String,
Box<dyn Fn(HttpRequest<Vec<u8>>) -> HttpResponse<Cow<'static, [u8]>> + 'static>,
@@ -56,7 +49,6 @@ impl Config {
Self {
window,
protocols: Vec::new(),
file_drop_handler: None,
pre_rendered: None,
disable_context_menu: !cfg!(debug_assertions),
resource_dir: None,
+5 -11
View File
@@ -3,7 +3,7 @@ use crate::{
assets::AssetHandlerRegistry,
edits::EditQueue,
file_upload::NativeFileHover,
ipc::{EventData, UserWindowEvent},
ipc::UserWindowEvent,
query::QueryEngine,
shortcut::{HotKey, ShortcutHandle, ShortcutRegistryError},
webview::WebviewInstance,
@@ -17,14 +17,13 @@ use dioxus_interpreter_js::MutationState;
use std::{
cell::RefCell,
rc::{Rc, Weak},
sync::Arc,
};
use tao::{
event::Event,
event_loop::EventLoopWindowTarget,
window::{Fullscreen as WryFullscreen, Window, WindowId},
};
use wry::{FileDropEvent, RequestAsyncResponder, WebView};
use wry::{RequestAsyncResponder, WebView};
#[cfg(target_os = "ios")]
use tao::platform::ios::WindowExtIOS;
@@ -130,12 +129,7 @@ impl DesktopService {
self.shared
.proxy
.send_event(UserWindowEvent(EventData::NewWindow, cx.id()))
.unwrap();
self.shared
.proxy
.send_event(UserWindowEvent(EventData::Poll, cx.id()))
.send_event(UserWindowEvent::NewWindow)
.unwrap();
self.shared.pending_webviews.borrow_mut().push(window);
@@ -167,7 +161,7 @@ impl DesktopService {
let _ = self
.shared
.proxy
.send_event(UserWindowEvent(EventData::CloseWindow, self.id()));
.send_event(UserWindowEvent::CloseWindow(self.id()));
}
/// Close a particular window, given its ID
@@ -175,7 +169,7 @@ impl DesktopService {
let _ = self
.shared
.proxy
.send_event(UserWindowEvent(EventData::CloseWindow, id));
.send_event(UserWindowEvent::CloseWindow(id));
}
/// change window to fullscreen
+10 -4
View File
@@ -12,7 +12,13 @@ use dioxus_html::{
};
use muda::accelerator::Modifiers;
use serde::Deserialize;
use std::{cell::Cell, path::PathBuf, rc::Rc, str::FromStr, sync::Arc};
use std::{
cell::{Cell, RefCell},
path::PathBuf,
rc::Rc,
str::FromStr,
sync::Arc,
};
use wry::FileDropEvent;
#[derive(Debug, Deserialize)]
@@ -156,15 +162,15 @@ impl HasFormData for DesktopFileUploadForm {
#[derive(Default, Clone)]
pub struct NativeFileHover {
event: Rc<Cell<Option<FileDropEvent>>>,
event: Rc<RefCell<Option<FileDropEvent>>>,
}
impl NativeFileHover {
pub fn set(&self, event: FileDropEvent) {
self.event.set(Some(event));
self.event.borrow_mut().replace(event);
}
pub fn current(&self) -> Option<FileDropEvent> {
self.event.as_ref().clone().take()
self.event.borrow_mut().clone()
}
}
+7 -11
View File
@@ -1,18 +1,17 @@
use global_hotkey::GlobalHotKeyEvent;
use serde::{Deserialize, Serialize};
use tao::window::WindowId;
/// A pair of data
#[derive(Debug, Clone)]
pub struct UserWindowEvent(pub EventData, pub WindowId);
pub enum UserWindowEvent {
/// A global hotkey event
GlobalHotKeyEvent(GlobalHotKeyEvent),
/// The data that might eminate from any window/webview
#[derive(Debug, Clone)]
pub enum EventData {
/// Poll the virtualdom
Poll,
Poll(WindowId),
/// Handle an ipc message eminating from the window.postMessage of a given webview
Ipc(IpcMessage),
Ipc { id: WindowId, msg: IpcMessage },
/// Handle a hotreload event, basically telling us to update our templates
#[cfg(all(feature = "hot-reload", debug_assertions))]
@@ -22,7 +21,7 @@ pub enum EventData {
NewWindow,
/// Close a given window (could be any window!)
CloseWindow,
CloseWindow(WindowId),
}
/// A message struct that manages the communication between the webview and the eventloop code
@@ -42,16 +41,13 @@ pub enum IpcMethod<'a> {
Query,
BrowserOpen,
Initialize,
FileDrag,
Other(&'a str),
}
impl IpcMessage {
pub(crate) fn method(&self) -> IpcMethod {
match self.method.as_str() {
// todo: this is a misspelling, needs to be fixed
"file_dialog" => IpcMethod::FileDialog,
"file_drag" => IpcMethod::FileDrag,
"user_event" => IpcMethod::UserEvent,
"query" => IpcMethod::Query,
"browser_open" => IpcMethod::BrowserOpen,
+11 -9
View File
@@ -1,7 +1,7 @@
pub use crate::Config;
use crate::{
app::App,
ipc::{EventData, IpcMethod, UserWindowEvent},
ipc::{IpcMethod, UserWindowEvent},
};
use dioxus_core::*;
use std::any::Any;
@@ -15,6 +15,7 @@ pub fn launch_virtual_dom_blocking(virtual_dom: VirtualDom, desktop_config: Conf
let (event_loop, mut app) = App::new(desktop_config, virtual_dom);
event_loop.run(move |window_event, _, control_flow| {
// Set the control flow and check if any events need to be handled in the app itself
app.tick(&window_event);
match window_event {
@@ -26,19 +27,20 @@ pub fn launch_virtual_dom_blocking(virtual_dom: VirtualDom, desktop_config: Conf
WindowEvent::Destroyed { .. } => app.window_destroyed(window_id),
_ => {}
},
Event::UserEvent(UserWindowEvent(event, id)) => match event {
EventData::Poll => app.poll_vdom(id),
EventData::NewWindow => app.handle_new_window(),
EventData::CloseWindow => app.handle_close_msg(id),
Event::UserEvent(event) => match event {
UserWindowEvent::Poll(id) => app.poll_vdom(id),
UserWindowEvent::NewWindow => app.handle_new_window(),
UserWindowEvent::CloseWindow(id) => app.handle_close_msg(id),
UserWindowEvent::GlobalHotKeyEvent(evnt) => app.handle_global_hotkey(evnt),
#[cfg(all(feature = "hot-reload", debug_assertions))]
EventData::HotReloadEvent(msg) => app.handle_hot_reload_msg(msg),
EventData::Ipc(msg) => match msg.method() {
UserWindowEvent::HotReloadEvent(msg) => app.handle_hot_reload_msg(msg),
UserWindowEvent::Ipc { id, msg } => match msg.method() {
IpcMethod::Initialize => app.handle_initialize_msg(id),
IpcMethod::FileDialog => app.handle_file_dialog_msg(msg, id),
IpcMethod::FileDrag => app.handle_file_drag(msg, id),
IpcMethod::UserEvent => app.handle_user_event_msg(msg, id),
IpcMethod::Query => app.handle_query_msg(msg, id),
IpcMethod::BrowserOpen => app.handle_browser_open(msg),
IpcMethod::Initialize => app.handle_initialize_msg(id),
IpcMethod::Other(_) => {}
},
},
-6
View File
@@ -80,10 +80,4 @@ pub struct GlobalHotKeyEvent {
pub id: u32,
}
impl GlobalHotKeyEvent {
pub fn receiver() -> crossbeam_channel::Receiver<GlobalHotKeyEvent> {
crossbeam_channel::unbounded().1
}
}
pub(crate) type Code = dioxus_html::input_data::keyboard_types::Code;
+1
View File
@@ -50,6 +50,7 @@ pub(super) fn index_request(
}
None => assets_head(),
};
if let Some(head) = head {
index.insert_str(index.find("</head>").expect("Head element to exist"), &head);
}
+6 -3
View File
@@ -1,13 +1,17 @@
use std::{cell::RefCell, rc::Rc};
use crate::DesktopContext;
use futures_util::{FutureExt, StreamExt};
use generational_box::Owner;
use serde::{de::DeserializeOwned, Deserialize};
use serde_json::Value;
use slab::Slab;
use std::{cell::RefCell, rc::Rc};
use thiserror::Error;
/*
todo:
- write this in the interpreter itself rather than in blobs of inline javascript...
- it could also be simpler, probably?
*/
const DIOXUS_CODE: &str = r#"
let dioxus = {
recv: function () {
@@ -43,7 +47,6 @@ let dioxus = {
}"#;
/// Tracks what query ids are currently active
pub(crate) struct SharedSlab<T = ()> {
pub slab: Rc<RefCell<Slab<T>>>,
}
+2 -2
View File
@@ -1,4 +1,4 @@
use crate::ipc::{EventData, UserWindowEvent};
use crate::ipc::UserWindowEvent;
use futures_util::task::ArcWake;
use std::sync::Arc;
use tao::{event_loop::EventLoopProxy, window::WindowId};
@@ -24,7 +24,7 @@ pub fn tao_waker(proxy: EventLoopProxy<UserWindowEvent>, id: WindowId) -> std::t
fn wake_by_ref(arc_self: &Arc<Self>) {
_ = arc_self
.proxy
.send_event(UserWindowEvent(EventData::Poll, arc_self.id));
.send_event(UserWindowEvent::Poll(arc_self.id));
}
}
+21 -28
View File
@@ -1,13 +1,7 @@
use crate::{
app::SharedContext,
assets::AssetHandlerRegistry,
edits::EditQueue,
eval::DesktopEvalProvider,
file_upload::NativeFileHover,
ipc::{EventData, UserWindowEvent},
protocol,
waker::tao_waker,
Config, DesktopContext, DesktopService,
app::SharedContext, assets::AssetHandlerRegistry, edits::EditQueue, eval::DesktopEvalProvider,
file_upload::NativeFileHover, ipc::UserWindowEvent, protocol, waker::tao_waker, Config,
DesktopContext, DesktopService,
};
use dioxus_core::{ScopeId, VirtualDom};
use dioxus_html::prelude::EvalProvider;
@@ -61,6 +55,7 @@ impl WebviewInstance {
let mut web_context = WebContext::new(cfg.data_dir.clone());
let edit_queue = EditQueue::default();
let file_hover = NativeFileHover::default();
let asset_handlers = AssetHandlerRegistry::new(dom.runtime());
let headless = !cfg.window.window.visible;
@@ -72,6 +67,7 @@ impl WebviewInstance {
let asset_handlers_ = asset_handlers.clone();
let edit_queue_ = edit_queue.clone();
let proxy_ = shared.proxy.clone();
let file_hover_ = file_hover.clone();
let request_handler = move |request, responder: RequestAsyncResponder| {
// Try to serve the index file first
@@ -97,12 +93,17 @@ impl WebviewInstance {
let ipc_handler = move |payload: String| {
// defer the event to the main thread
if let Ok(message) = serde_json::from_str(&payload) {
_ = proxy_.send_event(UserWindowEvent(EventData::Ipc(message), window_id));
if let Ok(msg) = serde_json::from_str(&payload) {
_ = proxy_.send_event(UserWindowEvent::Ipc { id: window_id, msg });
}
};
let file_hover = NativeFileHover::default();
let file_drop_handler = move |evt| {
// Update the most recent file drop event - when the event comes in from the webview we can use the
// most recent event to build a new event with the files in it.
file_hover_.set(evt);
false
};
#[cfg(any(
target_os = "windows",
@@ -133,15 +134,7 @@ impl WebviewInstance {
.with_navigation_handler(|var| var.contains("dioxus")) // prevent all navigations
.with_asynchronous_custom_protocol(String::from("dioxus"), request_handler)
.with_web_context(&mut web_context)
.with_file_drop_handler({
let file_hover = file_hover.clone();
move |evt| {
println!("file drop: {:?}", evt);
// Update the most recent file hover status
file_hover.set(evt);
false
}
});
.with_file_drop_handler(file_drop_handler);
if let Some(color) = cfg.background_color {
webview = webview.with_background_color(color);
@@ -153,15 +146,15 @@ impl WebviewInstance {
const INITIALIZATION_SCRIPT: &str = r#"
if (document.addEventListener) {
document.addEventListener('contextmenu', function(e) {
e.preventDefault();
}, false);
document.addEventListener('contextmenu', function(e) {
e.preventDefault();
}, false);
} else {
document.attachEvent('oncontextmenu', function() {
window.event.returnValue = false;
});
document.attachEvent('oncontextmenu', function() {
window.event.returnValue = false;
});
}
"#;
"#;
if cfg.disable_context_menu {
// in release mode, we don't want to show the dev tool or reload menus