use std::sync::atomic::{AtomicU8, Ordering};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum InputProfile {
Desktop,
MobileIOS,
MobileAndroid,
MobileOther,
}
impl InputProfile {
pub fn is_mobile_touch(self) -> bool {
matches!(
self,
InputProfile::MobileIOS | InputProfile::MobileAndroid | InputProfile::MobileOther
)
}
pub fn recommended_ux_scale(self) -> f64 {
match self {
InputProfile::Desktop => 1.0,
InputProfile::MobileIOS | InputProfile::MobileAndroid | InputProfile::MobileOther => {
1.7
}
}
}
}
static CURRENT: AtomicU8 = AtomicU8::new(profile_code(InputProfile::Desktop));
pub fn set_input_profile(profile: InputProfile) {
CURRENT.store(profile_code(profile), Ordering::Relaxed);
}
pub fn current_input_profile() -> InputProfile {
profile_from_code(CURRENT.load(Ordering::Relaxed))
}
pub fn is_mobile_touch() -> bool {
current_input_profile().is_mobile_touch()
}
pub fn input_profile_from_hint(user_agent_or_platform: &str, pointer_coarse: bool) -> InputProfile {
let ua = user_agent_or_platform.to_ascii_lowercase();
if ua.contains("iphone") || ua.contains("ipad") || ua.contains("ipod") {
return InputProfile::MobileIOS;
}
if ua.contains("android") {
return InputProfile::MobileAndroid;
}
if pointer_coarse && (ua.contains("mac") || ua.contains("darwin")) {
return InputProfile::MobileIOS;
}
if pointer_coarse {
return InputProfile::MobileOther;
}
InputProfile::Desktop
}
const fn profile_code(p: InputProfile) -> u8 {
match p {
InputProfile::Desktop => 0,
InputProfile::MobileIOS => 1,
InputProfile::MobileAndroid => 2,
InputProfile::MobileOther => 3,
}
}
fn profile_from_code(c: u8) -> InputProfile {
match c {
1 => InputProfile::MobileIOS,
2 => InputProfile::MobileAndroid,
3 => InputProfile::MobileOther,
_ => InputProfile::Desktop,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ua_routes_to_correct_profile() {
assert_eq!(
input_profile_from_hint("Mozilla/5.0 (iPhone; CPU iPhone OS 17_4)", true),
InputProfile::MobileIOS
);
assert_eq!(
input_profile_from_hint("Mozilla/5.0 (Linux; Android 14; Pixel 8)", true),
InputProfile::MobileAndroid
);
assert_eq!(
input_profile_from_hint(
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit",
true
),
InputProfile::MobileIOS
);
assert_eq!(
input_profile_from_hint(
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit",
false
),
InputProfile::Desktop
);
assert_eq!(
input_profile_from_hint("CrOS x86_64", true),
InputProfile::MobileOther
);
}
#[test]
fn is_mobile_touch_helper() {
assert!(!InputProfile::Desktop.is_mobile_touch());
assert!(InputProfile::MobileIOS.is_mobile_touch());
assert!(InputProfile::MobileAndroid.is_mobile_touch());
assert!(InputProfile::MobileOther.is_mobile_touch());
}
}