//! Desktop notification when a render ends while the window is unfocused //! (Tim t1025u). Freedesktop notifications on Linux/BSD, a toast on Windows. /// How a single render or the Render Alles queue ended. #[derive(Clone, Debug, PartialEq, Eq)] pub enum RenderOutcome { /// One render (or the whole Render Alles queue) finished; `text` is the /// status line also shown in the window. Done { ok: bool, text: String }, } /// The toast to show, if any. #[derive(Clone, Debug, PartialEq, Eq)] pub struct Toast { pub summary: String, pub body: String, } /// Decide whether to notify: only when the window is not focused. pub fn toast_for(outcome: &RenderOutcome, window_focused: bool) -> Option { if window_focused { return None; } let RenderOutcome::Done { ok, text } = outcome; let summary = if *ok { crate::i18n::t("Render klaar") } else { crate::i18n::t("Render niet gelukt") }; Some(Toast { summary, body: crate::i18n::t(text), }) } /// Show the toast on a short-lived thread; delivery errors are ignored. pub fn show(toast: Toast) { let _ = std::thread::Builder::new() .name("render-notification".into()) .spawn(move || { let mut n = notify_rust::Notification::new(); n.summary(&["Paperdoll Renderer", &toast.summary].join(": ")) .body(&toast.body) .appname("Paperdoll Renderer"); #[cfg(all(unix, not(target_os = "macos")))] { n.icon(crate::icon::APP_ID) .hint(notify_rust::Hint::DesktopEntry(crate::icon::APP_ID.into())); } let _ = n.show(); }); } #[cfg(test)] mod tests { use super::*; #[test] fn focused_window_gets_no_toast() { let o = RenderOutcome::Done { ok: true, text: "Batch opgeslagen: x".into(), }; assert_eq!(toast_for(&o, true), None); } #[test] fn unfocused_window_gets_one_toast_with_status() { let o = RenderOutcome::Done { ok: true, text: "Batch opgeslagen: /p/out".into(), }; let t = toast_for(&o, false).unwrap(); assert!(t.body.contains("/p/out")); let f = toast_for( &RenderOutcome::Done { ok: false, text: "boom".into(), }, false, ) .unwrap(); assert_ne!(t.summary, f.summary); } }