refactor: migrate to shell-env and custom desktop notifications bridge

This commit is contained in:
Mohamed Boudra
2026-03-13 12:26:14 +07:00
parent ee8a81d2e1
commit 013f573cff
19 changed files with 436 additions and 531 deletions
@@ -0,0 +1,110 @@
use serde::{Deserialize, Serialize};
use serde_json::Value;
use tauri::{AppHandle, Runtime};
pub const DESKTOP_NOTIFICATION_CLICK_EVENT: &str = "desktop-notification-click";
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct DesktopNotificationInput {
pub title: String,
pub body: Option<String>,
pub data: Option<Value>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
struct DesktopNotificationClickPayload {
data: Option<Value>,
}
#[cfg(target_os = "macos")]
mod platform {
use super::{
AppHandle, DesktopNotificationClickPayload, DesktopNotificationInput,
DESKTOP_NOTIFICATION_CLICK_EVENT,
};
use std::sync::OnceLock;
use tauri::{async_runtime, Emitter, Runtime};
const MACOS_NOTIFICATION_SENDER_BUNDLE_ID: &str = "dev.paseo.desktop";
static MACOS_NOTIFICATION_SENDER_INIT: OnceLock<Result<(), String>> = OnceLock::new();
fn ensure_notification_sender() -> Result<(), String> {
MACOS_NOTIFICATION_SENDER_INIT
.get_or_init(|| {
mac_notification_sys::set_application(MACOS_NOTIFICATION_SENDER_BUNDLE_ID)
.map_err(|error| {
format!(
"Failed to initialize macOS notification sender for {}: {error}",
MACOS_NOTIFICATION_SENDER_BUNDLE_ID
)
})
})
.clone()
}
pub fn send_notification<R: Runtime>(
app: AppHandle<R>,
input: DesktopNotificationInput,
) -> Result<(), String> {
let _task = async_runtime::spawn_blocking(move || {
if let Err(error) = ensure_notification_sender() {
log::warn!("{error}");
return;
}
let mut notification = mac_notification_sys::Notification::default();
notification
.title(&input.title)
.message(input.body.as_deref().unwrap_or(""))
.wait_for_click(true);
match notification.send() {
Ok(mac_notification_sys::NotificationResponse::Click) => {
let payload = DesktopNotificationClickPayload { data: input.data };
if let Err(error) = app.emit(DESKTOP_NOTIFICATION_CLICK_EVENT, payload) {
log::warn!("failed to emit desktop notification click event: {error}");
}
}
Ok(_) => {}
Err(error) => {
log::warn!("failed to send macOS notification: {error}");
}
}
});
Ok(())
}
}
#[cfg(not(target_os = "macos"))]
mod platform {
use super::{AppHandle, DesktopNotificationInput};
use tauri::Runtime;
use tauri_plugin_notification::NotificationExt;
pub fn send_notification<R: Runtime>(
app: AppHandle<R>,
input: DesktopNotificationInput,
) -> Result<(), String> {
let mut notification = app.notification().builder().title(&input.title);
if let Some(body) = &input.body {
notification = notification.body(body);
}
notification
.show()
.map_err(|error| format!("Failed to send desktop notification: {error}"))?;
Ok(())
}
}
#[tauri::command]
pub async fn send_desktop_notification<R: Runtime>(
app: AppHandle<R>,
input: DesktopNotificationInput,
) -> Result<(), String> {
platform::send_notification(app, input)
}
+3
View File
@@ -11,7 +11,9 @@ use tauri::menu::{Menu, MenuItemBuilder, MenuItemKind, PredefinedMenuItem, Subme
use tauri::{AppHandle, Manager, WebviewWindow};
use tauri_plugin_updater::UpdaterExt;
mod desktop_notifications;
mod runtime_manager;
use desktop_notifications::send_desktop_notification;
use runtime_manager::{
cli_symlink_instructions, close_local_daemon_transport, managed_daemon_logs,
managed_daemon_pairing, managed_daemon_status, managed_runtime_status,
@@ -544,6 +546,7 @@ pub fn run() {
read_file_base64,
delete_attachment_file,
garbage_collect_attachment_files,
send_desktop_notification,
webview_log
])
.setup(|app| {