diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 0bb958b..4b80728 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -809,6 +809,16 @@ dependencies = [ "dirs-sys", ] +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + [[package]] name = "dirs-sys" version = "0.4.1" @@ -821,6 +831,17 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + [[package]] name = "dispatch" version = "0.2.0" @@ -2124,6 +2145,19 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" +[[package]] +name = "mac-notification-sys" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce8f34f3717aa37177e723df6c1fc5fb02b2a1087374ea3fe0ea42316dc8f91" +dependencies = [ + "cc", + "dirs-next", + "objc-foundation", + "objc_id", + "time", +] + [[package]] name = "malloc_buf" version = "0.0.6" @@ -2269,6 +2303,19 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" +[[package]] +name = "notify-rust" +version = "4.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5134a72dc570b178bff81b01e81ab14a6fcc015391ed4b3b14853090658cd3a3" +dependencies = [ + "log", + "mac-notification-sys", + "serde", + "tauri-winrt-notification", + "zbus", +] + [[package]] name = "num-conv" version = "0.1.0" @@ -2314,6 +2361,17 @@ dependencies = [ "malloc_buf", ] +[[package]] +name = "objc-foundation" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" +dependencies = [ + "block", + "objc", + "objc_id", +] + [[package]] name = "objc-sys" version = "0.3.5" @@ -2532,6 +2590,15 @@ dependencies = [ "objc2-foundation", ] +[[package]] +name = "objc_id" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +dependencies = [ + "objc", +] + [[package]] name = "object" version = "0.36.5" @@ -2594,6 +2661,7 @@ dependencies = [ "tauri-build", "tauri-plugin-global-shortcut", "tauri-plugin-http", + "tauri-plugin-notification", "tauri-plugin-oauth", "tauri-plugin-shell", "tauri-plugin-single-instance", @@ -2838,7 +2906,7 @@ checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016" dependencies = [ "base64 0.22.1", "indexmap 2.7.0", - "quick-xml", + "quick-xml 0.32.0", "serde", "time", ] @@ -2967,6 +3035,15 @@ dependencies = [ "psl-types", ] +[[package]] +name = "quick-xml" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" +dependencies = [ + "memchr", +] + [[package]] name = "quick-xml" version = "0.32.0" @@ -3847,7 +3924,7 @@ dependencies = [ "tao-macros", "unicode-segmentation", "url", - "windows", + "windows 0.58.0", "windows-core 0.58.0", "windows-version", "x11-dl", @@ -3918,7 +3995,7 @@ dependencies = [ "webkit2gtk", "webview2-com", "window-vibrancy", - "windows", + "windows 0.58.0", ] [[package]] @@ -4061,6 +4138,25 @@ dependencies = [ "urlpattern", ] +[[package]] +name = "tauri-plugin-notification" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46ab803095f14ac6521fdb6477210a49e86fed6623c3c97d8e4b2b35e045e922" +dependencies = [ + "log", + "notify-rust", + "rand 0.8.5", + "serde", + "serde_json", + "serde_repr", + "tauri", + "tauri-plugin", + "thiserror 2.0.3", + "time", + "url", +] + [[package]] name = "tauri-plugin-oauth" version = "2.0.0" @@ -4143,7 +4239,7 @@ dependencies = [ "tauri-utils", "thiserror 2.0.3", "url", - "windows", + "windows 0.58.0", ] [[package]] @@ -4168,7 +4264,7 @@ dependencies = [ "url", "webkit2gtk", "webview2-com", - "windows", + "windows 0.58.0", "wry", ] @@ -4219,6 +4315,17 @@ dependencies = [ "toml 0.7.8", ] +[[package]] +name = "tauri-winrt-notification" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f89f5fb70d6f62381f5d9b2ba9008196150b40b75f3068eb24faeddf1c686871" +dependencies = [ + "quick-xml 0.31.0", + "windows 0.56.0", + "windows-version", +] + [[package]] name = "tempfile" version = "3.14.0" @@ -4880,10 +4987,10 @@ checksum = "6f61ff3d9d0ee4efcb461b14eb3acfda2702d10dc329f339303fc3e57215ae2c" dependencies = [ "webview2-com-macros", "webview2-com-sys", - "windows", + "windows 0.58.0", "windows-core 0.58.0", - "windows-implement", - "windows-interface", + "windows-implement 0.58.0", + "windows-interface 0.58.0", ] [[package]] @@ -4904,7 +5011,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3a3e2eeb58f82361c93f9777014668eb3d07e7d174ee4c819575a9208011886" dependencies = [ "thiserror 1.0.69", - "windows", + "windows 0.58.0", "windows-core 0.58.0", ] @@ -4953,6 +5060,16 @@ dependencies = [ "windows-version", ] +[[package]] +name = "windows" +version = "0.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1de69df01bdf1ead2f4ac895dc77c9351aefff65b2f3db429a343f9cbf05e132" +dependencies = [ + "windows-core 0.56.0", + "windows-targets 0.52.6", +] + [[package]] name = "windows" version = "0.58.0" @@ -4972,19 +5089,42 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-core" +version = "0.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4698e52ed2d08f8658ab0c39512a7c00ee5fe2688c65f8c0a4f06750d729f2a6" +dependencies = [ + "windows-implement 0.56.0", + "windows-interface 0.56.0", + "windows-result 0.1.2", + "windows-targets 0.52.6", +] + [[package]] name = "windows-core" version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" dependencies = [ - "windows-implement", - "windows-interface", - "windows-result", + "windows-implement 0.58.0", + "windows-interface 0.58.0", + "windows-result 0.2.0", "windows-strings", "windows-targets 0.52.6", ] +[[package]] +name = "windows-implement" +version = "0.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "windows-implement" version = "0.58.0" @@ -4996,6 +5136,17 @@ dependencies = [ "syn 2.0.90", ] +[[package]] +name = "windows-interface" +version = "0.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "windows-interface" version = "0.58.0" @@ -5013,11 +5164,20 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" dependencies = [ - "windows-result", + "windows-result 0.2.0", "windows-strings", "windows-targets 0.52.6", ] +[[package]] +name = "windows-result" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-result" version = "0.2.0" @@ -5033,7 +5193,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ - "windows-result", + "windows-result 0.2.0", "windows-targets 0.52.6", ] @@ -5328,7 +5488,7 @@ dependencies = [ "webkit2gtk", "webkit2gtk-sys", "webview2-com", - "windows", + "windows 0.58.0", "windows-core 0.58.0", "windows-version", "x11-dl", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 68a0f64..e2ea76a 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -20,6 +20,7 @@ tauri-build = { version = "2.0.3", features = [] } [dependencies] serde_json = "1.0.133" serde = { version = "1.0.216", features = ["derive"] } +tokio = { version = "1", features = ["full"] } tauri = { version = "2.1.1", features = ["tray-icon", "image-ico", "image-png", "macos-proxy"] } tauri-plugin-window-state = "2.2.0" tauri-plugin-oauth = "2" @@ -28,7 +29,7 @@ tauri-plugin-http = "2.2.0" tauri-plugin-global-shortcut = { version = "2.2.0" } tauri-plugin-shell = "2.2.0" tauri-plugin-single-instance = "2" -tokio = { version = "1", features = ["full"] } +tauri-plugin-notification = "2.2.0" [features] # this feature is used for development builds from development cli diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json index 653622b..6f9e316 100644 --- a/src-tauri/capabilities/default.json +++ b/src-tauri/capabilities/default.json @@ -7,12 +7,18 @@ "urls": ["https://*.*"] }, "permissions": [ + "shell:allow-open", "core:window:allow-theme", "core:window:allow-start-dragging", "core:window:allow-toggle-maximize", "core:window:allow-is-fullscreen", "core:window:allow-set-fullscreen", "core:webview:allow-internal-toggle-devtools", - "shell:allow-open" + "notification:allow-is-permission-granted", + "notification:allow-notify", + "notification:allow-get-active", + "notification:allow-register-listener", + "notification:allow-register-action-types", + "notification:default" ] } diff --git a/src-tauri/src/app/invoke.rs b/src-tauri/src/app/invoke.rs index 078ee2c..a07b358 100644 --- a/src-tauri/src/app/invoke.rs +++ b/src-tauri/src/app/invoke.rs @@ -18,6 +18,13 @@ pub struct BinaryDownloadParams { binary: Vec, } +#[derive(serde::Deserialize)] +pub struct NotificationParams { + title: String, + body: String, + icon: String, +} + #[command] pub async fn download_file(app: AppHandle, params: DownloadFileParams) -> Result<(), String> { let window: WebviewWindow = app.get_webview_window("pake").unwrap(); @@ -71,3 +78,16 @@ pub async fn download_file_by_binary( } } } + +#[command] +pub fn send_notification(app: AppHandle, params: NotificationParams) -> Result<(), String> { + use tauri_plugin_notification::NotificationExt; + app.notification() + .builder() + .title(¶ms.title) + .body(¶ms.body) + .icon(¶ms.icon) + .show() + .unwrap(); + Ok(()) +} diff --git a/src-tauri/src/inject/event.js b/src-tauri/src/inject/event.js index d5d55f7..8477741 100644 --- a/src-tauri/src/inject/event.js +++ b/src-tauri/src/inject/event.js @@ -187,7 +187,6 @@ document.addEventListener('DOMContentLoaded', () => { }; const detectAnchorElementClick = e => { - const anchorElement = e.target.closest('a'); if (anchorElement && anchorElement.href) { @@ -256,6 +255,38 @@ document.addEventListener('DOMContentLoaded', () => { ); }); +document.addEventListener('DOMContentLoaded', function () { + let permVal = 'granted'; + window.Notification = function (title, options) { + const { invoke } = window.__TAURI__.core; + const body = options?.body || ''; + let icon = options?.icon || ''; + + // If the icon is a relative path, convert to full path using URI + if (icon.startsWith('/')) { + icon = window.location.origin + icon; + } + + invoke('send_notification', { + params: { + title, + body, + icon, + }, + }); + }; + + window.Notification.requestPermission = async () => 'granted'; + + Object.defineProperty(window.Notification, 'permission', { + enumerable: true, + get: () => permVal, + set: v => { + permVal = v; + }, + }); +}); + function setDefaultZoom() { const htmlZoom = window.localStorage.getItem('htmlZoom'); if (htmlZoom) { diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 45b077b..87f8d68 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -3,7 +3,7 @@ mod app; mod util; use app::{invoke, menu::set_system_tray, window}; -use invoke::{download_file, download_file_by_binary}; +use invoke::{download_file, download_file_by_binary, send_notification}; use std::str::FromStr; use std::sync::{Arc, Mutex}; use std::time::{Duration, Instant}; @@ -38,10 +38,12 @@ pub fn run_app() { .plugin(tauri_plugin_oauth::init()) .plugin(tauri_plugin_http::init()) .plugin(tauri_plugin_shell::init()) + .plugin(tauri_plugin_notification::init()) .plugin(tauri_plugin_single_instance::init(|_, _, _| ())) .invoke_handler(tauri::generate_handler![ download_file, - download_file_by_binary + download_file_by_binary, + send_notification, ]) .setup(move |app| { let data_dir = get_data_dir(app.app_handle(), tauri_config.clone());