Skip to main content

wayle_notification/
service.rs

1use std::sync::Arc;
2
3use derive_more::Debug;
4use tokio::sync::broadcast;
5use tokio_util::sync::CancellationToken;
6use tracing::{instrument, warn};
7use wayle_core::Property;
8use zbus::Connection;
9
10use crate::{
11    builder::NotificationServiceBuilder, core::notification::Notification, error::Error,
12    events::NotificationEvent, persistence::NotificationStore, popup_timer::PopupTimerManager,
13    types::ClosedReason,
14};
15
16/// Desktop notification service. See [crate-level docs](crate) for usage.
17#[derive(Debug)]
18pub struct NotificationService {
19    #[debug(skip)]
20    pub(crate) cancellation_token: CancellationToken,
21    #[debug(skip)]
22    pub(crate) notif_tx: broadcast::Sender<NotificationEvent>,
23    #[debug(skip)]
24    pub(crate) store: Option<NotificationStore>,
25    #[debug(skip)]
26    pub(crate) connection: Connection,
27
28    /// All received notifications.
29    pub notifications: Property<Vec<Arc<Notification>>>,
30    /// Currently visible popups.
31    pub popups: Property<Vec<Arc<Notification>>>,
32    /// Popup display duration in milliseconds.
33    pub popup_duration: Property<u32>,
34    /// Do Not Disturb mode; suppresses popups when true.
35    pub dnd: Property<bool>,
36    /// Auto-remove expired notifications.
37    pub remove_expired: Property<bool>,
38    /// Glob patterns for blocking notifications by app name.
39    pub blocklist: Property<Vec<String>>,
40    #[debug(skip)]
41    pub(crate) popup_timers: Arc<PopupTimerManager>,
42}
43
44impl NotificationService {
45    /// Creates a new notification service instance.
46    ///
47    /// # Errors
48    /// Returns error if D-Bus connection fails or service registration fails.
49    #[instrument(name = "NotificationService::new", err)]
50    pub async fn new() -> Result<Arc<Self>, Error> {
51        Self::builder().build().await
52    }
53
54    /// Creates a builder for configuring a NotificationService.
55    pub fn builder() -> NotificationServiceBuilder {
56        NotificationServiceBuilder::new()
57    }
58
59    /// Dismisses all notifications and emits `NotificationClosed` for each.
60    ///
61    /// # Errors
62    /// Returns error if the event channel is closed.
63    #[instrument(skip(self), err)]
64    pub async fn dismiss_all(&self) -> Result<(), Error> {
65        let notifications = self.notifications.get();
66
67        for notif in notifications.iter() {
68            if let Err(error) = self.notif_tx.send(NotificationEvent::Remove(
69                notif.id,
70                ClosedReason::DismissedByUser,
71            )) {
72                warn!(error = %error, id = notif.id, "cannot dismiss notification");
73            }
74        }
75
76        Ok(())
77    }
78
79    /// Sets the Do Not Disturb mode.
80    ///
81    /// When enabled, new notifications will not appear as popups but will
82    /// still be added to the notification list.
83    pub fn set_dnd(&self, dnd: bool) {
84        self.dnd.set(dnd)
85    }
86
87    /// Sets the duration for how long popup notifications are displayed.
88    pub fn set_popup_duration(&self, duration: u32) {
89        self.popup_duration.set(duration)
90    }
91
92    /// Replaces the blocklist patterns.
93    pub fn set_blocklist(&self, patterns: Vec<String>) {
94        self.blocklist.set(patterns)
95    }
96
97    /// Removes a popup from the visible list without affecting notification history.
98    ///
99    /// Cancels any running popup timer for this ID.
100    pub fn dismiss_popup(&self, id: u32) {
101        self.popup_timers.cancel(id);
102
103        let mut list = self.popups.get();
104        list.retain(|popup| popup.id != id);
105        self.popups.set(list);
106    }
107
108    /// Pauses the popup countdown timer.
109    pub fn inhibit_popup(&self, id: u32) {
110        self.popup_timers.pause(id);
111    }
112
113    /// Resumes the popup countdown timer after a pause.
114    pub fn release_popup(&self, id: u32) {
115        self.popup_timers.resume(id);
116    }
117}
118
119impl Drop for NotificationService {
120    fn drop(&mut self) {
121        self.cancellation_token.cancel();
122    }
123}