feat(gui): desktop notification when a viewer joins or leaves
The host screen pops a desktop notification on each viewer join/leave, so you know someone connected while the window is in the background. Fired on a detached thread (the D-Bus call never touches the egui frame) and gated on the same viewer-list transitions, so stopping the host — which drops the child and stops pumping events — doesn't spray a notification per remaining viewer. notify-rust's default features give the pure-Rust zbus backend, so this adds no system libdbus dependency and no GTK event loop (gui feature only; the headless build is untouched). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+28
-1
@@ -78,6 +78,23 @@ fn short_id(id: &str) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
/// Fire a desktop notification, on a detached thread so the D-Bus round-trip
|
||||
/// can't stall the egui frame. Best-effort: with no notification daemon it
|
||||
/// just does nothing. (notify-rust talks D-Bus via pure-Rust zbus, so this
|
||||
/// needs no system libdbus and no GTK event loop.)
|
||||
fn notify(summary: &'static str, body: String) {
|
||||
std::thread::spawn(move || {
|
||||
if let Err(e) = notify_rust::Notification::new()
|
||||
.appname("PixelPass")
|
||||
.summary(summary)
|
||||
.body(&body)
|
||||
.show()
|
||||
{
|
||||
tracing::warn!("desktop notification failed: {e}");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Which screen the single window is currently showing.
|
||||
#[derive(Default, PartialEq)]
|
||||
enum Screen {
|
||||
@@ -570,13 +587,23 @@ impl PixelPassApp {
|
||||
self.host.active = active;
|
||||
self.host.max = max;
|
||||
if !self.host.viewers.contains(&id) {
|
||||
notify(
|
||||
"PixelPass — viewer connected",
|
||||
format!("endpoint {} is now watching ({active}/{max})", short_id(&id)),
|
||||
);
|
||||
self.host.viewers.push(id);
|
||||
}
|
||||
}
|
||||
ChildEvent::ViewerLeft { id, active, max } => {
|
||||
self.host.active = active;
|
||||
self.host.max = max;
|
||||
self.host.viewers.retain(|v| v != &id);
|
||||
if self.host.viewers.iter().any(|v| v == &id) {
|
||||
notify(
|
||||
"PixelPass — viewer disconnected",
|
||||
format!("endpoint {} left ({active}/{max})", short_id(&id)),
|
||||
);
|
||||
self.host.viewers.retain(|v| v != &id);
|
||||
}
|
||||
}
|
||||
ChildEvent::Capture { state } => {
|
||||
self.host.capturing = matches!(state, child::CaptureState::Started);
|
||||
|
||||
Reference in New Issue
Block a user