You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tauri-plugins-workspace/plugins/notification/src/desktop.rs

269 lines
8.7 KiB

// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use serde::de::DeserializeOwned;
use tauri::{plugin::PluginApi, AppHandle, Runtime};
use crate::{models::*, NotificationBuilder};
pub fn init<R: Runtime, C: DeserializeOwned>(
app: &AppHandle<R>,
_api: PluginApi<R, C>,
) -> crate::Result<Notification<R>> {
Ok(Notification(app.clone()))
}
/// Access to the notification APIs.
pub struct Notification<R: Runtime>(AppHandle<R>);
impl<R: Runtime> crate::NotificationBuilder<R> {
pub 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);
}
#[cfg(feature = "windows7-compat")]
{
notification.notify(&self.app)?;
}
#[cfg(not(feature = "windows7-compat"))]
notification.show()?;
Ok(())
}
}
impl<R: Runtime> Notification<R> {
pub fn builder(&self) -> NotificationBuilder<R> {
NotificationBuilder::new(self.0.clone())
}
pub fn request_permission(&self) -> crate::Result<PermissionState> {
Ok(PermissionState::Granted)
}
pub fn permission_state(&self) -> crate::Result<PermissionState> {
Ok(PermissionState::Granted)
}
}
mod imp {
//! Types and functions related to desktop notifications.
#[cfg(windows)]
use std::path::MAIN_SEPARATOR as SEP;
/// The desktop notification definition.
///
/// Allows you to construct a Notification data and send it.
///
/// # Examples
/// ```rust,no_run
/// use tauri_plugin_notification::NotificationExt;
/// // first we build the application to access the Tauri configuration
/// let app = tauri::Builder::default()
/// // on an actual app, remove the string argument
/// .build(tauri::generate_context!("test/tauri.conf.json"))
/// .expect("error while building tauri application");
///
/// // shows a notification with the given title and body
/// app.notification()
/// .builder()
/// .title("New message")
/// .body("You've got a new message.")
/// .show();
///
/// // run the app
/// app.run(|_app_handle, _event| {});
/// ```
#[allow(dead_code)]
#[derive(Debug, Default)]
pub struct Notification {
/// The notification body.
body: Option<String>,
/// The notification title.
title: Option<String>,
/// The notification icon.
icon: Option<String>,
/// The notification identifier
identifier: String,
}
impl Notification {
/// Initializes a instance of a Notification.
pub fn new(identifier: impl Into<String>) -> Self {
Self {
identifier: identifier.into(),
..Default::default()
}
}
/// Sets the notification body.
#[must_use]
pub fn body(mut self, body: impl Into<String>) -> Self {
self.body = Some(body.into());
self
}
/// Sets the notification title.
#[must_use]
pub fn title(mut self, title: impl Into<String>) -> Self {
self.title = Some(title.into());
self
}
/// Sets the notification icon.
#[must_use]
pub fn icon(mut self, icon: impl Into<String>) -> Self {
self.icon = Some(icon.into());
self
}
/// Shows the notification.
///
/// # Examples
///
/// ```no_run
/// use tauri_plugin_notification::NotificationExt;
///
/// tauri::Builder::default()
/// .setup(|app| {
/// app.notification()
/// .builder()
/// .title("Tauri")
/// .body("Tauri is awesome!")
/// .show()
/// .unwrap();
/// Ok(())
/// })
/// .run(tauri::generate_context!("test/tauri.conf.json"))
/// .expect("error while running tauri application");
/// ```
///
/// ## Platform-specific
///
/// - **Windows**: Not supported on Windows 7. If your app targets it, enable the `windows7-compat` feature and use [`Self::notify`].
#[cfg_attr(
all(not(doc_cfg), feature = "windows7-compat"),
deprecated = "This function does not work on Windows 7. Use `Self::notify` instead."
)]
pub fn show(self) -> crate::Result<()> {
let mut notification = crate::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();
// set the notification's System.AppUserModel.ID only when running the installed app
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 _ = crate::notify_rust::set_application(if cfg!(feature = "custom-protocol") {
&self.identifier
} else {
"com.apple.Terminal"
});
}
tauri::async_runtime::spawn(async move {
let _ = notification.show();
});
Ok(())
}
/// Shows the notification. This API is similar to [`Self::show`], but it also works on Windows 7.
///
/// # Examples
///
/// ```no_run
/// use tauri_plugin_notification::NotificationExt;
///
/// tauri::Builder::default()
/// .setup(move |app| {
/// app.notification().builder()
/// .title("Tauri")
/// .body("Tauri is awesome!")
/// .show()
/// .unwrap();
/// Ok(())
/// })
/// .run(tauri::generate_context!("test/tauri.conf.json"))
/// .expect("error while running tauri application");
/// ```
#[cfg(feature = "windows7-compat")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "windows7-compat")))]
#[allow(unused_variables)]
pub fn notify<R: tauri::Runtime>(self, app: &tauri::AppHandle<R>) -> crate::Result<()> {
#[cfg(windows)]
{
fn is_windows_7() -> bool {
let v = windows_version::OsVersion::current();
// windows 7 is 6.1
v.major == 6 && v.minor == 1
}
if is_windows_7() {
self.notify_win7(app)
} else {
#[allow(deprecated)]
self.show()
}
}
#[cfg(not(windows))]
{
#[allow(deprecated)]
self.show()
}
}
#[cfg(all(windows, feature = "windows7-compat"))]
fn notify_win7<R: tauri::Runtime>(self, app: &tauri::AppHandle<R>) -> crate::Result<()> {
let app_ = app.clone();
let _ = app.clone().run_on_main_thread(move || {
let mut notification = win7_notifications::Notification::new();
if let Some(body) = self.body {
notification.body(&body);
}
if let Some(title) = self.title {
notification.summary(&title);
}
if let Some(icon) = app_.default_window_icon() {
notification.icon(icon.rgba().to_vec(), icon.width(), icon.height());
}
let _ = notification.show();
});
Ok(())
}
}
}