use super::{IPlatformSettings, PlatformColorValues, PlatformThemeVariant};
use crate::input::platform::PlatformHotkeyConfiguration;
use crate::input::PointerType;
use crate::reactive::{Disposable, IDisposable};
use crate::utilities::HandlerList;
use crate::{FerroLocator, LocatorExtensions, Size};
use std::rc::Rc;
use std::time::Duration;
const TOUCH_TAP_SIZE: f64 = 10.0;
const TOUCH_DOUBLE_TAP_SIZE: f64 = 50.0;
#[derive(Default)]
pub struct DefaultPlatformSettings {
color_values_changed: Rc<HandlerList<dyn Fn(&PlatformColorValues)>>,
preferred_application_language_changed: Rc<HandlerList<dyn Fn()>>,
}
impl DefaultPlatformSettings {
pub fn new() -> Self {
Self::default()
}
pub fn on_color_values_changed(&self, color_values: PlatformColorValues) {
if self.color_values_changed.is_empty() {
return;
}
for (_, handler) in self.color_values_changed.snapshot().iter() {
handler(&color_values);
}
}
pub fn on_preferred_application_language_changed(&self) {
if self.preferred_application_language_changed.is_empty() {
return;
}
for (_, handler) in self.preferred_application_language_changed.snapshot().iter() {
handler();
}
}
fn language_tag_from_locale(locale: &str) -> String {
let name = locale.split(['.', '@']).next().unwrap_or("");
if name.is_empty() || name == "C" || name == "POSIX" {
return String::new();
}
name.replace('_', "-")
}
}
impl IPlatformSettings for DefaultPlatformSettings {
fn get_tap_size(&self, type_: PointerType) -> Size {
match type_ {
PointerType::Touch | PointerType::Pen => Size::new(TOUCH_TAP_SIZE, TOUCH_TAP_SIZE),
PointerType::Mouse => Size::new(4.0, 4.0),
}
}
fn get_double_tap_size(&self, type_: PointerType) -> Size {
match type_ {
PointerType::Touch | PointerType::Pen => Size::new(TOUCH_DOUBLE_TAP_SIZE, TOUCH_DOUBLE_TAP_SIZE),
PointerType::Mouse => Size::new(4.0, 4.0),
}
}
fn get_double_tap_time(&self, _type: PointerType) -> Duration {
Duration::from_millis(500)
}
fn hold_wait_duration(&self) -> Duration {
Duration::from_millis(300)
}
fn hotkey_configuration(&self) -> Rc<PlatformHotkeyConfiguration> {
FerroLocator::current().get_required_service::<PlatformHotkeyConfiguration>()
}
fn preferred_application_language(&self) -> String {
["LC_ALL", "LC_MESSAGES", "LANG"]
.iter()
.filter_map(|name| std::env::var(name).ok())
.find(|value| !value.is_empty())
.map(|value| Self::language_tag_from_locale(&value))
.unwrap_or_default()
}
fn get_color_values(&self) -> PlatformColorValues {
PlatformColorValues::new().with_theme_variant(PlatformThemeVariant::Light)
}
fn color_values_changed(&self, handler: Rc<dyn Fn(&PlatformColorValues)>) -> Rc<dyn IDisposable> {
let token = self.color_values_changed.add(handler);
let handlers = self.color_values_changed.clone();
Disposable::create(move || {
handlers.remove(token);
})
}
fn preferred_application_language_changed(&self, handler: Rc<dyn Fn()>) -> Rc<dyn IDisposable> {
let token = self.preferred_application_language_changed.add(handler);
let handlers = self.preferred_application_language_changed.clone();
Disposable::create(move || {
handlers.remove(token);
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::cell::RefCell;
#[test]
fn default_color_values_are_light() {
let settings = DefaultPlatformSettings::new();
assert_eq!(settings.get_color_values(), PlatformColorValues::new());
assert_eq!(settings.get_color_values().theme_variant(), PlatformThemeVariant::Light);
}
#[test]
fn change_events_reach_subscribers_until_disposed() {
let settings = DefaultPlatformSettings::new();
let log = Rc::new(RefCell::new(Vec::new()));
let colors = {
let log = log.clone();
settings.color_values_changed(Rc::new(move |values: &PlatformColorValues| {
log.borrow_mut().push(format!("{:?}", values.theme_variant()))
}))
};
let language = {
let log = log.clone();
settings.preferred_application_language_changed(Rc::new(move || log.borrow_mut().push("language".to_string())))
};
settings.on_color_values_changed(PlatformColorValues::new().with_theme_variant(PlatformThemeVariant::Dark));
settings.on_preferred_application_language_changed();
assert_eq!(*log.borrow(), ["Dark", "language"]);
colors.dispose();
language.dispose();
settings.on_color_values_changed(PlatformColorValues::new());
settings.on_preferred_application_language_changed();
assert_eq!(log.borrow().len(), 2);
}
#[test]
fn language_tag_is_derived_from_the_locale_name() {
assert_eq!(DefaultPlatformSettings::language_tag_from_locale("en_US.UTF-8"), "en-US");
assert_eq!(DefaultPlatformSettings::language_tag_from_locale("sr_RS@latin"), "sr-RS");
assert_eq!(DefaultPlatformSettings::language_tag_from_locale("pl"), "pl");
assert_eq!(DefaultPlatformSettings::language_tag_from_locale("C"), "");
assert_eq!(DefaultPlatformSettings::language_tag_from_locale("POSIX"), "");
assert_eq!(DefaultPlatformSettings::language_tag_from_locale(""), "");
}
}