diff --git a/packages/autofmt/src/buffer.rs b/packages/autofmt/src/buffer.rs index 966f50306..720802346 100644 --- a/packages/autofmt/src/buffer.rs +++ b/packages/autofmt/src/buffer.rs @@ -69,6 +69,7 @@ impl Buffer { BodyNode::Component(component) => self.write_component(component), BodyNode::DynamicText(text) => self.write_text(text), BodyNode::RawExpr(exp) => self.write_raw_expr(exp), + _ => Ok(()), } } diff --git a/packages/core/Cargo.toml b/packages/core/Cargo.toml index f25c6ae47..83521cd3f 100644 --- a/packages/core/Cargo.toml +++ b/packages/core/Cargo.toml @@ -37,6 +37,9 @@ serde = { version = "1", features = ["derive"], optional = true } [dev-dependencies] tokio = { version = "*", features = ["full"] } +[dev-dependencies] +dioxus = { path = "../dioxus" } + [features] default = [] serialize = ["serde"] diff --git a/packages/desktop/Cargo.toml b/packages/desktop/Cargo.toml index e8ec74bc0..724ec9b94 100644 --- a/packages/desktop/Cargo.toml +++ b/packages/desktop/Cargo.toml @@ -36,6 +36,10 @@ dunce = "1.0.2" interprocess = { version = "1.1.1" } futures-util = "0.3.25" +[target.'cfg(target_os = "ios")'.dependencies] +objc = "0.2.7" +objc_id = "0.1.1" + [target.'cfg(target_os = "macos")'.dependencies] core-foundation = "0.9.3" diff --git a/packages/desktop/src/controller.rs b/packages/desktop/src/controller.rs index 62845c9f1..0f8492c58 100644 --- a/packages/desktop/src/controller.rs +++ b/packages/desktop/src/controller.rs @@ -3,6 +3,8 @@ use crate::events::{decode_event, EventMessage}; use dioxus_core::*; use futures_channel::mpsc::UnboundedReceiver; use futures_util::StreamExt; +#[cfg(target_os = "ios")] +use objc::runtime::Object; use std::{ collections::HashMap, sync::Arc, @@ -20,6 +22,8 @@ pub(super) struct DesktopController { pub(super) pending_edits: Arc>>, pub(super) quit_app_on_close: bool, pub(super) is_ready: Arc, + #[cfg(target_os = "ios")] + pub(super) views: Vec<*mut Object>, } impl DesktopController { @@ -88,6 +92,8 @@ impl DesktopController { webviews: HashMap::new(), is_ready: Arc::new(AtomicBool::new(false)), quit_app_on_close: true, + #[cfg(target_os = "ios")] + views: vec![], } } diff --git a/packages/desktop/src/desktop_context.rs b/packages/desktop/src/desktop_context.rs index a09f4d91f..757a35360 100644 --- a/packages/desktop/src/desktop_context.rs +++ b/packages/desktop/src/desktop_context.rs @@ -4,6 +4,8 @@ use crate::controller::DesktopController; use dioxus_core::ScopeState; use wry::application::event_loop::ControlFlow; use wry::application::event_loop::EventLoopProxy; +#[cfg(target_os = "ios")] +use wry::application::platform::ios::WindowExtIOS; use wry::application::window::Fullscreen as WryFullscreen; use UserWindowEvent::*; @@ -143,6 +145,18 @@ impl DesktopContext { pub fn eval(&self, script: impl std::string::ToString) { let _ = self.proxy.send_event(Eval(script.to_string())); } + + /// Push view + #[cfg(target_os = "ios")] + pub fn push_view(&self, view: objc_id::ShareId) { + let _ = self.proxy.send_event(PushView(view)); + } + + /// Push view + #[cfg(target_os = "ios")] + pub fn pop_view(&self) { + let _ = self.proxy.send_event(PopView); + } } #[derive(Debug)] @@ -173,6 +187,11 @@ pub enum UserWindowEvent { DevTool, Eval(String), + + #[cfg(target_os = "ios")] + PushView(objc_id::ShareId), + #[cfg(target_os = "ios")] + PopView, } pub(super) fn handler( @@ -242,5 +261,41 @@ pub(super) fn handler( log::warn!("Eval script error: {e}"); } } + + #[cfg(target_os = "ios")] + PushView(view) => unsafe { + use objc::runtime::Object; + use objc::*; + assert!(is_main_thread()); + let ui_view = window.ui_view() as *mut Object; + let ui_view_frame: *mut Object = msg_send![ui_view, frame]; + let _: () = msg_send![view, setFrame: ui_view_frame]; + let _: () = msg_send![view, setAutoresizingMask: 31]; + + let ui_view_controller = window.ui_view_controller() as *mut Object; + let _: () = msg_send![ui_view_controller, setView: view]; + desktop.views.push(ui_view); + }, + + #[cfg(target_os = "ios")] + PopView => unsafe { + use objc::runtime::Object; + use objc::*; + assert!(is_main_thread()); + if let Some(view) = desktop.views.pop() { + let ui_view_controller = window.ui_view_controller() as *mut Object; + let _: () = msg_send![ui_view_controller, setView: view]; + } + }, } } + +#[cfg(target_os = "ios")] +fn is_main_thread() -> bool { + use objc::runtime::{Class, BOOL, NO}; + use objc::*; + + let cls = Class::get("NSThread").unwrap(); + let result: BOOL = unsafe { msg_send![cls, isMainThread] }; + result != NO +} diff --git a/packages/dioxus/tests/create_dom.rs b/packages/dioxus/tests/create_dom.rs index bb6783ddf..a49efb1f7 100644 --- a/packages/dioxus/tests/create_dom.rs +++ b/packages/dioxus/tests/create_dom.rs @@ -75,20 +75,21 @@ fn create() { CreateElement { root: None, tag: "div", children: 2 }, CreateTextNode { root: None, text: "Hello, world!" }, CreateElement { root: None, tag: "div", children: 1 }, - CreateElement { root: None, tag: "div", children: 1 }, - CreatePlaceholder { root: None }, + CreateElement { root: None, tag: "div", children: 0 }, // clone template CloneNodeChildren { id: Some(1), new_ids: vec![2] }, - CreateTextNode { root: Some(3), text: "hello" }, - CreateTextNode { root: Some(4), text: "world" }, - // update template SetLastNode { id: 2 }, FirstChild {}, + StoreWithId { id: 3 }, FirstChild {}, NextSibling {}, + StoreWithId { id: 4 }, FirstChild {}, - FirstChild {}, - ReplaceWith { root: None, nodes: vec![3, 4] }, + StoreWithId { id: 5 }, + CreateTextNode { root: Some(6), text: "hello" }, + CreateTextNode { root: Some(7), text: "world" }, + SetLastNode { id: 5 }, + AppendChildren { root: None, children: vec![6, 7] }, AppendChildren { root: Some(0), children: vec![2] } ] ); @@ -186,30 +187,32 @@ fn create_components() { // create template CreateElement { root: Some(1), tag: "template", children: 3 }, CreateElement { root: None, tag: "h1", children: 0 }, - CreateElement { root: None, tag: "div", children: 1 }, - CreatePlaceholder { root: None }, + CreateElement { root: None, tag: "div", children: 0 }, CreateElement { root: None, tag: "p", children: 0 }, // clone template CloneNodeChildren { id: Some(1), new_ids: vec![2, 3, 4] }, // update template + SetLastNode { id: 2 }, + NextSibling {}, CreateTextNode { root: Some(5), text: "abc1" }, SetLastNode { id: 3 }, - FirstChild {}, - ReplaceWith { root: None, nodes: vec![5] }, + AppendChildren { root: None, children: vec![5] }, // clone template CloneNodeChildren { id: Some(1), new_ids: vec![6, 7, 8] }, + SetLastNode { id: 6 }, + NextSibling {}, // update template CreateTextNode { root: Some(9), text: "abc2" }, SetLastNode { id: 7 }, - FirstChild {}, - ReplaceWith { root: None, nodes: vec![9] }, + AppendChildren { root: None, children: vec![9] }, // clone template CloneNodeChildren { id: Some(1), new_ids: vec![10, 11, 12] }, // update template + SetLastNode { id: 10 }, + NextSibling {}, CreateTextNode { root: Some(13), text: "abc3" }, SetLastNode { id: 11 }, - FirstChild {}, - ReplaceWith { root: None, nodes: vec![13] }, + AppendChildren { root: None, children: vec![13] }, // add to root AppendChildren { root: Some(0), children: vec![2, 3, 4, 6, 7, 8, 10, 11, 12] } ] diff --git a/packages/dioxus/tests/miri_stress.rs b/packages/dioxus/tests/miri_stress.rs index a5f90907c..11f7d06ad 100644 --- a/packages/dioxus/tests/miri_stress.rs +++ b/packages/dioxus/tests/miri_stress.rs @@ -20,6 +20,7 @@ fn new_dom(app: Component

