Skip to main content

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