Files
crowd-funder-from-jason/doc/DAILY_NOTIFICATION_BUG_DIAGNOSIS.md

6.6 KiB
Raw Blame History

Daily Notification Bugs — Diagnosis (Plugin + App)

Context: Fixes were applied in both the plugin and the app, but "reset doesn't fire" and "notification text defaults to fallback" still occur. This doc summarizes what was checked and what to do next.


What Was Verified

App integration (correct)

  • NativeNotificationService.ts

    • Pre-cancel is gated: only iOS calls cancelDailyReminder() before scheduling (lines 289305). Android skips it.
    • Schedules with id: this.reminderId ("daily_timesafari_reminder"), plus time, title, body.
    • Calls DailyNotification.scheduleDailyNotification(scheduleOptions) (not scheduleDailyReminder).
  • AccountViewView.vue

    • editReminderNotification() only calls cancelDailyNotification() when not Android (lines 13031305). On Android it only calls scheduleDailyNotification().

So the app is not double-cancelling on Android and is passing the expected options.

Plugin in apps node_modules (fixed code present)

  • node_modules/@timesafari/daily-notification-plugin is at version 1.1.4 and contains:
    • NotifyReceiver.kt: DB idempotence is skipped when skipPendingIntentIdempotence=true (wrapped in if (!skipPendingIntentIdempotence)).
    • DailyNotificationWorker.java: preserveStaticReminder read from input, stable scheduleId for static reminders, and scheduleExactNotification(..., preserveStaticReminder, ...).
    • DailyNotificationPlugin.kt: cancelDailyReminder(call) implemented.

So the source the app uses (from its dependency) already has the fixes.

Plugin schedule path (correct)

  • App calls scheduleDailyNotification → plugins scheduleDailyNotification(call)ScheduleHelper.scheduleDailyNotification(...).
  • That helper calls NotifyReceiver.cancelNotification(context, scheduleId) then scheduleExactNotification(..., skipPendingIntentIdempotence = true).
  • So the “re-set” path does set skipPendingIntentIdempotence = true and the DB idempotence skip should apply.

Likely Causes Why Bugs Still Appear

1. Stale Android build / old APK

The Android app compiles the plugin from:

android/capacitor.settings.gradle
project(':timesafari-daily-notification-plugin').projectDir = new File('../node_modules/@timesafari/daily-notification-plugin/android')

If the app was not fully rebuilt after the plugin in node_modules was updated, the running APK may still contain old plugin code.

Do this:

  • In the app repo (crowd-funder-for-time-pwa):
    • ./gradlew clean (or Android Studio → Build → Clean Project)
    • Build and reinstall the app (e.g. Run on device/emulator).
  • Confirm youre not installing an older APK from somewhere else.

2. Dependency not actually updated after plugin changes

The app depends on:

"@timesafari/daily-notification-plugin": "git+https://gitea.anomalistdesign.com/trent_larson/daily-notification-plugin.git#master"

If the fixes were only made in a different clone (e.g. daily-notification-plugin_test) and never pushed to that gitea master, then:

  • npm install / npm update in the app would not pull the fixes.
  • The apps node_modules would only have the fixes if they were copied/linked from the fixed repo.

Do this:

  • If the fixes live in another clone: either push the fixed plugin to gitea master and run npm update @timesafari/daily-notification-plugin (then npx cap sync android, then clean build), or point the app at the fixed plugin locally, e.g. in app package.json:
    • "@timesafari/daily-notification-plugin": "file:../daily-notification-plugin"
      (adjust path to your fixed plugin repo), then npm install, npx cap sync android, clean build and reinstall.

3. Fallback text from native fetcher (Bug 2 only)

TimeSafariNativeFetcher.java in the app is still a placeholder: it always returns:

  • Title: "TimeSafari Update"
  • Body: "Check your starred projects for updates!"

That only affects flows that fetch content (e.g. prefetch or any path that uses the fetcher for display). The static daily reminder path does not use the fetcher for display: title/body come from the schedule Intent and WorkManager input. So if you only use the “daily reminder” (one time + custom title/body), the fetcher placeholder should not be the cause. If you have any flow that relies on fetched content for the text, youll see that placeholder until the fetcher is implemented and wired (and optionally token persistence).


Verification Steps (after clean build + reinstall)

  1. Reset / “re-set” (Bug 1)

    • Set reminder for 23 minutes from now.
    • Edit and save without changing the time.
    • Wait for the time; the notification should fire.
    • In logcat, filter by the plugins tags and look for:
      • Skipping DB idempotence (skipPendingIntentIdempotence=true) for scheduleId=...
      • Scheduling next daily alarm: id=daily_timesafari_reminder ...
        If you see these, the fixed path is running.
  2. Static text on rollover (Bug 2)

    • Set a custom title/body, let the notification fire once.
    • In logcat look for:
      • DN|ROLLOVER next=... scheduleId=daily_timesafari_reminder static=true
        If you see static=true and the same scheduleId, the next occurrence should keep your custom text.
  3. Plugin version at build time

    • In the apps node_modules/@timesafari/daily-notification-plugin/package.json, confirm "version": "1.1.4" (or the version that includes the fixes).
    • After that, a clean build ensures that version is whats in the APK.

Summary

Check Status
App gates cancel on Android OK
App calls scheduleDailyNotification with id/title/body OK
Plugin in app node_modules has DB idempotence skip OK (1.1.4)
Plugin in app node_modules has static rollover fix OK
Plugin in app node_modules has cancelDailyReminder OK
Schedule path passes skipPendingIntentIdempotence = true OK

See also: doc/plugin-feedback-android-rollover-double-fire-and-user-content.md — when two notifications fire (e.g. one ~3 min early, one on the dot) and neither shows user-set content.

Most likely the app is still running an old Android build. Do a clean build and reinstall, and ensure the plugin dependency in the app really points at the fixed code (gitea master or local path). Then re-test and check logcat for the lines above. If the bugs persist after that, the next step is to capture a full logcat from “edit reminder (same time)” through the next fire and from “first fire” through “next day” to see which path runs.