pytauri_core/plugins/notification/
mod.rs1use std::{
2 error::Error,
3 fmt::{Debug, Display, Formatter},
4};
5
6use pyo3::{prelude::*, types::PyDict};
7use pyo3_utils::{
8 from_py_dict::{derive_from_py_dict, FromPyDict as _, NotRequired},
9 py_wrapper::{PyWrapper, PyWrapperT2},
10};
11use tauri_plugin_notification::{self as plugin, NotificationExt as _};
12
13use crate::{
14 ext_mod::{manager_method_impl, plugin::Plugin, ImplManager},
15 tauri_runtime::Runtime,
16};
17
18#[derive(Debug)]
19struct PluginError(plugin::Error);
20
21impl Display for PluginError {
22 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
23 Display::fmt(&self.0, f)
24 }
25}
26
27impl Error for PluginError {}
28
29impl From<PluginError> for PyErr {
30 fn from(value: PluginError) -> Self {
31 match value.0 {
32 plugin::Error::Io(e) => e.into(),
33 }
34 }
35}
36
37impl From<plugin::Error> for PluginError {
38 fn from(value: plugin::Error) -> Self {
39 Self(value)
40 }
41}
42
43#[pyfunction]
45pub fn init() -> Plugin {
46 Plugin::new(Box::new(|| Box::new(plugin::init::<Runtime>())))
47}
48
49#[non_exhaustive]
51pub struct NotificationBuilderArgs {
52 id: NotRequired<i32>,
53 channel_id: NotRequired<String>,
54 title: NotRequired<String>,
55 body: NotRequired<String>,
56 large_body: NotRequired<String>,
58 summary: NotRequired<String>,
59 action_type_id: NotRequired<String>,
60 group: NotRequired<String>,
61 group_summary: bool,
62 sound: NotRequired<String>,
63 inbox_line: NotRequired<String>,
64 icon: NotRequired<String>,
65 large_icon: NotRequired<String>,
66 icon_color: NotRequired<String>,
67 ongoing: bool,
70 auto_cancel: bool,
71 silent: bool,
72}
73
74derive_from_py_dict!(NotificationBuilderArgs {
75 #[pyo3(default)]
76 id,
77 #[pyo3(default)]
78 channel_id,
79 #[pyo3(default)]
80 title,
81 #[pyo3(default)]
82 body,
83 #[pyo3(default)]
84 large_body,
85 #[pyo3(default)]
86 summary,
87 #[pyo3(default)]
88 action_type_id,
89 #[pyo3(default)]
90 group,
91 #[pyo3(default)]
92 group_summary,
93 #[pyo3(default)]
94 sound,
95 #[pyo3(default)]
96 inbox_line,
97 #[pyo3(default)]
98 icon,
99 #[pyo3(default)]
100 large_icon,
101 #[pyo3(default)]
102 icon_color,
103 #[pyo3(default)]
104 ongoing,
105 #[pyo3(default)]
106 auto_cancel,
107 #[pyo3(default)]
108 silent,
109});
110
111impl NotificationBuilderArgs {
112 fn from_kwargs(kwargs: Option<&Bound<'_, PyDict>>) -> PyResult<Option<Self>> {
115 kwargs
116 .map(NotificationBuilderArgs::from_py_dict)
117 .transpose()
118 }
119
120 fn apply_to_builder(
121 self,
122 mut builder: plugin::NotificationBuilder<Runtime>,
123 ) -> plugin::NotificationBuilder<Runtime> {
124 let Self {
125 id,
126 channel_id,
127 title,
128 body,
129 large_body,
130 summary,
131 action_type_id,
132 group,
133 group_summary,
134 sound,
135 inbox_line,
136 icon,
137 large_icon,
138 icon_color,
139 ongoing,
140 auto_cancel,
141 silent,
142 } = self;
143
144 if let Some(id) = id.0 {
145 builder = builder.id(id);
146 }
147 if let Some(channel_id) = channel_id.0 {
148 builder = builder.channel_id(channel_id);
149 }
150 if let Some(title) = title.0 {
151 builder = builder.title(title);
152 }
153 if let Some(body) = body.0 {
154 builder = builder.body(body);
155 }
156 if let Some(large_body) = large_body.0 {
157 builder = builder.large_body(large_body);
158 }
159 if let Some(summary) = summary.0 {
160 builder = builder.summary(summary);
161 }
162 if let Some(action_type_id) = action_type_id.0 {
163 builder = builder.action_type_id(action_type_id);
164 }
165 if let Some(group) = group.0 {
166 builder = builder.group(group);
167 }
168 if group_summary {
169 builder = builder.group_summary();
170 }
171 if let Some(sound) = sound.0 {
172 builder = builder.sound(sound);
173 }
174 if let Some(inbox_line) = inbox_line.0 {
175 builder = builder.inbox_line(inbox_line);
176 }
177 if let Some(icon) = icon.0 {
178 builder = builder.icon(icon);
179 }
180 if let Some(large_icon) = large_icon.0 {
181 builder = builder.large_icon(large_icon);
182 }
183 if let Some(icon_color) = icon_color.0 {
184 builder = builder.icon_color(icon_color);
185 }
186 if ongoing {
187 builder = builder.ongoing();
188 }
189 if auto_cancel {
190 builder = builder.auto_cancel();
191 }
192 if silent {
193 builder = builder.silent();
194 }
195
196 builder
197 }
198}
199
200#[pyclass(frozen)]
202#[non_exhaustive]
203pub struct NotificationBuilder(pub PyWrapper<PyWrapperT2<plugin::NotificationBuilder<Runtime>>>);
204
205impl NotificationBuilder {
206 fn new(builder: plugin::NotificationBuilder<Runtime>) -> Self {
207 Self(PyWrapper::new2(builder))
208 }
209}
210
211#[pymethods]
212impl NotificationBuilder {
213 #[pyo3(signature = (**kwargs))]
214 fn show(&self, kwargs: Option<&Bound<'_, PyDict>>) -> PyResult<()> {
215 let args = NotificationBuilderArgs::from_kwargs(kwargs)?;
216
217 let mut builder = self.0.try_take_inner()??;
218
219 if let Some(args) = args {
220 builder = args.apply_to_builder(builder);
221 }
222
223 builder
225 .show()
226 .map_err(PluginError::from)
227 .map_err(PyErr::from)
228 }
229}
230
231#[pyclass(frozen)]
233#[non_exhaustive]
234pub struct NotificationExt;
235
236pub type ImplNotificationExt = ImplManager;
238
239#[pymethods]
240impl NotificationExt {
241 #[staticmethod]
242 fn builder(slf: ImplNotificationExt, py: Python<'_>) -> PyResult<NotificationBuilder> {
243 manager_method_impl!(py, &slf, |_py, manager| {
244 let builder = manager.notification().builder();
246 Ok(NotificationBuilder::new(builder))
247 })?
248 }
249}
250
251#[pymodule(submodule, gil_used = false)]
253pub mod notification {
254 #[pymodule_export]
255 pub use super::{init, NotificationBuilder, NotificationExt};
256
257 pub use super::{ImplNotificationExt, NotificationBuilderArgs};
258}