Files
thoughtsync/android/app/src/main/res/drawable/ic_notification.xml
T
bvandeusen 785ebdba59
Desktop (Tauri) / Windows installer (cross-compiled) (push) Successful in 3m0s
Android / Kotlin + Rust (debug APK) (push) Failing after 5m13s
Desktop (Tauri) / Tauri desktop (Linux) (push) Successful in 5m37s
Desktop (Tauri) / Update manifest (push) Successful in 5s
android: reminders that actually reach you (M12 step 6)
Reminders have been settable since the editor landed and have never once gone
off. The board showed them overdue in red, which tells you what you already know
by the time you are looking at the board.

**AlarmManager, not WorkManager.** The background sync is right to be on
WorkManager — nobody minds whether it runs at 3:05 or 3:19. A reminder minds
very much. WorkManager's periodic floor is fifteen minutes and it batches into
maintenance windows, so "remind me at 09:00" would routinely arrive at 09:14,
which is not a reminder, it is a rebuke.

**One alarm, not one per reminder.** Only the earliest future reminder is ever
scheduled; when it fires, everything due is announced and the next is scheduled.
A hundred reminders cost one alarm, and there is no incremental bookkeeping to
drift — `Reminders.refresh` recomputes the whole picture from the store, and is
called from everywhere anything could have changed: an edit, a foreground, a
background sync, boot, and an app update.

Boot and MY_PACKAGE_REPLACED both matter and both are easy to forget. Pending
alarms survive neither, and this app updates by APK from its own server, so
without that receiver a phone would silently stop reminding anyone of anything
after a restart — the worst kind of failure, because nothing appears wrong.

**Neither permission is treated as a prerequisite.**

SCHEDULE_EXACT_ALARM, not USE_EXACT_ALARM: the latter is granted at install with
no prompt and is reserved for apps whose whole purpose is an alarm clock or a
calendar, which this is not. Refusing the former costs precision, not the
feature — it falls back to an inexact alarm, because a reminder a few minutes
late beats no reminder.

POST_NOTIFICATIONS is asked for on the first launch where a reminder actually
exists, never at launch on an empty board. Android gives an app essentially one
chance at that dialog, and spending it before the person has any idea what this
app would send them is spending it on nothing. For anyone who refuses, or who
turns notifications off later in system settings, the Reminders view carries a
standing notice with a button to the right screen — a feature that silently does
nothing is worse than one that is plainly absent.

**A first run adopts overdue reminders silently.** The storm case is linking a
server and pulling months of history; a hundred notifications the moment someone
signs in is a good way to have the feature turned off before it is ever useful.
After that, a missed reminder is announced up to a day late — the web uses
fifteen minutes because an open tab has been polling every forty-five seconds,
but a phone can be switched off all night.

Done and Snooze act from the shade without opening the app. The dedupe key is
note id plus remind_at, the same one the web store uses, so snoozing produces a
new occurrence rather than one already dealt with.

Tapping a notification opens that note. The extra is CONSUMED when read: the
Activity keeps the intent it was launched with, so without that, rotating the
phone would replay it and reopen a note the person had already closed.

`Reminders` split into scheduling policy and `ReminderNotification` rendering
after detekt counted fourteen functions in one object — it was right, they answer
different questions and change for different reasons. `ForegroundTransitions`
moves to the ui package; the reminder notice needs it to re-read a permission the
person may have just changed in a system screen this app cannot observe.

Known gap, pre-existing and shared with every surface: `complete_reminder` in the
core clears a reminder without advancing recurrence — its own comment says so.
So tapping Done on a daily reminder ends it rather than moving it to tomorrow.
Not changed here because it is core behaviour the desktop and web also have, but
notifications make it much easier to hit, and it should be next.
2026-08-19 20:06:05 -04:00

21 lines
956 B
XML

<?xml version="1.0" encoding="utf-8"?>
<!--
The status-bar icon for a reminder.
A flat white silhouette on transparency, because that is the only thing Android
renders here — a status-bar icon is used as a MASK, so the launcher icon (which
is a full-colour adaptive asset) would come out as a solid white blob. This is
the Material bell, matching the icon the editor's reminder button already uses,
so the same idea wears the same shape in both places.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#FFFFFFFF">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M12,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.89,2 2,2zM18,16v-5c0,-3.07 -1.64,-5.64 -4.5,-6.32V4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68C7.63,5.36 6,7.92 6,11v5l-2,2v1h16v-1l-2,-2z" />
</vector>