use {
compo::prelude::*,
objc2::{ClassType, MainThreadMarker, MainThreadOnly, Message, msg_send, rc::Retained},
objc2_foundation::{NSObjectProtocol, NSPoint, NSRect, NSSize},
objc2_ui_kit::{UIApplication, UIColor, UIScene, UIViewController, UIWindow, UIWindowScene},
tracing::{error, info},
};
#[component]
pub async fn window(
#[default = "Window example"] title: &str,
#[default = 375] width: i32,
#[default = 667] height: i32,
#[default = 100] left: i32,
#[default = 100] top: i32,
#[default = true] visible: bool,
#[default = true] enabled: bool,
) {
let Some(mtm) = MainThreadMarker::new() else {
error!("Window component must be running on main thread.");
return;
};
#[field]
let window: Option<Retained<UIWindow>> = None;
#[field]
let view_controller: Option<Retained<UIViewController>> = None;
if *visible {
if window.is_none() {
unsafe {
let frame = NSRect {
origin: NSPoint {
x: *left as f64,
y: *top as f64,
},
size: NSSize {
width: *width as f64,
height: *height as f64,
},
};
let window_instance: Retained<UIWindow>;
if let Some(scene) = get_current_window_scene(mtm) {
window_instance = msg_send![UIWindow::alloc(mtm), initWithWindowScene: &*scene];
} else {
window_instance = msg_send![UIWindow::alloc(mtm), initWithFrame: frame];
}
let root_controller = UIViewController::new(mtm);
if let Some(view) = root_controller.view() {
let white_color = UIColor::whiteColor();
view.setBackgroundColor(Some(&white_color));
} else {
error!("Can't get the view in root controller.");
}
window_instance.setRootViewController(Some(&root_controller));
window_instance.setFrame(frame);
window.replace(window_instance);
view_controller.replace(root_controller);
}
}
if let Some(window_ref) = window.as_ref() {
unsafe {
let frame = NSRect {
origin: NSPoint {
x: *left as f64,
y: *top as f64,
},
size: NSSize {
width: *width as f64,
height: *height as f64,
},
};
window_ref.setFrame(frame);
window_ref.setUserInteractionEnabled(*enabled);
window_ref.makeKeyAndVisible();
info!(
"iOS window updated: {}x{} at ({}, {}), enabled: {}, visible: {}",
*width, *height, *left, *top, *enabled, *visible
);
}
} else {
error!("Failed to create iOS window.");
}
} else if let Some(window_ref) = window.take() {
unsafe {
window_ref.setHidden(true);
view_controller.take();
}
info!("iOS window hidden");
}
}
unsafe fn get_current_window_scene(mtm: MainThreadMarker) -> Option<Retained<UIScene>> {
let app = UIApplication::sharedApplication(mtm);
let connected_scenes = app.connectedScenes();
let scene_enumerator = unsafe { connected_scenes.objectEnumerator() };
while let Some(scene) = scene_enumerator.nextObject() {
if scene.isKindOfClass(&UIWindowScene::class()) {
return Some(scene.retain());
}
}
None
}