fix merge

This commit is contained in:
Evan Almloff 2024-01-08 14:51:35 -06:00
parent 56798b3d1c
commit 194c9d43e3
11 changed files with 234 additions and 31 deletions

View file

@ -0,0 +1 @@

View file

@ -12,7 +12,7 @@ use crate::{
use crossbeam_channel::Receiver; use crossbeam_channel::Receiver;
use dioxus_core::{Component, ElementId, VirtualDom}; use dioxus_core::{Component, ElementId, VirtualDom};
use dioxus_html::{ use dioxus_html::{
native_bind::NativeFileEngine, FileEngine, HasFormData, HtmlEvent, MountedData, native_bind::NativeFileEngine, FileEngine, HasFileData, HasFormData, HtmlEvent, MountedData,
PlatformEventData, SerializedHtmlEventConverter, PlatformEventData, SerializedHtmlEventConverter,
}; };
use std::{ use std::{
@ -280,11 +280,13 @@ impl<P: 'static> App<P> {
files: Arc<NativeFileEngine>, files: Arc<NativeFileEngine>,
} }
impl HasFormData for DesktopFileUploadForm { impl HasFileData for DesktopFileUploadForm {
fn files(&self) -> Option<Arc<dyn FileEngine>> { fn files(&self) -> Option<Arc<dyn FileEngine>> {
Some(self.files.clone()) Some(self.files.clone())
} }
}
impl HasFormData for DesktopFileUploadForm {
fn as_any(&self) -> &dyn std::any::Any { fn as_any(&self) -> &dyn std::any::Any {
self self
} }

View file

@ -94,11 +94,10 @@ impl WebviewInstance {
.unwrap() .unwrap()
.with_ipc_handler(ipc_handler) .with_ipc_handler(ipc_handler)
.with_asynchronous_custom_protocol(String::from("dioxus"), request_handler) .with_asynchronous_custom_protocol(String::from("dioxus"), request_handler)
.with_file_drop_handler(file_drop_handler)
.with_web_context(&mut web_context); .with_web_context(&mut web_context);
if let Some(handler) = file_handler { if let Some(handler) = file_handler {
webview = webview.with_file_drop_handler(handler) webview = webview.with_file_drop_handler(move |evt| handler(window_id, evt))
} }
// This was removed from wry, I'm not sure what replaced it // This was removed from wry, I'm not sure what replaced it

View file

@ -1,14 +1,13 @@
use crate::file_data::{FileEngine, HasFileData};
use crate::geometry::{ClientPoint, Coordinates, ElementPoint, PagePoint, ScreenPoint}; use crate::geometry::{ClientPoint, Coordinates, ElementPoint, PagePoint, ScreenPoint};
use crate::input_data::{MouseButton, MouseButtonSet}; use crate::input_data::{MouseButton, MouseButtonSet};
use crate::prelude::*; use crate::prelude::*;
use crate::FileEngine;
use dioxus_core::Event; use dioxus_core::Event;
use keyboard_types::Modifiers; use keyboard_types::Modifiers;
use crate::HasMouseData; use crate::HasMouseData;
use dioxus_core::Event;
use std::fmt::Debug; use std::fmt::Debug;
pub type DragEvent = Event<DragData>; pub type DragEvent = Event<DragData>;
@ -57,11 +56,12 @@ impl DragData {
/// Downcast this event data to a specific type /// Downcast this event data to a specific type
pub fn downcast<T: 'static>(&self) -> Option<&T> { pub fn downcast<T: 'static>(&self) -> Option<&T> {
self.inner.as_any().downcast_ref::<T>() HasDragData::as_any(&*self.inner).downcast_ref::<T>()
} }
}
/// Get the files of the form event impl HasFileData for DragData {
pub fn files(&self) -> Option<std::sync::Arc<dyn FileEngine>> { fn files(&self) -> Option<std::sync::Arc<dyn FileEngine>> {
self.inner.files() self.inner.files()
} }
} }
@ -112,19 +112,34 @@ impl PointerInteraction for DragData {
#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Clone)] #[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Clone)]
pub struct SerializedDragData { pub struct SerializedDragData {
mouse: crate::point_interaction::SerializedPointInteraction, mouse: crate::point_interaction::SerializedPointInteraction,
files: Option<crate::file_data::SerializedFileEngine>,
} }
#[cfg(feature = "serialize")] #[cfg(feature = "serialize")]
impl From<&DragData> for SerializedDragData { impl SerializedDragData {
fn from(data: &DragData) -> Self { fn new(drag: &DragData, files: Option<crate::file_data::SerializedFileEngine>) -> Self {
Self { Self {
mouse: crate::point_interaction::SerializedPointInteraction::from(data), mouse: crate::point_interaction::SerializedPointInteraction::from(drag),
files,
} }
} }
} }
#[cfg(feature = "serialize")] #[cfg(feature = "serialize")]
impl HasDragData for SerializedDragData {} impl HasDragData for SerializedDragData {
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
#[cfg(feature = "serialize")]
impl HasFileData for SerializedDragData {
fn files(&self) -> Option<std::sync::Arc<dyn FileEngine>> {
self.files
.as_ref()
.map(|files| std::sync::Arc::new(files.clone()) as _)
}
}
#[cfg(feature = "serialize")] #[cfg(feature = "serialize")]
impl HasMouseData for SerializedDragData { impl HasMouseData for SerializedDragData {
@ -180,7 +195,7 @@ impl PointerInteraction for SerializedDragData {
#[cfg(feature = "serialize")] #[cfg(feature = "serialize")]
impl serde::Serialize for DragData { impl serde::Serialize for DragData {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
SerializedDragData::from(self).serialize(serializer) SerializedDragData::new(self, None).serialize(serializer)
} }
} }
@ -195,7 +210,10 @@ impl<'de> serde::Deserialize<'de> for DragData {
} }
/// A trait for any object that has the data for a drag event /// A trait for any object that has the data for a drag event
pub trait HasDragData: HasMouseData {} pub trait HasDragData: HasMouseData + HasFileData {
/// return self as Any
fn as_any(&self) -> &dyn std::any::Any;
}
impl_event! { impl_event! {
DragData; DragData;

View file

@ -1,4 +1,6 @@
use std::{any::Any, collections::HashMap, fmt::Debug}; use crate::file_data::FileEngine;
use crate::file_data::HasFileData;
use std::{collections::HashMap, fmt::Debug};
use dioxus_core::Event; use dioxus_core::Event;
@ -116,7 +118,7 @@ impl FormData {
pub struct SerializedFormData { pub struct SerializedFormData {
value: String, value: String,
values: HashMap<String, FormValue>, values: HashMap<String, FormValue>,
files: Option<SerializedFileEngine>, files: Option<crate::file_data::SerializedFileEngine>,
} }
#[cfg(feature = "serialize")] #[cfg(feature = "serialize")]
@ -125,7 +127,7 @@ impl SerializedFormData {
pub fn new( pub fn new(
value: String, value: String,
values: HashMap<String, FormValue>, values: HashMap<String, FormValue>,
files: Option<SerializedFileEngine>, files: Option<crate::file_data::SerializedFileEngine>,
) -> Self { ) -> Self {
Self { Self {
value, value,
@ -148,7 +150,7 @@ impl SerializedFormData {
resolved_files.insert(file, bytes.unwrap_or_default()); resolved_files.insert(file, bytes.unwrap_or_default());
} }
Some(SerializedFileEngine { Some(crate::file_data::SerializedFileEngine {
files: resolved_files, files: resolved_files,
}) })
} }

View file

@ -0,0 +1,53 @@
use std::{any::Any, collections::HashMap};
pub trait HasFileData: std::any::Any {
fn files(&self) -> Option<std::sync::Arc<dyn FileEngine>> {
None
}
}
#[cfg(feature = "serialize")]
/// A file engine that serializes files to bytes
#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Clone)]
pub struct SerializedFileEngine {
pub files: HashMap<String, Vec<u8>>,
}
#[cfg(feature = "serialize")]
#[async_trait::async_trait(?Send)]
impl FileEngine for SerializedFileEngine {
fn files(&self) -> Vec<String> {
self.files.keys().cloned().collect()
}
async fn read_file(&self, file: &str) -> Option<Vec<u8>> {
self.files.get(file).cloned()
}
async fn read_file_to_string(&self, file: &str) -> Option<String> {
self.read_file(file)
.await
.map(|bytes| String::from_utf8_lossy(&bytes).to_string())
}
async fn get_native_file(&self, file: &str) -> Option<Box<dyn Any>> {
self.read_file(file)
.await
.map(|val| Box::new(val) as Box<dyn Any>)
}
}
#[async_trait::async_trait(?Send)]
pub trait FileEngine {
// get a list of file names
fn files(&self) -> Vec<String>;
// read a file to bytes
async fn read_file(&self, file: &str) -> Option<Vec<u8>>;
// read a file to string
async fn read_file_to_string(&self, file: &str) -> Option<String>;
// returns a file in platform's native representation
async fn get_native_file(&self, file: &str) -> Option<Box<dyn Any>>;
}

View file

@ -22,6 +22,8 @@ pub use elements::HtmlCtx;
#[cfg(feature = "html-to-rsx")] #[cfg(feature = "html-to-rsx")]
pub use elements::{map_html_attribute_to_rsx, map_html_element_to_rsx}; pub use elements::{map_html_attribute_to_rsx, map_html_element_to_rsx};
pub mod events; pub mod events;
pub(crate) mod file_data;
pub use file_data::*;
pub mod geometry; pub mod geometry;
mod global_attributes; mod global_attributes;
pub mod input_data; pub mod input_data;

View file

@ -1,10 +1,11 @@
use std::any::Any; use std::any::Any;
use std::path::PathBuf; use std::path::PathBuf;
use crate::FileEngine;
use tokio::fs::File; use tokio::fs::File;
use tokio::io::AsyncReadExt; use tokio::io::AsyncReadExt;
use crate::file_data::FileEngine;
pub struct NativeFileEngine { pub struct NativeFileEngine {
files: Vec<PathBuf>, files: Vec<PathBuf>,
} }

View file

@ -3,6 +3,7 @@ use crate::events::{
AnimationData, CompositionData, KeyboardData, MouseData, PointerData, TouchData, AnimationData, CompositionData, KeyboardData, MouseData, PointerData, TouchData,
TransitionData, WheelData, TransitionData, WheelData,
}; };
use crate::file_data::{FileEngine, HasFileData};
use crate::geometry::{ClientPoint, ElementPoint, PagePoint, ScreenPoint}; use crate::geometry::{ClientPoint, ElementPoint, PagePoint, ScreenPoint};
use crate::input_data::{decode_key_location, decode_mouse_button_set, MouseButton}; use crate::input_data::{decode_key_location, decode_mouse_button_set, MouseButton};
use crate::prelude::*; use crate::prelude::*;
@ -103,8 +104,6 @@ impl ModifiersInteraction for KeyboardEvent {
} }
} }
impl HasDragData for MouseEvent {}
impl InteractionLocation for MouseEvent { impl InteractionLocation for MouseEvent {
fn client_coordinates(&self) -> ClientPoint { fn client_coordinates(&self) -> ClientPoint {
ClientPoint::new(self.client_x().into(), self.client_y().into()) ClientPoint::new(self.client_x().into(), self.client_y().into())
@ -162,6 +161,14 @@ impl HasMouseData for MouseEvent {
} }
} }
impl HasFileData for MouseEvent {}
impl HasDragData for MouseEvent {
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
impl ModifiersInteraction for TouchEvent { impl ModifiersInteraction for TouchEvent {
fn modifiers(&self) -> Modifiers { fn modifiers(&self) -> Modifiers {
let mut modifiers = Modifiers::empty(); let mut modifiers = Modifiers::empty();
@ -512,3 +519,23 @@ impl HasMediaData for web_sys::Event {
self self
} }
} }
impl HasFileData for web_sys::Event {
fn files(&self) -> Option<std::sync::Arc<dyn FileEngine>> {
#[cfg(not(feature = "file_engine"))]
let files = None;
#[cfg(feature = "file_engine")]
let files = element
.dyn_ref()
.and_then(|input: &web_sys::HtmlInputElement| {
input.files().and_then(|files| {
#[allow(clippy::arc_with_non_send_sync)]
crate::file_engine::WebFileEngine::new(files).map(|f| {
std::sync::Arc::new(f) as std::sync::Arc<dyn dioxus_html::FileEngine>
})
})
});
files
}
}

View file

@ -3,8 +3,8 @@ use crossterm::event::{
MouseEventKind, MouseEventKind,
}; };
use dioxus_html::{ use dioxus_html::{
HasFormData, HasKeyboardData, HasWheelData, SerializedFocusData, SerializedKeyboardData, HasFileData, HasFormData, HasKeyboardData, HasWheelData, SerializedFocusData,
SerializedMouseData, SerializedWheelData, SerializedKeyboardData, SerializedMouseData, SerializedWheelData,
}; };
use dioxus_native_core::prelude::*; use dioxus_native_core::prelude::*;
use dioxus_native_core::real_dom::NodeImmutable; use dioxus_native_core::real_dom::NodeImmutable;
@ -86,6 +86,8 @@ impl HasFormData for FormData {
} }
} }
impl HasFileData for FormData {}
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Files { pub struct Files {
files: FxHashMap<String, File>, files: FxHashMap<String, File>,

View file

@ -1,12 +1,16 @@
use std::{any::Any, collections::HashMap}; use std::{any::Any, collections::HashMap};
use dioxus_html::{ use dioxus_html::{
prelude::FormValue, FileEngine, FormData, HasFormData, HasImageData, HtmlEventConverter, point_interaction::{
ImageData, MountedData, PlatformEventData, ScrollData, InteractionElementOffset, InteractionLocation, ModifiersInteraction, PointerInteraction,
},
prelude::FormValue,
DragData, FileEngine, FormData, HasDragData, HasFileData, HasFormData, HasImageData,
HasMouseData, HtmlEventConverter, ImageData, MountedData, PlatformEventData, ScrollData,
}; };
use js_sys::Array; use js_sys::Array;
use wasm_bindgen::{prelude::wasm_bindgen, JsCast, JsValue}; use wasm_bindgen::{prelude::wasm_bindgen, JsCast, JsValue};
use web_sys::{Document, Element, Event}; use web_sys::{Document, Element, Event, MouseEvent};
pub(crate) struct WebEventConverter; pub(crate) struct WebEventConverter;
@ -44,7 +48,11 @@ impl HtmlEventConverter for WebEventConverter {
#[inline(always)] #[inline(always)]
fn convert_drag_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::DragData { fn convert_drag_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::DragData {
downcast_event(event).raw.clone().into() let event = downcast_event(event);
DragData::new(WebDragData::new(
event.element.clone(),
event.raw.clone().unchecked_into(),
))
} }
#[inline(always)] #[inline(always)]
@ -180,8 +188,10 @@ impl WebEventExt<web_sys::CompositionEvent> for dioxus_html::CompositionData {
impl WebEventExt<web_sys::MouseEvent> for dioxus_html::DragData { impl WebEventExt<web_sys::MouseEvent> for dioxus_html::DragData {
fn web_event(&self) -> &web_sys::MouseEvent { fn web_event(&self) -> &web_sys::MouseEvent {
self.downcast::<web_sys::MouseEvent>() &self
.downcast::<WebDragData>()
.expect("event should be a WebMouseEvent") .expect("event should be a WebMouseEvent")
.raw
} }
} }
@ -403,6 +413,12 @@ impl HasFormData for WebFormData {
values values
} }
fn as_any(&self) -> &dyn Any {
&self.raw as &dyn Any
}
}
impl HasFileData for WebFormData {
fn files(&self) -> Option<std::sync::Arc<dyn FileEngine>> { fn files(&self) -> Option<std::sync::Arc<dyn FileEngine>> {
#[cfg(not(feature = "file_engine"))] #[cfg(not(feature = "file_engine"))]
let files = None; let files = None;
@ -421,9 +437,89 @@ impl HasFormData for WebFormData {
files files
} }
}
fn as_any(&self) -> &dyn Any { struct WebDragData {
&self.raw as &dyn Any element: Element,
raw: MouseEvent,
}
impl WebDragData {
fn new(element: Element, raw: MouseEvent) -> Self {
Self { element, raw }
}
}
impl HasDragData for WebDragData {
fn as_any(&self) -> &dyn std::any::Any {
&self.raw as &dyn std::any::Any
}
}
impl HasMouseData for WebDragData {
fn as_any(&self) -> &dyn std::any::Any {
&self.raw as &dyn std::any::Any
}
}
impl PointerInteraction for WebDragData {
fn trigger_button(&self) -> Option<dioxus_html::input_data::MouseButton> {
self.raw.trigger_button()
}
fn held_buttons(&self) -> dioxus_html::input_data::MouseButtonSet {
self.raw.held_buttons()
}
}
impl ModifiersInteraction for WebDragData {
fn modifiers(&self) -> dioxus_html::prelude::Modifiers {
self.raw.modifiers()
}
}
impl InteractionElementOffset for WebDragData {
fn coordinates(&self) -> dioxus_html::geometry::Coordinates {
self.raw.coordinates()
}
fn element_coordinates(&self) -> dioxus_html::geometry::ElementPoint {
self.raw.element_coordinates()
}
}
impl InteractionLocation for WebDragData {
fn client_coordinates(&self) -> dioxus_html::geometry::ClientPoint {
self.raw.client_coordinates()
}
fn screen_coordinates(&self) -> dioxus_html::geometry::ScreenPoint {
self.raw.screen_coordinates()
}
fn page_coordinates(&self) -> dioxus_html::geometry::PagePoint {
self.raw.page_coordinates()
}
}
impl HasFileData for WebDragData {
fn files(&self) -> Option<std::sync::Arc<dyn FileEngine>> {
#[cfg(not(feature = "file_engine"))]
let files = None;
#[cfg(feature = "file_engine")]
let files = self
.element
.dyn_ref()
.and_then(|input: &web_sys::HtmlInputElement| {
input.files().and_then(|files| {
#[allow(clippy::arc_with_non_send_sync)]
crate::file_engine::WebFileEngine::new(files).map(|f| {
std::sync::Arc::new(f) as std::sync::Arc<dyn dioxus_html::FileEngine>
})
})
});
files
} }
} }