use std::cell::Cell; use icrate::Foundation::{MainThreadMarker, NSObject}; use objc2::rc::Id; use objc2::{declare_class, msg_send_id, mutability, ClassType, DeclaredClass}; use super::app_state::{self}; use super::uikit::{ UIDevice, UIInterfaceOrientationMask, UIResponder, UIStatusBarStyle, UIView, UIViewController, }; use crate::{ platform::ios::ValidOrientations, platform_impl::platform::ffi::{UIRectEdge, UIUserInterfaceIdiom}, window::WindowAttributes, }; pub struct ViewControllerState { prefers_status_bar_hidden: Cell, preferred_status_bar_style: Cell, prefers_home_indicator_auto_hidden: Cell, supported_orientations: Cell, preferred_screen_edges_deferring_system_gestures: Cell, } declare_class!( pub(crate) struct WinitViewController; unsafe impl ClassType for WinitViewController { #[inherits(UIResponder, NSObject)] type Super = UIViewController; type Mutability = mutability::InteriorMutable; const NAME: &'static str = "WinitUIViewController"; } impl DeclaredClass for WinitViewController { type Ivars = ViewControllerState; } unsafe impl WinitViewController { #[method(shouldAutorotate)] fn should_autorotate(&self) -> bool { true } #[method(prefersStatusBarHidden)] fn prefers_status_bar_hidden(&self) -> bool { self.ivars().prefers_status_bar_hidden.get() } #[method(preferredStatusBarStyle)] fn preferred_status_bar_style(&self) -> UIStatusBarStyle { self.ivars().preferred_status_bar_style.get() } #[method(prefersHomeIndicatorAutoHidden)] fn prefers_home_indicator_auto_hidden(&self) -> bool { self.ivars().prefers_home_indicator_auto_hidden.get() } #[method(supportedInterfaceOrientations)] fn supported_orientations(&self) -> UIInterfaceOrientationMask { self.ivars().supported_orientations.get() } #[method(preferredScreenEdgesDeferringSystemGestures)] fn preferred_screen_edges_deferring_system_gestures(&self) -> UIRectEdge { self.ivars() .preferred_screen_edges_deferring_system_gestures .get() } } ); impl WinitViewController { pub(crate) fn set_prefers_status_bar_hidden(&self, val: bool) { self.ivars().prefers_status_bar_hidden.set(val); self.setNeedsStatusBarAppearanceUpdate(); } pub(crate) fn set_preferred_status_bar_style(&self, val: UIStatusBarStyle) { self.ivars().preferred_status_bar_style.set(val); self.setNeedsStatusBarAppearanceUpdate(); } pub(crate) fn set_prefers_home_indicator_auto_hidden(&self, val: bool) { self.ivars().prefers_home_indicator_auto_hidden.set(val); let os_capabilities = app_state::os_capabilities(); if os_capabilities.home_indicator_hidden { self.setNeedsUpdateOfHomeIndicatorAutoHidden(); } else { os_capabilities.home_indicator_hidden_err_msg("ignoring") } } pub(crate) fn set_preferred_screen_edges_deferring_system_gestures(&self, val: UIRectEdge) { self.ivars() .preferred_screen_edges_deferring_system_gestures .set(val); let os_capabilities = app_state::os_capabilities(); if os_capabilities.defer_system_gestures { self.setNeedsUpdateOfScreenEdgesDeferringSystemGestures(); } else { os_capabilities.defer_system_gestures_err_msg("ignoring") } } pub(crate) fn set_supported_interface_orientations( &self, mtm: MainThreadMarker, valid_orientations: ValidOrientations, ) { let mask = match ( valid_orientations, UIDevice::current(mtm).userInterfaceIdiom(), ) { (ValidOrientations::LandscapeAndPortrait, UIUserInterfaceIdiom::Phone) => { UIInterfaceOrientationMask::AllButUpsideDown } (ValidOrientations::LandscapeAndPortrait, _) => UIInterfaceOrientationMask::All, (ValidOrientations::Landscape, _) => UIInterfaceOrientationMask::Landscape, (ValidOrientations::Portrait, UIUserInterfaceIdiom::Phone) => { UIInterfaceOrientationMask::Portrait } (ValidOrientations::Portrait, _) => { UIInterfaceOrientationMask::Portrait | UIInterfaceOrientationMask::PortraitUpsideDown } }; self.ivars().supported_orientations.set(mask); UIViewController::attemptRotationToDeviceOrientation(); } pub(crate) fn new( mtm: MainThreadMarker, window_attributes: &WindowAttributes, view: &UIView, ) -> Id { // These are set properly below, we just to set them to something in the meantime. let this = Self::alloc().set_ivars(ViewControllerState { prefers_status_bar_hidden: Cell::new(false), preferred_status_bar_style: Cell::new(UIStatusBarStyle::Default), prefers_home_indicator_auto_hidden: Cell::new(false), supported_orientations: Cell::new(UIInterfaceOrientationMask::All), preferred_screen_edges_deferring_system_gestures: Cell::new(UIRectEdge::NONE), }); let this: Id = unsafe { msg_send_id![super(this), init] }; this.set_prefers_status_bar_hidden( window_attributes .platform_specific .prefers_status_bar_hidden, ); this.set_preferred_status_bar_style( window_attributes .platform_specific .preferred_status_bar_style .into(), ); this.set_supported_interface_orientations( mtm, window_attributes.platform_specific.valid_orientations, ); this.set_prefers_home_indicator_auto_hidden( window_attributes .platform_specific .prefers_home_indicator_hidden, ); this.set_preferred_screen_edges_deferring_system_gestures( window_attributes .platform_specific .preferred_screen_edges_deferring_system_gestures .into(), ); this.setView(Some(view)); this } }