mirror of
https://github.com/safing/portmaster
synced 2025-04-22 11:59:09 +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
desktop/tauri/src-tauri
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-shell",
|
||||
"tauri-plugin-single-instance",
|
||||
"tauri-winrt-notification 0.3.0",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-websockets",
|
||||
|
@ -4158,7 +4159,7 @@ dependencies = [
|
|||
"log",
|
||||
"mac-notification-sys",
|
||||
"serde",
|
||||
"tauri-winrt-notification",
|
||||
"tauri-winrt-notification 0.2.1",
|
||||
"zbus",
|
||||
]
|
||||
|
||||
|
@ -6964,7 +6965,7 @@ dependencies = [
|
|||
"serde_repr",
|
||||
"tauri",
|
||||
"tauri-plugin",
|
||||
"tauri-winrt-notification",
|
||||
"tauri-winrt-notification 0.2.1",
|
||||
"thiserror",
|
||||
"time",
|
||||
"url",
|
||||
|
@ -7158,6 +7159,17 @@ dependencies = [
|
|||
"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]]
|
||||
name = "tempfile"
|
||||
version = "3.10.1"
|
||||
|
|
|
@ -61,6 +61,7 @@ gio-sys = "0.18.1"
|
|||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
windows-service = "0.6.0"
|
||||
windows = { version = "0.54.0", features = ["Win32_Foundation", "Win32_UI_Shell", "Win32_UI_WindowsAndMessaging"] }
|
||||
tauri-winrt-notification = "0.3.0"
|
||||
|
||||
[dev-dependencies]
|
||||
which = "6.0.0"
|
||||
|
|
|
@ -3,9 +3,7 @@ use crate::portapi::message::*;
|
|||
use crate::portapi::models::notification::*;
|
||||
use crate::portapi::types::*;
|
||||
use log::error;
|
||||
use notify_rust;
|
||||
use serde_json::json;
|
||||
#[allow(unused_imports)]
|
||||
use tauri::async_runtime;
|
||||
|
||||
pub async fn notification_handler(cli: PortAPI) {
|
||||
|
@ -34,59 +32,7 @@ pub async fn notification_handler(cli: PortAPI) {
|
|||
if n.selected_action_id != "" {
|
||||
return;
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
show_notification(&cli, key, n).await;
|
||||
}
|
||||
Err(err) => match 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