dioxus_notification/
lib.rs

1//! Send desktop notifications.
2//!
3//! This crate only supports desktop targets (Windows, MacOS, & Linux).
4#![deny(missing_docs)]
5
6use std::{
7    error::Error,
8    fmt::{self, Display},
9    path::{Path, PathBuf},
10};
11
12/// Provides a builder API and contains relevant notification info.
13///
14/// # Examples
15///
16/// ```
17/// use dioxus_notification::Notification;
18///
19/// Notification::new()
20///     .app_name("dioxus test".to_string())
21///     .summary("hi, this is dioxus test".to_string())
22///     .body("lorem ipsum??".to_string())
23///     .show()
24///     .unwrap();
25///
26/// ```
27#[derive(Debug, Clone, Default)]
28pub struct Notification {
29    app_name: String,
30    summary: String,
31    body: String,
32    icon_path: PathBuf,
33    timeout: NotificationTimeout,
34}
35
36/// Represents the notification's timeout.
37#[derive(Debug, PartialEq, Clone, Default)]
38pub enum NotificationTimeout {
39    /// Default depends on the target OS.
40    #[default]
41    Default,
42    /// A notification that has to be manually acknowledged.
43    Never,
44    /// A notification that times out after a duration.
45    Duration(std::time::Duration),
46}
47
48cfg_if::cfg_if! {
49    if #[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))] {
50        use notify_rust::Timeout;
51        impl From<NotificationTimeout> for Timeout {
52            fn from(value: NotificationTimeout) -> Self {
53                match value {
54                    NotificationTimeout::Default => Timeout::Default,
55                    NotificationTimeout::Never => Timeout::Never,
56                    NotificationTimeout::Duration(dur) => Timeout::Milliseconds(dur.as_millis().try_into().unwrap()),
57                }
58            }
59        }
60    }
61}
62
63impl Notification {
64    /// Creates a new notification with empty/default values.
65    pub fn new() -> Self {
66        Self::default()
67    }
68
69    /// Show the final notification.
70    pub fn show(&self) -> Result<(), NotificationError> {
71        self.show_inner()
72    }
73
74    // Unsupported fallback.
75    #[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))]
76    fn show_inner(&self) -> Result<(), NotificationError> {
77        Err(NotificationError::Unsupported)
78    }
79
80    // notify_rust implementation supporting windows, mac, and linux.
81    #[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))]
82    fn show_inner(&self) -> Result<(), NotificationError> {
83        let icon_path =
84            self.icon_path
85                .as_os_str()
86                .to_str()
87                .ok_or(NotificationError::FailedToShow(
88                    "failed to convert icon path into str".into(),
89                ))?;
90
91        notify_rust::Notification::new()
92            .appname(&self.app_name)
93            .summary(&self.summary)
94            .body(&self.body)
95            .icon(icon_path)
96            .timeout(self.timeout.clone())
97            .show()
98            .map_err(|e| NotificationError::FailedToShow(e.into()))?;
99
100        Ok(())
101    }
102
103    /// Set the application's name for the notification.
104    pub fn app_name(&mut self, value: impl ToString) -> &mut Self {
105        self.app_name = value.to_string();
106        self
107    }
108
109    /// Set the summary content of the notification.
110    pub fn summary(&mut self, value: impl ToString) -> &mut Self {
111        self.summary = value.to_string();
112        self
113    }
114
115    /// Set the body content of the notification.
116    pub fn body(&mut self, value: impl ToString) -> &mut Self {
117        self.body = value.to_string();
118        self
119    }
120
121    /// Set full path to image.
122    ///
123    /// Not supported on MacOS.
124    pub fn icon_path(&mut self, value: impl AsRef<Path>) -> &mut Self {
125        self.icon_path = value.as_ref().to_path_buf();
126        self
127    }
128
129    /// Set a timeout for when the notification should hide.
130    pub fn timeout(&mut self, value: NotificationTimeout) -> &mut Self {
131        self.timeout = value;
132        self
133    }
134}
135
136#[test]
137#[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))]
138fn test_notification() {
139    Notification::new()
140        .app_name("dioxus test".to_string())
141        .summary("hi, this is dioxus test".to_string())
142        .body("lorem ipsum??".to_string())
143        .show()
144        .unwrap();
145}
146
147/// Represents errors when utilizing the notification abstraction.
148#[derive(Debug)]
149pub enum NotificationError {
150    /// Notification is unsupported on this platform.
151    Unsupported,
152    /// Failure to show a notification.
153    FailedToShow(Box<dyn Error>),
154}
155
156impl Error for NotificationError {}
157impl Display for NotificationError {
158    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
159        match self {
160            Self::Unsupported => write!(f, "notification is not supported on this platform"),
161            Self::FailedToShow(err) => write!(f, "failed to show notification: {err}"),
162        }
163    }
164}