use std::{collections::HashSet, sync::Arc};
use zng_txt::Txt;
use zng_view_api::{
Event,
dialog::{DialogCapability, DialogId, Notification, NotificationResponse},
};
use crate::{AppEvent, AppEventSender};
#[derive(Default)]
pub struct NotificationService {
running_count: Arc<()>,
}
impl NotificationService {
pub fn capabilities(&self) -> DialogCapability {
DialogCapability::NOTIFICATION | DialogCapability::NOTIFICATION_ACTIONS
}
pub fn notification_dialog(&mut self, app_sender: &AppEventSender, id: DialogId, dialog: Notification) {
let mut n = notify_rust::Notification::new();
n.summary(&dialog.title).body(&dialog.message);
if let Some(t) = dialog.timeout {
n.timeout(t);
}
n.appname(&zng_env::about().app);
for a in &dialog.actions {
n.action(&a.id, &a.label);
}
if Arc::strong_count(&self.running_count) >= 16 {
let _ = app_sender.send(AppEvent::Notify(Event::NotificationResponse(
id,
NotificationResponse::Error("reached limit of active notifications".into()),
)));
return;
}
let app_sender = app_sender.clone();
let actions: HashSet<_> = dialog.actions.into_iter().map(|a| a.id).collect();
let count = self.running_count.clone();
let _ = std::thread::Builder::new()
.name("notify_rust".to_owned())
.stack_size(256 * 1024)
.spawn(move || {
let _count = count;
match n.show() {
Ok(handle) => {
let mut r = Txt::from_static("");
handle.wait_for_action(|action| {
r = Txt::from_str(action);
});
let r = if actions.contains(&r) {
NotificationResponse::Action(r)
} else {
NotificationResponse::Dismissed
};
let _ = app_sender.send(AppEvent::Notify(Event::NotificationResponse(id, r)));
}
Err(e) => {
use zng_txt::ToTxt as _;
use zng_view_api::Event;
use crate::AppEvent;
tracing::error!("failed to show notification, {e}");
let _ = app_sender.send(AppEvent::Notify(Event::NotificationResponse(
id,
NotificationResponse::Error(e.to_txt()),
)));
}
}
});
}
pub fn update_notification(&mut self, app_sender: &AppEventSender, id: DialogId, dialog: Notification) {
let _ = (app_sender, id, dialog);
}
}