Originally created by: kristofferR
Three pieces of macOS notification polish. Note: request identifiers are already unique per notification (page notifySeq), so grouping is purely additive — no replacement-semantics change.
1. Grouping. In deliver_notification_macos, when a validated thread id is available, setThreadIdentifier(thread_id) — banners stack per conversation Messages-style. Skip summaryArgument (deprecated and ignored; the crate marks it so). Sync alerts get no thread identifier.
2. Clear-on-read. Trigger: "user opened thread X while the window is actually visible" (true read receipts aren't reliably observable; the unread-row scan lags during hydration). Page side: extend inject/src/messenger/features/thread-nav.ts — watch location.pathname (1 s poll + visibilitychange/focus listeners, matching existing poll patterns) and when it matches /t/<id>/ (existing threadPathId helper) and document.hasFocus() && !document.hidden, emit carrier:thread-viewed {thread_path}; dedupe consecutive emissions, re-emit on focus regain. Rust side: new listen_any → validated_thread_path → macOS-only clear_delivered_for_thread(thread_id): getDeliveredNotificationsWithCompletionHandler → collect request identifiers whose content().threadIdentifier() matches → removeDeliveredNotificationsWithIdentifiers. No Rust-side bookkeeping needed, and it also clears banners from a previous app run. Also called after a successful quick-reply ack (the quick-reply issue).
3. Dock bounce (optional, off by default). New shared setting attention_on_message (platform-neutral name — the Windows integration push reuses it for taskbar flash in [#182]; row shown on macOS/Windows with a per-OS label, gated the way menu_bar_only is). Trigger in show_message_notification's macOS branch after mute/dedupe/rate-limit (bounces inherit spam protection), only when the main window reports !is_focused(); not for sync alerts. Mechanism: Tauri already exposes it — window.request_user_attention(Some(UserAttentionType::Informational)) reaches [NSApp requestUserAttention:NSInformationalRequest]; no new dependency. Auto-cancels on activation; harmless no-op in menu_bar_only mode (no Dock tile). Works even when notification auth is denied — worth keeping in mind as partial coverage of that case.
Testing. Unit: thread-id extraction, carrier:thread-viewed payload parsing, page-side dedupe state machine (bun test). Manual: three messages in one thread → stacked group; open the thread in Carrier → stack clears; bounce only when unfocused and setting on.
Part of [#179].
Tickets: #179
Tickets: #180
Tickets: #181
Tickets: #182
Tickets: #187
Tickets: #230
Originally posted by: kristofferR
Shipped in [#230], released in v1.9.0.
All three landed as independent settings: Group by Conversation (
setThreadIdentifierper validated thread), Clear When Viewed (carrier:thread-viewedfrom the page when a thread is open in a focused, visible window →clear_delivered_for_thread, which also clears banners left from a previous run), and Bounce Dock Icon (attention_on_message, off by default, after mute/dedupe/rate-limit and only while the window is unfocused).Related
Tickets:
#230Ticket changed by: kristofferR