feat(android): improve New Activity notification copy in TimeSafariNativeFetcher
Aggregate API rows into one notification with Starred Project Update(s) titles, plan names in typographic quotes, and "+ N more have been updated." for multiples. Stop emitting the empty-data "No Project Updates" fallback. Sync internal docs.
This commit is contained in:
@@ -193,7 +193,7 @@ Use this to verify that when a **starred** plan has **new** activity reported by
|
||||
|
||||
The steps and expected notification copy below are **Android-specific**: this repo registers `TimeSafariNativeFetcher` only on Android today. Do not assume the same strings or behavior on iOS until native fetcher parity exists; see **`doc/notification-from-api-call.md`** (iOS checklist and remaining tasks).
|
||||
|
||||
**How it works (short):** On Android, `TimeSafariNativeFetcher` POSTs to `/api/v2/report/plansLastUpdatedBetween` with `planIds` from the plugin (`updateStarredPlans`) and `afterId` from stored `last_acked_jwt_id` (or `"0"` initially). When the response `data` array is **non-empty**, each row becomes notification content with titles like `Update: <last 8 chars of handleId>` and bodies like `Plan <last 12 chars of handleId> has been updated.` When `data` is **empty**, the fetcher still supplies a single item: title **No Project Updates**, body **No updates in your starred projects.** (See `android/app/src/main/java/app/timesafari/TimeSafariNativeFetcher.java`.)
|
||||
**How it works (short):** On Android, `TimeSafariNativeFetcher` POSTs to `/api/v2/report/plansLastUpdatedBetween` with `planIds` from the plugin (`updateStarredPlans`) and `afterId` from stored `last_acked_jwt_id` (or `"0"` initially). When the response `data` array is **non-empty**, the fetcher builds **one** `NotificationContent`: title **Starred Project Update** (one row) or **Starred Project Updates** (two or more rows); body uses each row’s `plan.name` when present (else **Unnamed Project**). For a single update: `[name] has been updated.` For multiple: typographic quotes around the first row’s name, then ` + N more have been updated.` (with `N` = number of additional rows). When `data` is **empty**, the fetcher returns **no** notification items (no “nothing to report” notification). (See `android/app/src/main/java/app/timesafari/TimeSafariNativeFetcher.java`.)
|
||||
|
||||
**Procedure (repeatable on device)**
|
||||
|
||||
@@ -202,15 +202,15 @@ The steps and expected notification copy below are **Android-specific**: this re
|
||||
3. Turn **New Activity Notification** on and pick a time **2–5 minutes ahead** (same quick-test pattern as above).
|
||||
4. Open **Account** once (or finish the enable flow) so `updateStarredPlans({ planIds })` runs with current `starredPlanHandleIds`.
|
||||
5. **Background the app** (home out; do not force-quit). Prefetch runs on the cron **~5 minutes before** the chosen time; the user notification fires at the chosen time.
|
||||
6. **Produce new activity the API will return:** before that prefetch window (i.e. early enough that the scheduled content fetch still sees it), make a real change to the starred plan so `plansLastUpdatedBetween` returns **new** rows after the current `afterId` (e.g. an edit or other update your backend exposes through that report). If you change the plan **after** prefetch already ran with no new rows, you may only see **No Project Updates** until the next prefetch cycle (typically the next day at the same T−5 schedule, unless you reschedule).
|
||||
6. **Produce new activity the API will return:** before that prefetch window (i.e. early enough that the scheduled content fetch still sees it), make a real change to the starred plan so `plansLastUpdatedBetween` returns **new** rows after the current `afterId` (e.g. an edit or other update your backend exposes through that report). If you change the plan **after** prefetch already ran with no new rows, you may not get an API-derived notification until the next prefetch cycle (typically the next day at the same T−5 schedule, unless you reschedule).
|
||||
|
||||
**What to verify**
|
||||
|
||||
- **One notification** at the chosen time (no extra static “Daily Check-In” after the fix—see “What to verify (after fix)” above).
|
||||
- **Success path (API returns updates):** Title/body match the **Update: …** / **Plan … has been updated.** pattern (truncated handle segments), not the generic `buildDualScheduleConfig` defaults (**New Activity** / **Check your starred projects and offers for updates.**), which apply when the plugin falls back—e.g. fetch failure—not when the Android fetcher successfully returns Endorser-parsed content.
|
||||
- **Contrast (cursor caught up, no new rows):** After a successful fetch that returned data, `last_acked_jwt_id` advances. Without further plan changes, a later run may show **No Project Updates** / **No updates in your starred projects.**—useful to compare against the “has activity” case.
|
||||
- **Success path (API returns updates):** Title/body match **Starred Project Update(s)** and the `[name] has been updated.` / `[first name] + N more have been updated.` patterns (names from `plan.name`), not the generic `buildDualScheduleConfig` defaults (**New Activity** / **Check your starred projects and offers for updates.**), which apply when the plugin falls back—e.g. fetch failure—not when the Android fetcher successfully returns Endorser-parsed content.
|
||||
- **Contrast (cursor caught up, no new rows):** After a successful fetch that returned data, `last_acked_jwt_id` advances. Without further plan changes, a later prefetch may return an empty `data` array; the fetcher then supplies **no** Endorser-derived notification (useful to compare against the “has activity” case; the plugin may still show dual-schedule fallback text depending on configuration).
|
||||
|
||||
**Repeatability:** Each successful fetch that returns data moves the `afterId` cursor forward. To see **Update: …** again on subsequent tests, make **another** qualifying plan change (or accept heavier setup such as clearing app/plugin storage to reset cursor—usually unnecessary).
|
||||
**Repeatability:** Each successful fetch that returns data moves the `afterId` cursor forward. To see **Starred Project Update** copy again on subsequent tests, make **another** qualifying plan change (or accept heavier setup such as clearing app/plugin storage to reset cursor—usually unnecessary).
|
||||
|
||||
**Debugging:** On Android, filter **logcat** for `TimeSafariNativeFetcher` (e.g. HTTP 200, `Fetched N notification(s)`) to confirm prefetch ran and how many `NotificationContent` items were built.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user