rnotifylib/destination/kinds/
desktop.rs

1use std::error::Error;
2use std::fmt::Debug;
3use notify_rust::{Notification, Urgency};
4use serde::{Serialize, Deserialize};
5use crate::destination::{MessageDestination, SerializableDestination};
6use crate::message::{Level, Message};
7
8/// Receive a notification to the desktop
9///
10/// # KDE #
11/// You need to enable "Other applications" notifications to show in tray
12/// if you want these to persist - at least when running with `cargo run` / without
13/// an installation.
14#[derive(Debug, Serialize, Deserialize)]
15pub struct DesktopNotificationReceiver {}
16
17impl MessageDestination for DesktopNotificationReceiver {
18    fn send(&self, message: &Message) -> Result<(), Box<dyn Error>> {
19        let mut notification = Notification::new();
20        let mut title = String::new();
21        if let Some(message_title) = message.get_title() {
22            title.push_str(message_title)
23        }
24        if let Some(component) = message.get_component() {
25            if !title.is_empty() {
26                title.push_str(" - ");
27            }
28            title.push_str(&format!("{}", component));
29        }
30        notification.summary(&title)
31            .auto_icon();
32
33        let body = format!("{}\nFrom: {}", message.get_message_detail().raw(), message.get_author());
34
35        notification.body(&body);
36
37        #[cfg(all(unix, not(target_os = "macos")))]
38        {
39            let urgency = match message.get_level() {
40                Level::Info => Urgency::Normal,
41                Level::Warn => Urgency::Normal,
42                Level::Error => Urgency::Critical,
43                Level::SelfError => Urgency::Critical,
44            };
45
46            notification.urgency(urgency);
47
48
49            // TODO: Can we set icon on macos / windows
50            // https://wiki.archlinux.org/title/Desktop_notifications#Bash
51            // https://specifications.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html
52            let icon = match message.get_level() {
53                Level::Info =>      "dialog-information",
54                Level::Warn =>      "dialog-warning",
55                Level::Error =>     "dialog-error",
56                Level::SelfError => "dialog-error",
57            };
58            notification.icon(icon);
59        }
60
61        notification.show()?;
62
63        Ok(())
64    }
65}
66
67
68#[typetag::serde(name = "Desktop")]
69impl SerializableDestination for DesktopNotificationReceiver {
70    fn as_message_destination(&self) -> &dyn MessageDestination {
71        self
72    }
73}