Skip to main content

lingxia_platform/
banner_background.rs

1use crate::traits::app_runtime::DesktopBannerBackground;
2
3impl DesktopBannerBackground {
4    pub fn parse(value: &str) -> Result<Self, String> {
5        let value = value.trim();
6        if value.is_empty() || value.eq_ignore_ascii_case("system") {
7            return Ok(Self::System);
8        }
9        if value.eq_ignore_ascii_case("light") {
10            return Ok(Self::Light);
11        }
12        if value.eq_ignore_ascii_case("dark") {
13            return Ok(Self::Dark);
14        }
15        parse_css_color(value)
16            .map(|(r, g, b, a)| Self::Color { r, g, b, a })
17            .ok_or_else(|| {
18                "banner background must be system, light, dark, or #RGB/#RRGGBB/#RRGGBBAA".into()
19            })
20    }
21
22    pub fn as_ffi(&self) -> String {
23        match self {
24            Self::System => String::new(),
25            Self::Light => "light".into(),
26            Self::Dark => "dark".into(),
27            Self::Color { r, g, b, a } if *a == 255 => format!("#{r:02x}{g:02x}{b:02x}"),
28            Self::Color { r, g, b, a } => format!("#{r:02x}{g:02x}{b:02x}{a:02x}"),
29        }
30    }
31
32    pub fn prefers_dark_content(&self) -> bool {
33        match self {
34            Self::Light => true,
35            Self::Dark | Self::System => false,
36            Self::Color { r, g, b, .. } => relative_luminance(*r, *g, *b) > 0.55,
37        }
38    }
39}
40
41fn parse_css_color(value: &str) -> Option<(u8, u8, u8, u8)> {
42    let hex = value.strip_prefix('#')?;
43    let digits = hex.as_bytes();
44    let nibble = |byte| match byte {
45        b'0'..=b'9' => Some(byte - b'0'),
46        b'a'..=b'f' => Some(byte - b'a' + 10),
47        b'A'..=b'F' => Some(byte - b'A' + 10),
48        _ => None,
49    };
50    let pair = |hi, lo| Some(nibble(hi)? * 16 + nibble(lo)?);
51    match digits {
52        [r, g, b] => Some((nibble(*r)? * 17, nibble(*g)? * 17, nibble(*b)? * 17, 255)),
53        [r1, r2, g1, g2, b1, b2] => Some((pair(*r1, *r2)?, pair(*g1, *g2)?, pair(*b1, *b2)?, 255)),
54        [r1, r2, g1, g2, b1, b2, a1, a2] => Some((
55            pair(*r1, *r2)?,
56            pair(*g1, *g2)?,
57            pair(*b1, *b2)?,
58            pair(*a1, *a2)?,
59        )),
60        _ => None,
61    }
62}
63
64fn relative_luminance(r: u8, g: u8, b: u8) -> f32 {
65    0.2126 * (r as f32 / 255.0) + 0.7152 * (g as f32 / 255.0) + 0.0722 * (b as f32 / 255.0)
66}