1#![cfg_attr(docsrs, feature(doc_cfg))]
2#![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/README.md"))]
3#![warn(missing_docs, rust_2018_idioms, future_incompatible, keyword_idents)]
5
6pub mod error;
7mod integration;
8mod platform;
9mod theme;
10
11use error::Error;
12
13use async_stream::stream;
14use futures_core::stream::Stream;
15use std::hash::Hash;
16use uuid::Uuid;
17
18#[doc(inline)]
19pub use theme::{Theme, ThemeColor, ThemeContrast, ThemeKind, ThemePalette, ThemeScheme};
20
21pub struct SystemTheme {
23 platform: platform::Platform,
24 identifier: Uuid,
25}
26
27impl Hash for SystemTheme {
28 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
29 self.identifier.hash(state);
30 }
31}
32
33impl SystemTheme {
34 pub fn new() -> Result<Self, Error> {
36 Ok(Self {
37 platform: platform::Platform::new()?,
38 identifier: Uuid::new_v4(),
39 })
40 }
41
42 pub fn get_kind(&self) -> Result<ThemeKind, Error> {
44 self.platform.theme_kind()
45 }
46
47 pub fn get_scheme(&self) -> Result<ThemeScheme, Error> {
49 self.platform.theme_scheme()
50 }
51
52 pub fn get_contrast(&self) -> Result<ThemeContrast, Error> {
54 self.platform.theme_contrast()
55 }
56
57 pub fn get_accent(&self) -> Result<ThemeColor, Error> {
59 self.platform.theme_accent()
60 }
61
62 pub fn get_theme(&self) -> Theme {
67 let kind = self.get_kind().unwrap_or_default();
68
69 let scheme = self.get_scheme().unwrap_or_default();
70 let contrast = self.get_contrast().unwrap_or_default();
71
72 Theme::new(kind, scheme, contrast, self.get_accent().ok())
73 }
74
75 pub fn subscribe(&self) -> impl Stream<Item = ()> {
77 let notify = self.platform.get_notify();
78 stream! {
79 let mut notified = notify.notified();
80 loop {
81 notified.await;
83 notified = notify.notified();
85 yield ();
86 }
87 }
88 }
89}