From 5a9bfa8fe4dc31982644733ad2483dedea161ee7 Mon Sep 17 00:00:00 2001 From: Lotus CI Date: Wed, 23 Sep 2026 19:49:54 -0400 Subject: [PATCH] feat(native): "Mark as read" button on rich toasts (#9) Toasts with a room id get a Mark as read action next to Send; it emits `lotus-notification-mark-read {roomId}` without raising the window, and cinny marks the room read through its existing markAsRead path. Invite toasts (no room id) get neither button. Bump cinny to 23649f12. Closes #9 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA --- cinny | 2 +- src-tauri/src/native/toast.rs | 27 +++++++++++++++++++++++---- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/cinny b/cinny index 3b6de2f..23649f1 160000 --- a/cinny +++ b/cinny @@ -1 +1 @@ -Subproject commit 3b6de2fdacd7b73cd02421083d31487821db328a +Subproject commit 23649f1255d23e29ded9b485097a3adc601da93f diff --git a/src-tauri/src/native/toast.rs b/src-tauri/src/native/toast.rs index 9247d4d..2270055 100644 --- a/src-tauri/src/native/toast.rs +++ b/src-tauri/src/native/toast.rs @@ -24,6 +24,10 @@ //! `thread_id`), never the tag. Toasts without a room id (invites) get no reply //! box. //! +//! Mark as read (cinny-desktop #9): toasts with a room id also carry a +//! **Mark as read** button (`arguments="mark_read"`); activating it forwards the +//! room id so the web client sends the read receipt, without raising the window. +//! //! If ANY WinRT step fails (most importantly: no registered AppUserModelID — see //! the runtime note below), we fall back to the plain `tauri-plugin-notification` //! notification so notifications always work. @@ -161,13 +165,17 @@ fn show_windows_toast( _ => String::new(), }; - // An inline reply input and a foreground Send action, only when there is a - // room to reply to. `hint-inputId="reply"` binds the Send button to the text - // box so the reply text arrives in `UserInput()` keyed "reply". + // An inline reply input, a Send action and Mark as read, only when there is + // a room to act on. `hint-inputId="reply"` binds the Send button to the text + // box so the reply text arrives in `UserInput()` keyed "reply". Both are + // "foreground" because the in-process Activated event (not COM background + // activation) is what an unpackaged app receives; `arguments` tells them + // apart. let actions = if room_id.is_some() { r#" + "# } else { "" @@ -225,8 +233,19 @@ fn show_windows_toast( // Extract the reply text (if the Send action / input was used). let reply = read_reply(&activated_args).unwrap_or_default(); + let action = activated_args + .Arguments() + .map(|a| a.to_string()) + .unwrap_or_default(); - if !reply.is_empty() { + if action == "mark_read" { + // Mark as read: no window raise, like the quick reply. + let payload = serde_json::json!({ + "roomId": room_id_owned.as_deref(), + }) + .to_string(); + super::emit_to_web(&app_activated, "lotus-notification-mark-read", &payload); + } else if !reply.is_empty() { // Quick reply: forward the room id + text to the web client. let payload = serde_json::json!({ "roomId": room_id_owned.as_deref(),