Skip to main content

wasm_toolkit/window_ops/
match_media.rs

1use std::{cell::RefCell, rc::Rc};
2
3use async_channel::{Receiver, bounded};
4use wasm_bindgen::{JsCast, prelude::Closure};
5use web_sys::{Event, MediaQueryList};
6
7use crate::{WasmToolkitCommon, WasmToolkitError, WasmToolkitResult, WasmWindow};
8
9impl WasmWindow {
10    pub fn match_media(&self, query: &str) -> WasmToolkitResult<MediaQueryList> {
11        self.inner()
12            .match_media(query)
13            .map_err(|error| {
14                let outcome = WasmToolkitCommon::exception_or_stringify(&error);
15
16                WasmToolkitError::Op(outcome)
17            })?
18            .ok_or(WasmToolkitError::MatchMediaQueryUnsupported)
19    }
20
21    pub fn query_dark_mode(&self) -> WasmToolkitResult<MediaQueryList> {
22        self.match_media("(prefers-color-scheme: dark)")
23    }
24
25    pub fn is_dark_mode(&self) -> WasmToolkitResult<bool> {
26        Ok(self.query_dark_mode()?.matches())
27    }
28
29    pub async fn watch_dark_mode(&self) -> WasmToolkitResult<Receiver<bool>> {
30        let (sender, receiver) = bounded::<bool>(1);
31
32        let query = Rc::new(RefCell::new(self.query_dark_mode()?));
33        let query_spawned = query.clone();
34
35        let callback = Closure::wrap(Box::new(move |_value: Event| {
36            let sender = sender.clone();
37            let query_spawned = query_spawned.clone();
38
39            wasm_bindgen_futures::spawn_local(async move {
40                let is_dark_mode = query_spawned.borrow().matches();
41
42                if let Err(error) = sender.send(is_dark_mode).await {
43                    web_sys::console::error_2(
44                        &"Dark mode listener error: ".into(),
45                        &error.to_string().into(),
46                    );
47                }
48            });
49        }) as Box<dyn Fn(_)>);
50
51        if let Ok(callback_fn) = callback.as_ref().clone().dyn_into::<js_sys::Function>() {
52            wasm_bindgen_futures::spawn_local(async move {
53                query.borrow_mut().set_onchange(Some(&callback_fn));
54            });
55            callback.forget();
56
57            Ok(receiver)
58        } else {
59            web_sys::console::error_1(
60                        &"Unable to set `onchange` event lister for event checking when a user switches from dark mode to light mode and vise-versa!".into(),
61                    );
62
63            Err(WasmToolkitError::AddEventListener(
64                "`onchange` event listener for checking dark and light modes".to_string(),
65            ))
66        }
67    }
68}