use crate::{ApplicationDefaults, EdgeInsets, LocaleResolver, TextDirection};
use icu_locale::Locale;
use incular_core::{Rect, Size};
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum Brightness {
#[default]
Light,
Dark,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum TargetPlatform {
Android,
Fuchsia,
Ios,
Linux,
MacOs,
Windows,
}
impl TargetPlatform {
#[must_use]
pub const fn host() -> Self {
if cfg!(target_os = "ios") {
Self::Ios
} else if cfg!(target_os = "macos") {
Self::MacOs
} else if cfg!(target_os = "windows") {
Self::Windows
} else if cfg!(target_os = "linux") {
Self::Linux
} else if cfg!(target_os = "fuchsia") {
Self::Fuchsia
} else {
Self::Android
}
}
#[must_use]
pub const fn is_apple(self) -> bool {
matches!(self, Self::Ios | Self::MacOs)
}
#[must_use]
pub const fn is_desktop(self) -> bool {
matches!(self, Self::Linux | Self::MacOs | Self::Windows)
}
}
impl Default for TargetPlatform {
fn default() -> Self {
Self::host()
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub enum NavigationMode {
#[default]
Traditional,
Directional,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum ContentSensitivity {
#[default]
NotSensitive,
AutoSensitive,
Sensitive,
}
impl ContentSensitivity {
#[must_use]
pub const fn max(self, other: Self) -> Self {
if self as u8 >= other as u8 {
self
} else {
other
}
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct InputCapabilities {
pub mouse: bool,
pub touch: bool,
pub keyboard: bool,
pub stylus: bool,
pub trackpad: bool,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub enum DisplayFeatureType {
#[default]
Unknown,
Fold,
Hinge,
Cutout,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub enum DisplayFeatureState {
#[default]
Unknown,
PostureFlat,
PostureHalfOpened,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct DisplayFeature {
pub bounds: Rect,
pub kind: DisplayFeatureType,
pub state: DisplayFeatureState,
}
#[derive(Clone, Debug, PartialEq)]
pub struct RuntimeEnvironment {
pub viewport: Size,
pub physical_width: u32,
pub physical_height: u32,
pub scale_factor: f64,
pub brightness: Brightness,
pub text_scale: f32,
pub safe_insets: EdgeInsets,
pub view_padding: EdgeInsets,
pub view_insets: EdgeInsets,
pub locales: Vec<Locale>,
pub text_direction: TextDirection,
pub reduced_motion: bool,
pub high_contrast: bool,
pub system_gesture_insets: EdgeInsets,
pub display_features: Vec<DisplayFeature>,
pub always_use_24_hour_format: bool,
pub accessible_navigation: bool,
pub invert_colors: bool,
pub on_off_switch_labels: bool,
pub bold_text: bool,
pub supports_announce: bool,
pub navigation_mode: NavigationMode,
pub supports_showing_system_context_menu: bool,
pub line_height_scale_factor_override: Option<f32>,
pub letter_spacing_override: Option<f32>,
pub word_spacing_override: Option<f32>,
pub paragraph_spacing_override: Option<f32>,
pub input: InputCapabilities,
pub window_focused: bool,
pub window_occluded: bool,
}
impl Default for RuntimeEnvironment {
fn default() -> Self {
let defaults = ApplicationDefaults::DEFAULT;
Self {
viewport: Size::ZERO,
physical_width: 0,
physical_height: 0,
scale_factor: defaults.scale_factor,
brightness: defaults.brightness,
text_scale: defaults.text_scale,
safe_insets: EdgeInsets::ZERO,
view_padding: EdgeInsets::ZERO,
view_insets: EdgeInsets::ZERO,
locales: Vec::new(),
text_direction: defaults.text_direction,
reduced_motion: defaults.reduced_motion,
high_contrast: false,
system_gesture_insets: EdgeInsets::ZERO,
display_features: Vec::new(),
always_use_24_hour_format: false,
accessible_navigation: false,
invert_colors: false,
on_off_switch_labels: false,
bold_text: false,
supports_announce: false,
navigation_mode: NavigationMode::Traditional,
supports_showing_system_context_menu: false,
line_height_scale_factor_override: None,
letter_spacing_override: None,
word_spacing_override: None,
paragraph_spacing_override: None,
input: InputCapabilities::default(),
window_focused: false,
window_occluded: false,
}
}
}
impl RuntimeEnvironment {
#[must_use]
pub fn normalized(mut self) -> Self {
self.scale_factor = if self.scale_factor.is_finite() && self.scale_factor > 0.0 {
self.scale_factor
} else {
1.0
};
self.text_scale = if self.text_scale.is_finite() && self.text_scale > 0.0 {
self.text_scale
} else {
1.0
};
self.safe_insets = self.safe_insets.normalized();
self.view_padding = self.view_padding.normalized();
self.view_insets = self.view_insets.normalized();
self.system_gesture_insets = self.system_gesture_insets.normalized();
if let Some(locale) = self.primary_locale() {
self.text_direction = LocaleResolver::text_direction(locale);
}
self
}
#[must_use]
pub fn primary_locale(&self) -> Option<&Locale> {
self.locales.first()
}
#[must_use]
pub fn resolve_locale(&self, supported: &[Locale]) -> Option<Locale> {
LocaleResolver::resolve(&self.locales, supported)
}
}