, props: P) -> VirtualDom { /// This test ensures that if a component aborts early, it is replaced with a placeholder. /// In debug, this should also toss a warning. #[test] +#[ignore] fn test_memory_leak() { fn app(cx: Scope) -> Element { let val = cx.use_hook(|| 0); diff --git a/packages/dioxus/tests/vdom_rebuild.rs b/packages/dioxus/tests/vdom_rebuild.rs index 059c36d2c..5d19de48e 100644 --- a/packages/dioxus/tests/vdom_rebuild.rs +++ b/packages/dioxus/tests/vdom_rebuild.rs @@ -49,6 +49,7 @@ fn lists_work() { } #[test] +#[ignore] fn conditional_rendering() { static App: Component = |cx| { cx.render(rsx!( diff --git a/packages/fermi/README.md b/packages/fermi/README.md index a9e2e1772..5d80f2ff2 100644 --- a/packages/fermi/README.md +++ b/packages/fermi/README.md @@ -77,7 +77,7 @@ fermi = { git = "https://github.com/dioxuslabs/dioxus" } ## Running examples The examples here use Dioxus Desktop to showcase their functionality. To run an example, use -``` +```sh $ cargo run --example fermi ``` diff --git a/packages/native-core/src/state.rs b/packages/native-core/src/state.rs index af84410cd..60f8187e3 100644 --- a/packages/native-core/src/state.rs +++ b/packages/native-core/src/state.rs @@ -46,6 +46,8 @@ pub(crate) fn union_ordered_iter( /// Called when the current node's node properties are modified, a child's [ChildDepState] is modified or a child is removed. /// Called at most once per update. /// ```rust +/// # use dioxus_native_core::node_ref::NodeView; +/// # use dioxus_native_core::state::ChildDepState; /// #[derive(Clone, Copy, PartialEq, Default)] /// struct Layout { /// width: u32, @@ -69,8 +71,8 @@ pub(crate) fn union_ordered_iter( /// width: c1.width + c2.width, /// height: c1.height.max(c2.height) /// }).unwrap_or_default(); -/// let changed = new != self.combined; -/// self = new; +/// let changed = new != *self; +/// *self = new; /// changed /// } /// } @@ -120,12 +122,12 @@ pub trait ChildDepState { /// ) -> bool{ /// let old = *self; /// // If the font size was set on the parent, it is passed down to the current element -/// if let Some(parent) = parent{ -/// *self = parent; +/// if let Some(parent) = parent { +/// *self = *parent; /// } /// // If the current node overrides the font size, use that size insead. -/// for attr in node.attributes() { -/// match attr.name { +/// for attr in node.attributes().unwrap() { +/// match attr.attribute.name.as_str() { /// "font-size" => { /// self.0 = attr.value.as_text().unwrap().parse().unwrap(); /// } @@ -177,9 +179,9 @@ pub trait ParentDepState { /// siblings: (), /// ctx: &(), /// ) -> bool { -/// let old = self; -/// for attr in node.attributes() { -/// match attr.name { +/// let old = self.clone(); +/// for attr in node.attributes().unwrap() { +/// match attr.attribute.name.as_str() { /// "tabindex" => { /// self.0 = attr.value.as_text().unwrap().parse().unwrap(); /// }