From 20384d2f020e3d909520e3701a777571de6c151d Mon Sep 17 00:00:00 2001 From: Arend van Beelen jr Date: Fri, 20 Oct 2023 12:26:10 +0200 Subject: [PATCH] On iOS, add configuration for status bar style Co-authored-by: Mads Marquart --- CHANGELOG.md | 1 + FEATURES.md | 2 +- src/platform/ios.rs | 50 +++++++++++++++++-- src/platform_impl/ios/uikit/mod.rs | 2 + .../ios/uikit/status_bar_style.rs | 27 ++++++++++ src/platform_impl/ios/view.rs | 18 ++++++- src/platform_impl/ios/window.rs | 8 ++- 7 files changed, 100 insertions(+), 8 deletions(-) create mode 100644 src/platform_impl/ios/uikit/status_bar_style.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 54f293116f..2ab97bb223 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ And please only add new entries to the top of this list, right below the `# Unre - On Android, fix `DeviceId` to contain device id's. - Add `Window::set_blur` to request a blur behind the window; implemented on Wayland for now. - On Web, fix `ControlFlow::WaitUntil` to never wake up **before** the given time. +- On iOS, add ability to change the status bar style. - Add `Window::show_window_menu` to request a titlebar/system menu; implemented on Wayland/Windows for now. - On iOS, send events `WindowEvent::Occluded(false)`, `WindowEvent::Occluded(true)` when application enters/leaves foreground. - **Breaking** add `Event::MemoryWarning`; implemented on iOS/Android. diff --git a/FEATURES.md b/FEATURES.md index 8e1399d9e4..5a40873a2f 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -150,7 +150,7 @@ If your PR makes notable changes to Winit's features, please update this section * Setting the `UIView` hidpi factor * Valid orientations * Home indicator visibility -* Status bar visibility +* Status bar visibility and style * Deferrring system gestures * Getting the device idiom * Getting the preferred video mode diff --git a/src/platform/ios.rs b/src/platform/ios.rs index 2097453917..3c2687e807 100644 --- a/src/platform/ios.rs +++ b/src/platform/ios.rs @@ -69,11 +69,25 @@ pub trait WindowExtIOS { /// /// The default is to prefer showing the status bar. /// - /// This changes the value returned by - /// [`-[UIViewController prefersStatusBarHidden]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621440-prefersstatusbarhidden?language=objc), - /// and then calls - /// [`-[UIViewController setNeedsStatusBarAppearanceUpdate]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621354-setneedsstatusbarappearanceupdat?language=objc). + /// This sets the value of the + /// [`prefersStatusBarHidden`](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621440-prefersstatusbarhidden?language=objc) + /// property. + /// + /// [`setNeedsStatusBarAppearanceUpdate()`](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621354-setneedsstatusbarappearanceupdat?language=objc) + /// is also called for you. fn set_prefers_status_bar_hidden(&self, hidden: bool); + + /// Sets the preferred status bar style for the [`Window`]. + /// + /// The default is system-defined. + /// + /// This sets the value of the + /// [`preferredStatusBarStyle`](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621416-preferredstatusbarstyle?language=objc) + /// property. + /// + /// [`setNeedsStatusBarAppearanceUpdate()`](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621354-setneedsstatusbarappearanceupdat?language=objc) + /// is also called for you. + fn set_preferred_status_bar_style(&self, status_bar_style: StatusBarStyle); } impl WindowExtIOS for Window { @@ -107,6 +121,12 @@ impl WindowExtIOS for Window { self.window .maybe_queue_on_main(move |w| w.set_prefers_status_bar_hidden(hidden)) } + + #[inline] + fn set_preferred_status_bar_style(&self, status_bar_style: StatusBarStyle) { + self.window + .maybe_queue_on_main(move |w| w.set_preferred_status_bar_style(status_bar_style)) + } } /// Additional methods on [`WindowBuilder`] that are specific to iOS. @@ -154,6 +174,14 @@ pub trait WindowBuilderExtIOS { /// This sets the initial value returned by /// [`-[UIViewController prefersStatusBarHidden]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621440-prefersstatusbarhidden?language=objc). fn with_prefers_status_bar_hidden(self, hidden: bool) -> Self; + + /// Sets the style of the [`Window`]'s status bar. + /// + /// The default is system-defined. + /// + /// This sets the initial value returned by + /// [`-[UIViewController preferredStatusBarStyle]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621416-preferredstatusbarstyle?language=objc), + fn with_preferred_status_bar_style(self, status_bar_style: StatusBarStyle) -> Self; } impl WindowBuilderExtIOS for WindowBuilder { @@ -187,6 +215,12 @@ impl WindowBuilderExtIOS for WindowBuilder { self.platform_specific.prefers_status_bar_hidden = hidden; self } + + #[inline] + fn with_preferred_status_bar_style(mut self, status_bar_style: StatusBarStyle) -> Self { + self.platform_specific.preferred_status_bar_style = status_bar_style; + self + } } /// Additional methods on [`MonitorHandle`] that are specific to iOS. @@ -264,3 +298,11 @@ bitflags! { | ScreenEdge::BOTTOM.bits() | ScreenEdge::RIGHT.bits(); } } + +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +pub enum StatusBarStyle { + #[default] + Default, + LightContent, + DarkContent, +} diff --git a/src/platform_impl/ios/uikit/mod.rs b/src/platform_impl/ios/uikit/mod.rs index e2707c0f3a..fcbc828650 100644 --- a/src/platform_impl/ios/uikit/mod.rs +++ b/src/platform_impl/ios/uikit/mod.rs @@ -12,6 +12,7 @@ mod event; mod responder; mod screen; mod screen_mode; +mod status_bar_style; mod touch; mod trait_collection; mod view; @@ -25,6 +26,7 @@ pub(crate) use self::event::UIEvent; pub(crate) use self::responder::UIResponder; pub(crate) use self::screen::{UIScreen, UIScreenOverscanCompensation}; pub(crate) use self::screen_mode::UIScreenMode; +pub(crate) use self::status_bar_style::UIStatusBarStyle; pub(crate) use self::touch::{UITouch, UITouchPhase, UITouchType}; pub(crate) use self::trait_collection::{UIForceTouchCapability, UITraitCollection}; #[allow(unused_imports)] diff --git a/src/platform_impl/ios/uikit/status_bar_style.rs b/src/platform_impl/ios/uikit/status_bar_style.rs new file mode 100644 index 0000000000..e38fd669e4 --- /dev/null +++ b/src/platform_impl/ios/uikit/status_bar_style.rs @@ -0,0 +1,27 @@ +use crate::platform::ios::StatusBarStyle; +use icrate::Foundation::NSInteger; +use objc2::encode::{Encode, Encoding}; + +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +#[allow(dead_code)] +#[repr(isize)] +pub enum UIStatusBarStyle { + #[default] + Default = 0, + LightContent = 1, + DarkContent = 3, +} + +impl From for UIStatusBarStyle { + fn from(value: StatusBarStyle) -> Self { + match value { + StatusBarStyle::Default => Self::Default, + StatusBarStyle::LightContent => Self::LightContent, + StatusBarStyle::DarkContent => Self::DarkContent, + } + } +} + +unsafe impl Encode for UIStatusBarStyle { + const ENCODING: Encoding = NSInteger::ENCODING; +} diff --git a/src/platform_impl/ios/view.rs b/src/platform_impl/ios/view.rs index e564d86f15..17fb3c0e08 100644 --- a/src/platform_impl/ios/view.rs +++ b/src/platform_impl/ios/view.rs @@ -11,8 +11,8 @@ use objc2::{declare_class, extern_methods, msg_send, msg_send_id, mutability, Cl use super::app_state::{self, EventWrapper}; use super::uikit::{ UIApplication, UIDevice, UIEvent, UIForceTouchCapability, UIInterfaceOrientationMask, - UIResponder, UITouch, UITouchPhase, UITouchType, UITraitCollection, UIView, UIViewController, - UIWindow, + UIResponder, UIStatusBarStyle, UITouch, UITouchPhase, UITouchType, UITraitCollection, UIView, + UIViewController, UIWindow, }; use super::window::WindowId; use crate::{ @@ -267,6 +267,7 @@ impl WinitView { 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, @@ -297,6 +298,7 @@ declare_class!( &mut this.state, Box::new(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( @@ -320,6 +322,11 @@ declare_class!( self.state.prefers_status_bar_hidden.get() } + #[method(preferredStatusBarStyle)] + fn preferred_status_bar_style(&self) -> UIStatusBarStyle { + self.state.preferred_status_bar_style.get() + } + #[method(prefersHomeIndicatorAutoHidden)] fn prefers_home_indicator_auto_hidden(&self) -> bool { self.state.prefers_home_indicator_auto_hidden.get() @@ -345,6 +352,11 @@ impl WinitViewController { self.setNeedsStatusBarAppearanceUpdate(); } + pub(crate) fn set_preferred_status_bar_style(&self, val: UIStatusBarStyle) { + self.state.preferred_status_bar_style.set(val); + self.setNeedsStatusBarAppearanceUpdate(); + } + pub(crate) fn set_prefers_home_indicator_auto_hidden(&self, val: bool) { self.state.prefers_home_indicator_auto_hidden.set(val); let os_capabilities = app_state::os_capabilities(); @@ -403,6 +415,8 @@ impl WinitViewController { this.set_prefers_status_bar_hidden(platform_attributes.prefers_status_bar_hidden); + this.set_preferred_status_bar_style(platform_attributes.preferred_status_bar_style.into()); + this.set_supported_interface_orientations(mtm, platform_attributes.valid_orientations); this.set_prefers_home_indicator_auto_hidden( diff --git a/src/platform_impl/ios/window.rs b/src/platform_impl/ios/window.rs index cd82a20542..28c7f318cf 100644 --- a/src/platform_impl/ios/window.rs +++ b/src/platform_impl/ios/window.rs @@ -15,7 +15,7 @@ use crate::{ error::{ExternalError, NotSupportedError, OsError as RootOsError}, event::{Event, WindowEvent}, icon::Icon, - platform::ios::{ScreenEdge, ValidOrientations}, + platform::ios::{ScreenEdge, StatusBarStyle, ValidOrientations}, platform_impl::platform::{ app_state, monitor, EventLoopWindowTarget, Fullscreen, MonitorHandle, }, @@ -551,6 +551,11 @@ impl Inner { pub fn set_prefers_status_bar_hidden(&self, hidden: bool) { self.view_controller.set_prefers_status_bar_hidden(hidden); } + + pub fn set_preferred_status_bar_style(&self, status_bar_style: StatusBarStyle) { + self.view_controller + .set_preferred_status_bar_style(status_bar_style.into()); + } } impl Inner { @@ -659,5 +664,6 @@ pub struct PlatformSpecificWindowBuilderAttributes { pub valid_orientations: ValidOrientations, pub prefers_home_indicator_hidden: bool, pub prefers_status_bar_hidden: bool, + pub preferred_status_bar_style: StatusBarStyle, pub preferred_screen_edges_deferring_system_gestures: ScreenEdge, }