use incular_config::{EdgeInsets, InputCapabilities, Locale, RuntimeEnvironment};
use std::sync::{Arc, RwLock};
#[derive(Clone, Debug, Default, PartialEq)]
pub struct SystemEnvironmentPreferences {
pub locales: Option<Vec<Locale>>,
pub text_scale: Option<f32>,
pub reduced_motion: Option<bool>,
pub high_contrast: Option<bool>,
pub input: Option<InputCapabilities>,
pub safe_insets: Option<EdgeInsets>,
pub view_padding: Option<EdgeInsets>,
pub view_insets: Option<EdgeInsets>,
}
impl SystemEnvironmentPreferences {
pub fn apply_to(&self, environment: &mut RuntimeEnvironment) {
let defaults = RuntimeEnvironment::default();
environment.locales = self.locales.clone().unwrap_or(defaults.locales);
environment.text_scale = self.text_scale.unwrap_or(defaults.text_scale);
environment.reduced_motion = self.reduced_motion.unwrap_or(defaults.reduced_motion);
environment.high_contrast = self.high_contrast.unwrap_or(defaults.high_contrast);
environment.input = self.input.unwrap_or(defaults.input);
environment.safe_insets = self.safe_insets.unwrap_or(defaults.safe_insets);
environment.view_padding = self.view_padding.unwrap_or(defaults.view_padding);
environment.view_insets = self.view_insets.unwrap_or(defaults.view_insets);
}
}
pub trait SystemEnvironmentProvider {
fn snapshot(&self) -> SystemEnvironmentPreferences;
}
#[derive(Clone, Default)]
pub struct MemorySystemEnvironmentProvider {
snapshot: Arc<RwLock<SystemEnvironmentPreferences>>,
}
impl MemorySystemEnvironmentProvider {
#[must_use]
pub fn new(snapshot: SystemEnvironmentPreferences) -> Self {
Self {
snapshot: Arc::new(RwLock::new(snapshot)),
}
}
pub fn replace(&self, snapshot: SystemEnvironmentPreferences) -> bool {
let mut current = self.snapshot.write().expect("environment provider lock");
if *current == snapshot {
return false;
}
*current = snapshot;
true
}
}
impl SystemEnvironmentProvider for MemorySystemEnvironmentProvider {
fn snapshot(&self) -> SystemEnvironmentPreferences {
self.snapshot
.read()
.expect("environment provider lock")
.clone()
}
}
#[must_use]
pub fn canonicalize_system_locales(
locales: impl IntoIterator<Item = impl AsRef<str>>,
) -> Vec<Locale> {
let mut result = Vec::new();
for value in locales {
let Ok(locale) = value.as_ref().parse::<Locale>() else {
continue;
};
if !result.contains(&locale) {
result.push(locale);
}
}
result
}