tauri_plugin_notification/
lib.rs1#![doc(
12 html_logo_url = "https://github.com/tauri-apps/tauri/raw/dev/app-icon.png",
13 html_favicon_url = "https://github.com/tauri-apps/tauri/raw/dev/app-icon.png"
14)]
15
16use serde::Serialize;
17#[cfg(all(desktop, unix, not(target_os = "macos")))]
18use std::fmt;
19#[cfg(desktop)]
20use tauri::AppHandle;
21#[cfg(mobile)]
22use tauri::plugin::PluginHandle;
23use tauri::{
24 Manager, Runtime,
25 plugin::{Builder, TauriPlugin},
26};
27
28pub use models::*;
29pub use tauri::plugin::PermissionState;
30
31#[cfg(desktop)]
32mod desktop;
33#[cfg(mobile)]
34mod mobile;
35
36mod commands;
37mod error;
38mod models;
39
40pub use error::{Error, Result};
41
42#[cfg(desktop)]
43pub use desktop::Notification;
44#[cfg(mobile)]
45pub use mobile::Notification;
46
47#[derive(Debug)]
49pub struct NotificationBuilder<R: Runtime> {
50 #[cfg(desktop)]
51 app: AppHandle<R>,
52 #[cfg(mobile)]
53 handle: PluginHandle<R>,
54 pub(crate) data: NotificationData,
55 #[cfg(all(desktop, unix, not(target_os = "macos")))]
56 on_close: Option<OnClose>,
57}
58
59#[cfg(all(desktop, unix, not(target_os = "macos")))]
60pub(crate) struct OnClose(Box<dyn FnOnce() + Send + 'static>);
61
62#[cfg(all(desktop, unix, not(target_os = "macos")))]
63impl fmt::Debug for OnClose {
64 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65 f.write_str("OnClose")
66 }
67}
68
69impl<R: Runtime> NotificationBuilder<R> {
70 #[cfg(desktop)]
71 fn new(app: AppHandle<R>) -> Self {
72 Self {
73 app,
74 data: Default::default(),
75 #[cfg(all(desktop, unix, not(target_os = "macos")))]
76 on_close: None,
77 }
78 }
79
80 #[cfg(mobile)]
81 fn new(handle: PluginHandle<R>) -> Self {
82 Self {
83 handle,
84 data: Default::default(),
85 }
86 }
87
88 pub fn id(mut self, id: i32) -> Self {
90 self.data.id = id;
91 self
92 }
93
94 pub fn channel_id(mut self, id: impl Into<String>) -> Self {
102 self.data.channel_id.replace(id.into());
103 self
104 }
105
106 pub fn title(mut self, title: impl Into<String>) -> Self {
108 self.data.title.replace(title.into());
109 self
110 }
111
112 pub fn body(mut self, body: impl Into<String>) -> Self {
114 self.data.body.replace(body.into());
115 self
116 }
117
118 pub fn schedule(mut self, schedule: Schedule) -> Self {
120 self.data.schedule.replace(schedule);
121 self
122 }
123
124 pub fn large_body(mut self, large_body: impl Into<String>) -> Self {
128 self.data.large_body.replace(large_body.into());
129 self
130 }
131
132 pub fn summary(mut self, summary: impl Into<String>) -> Self {
134 self.data.summary.replace(summary.into());
135 self
136 }
137
138 pub fn action_type_id(mut self, action_type_id: impl Into<String>) -> Self {
140 self.data.action_type_id.replace(action_type_id.into());
141 self
142 }
143
144 pub fn group(mut self, group: impl Into<String>) -> Self {
148 self.data.group.replace(group.into());
149 self
150 }
151
152 pub fn group_summary(mut self) -> Self {
154 self.data.group_summary = true;
155 self
156 }
157
158 pub fn sound(mut self, sound: impl Into<String>) -> Self {
160 self.data.sound.replace(sound.into());
161 self
162 }
163
164 pub fn inbox_line(mut self, line: impl Into<String>) -> Self {
170 self.data.inbox_lines.push(line.into());
171 self
172 }
173
174 pub fn icon(mut self, icon: impl Into<String>) -> Self {
178 self.data.icon.replace(icon.into());
179 self
180 }
181
182 pub fn large_icon(mut self, large_icon: impl Into<String>) -> Self {
186 self.data.large_icon.replace(large_icon.into());
187 self
188 }
189
190 pub fn icon_color(mut self, icon_color: impl Into<String>) -> Self {
192 self.data.icon_color.replace(icon_color.into());
193 self
194 }
195
196 pub fn attachment(mut self, attachment: Attachment) -> Self {
198 self.data.attachments.push(attachment);
199 self
200 }
201
202 pub fn extra(mut self, key: impl Into<String>, value: impl Serialize) -> Self {
204 self.data
205 .extra
206 .insert(key.into(), serde_json::to_value(value).unwrap());
207 self
208 }
209
210 pub fn ongoing(mut self) -> Self {
216 self.data.ongoing = true;
217 self
218 }
219
220 pub fn auto_cancel(mut self) -> Self {
222 self.data.auto_cancel = true;
223 self
224 }
225
226 pub fn silent(mut self) -> Self {
228 self.data.silent = true;
229 self
230 }
231
232 #[cfg(all(desktop, unix, not(target_os = "macos")))]
242 pub fn on_close<F: FnOnce() + Send + 'static>(mut self, handler: F) -> Self {
243 self.on_close = Some(OnClose(Box::new(handler)));
244 self
245 }
246}
247
248pub trait NotificationExt<R: Runtime> {
250 fn notification(&self) -> &Notification<R>;
267}
268
269impl<R: Runtime, T: Manager<R>> crate::NotificationExt<R> for T {
270 fn notification(&self) -> &Notification<R> {
271 self.state::<Notification<R>>().inner()
272 }
273}
274
275pub fn init<R: Runtime>() -> TauriPlugin<R> {
277 let builder = Builder::new("notification");
278 #[cfg(mobile)]
280 let builder = builder.invoke_handler(tauri::generate_handler![
281 commands::notify,
282 commands::request_permission,
283 commands::is_permission_granted
284 ]);
285 #[cfg(desktop)]
286 let builder = builder
287 .invoke_handler(tauri::generate_handler![
288 commands::notify,
289 commands::request_permission,
290 commands::is_permission_granted,
291 commands::register_action_types,
292 commands::remove_active,
293 commands::register_listener,
294 commands::remove_listener
295 ])
296 .on_page_load(|webview, payload| {
298 if payload.event() == tauri::webview::PageLoadEvent::Started
299 && let Some(notification) = webview.try_state::<Notification<R>>()
300 {
301 notification.remove_webview_listeners(webview.label());
302 }
303 })
304 .on_event(|app, event| {
305 if let tauri::RunEvent::WindowEvent {
306 label,
307 event: tauri::WindowEvent::Destroyed,
308 ..
309 } = event
310 && let Some(notification) = app.try_state::<Notification<R>>()
311 {
312 notification.remove_window_listeners(label);
313 }
314 });
315 builder
316 .js_init_script(include_str!("init-iife.js").replace(
317 "__TEMPLATE_windows__",
318 if cfg!(windows) { "true" } else { "false" },
319 ))
320 .setup(|app, api| {
321 #[cfg(mobile)]
322 let notification = mobile::init(app, api)?;
323 #[cfg(desktop)]
324 let notification = desktop::init(app, api)?;
325 app.manage(notification);
326 Ok(())
327 })
328 .build()
329}