use serde::de::DeserializeOwned;
use tauri::{
plugin::{PermissionState, PluginApi},
AppHandle, Runtime,
};
use crate::NotificationsBuilder;
pub fn init<R: Runtime, C: DeserializeOwned>(
app: &AppHandle<R>,
_api: PluginApi<R, C>,
) -> crate::Result<Notifications<R>> {
Ok(Notifications(app.clone()))
}
pub struct Notifications<R: Runtime>(AppHandle<R>);
impl<R: Runtime> crate::NotificationsBuilder<R> {
pub async fn show(self) -> crate::Result<()> {
let mut notification = imp::Notification::new(self.app.config().identifier.clone());
if let Some(title) = self
.data
.title
.or_else(|| self.app.config().product_name.clone())
{
notification = notification.title(title);
}
if let Some(body) = self.data.body {
notification = notification.body(body);
}
if let Some(icon) = self.data.icon {
notification = notification.icon(icon);
}
notification.show()?;
Ok(())
}
}
impl<R: Runtime> Notifications<R> {
pub fn builder(&self) -> NotificationsBuilder<R> {
NotificationsBuilder::new(self.0.clone())
}
pub async fn request_permission(&self) -> crate::Result<PermissionState> {
Ok(PermissionState::Granted)
}
pub async fn register_for_push_notifications(&self) -> crate::Result<String> {
Err(crate::Error::Io(std::io::Error::other(
"Push notifications are not supported on desktop platforms",
)))
}
pub fn unregister_for_push_notifications(&self) -> crate::Result<()> {
Err(crate::Error::Io(std::io::Error::other(
"Push notifications are not supported on desktop platforms",
)))
}
pub async fn permission_state(&self) -> crate::Result<PermissionState> {
Ok(PermissionState::Granted)
}
pub async fn pending(&self) -> crate::Result<Vec<crate::PendingNotification>> {
Err(crate::Error::Io(std::io::Error::other(
"Pending notifications are not supported with notify-rust",
)))
}
pub async fn active(&self) -> crate::Result<Vec<crate::ActiveNotification>> {
Err(crate::Error::Io(std::io::Error::other(
"Active notifications are not supported with notify-rust",
)))
}
pub fn set_click_listener_active(&self, _active: bool) -> crate::Result<()> {
Err(crate::Error::Io(std::io::Error::other(
"Click listeners are not supported with notify-rust",
)))
}
pub fn remove_active(&self, _ids: Vec<i32>) -> crate::Result<()> {
Err(crate::Error::Io(std::io::Error::other(
"Removing active notifications is not supported with notify-rust",
)))
}
pub fn cancel(&self, _notifications: Vec<i32>) -> crate::Result<()> {
Err(crate::Error::Io(std::io::Error::other(
"Canceling notifications is not supported with notify-rust",
)))
}
pub fn cancel_all(&self) -> crate::Result<()> {
Err(crate::Error::Io(std::io::Error::other(
"Canceling notifications is not supported with notify-rust",
)))
}
pub fn register_action_types(&self, _types: Vec<crate::ActionType>) -> crate::Result<()> {
Err(crate::Error::Io(std::io::Error::other(
"Action types are not supported with notify-rust",
)))
}
pub fn create_channel(&self, _channel: crate::Channel) -> crate::Result<()> {
Err(crate::Error::Io(std::io::Error::other(
"Notification channels are not supported with notify-rust",
)))
}
pub fn delete_channel(&self, _id: impl Into<String>) -> crate::Result<()> {
Err(crate::Error::Io(std::io::Error::other(
"Notification channels are not supported with notify-rust",
)))
}
pub fn list_channels(&self) -> crate::Result<Vec<crate::Channel>> {
Err(crate::Error::Io(std::io::Error::other(
"Notification channels are not supported with notify-rust",
)))
}
}
mod imp {
#[cfg(windows)]
use std::path::MAIN_SEPARATOR as SEP;
#[allow(dead_code)]
#[derive(Debug, Default)]
pub struct Notification {
body: Option<String>,
title: Option<String>,
icon: Option<String>,
identifier: String,
}
impl Notification {
pub fn new(identifier: impl Into<String>) -> Self {
Self {
identifier: identifier.into(),
..Default::default()
}
}
#[must_use]
pub fn body(mut self, body: impl Into<String>) -> Self {
self.body = Some(body.into());
self
}
#[must_use]
pub fn title(mut self, title: impl Into<String>) -> Self {
self.title = Some(title.into());
self
}
#[must_use]
pub fn icon(mut self, icon: impl Into<String>) -> Self {
self.icon = Some(icon.into());
self
}
pub fn show(self) -> crate::Result<()> {
let mut notification = notify_rust::Notification::new();
if let Some(body) = self.body {
notification.body(&body);
}
if let Some(title) = self.title {
notification.summary(&title);
}
if let Some(icon) = self.icon {
notification.icon(&icon);
} else {
notification.auto_icon();
}
#[cfg(windows)]
{
let exe = tauri::utils::platform::current_exe()?;
let exe_dir = exe.parent().expect("failed to get exe directory");
let curr_dir = exe_dir.display().to_string();
if !(curr_dir.ends_with(format!("{SEP}target{SEP}debug").as_str())
|| curr_dir.ends_with(format!("{SEP}target{SEP}release").as_str()))
{
notification.app_id(&self.identifier);
}
}
#[cfg(target_os = "macos")]
{
let _ = notify_rust::set_application(if tauri::is_dev() {
"com.apple.Terminal"
} else {
&self.identifier
});
}
tauri::async_runtime::spawn(async move {
let _ = notification.show();
});
Ok(())
}
}
}