desktop: reminders reach you when the window isn't in front
CI & Build / Python lint (push) Successful in 2s
CI & Build / Build now, or wait for Android? (push) Successful in 2s
Android / Build, or is the channel already serving this? (push) Successful in 3s
Desktop (Tauri) / Build, or is the channel already serving this? (push) Successful in 3s
CI & Build / Web typecheck and unit tests (push) Successful in 9s
CI & Build / Python tests (push) Successful in 11s
CI & Build / integration (push) Successful in 36s
CI & Build / Build & push image (push) Skipped
Desktop (Tauri) / Web tests, clippy, Rust tests and rustfmt (push) Successful in 2m30s
Desktop (Tauri) / Windows installer (cross-compiled) (push) Successful in 2m38s
Desktop (Tauri) / Tauri desktop (Linux) (push) Successful in 3m38s
Desktop (Tauri) / Update manifest (push) Successful in 5s
Android / Kotlin + Rust (APK) (push) Successful in 8m45s

A Rust worker reads due reminders from the local store every 15 s and
announces each occurrence once: always to the main window as a toast, and
as a system notification (tauri-plugin-notification) when that window
isn't focused. The page no longer polls on the desktop; its Notification
went nowhere in WebKitGTK and its timer stopped with the window. The
Reminders page says what each surface actually does.

Core gains store::due_reminders, compared by instant, not by string.

Refs #5171

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-07 12:46:02 -04:00
co-authored by Claude Opus 5.5
parent 5989ffc1c6
commit df85535ea2
9 changed files with 942 additions and 25 deletions
+24
View File
@@ -295,3 +295,27 @@ export async function onCaptured(handler: () => void): Promise<() => void> {
if (!events) return () => {};
return events.listen(CAPTURED_EVENT, () => handler());
}
/** A reminder the desktop's reminder worker found due (desktop/src-tauri/src/reminders.rs). */
export interface DueReminder {
id: string;
title: string;
remind_at: string;
due_ms: number;
}
/** Fired at the main window for each reminder occurrence, once. */
const REMINDER_DUE_EVENT = "inkwell://reminder-due";
/**
* Run `handler` for each reminder the desktop announces. On the desktop the Rust
* worker decides what is due, and raises the system notification itself when the
* window isn't in front; the page only shows its toast.
*
* Returns an unlisten function, or a no-op where there is no event API.
*/
export async function onReminderDue(handler: (reminder: DueReminder) => void): Promise<() => void> {
const events = window.__TAURI__?.event;
if (!events) return () => {};
return events.listen<DueReminder>(REMINDER_DUE_EVENT, (e) => handler(e.payload));
}