mirror of
https://github.com/safing/portmaster
synced 2025-09-02 18:49:14 +00:00
[desktop] support for windows notifications
This commit is contained in:
parent
ff488351e4
commit
99b84d3f46
3 changed files with 112 additions and 57 deletions
16
desktop/tauri/src-tauri/Cargo.lock
generated
16
desktop/tauri/src-tauri/Cargo.lock
generated
|
@ -210,6 +210,7 @@ dependencies = [
|
||||||
"tauri-plugin-os",
|
"tauri-plugin-os",
|
||||||
"tauri-plugin-shell",
|
"tauri-plugin-shell",
|
||||||
"tauri-plugin-single-instance",
|
"tauri-plugin-single-instance",
|
||||||
|
"tauri-winrt-notification 0.3.0",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-websockets",
|
"tokio-websockets",
|
||||||
|
@ -4158,7 +4159,7 @@ dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"mac-notification-sys",
|
"mac-notification-sys",
|
||||||
"serde",
|
"serde",
|
||||||
"tauri-winrt-notification",
|
"tauri-winrt-notification 0.2.1",
|
||||||
"zbus",
|
"zbus",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -6964,7 +6965,7 @@ dependencies = [
|
||||||
"serde_repr",
|
"serde_repr",
|
||||||
"tauri",
|
"tauri",
|
||||||
"tauri-plugin",
|
"tauri-plugin",
|
||||||
"tauri-winrt-notification",
|
"tauri-winrt-notification 0.2.1",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"time",
|
"time",
|
||||||
"url",
|
"url",
|
||||||
|
@ -7158,6 +7159,17 @@ dependencies = [
|
||||||
"windows-version",
|
"windows-version",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tauri-winrt-notification"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "13966ea9e4bd4a3b86c332a93b70cc129a950e31c5f2212014c7ee5ebd110884"
|
||||||
|
dependencies = [
|
||||||
|
"quick-xml",
|
||||||
|
"windows 0.56.0",
|
||||||
|
"windows-version",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.10.1"
|
version = "3.10.1"
|
||||||
|
|
|
@ -61,6 +61,7 @@ gio-sys = "0.18.1"
|
||||||
[target.'cfg(target_os = "windows")'.dependencies]
|
[target.'cfg(target_os = "windows")'.dependencies]
|
||||||
windows-service = "0.6.0"
|
windows-service = "0.6.0"
|
||||||
windows = { version = "0.54.0", features = ["Win32_Foundation", "Win32_UI_Shell", "Win32_UI_WindowsAndMessaging"] }
|
windows = { version = "0.54.0", features = ["Win32_Foundation", "Win32_UI_Shell", "Win32_UI_WindowsAndMessaging"] }
|
||||||
|
tauri-winrt-notification = "0.3.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
which = "6.0.0"
|
which = "6.0.0"
|
||||||
|
|
|
@ -3,9 +3,7 @@ use crate::portapi::message::*;
|
||||||
use crate::portapi::models::notification::*;
|
use crate::portapi::models::notification::*;
|
||||||
use crate::portapi::types::*;
|
use crate::portapi::types::*;
|
||||||
use log::error;
|
use log::error;
|
||||||
use notify_rust;
|
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
#[allow(unused_imports)]
|
|
||||||
use tauri::async_runtime;
|
use tauri::async_runtime;
|
||||||
|
|
||||||
pub async fn notification_handler(cli: PortAPI) {
|
pub async fn notification_handler(cli: PortAPI) {
|
||||||
|
@ -34,59 +32,7 @@ pub async fn notification_handler(cli: PortAPI) {
|
||||||
if n.selected_action_id != "" {
|
if n.selected_action_id != "" {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
show_notification(&cli, key, n).await;
|
||||||
// TODO(ppacher): keep a reference of open notifications and close them
|
|
||||||
// if the user reacted inside the UI:
|
|
||||||
|
|
||||||
let mut notif = notify_rust::Notification::new();
|
|
||||||
notif.body(&n.message);
|
|
||||||
notif.timeout(notify_rust::Timeout::Never); // TODO(ppacher): use n.expires to calculate the timeout.
|
|
||||||
notif.summary(&n.title);
|
|
||||||
notif.icon("portmaster");
|
|
||||||
|
|
||||||
for action in n.actions {
|
|
||||||
notif.action(&action.id, &action.text);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
{
|
|
||||||
let cli_clone = cli.clone();
|
|
||||||
async_runtime::spawn(async move {
|
|
||||||
let res = notif.show();
|
|
||||||
match res {
|
|
||||||
Ok(handle) => {
|
|
||||||
handle.wait_for_action(|action| {
|
|
||||||
match action {
|
|
||||||
"__closed" => {
|
|
||||||
// timeout
|
|
||||||
}
|
|
||||||
|
|
||||||
value => {
|
|
||||||
let value = value.to_string().clone();
|
|
||||||
|
|
||||||
async_runtime::spawn(async move {
|
|
||||||
let _ = cli_clone
|
|
||||||
.request(Request::Update(
|
|
||||||
key,
|
|
||||||
Payload::JSON(
|
|
||||||
json!({
|
|
||||||
"SelectedActionID": value
|
|
||||||
})
|
|
||||||
.to_string(),
|
|
||||||
),
|
|
||||||
))
|
|
||||||
.await;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
error!("failed to display notification: {}", err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Err(err) => match err {
|
Err(err) => match err {
|
||||||
ParseError::JSON(err) => {
|
ParseError::JSON(err) => {
|
||||||
|
@ -101,3 +47,99 @@ pub async fn notification_handler(cli: PortAPI) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
pub async fn show_notification(cli: &PortAPI, key: String, n: Notification) {
|
||||||
|
let mut notif = notify_rust::Notification::new();
|
||||||
|
notif.body(&n.message);
|
||||||
|
notif.timeout(notify_rust::Timeout::Never); // TODO(ppacher): use n.expires to calculate the timeout.
|
||||||
|
notif.summary(&n.title);
|
||||||
|
notif.icon("portmaster");
|
||||||
|
|
||||||
|
for action in n.actions {
|
||||||
|
notif.action(&action.id, &action.text);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let cli_clone = cli.clone();
|
||||||
|
async_runtime::spawn(async move {
|
||||||
|
let res = notif.show();
|
||||||
|
// TODO(ppacher): keep a reference of open notifications and close them
|
||||||
|
// if the user reacted inside the UI:
|
||||||
|
match res {
|
||||||
|
Ok(handle) => {
|
||||||
|
handle.wait_for_action(|action| {
|
||||||
|
match action {
|
||||||
|
"__closed" => {
|
||||||
|
// timeout
|
||||||
|
}
|
||||||
|
|
||||||
|
value => {
|
||||||
|
let value = value.to_string().clone();
|
||||||
|
|
||||||
|
async_runtime::spawn(async move {
|
||||||
|
let _ = cli_clone
|
||||||
|
.request(Request::Update(
|
||||||
|
key,
|
||||||
|
Payload::JSON(
|
||||||
|
json!({
|
||||||
|
"SelectedActionID": value
|
||||||
|
})
|
||||||
|
.to_string(),
|
||||||
|
),
|
||||||
|
))
|
||||||
|
.await;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
error!("failed to display notification: {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
pub async fn show_notification(cli: &PortAPI, key: String, n: Notification) {
|
||||||
|
use tauri_winrt_notification::{Duration, Sound, Toast};
|
||||||
|
|
||||||
|
let mut toast = Toast::new("io.safing.portmaster")
|
||||||
|
.title(&n.title)
|
||||||
|
.text1(&n.message)
|
||||||
|
.sound(Some(Sound::Default))
|
||||||
|
.duration(Duration::Long);
|
||||||
|
|
||||||
|
for action in n.actions {
|
||||||
|
toast = toast.add_button(&action.text, &action.id);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let cli = cli.clone();
|
||||||
|
toast = toast.on_activated(move |action| -> windows::core::Result<()> {
|
||||||
|
if let Some(value) = action {
|
||||||
|
let cli = cli.clone();
|
||||||
|
let key = key.clone();
|
||||||
|
async_runtime::spawn(async move {
|
||||||
|
let _ = cli
|
||||||
|
.request(Request::Update(
|
||||||
|
key,
|
||||||
|
Payload::JSON(
|
||||||
|
json!({
|
||||||
|
"SelectedActionID": value
|
||||||
|
})
|
||||||
|
.to_string(),
|
||||||
|
),
|
||||||
|
))
|
||||||
|
.await;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// TODO(vladimir): If Action is None, the user clicked on the notification. Focus on the UI.
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
toast.show().expect("unable to send notification");
|
||||||
|
// TODO(vladimir): keep a reference of open notifications and close them
|
||||||
|
// if the user reacted inside the UI:
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue