1
0
Эх сурвалжийг харах

Implement push view for ios. (#612)

David Craven 2 жил өмнө
parent
commit
1e99e35572

+ 4 - 0
packages/desktop/Cargo.toml

@@ -34,6 +34,10 @@ dunce = "1.0.2"
 
 interprocess = { version = "1.1.1" }
 
+[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"
 

+ 6 - 0
packages/desktop/src/controller.rs

@@ -1,6 +1,8 @@
 use crate::desktop_context::{DesktopContext, UserWindowEvent};
 
 use dioxus_core::*;
+#[cfg(target_os = "ios")]
+use objc::runtime::Object;
 use std::{
     collections::HashMap,
     sync::Arc,
@@ -18,6 +20,8 @@ pub(super) struct DesktopController {
     pub(super) pending_edits: Arc<Mutex<Vec<String>>>,
     pub(super) quit_app_on_close: bool,
     pub(super) is_ready: Arc<AtomicBool>,
+    #[cfg(target_os = "ios")]
+    pub(super) views: Vec<*mut Object>,
 }
 
 impl DesktopController {
@@ -87,6 +91,8 @@ impl DesktopController {
             webviews: HashMap::new(),
             is_ready: Arc::new(AtomicBool::new(false)),
             quit_app_on_close: true,
+            #[cfg(target_os = "ios")]
+            views: vec![],
         }
     }
 

+ 55 - 0
packages/desktop/src/desktop_context.rs

@@ -2,6 +2,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::*;
@@ -134,6 +136,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<objc::runtime::Object>) {
+        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)]
@@ -164,6 +178,11 @@ pub enum UserWindowEvent {
     DevTool,
 
     Eval(String),
+
+    #[cfg(target_os = "ios")]
+    PushView(objc_id::ShareId<objc::runtime::Object>),
+    #[cfg(target_os = "ios")]
+    PopView,
 }
 
 pub(super) fn handler(
@@ -231,6 +250,32 @@ 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];
+            }
+        },
     }
 }
 
@@ -240,3 +285,13 @@ pub fn use_eval<S: std::string::ToString>(cx: &ScopeState) -> &dyn Fn(S) {
 
     cx.use_hook(|| move |script| desktop.eval(script))
 }
+
+#[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
+}