Skip to main content

entracte_lib/
notifications.rs

1use tauri::plugin::PermissionState;
2use tauri::{AppHandle, Runtime};
3
4/// Whether the app must call `request_permission()` for the current
5/// notification permission state before any `.show()` will surface a
6/// banner.
7///
8/// On macOS a fresh install starts in `Prompt` / `PromptWithRationale`
9/// (the OS "not determined" authorization status). Until the app
10/// explicitly requests authorization, `tauri-plugin-notification`'s
11/// `.show()` posts into a notification centre the app was never
12/// registered with, so every banner is silently dropped — which is why
13/// the pre-break notification never appeared even though the scheduler
14/// fired it (#135). `permission_state()` reporting a determined value
15/// (`Granted` / `Denied`) means the user has already answered, so we
16/// neither need nor want to re-prompt.
17pub fn should_request_notification_permission(state: PermissionState) -> bool {
18    matches!(
19        state,
20        PermissionState::Prompt | PermissionState::PromptWithRationale
21    )
22}
23
24/// Ensure the OS notification authorization has been requested at least
25/// once so scheduled break / pre-break / screen-time banners actually
26/// surface. Queries the current permission, and only on an undetermined
27/// state does it raise the request (which shows the macOS authorization
28/// dialog and registers the app with the notification centre).
29///
30/// The pure undetermined-vs-determined decision lives in
31/// [`should_request_notification_permission`]; everything here is the
32/// plugin-FFI shim around it.
33pub fn ensure_permission_requested<R: Runtime>(app: &AppHandle<R>) {
34    use tauri_plugin_notification::NotificationExt;
35
36    let state = match app.notification().permission_state() {
37        Ok(state) => state,
38        Err(e) => {
39            log::warn!("notifications: could not read permission state: {e}");
40            return;
41        }
42    };
43    if !should_request_notification_permission(state) {
44        return;
45    }
46    match app.notification().request_permission() {
47        Ok(new_state) => {
48            log::info!("notifications: requested permission, now {new_state:?}");
49        }
50        Err(e) => {
51            log::warn!("notifications: permission request failed: {e}");
52        }
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59
60    #[test]
61    fn requests_when_undetermined() {
62        assert!(should_request_notification_permission(
63            PermissionState::Prompt
64        ));
65        assert!(should_request_notification_permission(
66            PermissionState::PromptWithRationale
67        ));
68    }
69
70    #[test]
71    fn does_not_request_when_already_decided() {
72        assert!(!should_request_notification_permission(
73            PermissionState::Granted
74        ));
75        assert!(!should_request_notification_permission(
76            PermissionState::Denied
77        ));
78    }
79}