tauri_plugin_notifications/
desktop.rs1use serde::de::DeserializeOwned;
6use tauri::{
7 plugin::{PermissionState, PluginApi},
8 AppHandle, Runtime,
9};
10
11use crate::NotificationsBuilder;
12
13pub fn init<R: Runtime, C: DeserializeOwned>(
14 app: &AppHandle<R>,
15 _api: PluginApi<R, C>,
16) -> crate::Result<Notifications<R>> {
17 Ok(Notifications(app.clone()))
18}
19
20pub struct Notifications<R: Runtime>(AppHandle<R>);
24
25impl<R: Runtime> crate::NotificationsBuilder<R> {
26 pub fn show(self) -> crate::Result<()> {
27 let mut notification = imp::Notification::new(self.app.config().identifier.clone());
28
29 if let Some(title) = self
30 .data
31 .title
32 .or_else(|| self.app.config().product_name.clone())
33 {
34 notification = notification.title(title);
35 }
36 if let Some(body) = self.data.body {
37 notification = notification.body(body);
38 }
39 if let Some(icon) = self.data.icon {
40 notification = notification.icon(icon);
41 }
42
43 notification.show()?;
44
45 Ok(())
46 }
47}
48
49impl<R: Runtime> Notifications<R> {
50 pub fn builder(&self) -> NotificationsBuilder<R> {
51 NotificationsBuilder::new(self.0.clone())
52 }
53
54 pub fn request_permission(&self) -> crate::Result<PermissionState> {
55 Ok(PermissionState::Granted)
56 }
57
58 pub fn register_for_push_notifications(&self) -> crate::Result<String> {
59 Err(crate::Error::Io(std::io::Error::other(
60 "Push notifications are not supported on desktop platforms",
61 )))
62 }
63
64 pub fn unregister_for_push_notifications(&self) -> crate::Result<()> {
65 Err(crate::Error::Io(std::io::Error::other(
66 "Push notifications are not supported on desktop platforms",
67 )))
68 }
69
70 pub fn permission_state(&self) -> crate::Result<PermissionState> {
71 Ok(PermissionState::Granted)
72 }
73}
74
75mod imp {
76 #[cfg(windows)]
79 use std::path::MAIN_SEPARATOR as SEP;
80
81 #[allow(dead_code)]
85 #[derive(Debug, Default)]
86 pub struct Notification {
87 body: Option<String>,
89 title: Option<String>,
91 icon: Option<String>,
93 identifier: String,
95 }
96
97 impl Notification {
98 pub fn new(identifier: impl Into<String>) -> Self {
100 Self {
101 identifier: identifier.into(),
102 ..Default::default()
103 }
104 }
105
106 #[must_use]
108 pub fn body(mut self, body: impl Into<String>) -> Self {
109 self.body = Some(body.into());
110 self
111 }
112
113 #[must_use]
115 pub fn title(mut self, title: impl Into<String>) -> Self {
116 self.title = Some(title.into());
117 self
118 }
119
120 #[must_use]
122 pub fn icon(mut self, icon: impl Into<String>) -> Self {
123 self.icon = Some(icon.into());
124 self
125 }
126
127 pub fn show(self) -> crate::Result<()> {
129 let mut notification = notify_rust::Notification::new();
130 if let Some(body) = self.body {
131 notification.body(&body);
132 }
133 if let Some(title) = self.title {
134 notification.summary(&title);
135 }
136 if let Some(icon) = self.icon {
137 notification.icon(&icon);
138 } else {
139 notification.auto_icon();
140 }
141 #[cfg(windows)]
142 {
143 let exe = tauri::utils::platform::current_exe()?;
144 let exe_dir = exe.parent().expect("failed to get exe directory");
145 let curr_dir = exe_dir.display().to_string();
146 if !(curr_dir.ends_with(format!("{SEP}target{SEP}debug").as_str())
148 || curr_dir.ends_with(format!("{SEP}target{SEP}release").as_str()))
149 {
150 notification.app_id(&self.identifier);
151 }
152 }
153 #[cfg(target_os = "macos")]
154 {
155 let _ = notify_rust::set_application(if tauri::is_dev() {
156 "com.apple.Terminal"
157 } else {
158 &self.identifier
159 });
160 }
161
162 tauri::async_runtime::spawn(async move {
163 let _ = notification.show();
164 });
165
166 Ok(())
167 }
168 }
169}