100 Commits
Author SHA1 Message Date
Jose Olarte III cde2d5ab96 chore(release): release 5.0.0 after retiring scheduleApiNotifications
Bump to 5.0.0 for the breaking removal of the api_* create/schedule
path. clearApiNotifications remains for the host cleanup migration.
2026-09-24 16:50:51 +08:00
Jose Olarte III cf110f69fb remove scheduleApiNotifications so the plugin cannot create new api_* schedules 2026-09-23 20:09:12 +08:00
Jose Olarte III 5703d2a1e3 chore(release): release 4.0.1 with iOS Daily Reminder identifier separation 2026-06-09 19:30:05 +08:00
Jose Olarte III 9e81c89471 fix(ios): separate Daily Reminder identifiers from api_ namespace
Daily Reminders now use daily_<reminderId> for UNNotificationCenter
requests instead of sharing api_<epochMillis> with batch API notifications.
clearApiNotifications no longer removes new daily reminders.

Add legacy api_* cleanup on schedule/cancel/update and transitional
getScheduledReminders matching via stored predictiveEpochMillis.
Update TypeScript JSDoc for iOS identifier families.
2026-06-09 19:15:16 +08:00
Jose Olarte III 6e017aad09 chore(release): release 4.0.0 with API batch notification method names
Bump to 4.0.0 for the breaking rename to scheduleApiNotifications and
clearApiNotifications. Scheduling behavior and api_ identifiers are unchanged.
2026-06-09 18:11:24 +08:00
Jose Olarte III d4da7256a5 feat!: rename batch APIs to scheduleApiNotifications and clearApiNotifications
BREAKING CHANGE: Replaces scheduleNotifications, clearPredictiveNotifications,
and iOS clearAllNotifications. Behavior and api_ IDs unchanged.
2026-06-09 18:10:14 +08:00
Jose Olarte III 6de300b7d4 chore(release): release 3.0.4 with Android batch APIs and api_ ID namespace 2026-06-09 17:28:53 +08:00
Jose Olarte III ceaa4ada66 refactor: rename internal notification ID prefix from predictive_ to api_ 2026-06-09 17:27:15 +08:00
Jose Olarte III eca2bbf947 feat(android): schedule batch notifications with predictive_<epochMillis> IDs
Add scheduleNotifications so Android predictive scheduling matches
clearPredictiveNotifications and iOS batch API behavior.
2026-06-08 19:28:12 +08:00
Jose Olarte III fc5b4cd9fa feat(android): add clearPredictiveNotifications for predictive_* schedules only
Lets the app refresh API/predictive notifications without cancelAllNotifications
disabling Daily Reminders, dual schedules, or fetch jobs.
2026-06-08 18:45:11 +08:00
Jose Olarte III f82c427108 chore(release): release 3.0.3 with iOS notification diagnostics
Bump to 3.0.3 and add bridge-safe getPendingNotifications,
getDeliveredNotifications, and getNotificationSettings for local
notification debug panels.
2026-05-22 16:48:12 +08:00
Jose Olarte III 7f7d65cae6 feat(ios): add local notification diagnostics for debug panels
Expose bridge-safe pending, delivered, and settings snapshots from
UNUserNotificationCenter so apps can inspect local notification state
without native date objects or large payloads.

- Add getDeliveredNotifications and getNotificationSettings on iOS
- Harden getPendingNotifications with triggerTimestamp/triggerDateIso
- Always resolve with serializable values; omit userInfo from delivered
- Register new Capacitor methods and TypeScript definitions/web stubs
2026-05-21 18:20:29 +08:00
Jose Olarte III 4027bb0c37 docs: document plugin vs backend authentication boundaries
Clarify that the native Daily Notification Plugin does not
authenticate users or call notification-wakeup-service directly.
Authentication belongs in the host app; the plugin only schedules
local notifications and orchestrates host-provided content fetch.

Add docs/security-boundaries.md with responsibility matrix, auth
flow diagram, SPI boundary notes, and a warning against adding backend
auth logic to the plugin layer.
2026-05-20 22:35:13 +08:00
Jose Olarte III 750343ddb9 chore(release): bump plugin to 3.0.2 2026-05-05 19:10:16 +08:00
Jose Olarte III 60a5a30728 refactor(ios): unify predictive IDs to epoch ms and narrow batch APIs
Use predictive_<epochMillis> for reminders (next-occurrence ms), testAlarm
fire time, and scheduleNotifications; persist predictiveEpochMillis in
UserDefaults for cancel/update alignment.

clearAllNotifications removes only predictive_* pending and delivered
entries. scheduleNotifications is additive (no global clear) and skips
past timestamps.
2026-05-05 19:07:43 +08:00
Jose Olarte III 9db381c72b feat(ios): add batch UN notification replace-all API
Expose clearAllNotifications and scheduleNotifications on DailyNotification.
clearAllNotifications clears pending and delivered center notifications.
scheduleNotifications replaces pending requests from epoch-ms timestamps
with deterministic predictive_* IDs and DNP-BATCH logging.
2026-05-05 15:08:12 +08:00
Jose Olarte III 26f1ff0e08 fix(ios): use deterministic predictive notification identifiers
Replace reminder_* and random test alarm IDs with predictive_<Int>
so UNUserNotificationCenter replaces pending requests instead of
stacking. Daily reminders key off local HH:mm; testAlarm uses the
scheduled fire second. Dual notification id unchanged.
2026-05-05 14:53:06 +08:00
Jose Olarte III b6f663121d chore(release): bump to 3.0.1
Set package and lockfile to 3.0.1 and document the Android dual-schedule
empty native fetch fix in CHANGELOG.
2026-04-16 17:07:36 +08:00
Jose Olarte III 5756178c23 fix(android): skip dual notify when native fetch is empty
Dual native prefetch used to map an empty NotificationContent list to
synthetic JSON and still arm the chained notify alarm, which led hosts
such as TimeSafari to show marketing copy via show_default even when the
API had no rows.

Persist {"skipNotification":true} for an empty native result, skip
DualScheduleNotifyScheduler for that successful cycle while still
enqueueing dual fetch recovery, and teach DualScheduleHelper to return
no content for fresh skip payloads and for stale cache when
fallbackBehavior is skip. Add Robolectric tests for DualScheduleHelper
and the skip payload helper.
2026-04-16 17:05:15 +08:00
Jose Olarte III fbb5a94071 chore(release): v3.0.0 — iOS native fetcher, starred plans, chained dual (iOS + Android)
BREAKING CHANGE (iOS): configureNativeFetcher now requires
DailyNotificationPlugin.registerNativeFetcher(_) first, aligned with Android.

iOS:
- Add NativeNotificationContentFetcher SPI, registry, FetchContext, timeout helper
- Add updateStarredPlans / getStarredPlans; persist daily_notification_timesafari.starredPlanIds
- Chained dual: prefetch only on scheduleDualNotification; arm one-shot UN after fetch
- configureNativeFetcher invokes fetcher.configure; BG fetch prefers registered fetcher
- Public NotificationContent for host implementations

Android:
- Dual notify alarm scheduled after dual FetchWorker completes (DualScheduleNotifyScheduler)
- Persist dual_notify_schedule_id; remove upfront NotifyReceiver for dual setup

Docs: CONSUMING_APP_HANDOFF_IOS_NATIVE_FETCHER_AND_CHAINED_DUAL.md; CHANGELOG 3.0.0
Made-with: Cursor
2026-04-02 16:48:06 +08:00
Jose Olarte III 9121b1e0f7 feat(configureNativeFetcher): optional JWT pool for background native fetch
Add jwtTokens / jwtTokenPoolJson to the TypeScript API, parse and validate
(max 128) on Android and iOS, persist jwtTokenPool with native_fetcher_config
when persistToken is true (Android), and extend NativeNotificationContentFetcher
with a four-argument configure overload delegating to the existing three-arg
default. iOS stores the pool in UserDefaults JSON and uses primary jwt or first
pool entry in the plugin background fetch path. Bump version to 2.2.0. Update
TestNativeFetcher to exercise the new configure overload.
2026-03-27 16:30:31 +08:00
Jose Olarte III 469167a55f feat(android): dual prefetch delay, native fetcher, scoped content cache
- Schedule dual content fetch with WorkManager initialDelay to the next
  contentFetch cron; reschedule from prefs after success and on boot when
  dual_fetch_* exists (DualScheduleFetchRecovery + ReactivationManager).
- When contentFetch has no URL, call NativeNotificationContentFetcher with
  FetchContext (prefetch + next notify time); else keep HTTP/mock behavior.
- Add content_cache.cacheScope (dual|daily|legacy), Room v4 migration,
  getLatestByScope; DualScheduleHelper reads dual only; daily fetch paths
  write daily; NotifyReceiver prefers daily/legacy for legacy cache reads.
- Extract ScheduleCronUtils.calculateNextRunTimeMillis for shared cron math.
- Document in README/CHANGELOG; bump package to 2.1.5.
2026-03-25 18:05:57 +08:00
Jose Olarte III a5c5a7e74e docs(android): add dual schedule native fetch and cache scope plan
Add ANDROID_DUAL_SCHEDULE_NATIVE_FETCH_AND_CACHE_SCOPE.md describing the
pre-implementation plan: WorkManager initial delay for dual prefetch,
NativeNotificationContentFetcher when URL is absent, and cacheScope on
ContentCache to separate dual vs daily reminder cache rows.
2026-03-25 16:05:20 +08:00
Jose Olarte III fc1cebd720 chore(release): 2.1.4
Bump package, lockfile, podspec, definitions header, and FetchWorker mock
payload. Changelog section retitled to 2.1.4 (Android dual-schedule JSON
parsing fixes and README notes).
2026-03-20 21:21:52 +08:00
Jose Olarte III 5f12b69d2a fix(android): parse optional userNotification fields for dual/user schedule
parseUserNotificationConfig used getBoolean/getString for title, body, sound,
vibration, and priority; missing keys threw JSONException though TS marks them
optional. Add optBooleanOrNull/optStringOrNull (same pattern as optIntOrNull) and
defer to existing NotifyReceiver/DualScheduleHelper defaults.

Document in README; extend CHANGELOG [2.1.3].
2026-03-20 21:19:27 +08:00
Jose Olarte III 4dd1aea002 chore(release): 2.1.3
- Bump package, lockfile, iOS DailyNotificationPlugin.podspec, and synced
  version strings (definitions header, FetchWorker mock payload).
- Add CHANGELOG [2.1.3] for Android optional contentFetch fields and README.
2026-03-20 19:26:46 +08:00
Jose Olarte III 33010ad7cf fix(android): parse optional contentFetch timeout/retry fields for dual schedule
JSONObject.getInt threw when timeout/retryAttempts/retryDelay were omitted, but
TS ContentFetchConfig marks them optional. Use optIntOrNull so null passes
through and FetchWorker keeps its existing defaults.

Document omitted-field behavior in README under scheduleDualNotification.
2026-03-20 19:25:04 +08:00
Jose Olarte III ba1186c057 chore(release): bump @timesafari/daily-notification-plugin to 2.1.2 2026-03-20 16:47:32 +08:00
Jose Olarte III 757263c073 fix(android): remove duplicate scheduleId locals in DailyNotificationWorker
handleDisplayNotification already reads schedule_id after getInputData().
Inner branches redeclared String scheduleId, which javac rejects in the
same method scope. Drop the redundant lines; behavior unchanged.
2026-03-20 16:45:39 +08:00
Jose Olarte III 539b011fa8 chore(release): bump version to 2.1.1
Patch release for iOS build fix: unwrap optional title/body in
dual-notification path (NotificationContent).
2026-03-19 15:13:41 +08:00
Jose Olarte III d3ade1f27a fix(ios): unwrap optional title/body in dual-notification path
NotificationContent.title and .body are String?; assigning them to
non-optional String caused Swift build errors. Use ?? with the same
defaults as the config fallback so both branches yield non-optional
title/body.
2026-03-19 15:10:38 +08:00
Jose Olarte III 21ab05d63b docs(completion-plan): add app-side implementation blurb for Cursor
Add "For app-side implementation" paragraph so the completion plan can
be used in the app repo: focus §2/§3, plugin v2.1.0+, link/build check,
Edit flow with updateDualScheduleConfig, and key app file paths.
2026-03-19 14:33:50 +08:00
Jose Olarte III 87d24ca506 chore(release): bump plugin version to 2.1.0 2026-03-19 14:22:59 +08:00
Jose Olarte III 7b41ca9e0b feat(dual): complete scheduleDualNotification; add relationship (contentTimeout/fallbackBehavior)
Plugin (iOS):
- Real cron parsing in calculateNextRunTime(from:); stable dual id + replace semantics; UNCalendarNotificationTrigger for daily
- cancelDualSchedule() and updateDualScheduleConfig(); persist/clear dual config for relationship

Plugin (Android):
- cancelDualSchedule() and updateDualScheduleConfig(); FetchWorker.scheduleFetchForDual; ScheduleHelper.cancelDualSchedule; dual_notify_* id
- Persist dual config; DualScheduleHelper + Worker dual branch for relationship at fire time

Relationship:
- iOS: replace pending dual notification when fetch completes (contentTimeout/fallbackBehavior)
- Android: resolve config + content cache in Worker for dual_notify_*; show resolved title/body

Doc: COMPLETION-PLAN-SCHEDULE-DUAL-NOTIFICATION.md (two types, Edit/updateDualScheduleConfig, §1.3a, status)
2026-03-18 21:10:49 +08:00
Jose Olarte III 7a1e58a4b6 doc: add completion plan for scheduleDualNotification (iOS/Android)
- Checklist for completing dual-schedule (New Activity) on plugin and app
- Context: two notification types (Daily Reminder vs New Activity), isolation
- iOS: cron parsing, relationship, cancelDualSchedule, updateDualScheduleConfig
- Android: cancelDualSchedule; updateDualScheduleConfig for Edit time
- Consuming app: link/build verification, Edit flow use updateDualScheduleConfig
- Replace semantics and refs to plugin and app code
2026-03-18 17:41:49 +08:00
Jose Olarte III ca6a75ded8 chore(release): bump plugin version to 2.0.0
- package.json, package-lock.json
- ios/Plugin/Info.plist (CFBundleShortVersionString)
- ios/DailyNotificationPlugin.podspec
- Android: DailyNotificationPlugin.kt, NotifyReceiver.kt, FetchWorker.kt,
  ReactivationManager.kt (header @version and runtime version payloads)
- src/observability.ts (@version)

Major bump for com→org package rename (breaking change for consumers).
2026-03-12 14:37:24 +08:00
Jose Olarte III d8a0eaf413 refactor(android,ios): rename package com.timesafari to org.timesafari.dailynotification
- Android: move plugin source to org/timesafari/dailynotification, update
  namespace, manifest package, and all package/imports; change intent actions
  to org.timesafari.daily.NOTIFICATION and DISMISS
- iOS: update bundle IDs, BGTask identifiers, subsystem labels, and queue
  names in Plugin and Xcode projects
- Capacitor: update plugin class registration and appIds in configs
- Test apps (android-test-app, daily-notification-test, ios-test-app):
  applicationId/bundleId, manifests, ProGuard, scripts, and docs
- Docs: bulk update references; add CONSUMING_APP_MIGRATION_COM_TO_ORG.md
  for consuming app migration

BREAKING CHANGE: Consuming apps must update plugin class to
org.timesafari.dailynotification.DailyNotificationPlugin, manifest
receivers/actions, and iOS BGTask identifiers per migration doc.
2026-03-12 14:26:07 +08:00
Jose Olarte III b8d9b6247d chore(release): bump plugin version to 1.3.3
Sync version in package.json, package-lock.json, Android/Kotlin sources,
iOS Info.plist, and ios/DailyNotificationPlugin.podspec.
2026-03-09 20:32:02 +08:00
Jose Olarte III 6df1d4a7c6 fix(android): stop auto-opening Settings for exact alarm in scheduleDailyNotification
Remove the guard that opened system Settings and rejected when exact alarms
were not granted. Scheduling now proceeds using inexact/windowed fallback;
consuming apps can handle UX (e.g. optional hint or openExactAlarmSettings()).
2026-03-09 20:29:04 +08:00
Jose Olarte III daaf7aa62a chore(release): bump version to 1.3.2
Removes exact alarms (Android); delivery is now inexact/schedule-based.

- package.json, observability, ios Info.plist, android plugin version refs
2026-03-09 18:29:56 +08:00
Jose Olarte III 6ad7ff5fe1 docs: reorganize docs into subdirs and fix links
- Keep only index, getting-started, invariants, performance,
  troubleshooting, and file-organization-summary in docs/ root
- Add docs/architecture/ (storage, database interfaces, native fetcher)
- Add docs/deployment/ (deployment-guide, DEPLOYMENT_CHECKLIST)
- Add docs/compliance/ (accessibility, legal, observability)
- Move integration guides and host-app docs to docs/integration/
- Move design/planning and prefetch docs to docs/design/
- Move Android consuming-app and comparison docs to docs/platform/android/
- Move DEPLOYMENT_SUMMARY and TODO-CLASSIFICATION to docs/progress/
- Archive deprecated platform-capability-reference to docs/_archive/
- Point platform-capability links to alarms/01-platform-capability-reference.md
- Update docs/00-INDEX.md with new sections and paths
- Fix cross-references in README, deployment, progress, design, testing,
  and test-app docs
- Remove one-off COMMIT_MESSAGE.txt
2026-03-06 19:51:13 +08:00
Jose Olarte III f58eeda8a7 docs: move 6 root .md files into docs/progress and docs/_archive
- Move TODO.md, TODAY_SUMMARY.md, SESSION_RECONSTITUTION.md,
  BATCH_A_COMPLETION_SUMMARY.md to docs/progress/
- Move PR_DESCRIPTION.md, MERGE_READY_SUMMARY.md to docs/_archive/
- Update docs/00-INDEX.md with new progress and archive entries
- Note moves in docs/_archive/2025-12-16-consolidation/CONSOLIDATION_SOURCE_MAP.md

Root keeps only README, CHANGELOG, CONTRIBUTING, SECURITY, BUILDING,
ARCHITECTURE, API, USAGE.
2026-03-06 19:27:21 +08:00
Jose Olarte III 36356e0aca docs: point repo URLs to Gitea
Replace github.com/timesafari/daily-notification-plugin with
gitea.anomalistdesign.com/trent_larson/daily-notification-plugin
2026-03-06 19:16:30 +08:00
Jose Olarte III 6f4d946662 chore: bump plugin version to 1.3.1
Align package.json and all plugin version references (Android, TS
definitions, observability, web) to 1.3.1 after rollover-interval fixes.
2026-03-04 21:28:20 +08:00
Jose Olarte III c38f235647 fix(android): apply rollover interval for daily_rollover_* and allow ROLLOVER_ON_FIRE updates
- Bug 1: When the firing run used schedule_id daily_rollover_*, resolve the
  canonical notify schedule (first enabled with rolloverIntervalMinutes > 0)
  and use it to read the interval so the next run is current + interval
  instead of +24h. Add ScheduleHelper.getCanonicalRolloverScheduleBlocking().
- Bug 2: For ROLLOVER_ON_FIRE, do not skip scheduling when an existing
  PendingIntent is found for the same schedule id: cancel the existing alarm
  and set the new trigger time so the rollover chain (e.g. 21:10 → 21:20)
  is updated instead of treated as duplicate.
2026-03-04 21:17:26 +08:00
Jose Olarte III 2714480070 chore: bump plugin version to 1.3.0
Align package.json and all plugin version references (Android entity
strings and file headers, TypeScript definitions/observability/web)
with 1.3.0 for the rolloverIntervalMinutes release.
2026-03-03 17:48:18 +08:00
Jose Olarte III e873a46bbd feat(plugin): add optional rolloverIntervalMinutes for dev/testing
Add optional rolloverIntervalMinutes to scheduleDailyNotification so the
next occurrence can be scheduled N minutes after the current trigger
(e.g. 10 minutes) instead of 24 hours. Value is persisted and used on
rollover and after reboot.

- TypeScript: NotificationOptions.rolloverIntervalMinutes?: number
- Android: Schedule.rolloverIntervalMinutes in Room (migration 2→3);
  Plugin and ScheduleHelper persist it; Worker uses it in rollover and
  updates nextRunAt; ReactivationManager uses it in boot recovery
- iOS: NotificationContent.rolloverIntervalMinutes (Codable); Plugin
  passes it into content; Scheduler uses it in calculateNextScheduledTime
  and copies to nextContent on rollover

When absent or ≤0, behavior unchanged (24h). App can clear by calling
scheduleDailyNotification without the parameter.
2026-03-03 17:45:45 +08:00
Jose Olarte III aa0eaa5389 chore: bump plugin version to 1.2.1
Update package.json, iOS podspec, and Android plugin-version references
after fix for duplicate fallback notifications (cancel fetch-related
WorkManager jobs when scheduling daily notification).
2026-03-02 16:44:06 +08:00
Jose Olarte III c36781e440 fix(android): cancel only fetch-related WorkManager jobs when scheduling daily notification
Prevents a second notification (UUID alarm) with fallback or placeholder text by
cancelling pending prefetch/fetch work when the user schedules or reschedules.
cleanupExistingNotificationSchedules only cancels alarms for DB schedule IDs;
alarms from DailyNotificationFetchWorker use a UUID and were never cancelled.

Add ScheduleHelper.cancelFetchRelatedWorkManagerJobs() to cancel only the
prefetch and daily_notification_fetch tags (not display, dismiss, or maintenance).
Call it after cleanup and before scheduleDailyNotification. Future fetched-content
flows can use distinct WorkManager tags and will not be affected by this path.
2026-03-02 16:41:14 +08:00
Jose Olarte III cff7b659dc chore(version): bump plugin to 1.2.0
- package.json, README.md, podspec
- src: definitions.ts, observability.ts, web.ts
- android: DailyNotificationPlugin.kt, DailyNotificationWorker.java,
  FetchWorker.kt, NotifyReceiver.kt, ReactivationManager.kt,
  DailyNotificationStorageRoom.java
2026-02-26 18:30:32 +08:00
Jose Olarte III d3df4d9115 fix(android): single rollover alarm, user content, no main-thread DB
- Receiver: stop reading Room on main thread; pass schedule_id to Worker
  so title/body are resolved on a background thread (fixes
  db_fallback_failed / "Cannot access database on the main thread").
- Worker: use stable schedule_id for rollover so one alarm per reminder
  and reschedule cancels it; resolve user title/body by schedule_id when
  Intent lacks them; skip prefetch for static reminders to avoid a
  second alarm.
- ScheduleHelper: persist NotificationContentEntity for scheduleId when
  scheduling daily notification so rollover and post-reboot show user
  text.

Refs: plugin-feedback-android-rollover-double-fire-and-user-content
2026-02-26 18:28:40 +08:00
Jose Olarte III bc3bf484cc chore: bump plugin version to 1.1.9 2026-02-24 19:20:45 +08:00
Jose Olarte III 25f83cf1fa fix(android): always reschedule alarm on boot by skipping PendingIntent idempotence
Boot recovery was skipping reschedule when it found an "existing" PendingIntent.
AlarmManager alarms are not guaranteed to persist across reboot; on devices that
clear them, the skip caused the next notification (initial or rollover) to never
fire until the app was opened. Pass skipPendingIntentIdempotence = true for all
BOOT_RECOVERY call sites (BootReceiver, ReactivationManager.rescheduleAlarmForBoot)
so the alarm is always re-registered after reboot. Setting the same PendingIntent
again replaces any existing alarm, so no duplicate alarms.
2026-02-24 19:19:22 +08:00
Jose Olarte III 7188d32ae6 chore: bump plugin version to 1.1.8
- package.json: 1.1.7 → 1.1.8
- Android: ReactivationManager, FetchWorker, NotifyReceiver,
  DailyNotificationStorageRoom, DailyNotificationWorker (entity pluginVersion)
- TypeScript: web.ts, observability.ts, definitions.ts (@version)
2026-02-23 18:37:02 +08:00
Jose Olarte III 1157a0f1ef fix(android): restore user title/body after reboot so notification doesn't show fallback text
After device restart, PendingIntent extras (title, body, is_static_reminder) can be
missing when the alarm fires, so the worker took the Room/JIT path and showed
fallback text instead of the user's message.

- DailyNotificationReceiver: when intent has notification_id but missing title/body,
  load NotificationContentEntity from Room and pass title/body into Worker input
  with is_static_reminder=true.
- ReactivationManager: add getTitleBodyForSchedule(); use persisted title/body in
  rescheduleAlarm and rescheduleAlarmForBoot (and inner boot helper) instead of
  hardcoded "Daily Notification" / "Your daily update is ready".
- BootReceiver: use ReactivationManager.getTitleBodyForSchedule() when building
  UserNotificationConfig for notify schedules after boot.
- DailyNotificationWorker: when content from Room has both title and body, skip
  performJITFreshnessCheck so user text is not overwritten by fetcher placeholder.

Ref: plugin-feedback-android-post-reboot-fallback-text (crowd-funder-for-time-pwa)
2026-02-23 18:00:36 +08:00
Jose Olarte III c2b1a60804 chore(release): 1.1.7 2026-02-18 18:30:26 +08:00
Jose Olarte III fa8028a698 fix(android): prevent duplicate reminder notification on first-time setup
Do not enqueue DailyNotificationFetchWorker for static reminder schedules.
Display is already handled by the single NotifyReceiver alarm; prefetch was
using fallback content and scheduling a second alarm via legacy
DailyNotificationScheduler, causing two notifications at fire time.
2026-02-18 18:29:11 +08:00
Jose Olarte III 9feaf60c84 chore: bump plugin version to 1.1.6 2026-02-16 19:19:09 +08:00
Jose Olarte III aaeb71d31d fix(android): do not cancel PendingIntent before setAlarmClock on reschedule
Remove existingPendingIntent.cancel() in the "cancel existing alarm before
rescheduling" block. The cached PendingIntent can be the same instance passed
to setAlarmClock; cancelling it can prevent the new alarm from firing. Keep
only alarmManager.cancel(existingPendingIntent) to clear the previous alarm.
2026-02-16 19:16:18 +08:00
Jose Olarte III 531ce9f709 chore: bump plugin version to 1.1.5 2026-02-16 18:18:09 +08:00
Jose Olarte III 0b61d33f21 fix(android): avoid overwriting app schedule when rollover uses daily_rollover_ id
NotifyReceiver's post-schedule DB update no longer uses the "first enabled
notify schedule" fallback when stableScheduleId starts with "daily_rollover_".
That fallback was updating the app's schedule row (e.g. daily_timesafari_reminder)
with the rollover time and could leave the app's next alarm in a bad state after
a notification fired.

Add docs/CONSUMING_APP_ANDROID_NOTES.md with notes for consuming apps: debounce
double scheduleDailyNotification calls, and include DailyNotificationReceiver
in logcat when debugging alarms that are scheduled but do not fire.
2026-02-16 18:16:20 +08:00
Jose Olarte III 02a44a3e7b chore(release): bump plugin version to 1.1.4
Align version across package.json, iOS podspec, Android/TS sources,
README, and CHANGELOG after 1.1.4 fixes (reset alarm, static rollover,
cancelDailyReminder).

Changes:
- package.json: 1.1.3 → 1.1.4
- ios/DailyNotificationPlugin.podspec: 1.1.1 → 1.1.4
- Android: NotifyReceiver, ReactivationManager, FetchWorker,
  DailyNotificationStorageRoom — plugin version strings/comments
- src: web.ts, observability.ts, definitions.ts — @version headers
- README.md: version line
- CHANGELOG.md: add [1.1.4] - 2026-02-16 entry (fixes + cancelDailyReminder)

Files modified:
- package.json
- ios/DailyNotificationPlugin.podspec
- android/.../NotifyReceiver.kt, ReactivationManager.kt, FetchWorker.kt,
  storage/DailyNotificationStorageRoom.java
- src/web.ts, observability.ts, definitions.ts
- README.md, CHANGELOG.md
2026-02-16 17:02:38 +08:00
Jose Olarte III cb3cb5a78e fix(android): reset alarm and static reminder rollover; add cancelDailyReminder
Fixes two integration bugs with the consuming app (Time Safari) and adds
Android parity for cancel-by-id.

Problem:
- Re-setting a daily notification (edit/save same time) could cancel the
  alarm then skip re-scheduling because DB idempotence still ran and
  treated the update as a duplicate.
- After the first fire, rollover scheduled the next run with
  isStaticReminder=false, so title/body reverted to fallback.
- App calls cancelDailyReminder({ reminderId }) but Android had no
  implementation (only cancelAllNotifications and scheduleDailyReminder).

Changes:
- NotifyReceiver.kt: Run DB idempotence only when
  !skipPendingIntentIdempotence. When true (e.g. app reset flow), skip
  the check and log; prevents "no alarm" after cancel-then-schedule.
- DailyNotificationWorker.java: In scheduleNextNotification(), read
  is_static_reminder from WorkManager input; keep stable scheduleId for
  static reminders; pass preserveStaticReminder and reminderId into
  scheduleExactNotification(); add DN|ROLLOVER log.
- DailyNotificationPlugin.kt: Add cancelDailyReminder(call) that parses
  reminderId (or id, reminder_id, scheduleId), calls
  NotifyReceiver.cancelNotification(context, scheduleId), and does
  best-effort DB cleanup (setEnabled false, updateRunTimes null).

Files modified:
- android/.../NotifyReceiver.kt
- android/.../DailyNotificationWorker.java
- android/.../DailyNotificationPlugin.kt
2026-02-16 16:57:01 +08:00
Jose Olarte III a62f54b8a8 fix(android): Java call sites for scheduleExactNotification need 8th parameter
Add skipPendingIntentIdempotence (false) to NotifyReceiver.scheduleExactNotification
calls in DailyNotificationReceiver.java and DailyNotificationWorker.java so
consuming apps compile. Rollover paths do not skip idempotence.

- DailyNotificationReceiver: scheduleNextNotification() — add 8th arg false
- DailyNotificationWorker: scheduleNextNotification() — add 8th arg false
- Bump version to 1.1.3 (package.json, CHANGELOG, native/TS refs)
2026-02-13 19:51:49 +08:00
Jose Olarte III 7702bd3b81 fix(android): second daily notification not firing after reschedule
Cancel-then-schedule was skipped because the idempotence check still
found the cancelled PendingIntent in Android's cache. Skip
PendingIntent idempotence on the cancel-then-schedule path so the
new schedule is always set.

- NotifyReceiver.scheduleExactNotification: add
  skipPendingIntentIdempotence (used only from scheduleDailyNotification)
- ScheduleHelper: pass skipPendingIntentIdempotence=true after
  cancelNotification(scheduleId)
- Version 1.1.2: package.json, CHANGELOG, README, TS/Android refs
- docs/CONSUMING_APP_OPTIONAL_ANDROID_ID_CLEANUP.md: optional app
  cleanup to use one stable id on both platforms
2026-02-13 19:26:09 +08:00
Jose Olarte III 602eafc892 docs(testing): add PHYSICAL_DEVICE_GUIDE for Android hardware testing
Covers USB debugging setup, battery optimization settings for major OEMs
(Samsung, Xiaomi, OnePlus, Huawei, Oppo), log monitoring, and
troubleshooting. Complements EMULATOR_GUIDE for real-device validation.
2026-02-12 17:19:45 +08:00
Jose Olarte III a77f08052f chore(version): bump to 1.1.1 after Android alarm fix and EMULATOR_GUIDE docs 2026-02-05 19:36:33 +08:00
Jose Olarte III 442b826401 Merge branch 'android-fixes-2026-02' 2026-02-05 19:29:16 +08:00
Jose Olarte III 0bc75372b5 fix(android): target alarm broadcast to app package so receiver is triggered
Set Intent.setPackage(context.packageName) when creating PendingIntents
for AlarmManager so the broadcast is delivered to DailyNotificationReceiver
on all OEMs. Alarms were firing but the receiver was not invoked when the
component was not explicitly package-targeted.

- NotifyReceiver: setPackage on schedule, cancel, and isAlarmScheduled intents
- ReactivationManager: alarmsExist() use DailyNotificationReceiver + setPackage
- DailyNotificationScheduler: setPackage on ExactAlarmManager path intent
2026-02-05 19:28:30 +08:00
Jose Olarte III 57c7ddb7eb docs(testing): EMULATOR_GUIDE prerequisites, API 35, Apple Silicon; build.sh Android-only sync
EMULATOR_GUIDE.md:
- Add "Checking and Installing Prerequisites" (how to check Node, npm, Java,
  ANDROID_HOME, adb, emulator, AVDs; install steps; reference to
  scripts/check-environment.js)
- Use API 35 and Pixel8_API35 throughout to match project compileSdk/targetSdk
- Document arm64-v8a for Apple Silicon and x86_64 for Intel; add
  troubleshooting for "x86_64 not supported on aarch64 host"
- Bump version to 1.1.0 and last-updated date

test-apps/daily-notification-test/scripts/build.sh:
- When building only Android (--android / --run-android), run
  cap:sync:android instead of cap:sync so iOS pod install is skipped and
  Android build/run succeeds without fixing the iOS Podfile
2026-02-05 18:13:09 +08:00
Jose Olarte III a3afefeda9 docs(testing): EMULATOR_GUIDE prerequisites and API 35
- Add "Checking and Installing Prerequisites" section:
  - How to check Node, npm, Java, ANDROID_HOME, adb, emulator, AVDs
  - Reference scripts/check-environment.js for partial check
  - Install steps for Node, Java, Android SDK (cmdline-tools only),
    sdkmanager packages, and avdmanager AVD creation
- Align SDK and AVD with project: use API 35 (android-35, build-tools 35.0.0,
  Pixel8_API35) to match compileSdk/targetSdk in variables.gradle
- Bump guide version to 1.1.0 and last-updated date
2026-02-05 17:48:46 +08:00
Jose Olarte III bf90f158ac chore(version): bump to 1.1.0 after ios-2 merge
Version bump reflects new features merged from ios-2 branch:
- iOS rollover recovery for background/inactive app scenarios
- Build script improvements and iOS support
- Test app enhancements and UI improvements

This is a MINOR version bump per semantic versioning due to
backward-compatible feature additions.
2026-01-22 15:18:00 +08:00
Jose Olarte III 5dbe0d1455 Merge branch 'ios-2' 2026-01-22 14:43:52 +08:00
Jose Olarte III 7f79c5990b fix: include source files and build configs in package files for git installs 2026-01-19 18:57:53 +08:00
Jose Olarte III bef88ad844 feat: add prepare script for automatic build on git install 2026-01-19 18:47:32 +08:00
Jose Olarte III d0155f0b22 docs(building): update BUILDING.md with iOS prerequisites and clean-build script
Updates BUILDING.md to reflect recent changes in build-native.sh, especially
the Xcode Command Line Tools prerequisite check and the clean-build script.

Problem:
- BUILDING.md didn't mention Xcode Command Line Tools prerequisite
  (recently added to build-native.sh)
- clean-build.sh script exists but wasn't documented
- iOS build troubleshooting lacked Command Line Tools guidance

Changes:
- Add Xcode Command Line Tools to Prerequisites section
  - Document installation command (xcode-select --install)
  - Include verification steps (xcode-select -p, xcodebuild -version)
  - Note that build script automatically checks for these tools
  - Explain that sqlite3 is part of Command Line Tools

- Document clean-build.sh script in Build Scripts section
  - Basic usage: ./scripts/clean-build.sh
  - All options: --all, --clean-gradle-cache, --clean-derived-data,
    --reinstall-node
  - Explain when to use clean builds

- Enhance iOS Native Build Process section
  - Add prerequisite note about Command Line Tools
  - Include troubleshooting commands for pod install issues
  - Reference prerequisites section for details

- Add comprehensive troubleshooting sections
  - Clean Build section at start of Troubleshooting
    - Recommends clean-build as first step for many issues
    - Lists when to use clean builds
  - iOS Build Issues section
    - Command Line Tools configuration errors
    - SQLite/linker issues and pkgx conflicts
    - CocoaPods installation problems
    - All with clear solutions and commands

The documentation now accurately reflects:
- Xcode Command Line Tools as required iOS prerequisite
- clean-build.sh as available build tool
- Complete iOS troubleshooting workflow

Files modified:
- BUILDING.md
2026-01-16 15:38:41 +08:00
Jose Olarte III 2915fe7438 fix(build): add SQLite conflict detection and Command Line Tools verification
Prevents iOS build failures caused by pkgx SQLite linking conflicts and
ensures Xcode Command Line Tools are properly installed.

Problem:
- pkgx installs SQLite built for macOS, causing linker errors when building
  for iOS simulator: "linking in dylib built for 'macOS'"
- Missing Command Line Tools cause build failures without clear error messages

Changes:
- Add check_sqlite_conflicts() function
  - Detects pkgx SQLite installations in ~/.pkgx
  - Warns about macOS dylibs that will cause iOS simulator build failures
  - Checks for system SQLite from Command Line Tools
  - Validates library paths (DYLD_LIBRARY_PATH, LD_LIBRARY_PATH)

- Add check_command_line_tools() function
  - Verifies Xcode Command Line Tools are installed and configured
  - Checks for xcodebuild availability
  - Verifies sqlite3 is available (part of Command Line Tools)
  - Provides clear error messages with installation instructions

- Enhance pkgx detection in iOS build functions
  - Specifically searches for pkgx SQLite dylibs
  - Automatically removes pkgx paths from PATH environment variable
  - Provides detailed warnings about detected conflicts
  - Cleans all problematic environment variables before building

- Integrate checks into environment validation
  - Runs automatically when building for iOS
  - Provides early warnings before build starts
  - Fails fast with clear error messages if tools are missing

This fixes the linker error:
  "ld: building for 'iOS-simulator', but linking in dylib
   (/Users/trent/.pkgx/sqlite.org/v3.44.2/lib/libsqlite3.0.dylib)
   built for 'macOS'"

The build script now:
- Detects pkgx SQLite conflicts before building
- Automatically fixes environment variables
- Verifies Command Line Tools are installed
- Provides clear guidance for manual fixes if needed

Files modified:
- scripts/build-native.sh
2026-01-15 18:34:33 +08:00
Jose Olarte III 5247ebeecb fix(build): add Capacitor sync and auto-fix for Android test app builds
Fixed Android test app build failures by ensuring Capacitor is synced
before building and automatically fixing missing file references.

Changes:
- Add Capacitor Android sync step before building test app
  - Runs `npm run cap:sync:android` to create required project structure
  - Ensures `:capacitor-cordova-android-plugins` project exists before Gradle resolves dependencies
- Add automatic fix for missing cordova.variables.gradle reference
  - Detects when capacitor.build.gradle references non-existent file
  - Automatically comments out problematic `apply from` line
  - Uses platform-agnostic sed command (handles macOS and Linux)
  - Provides clear logging about what was fixed
- Reorganize build flow to match iOS pattern
  - Sync Capacitor first, then navigate to platform directory
  - Apply fixes, then build

This fixes the build error:
  "Could not resolve project :capacitor-cordova-android-plugins"
  "No matching variant of project :capacitor-cordova-android-plugins was found"

The build now completes successfully even when:
- Capacitor hasn't been synced yet
- capacitor.build.gradle references missing files

Files modified:
- scripts/build-native.sh
2026-01-15 15:51:08 +08:00
Jose Olarte III 20b33f6e31 fix(build): handle missing dependencies and Capacitor files during iOS build
Fixed build failures when test app dependencies aren't installed and when
Capacitor files don't exist during initial install.

Changes:
- Use `npx run-p` in test app build script to work without local install
- Add dependency check in build-native.sh before building Vue app
- Make fix-capacitor-plugins.js resilient to missing files during postinstall
  - Gracefully handles missing capacitor.plugins.json on first install
  - Provides clear messaging about when fixes will be applied
  - No longer exits with error when Capacitor hasn't been synced yet

This allows the build to complete successfully even when:
- npm dependencies aren't installed in test app
- Capacitor files don't exist yet (will be created during cap:sync:ios)

Files modified:
- scripts/build-native.sh
- test-apps/daily-notification-test/package.json
- test-apps/daily-notification-test/scripts/fix-capacitor-plugins.js
2026-01-15 15:37:32 +08:00
Jose Olarte III 630fd3de81 fix(ios): resolve SQLite linking conflicts with pkgx
Fixes iOS build failures caused by linker picking up macOS SQLite
libraries from pkgx instead of iOS system SQLite, resulting in
undefined symbol errors for all sqlite3 functions.

Changes:
- Explicitly link system SQLite library (-lsqlite3) in podspec
- Detect and unset pkgx environment variables during iOS builds
- Add warnings to guide users if manual intervention needed

The issue occurs when pkgx (or similar package managers) set
DYLD_LIBRARY_PATH or PKGX_DIR, causing the linker to find macOS
SQLite dylibs at /Users/*/.pkgx/sqlite.org/*/lib/libsqlite3.0.dylib
instead of the iOS system SQLite library.

This fix ensures the iOS build always uses the correct system SQLite
library regardless of environment variable interference.
2026-01-14 18:41:46 +08:00
Jose Olarte III aaac23111c chore(build): add clean-build script for troubleshooting
Adds a comprehensive clean script that removes all build artifacts,
caches, and dependencies to help reproduce build issues across
different development environments.

The script cleans:
- TypeScript build output (dist/)
- iOS plugin artifacts (Pods, Podfile.lock, build dirs)
- Android plugin artifacts (build dirs, optional .gradle cache)
- Test app artifacts (node_modules, dist/, iOS/Android builds)
- Optional: Xcode DerivedData, Gradle cache, node_modules reinstall

Usage:
  ./scripts/clean-build.sh              # Basic clean
  ./scripts/clean-build.sh --all        # Full clean with reinstall

This is particularly useful when troubleshooting build failures
that may be environment-specific (different Xcode, CocoaPods,
macOS, or Node versions).
2026-01-12 20:50:02 +08:00
Jose Olarte III d2a1041cc4 feat(ios): add missed rollover recovery for background/inactive app scenarios
Implement enhanced app launch recovery to detect and schedule missed rollover
notifications that occurred while the app was terminated, backgrounded, or
inactive.

Key improvements:
- Detect missed rollovers on app launch by checking for past notifications
  without next scheduled notification
- Add active rollover check when app becomes active (handles inactive app
  scenario where notifications fire silently)
- Calculate forward to future time when next scheduled time is in the past
  (handles delays > rollover interval)
- Enhance duplicate detection to exclude original notification from checks
- Retry rollover if previous attempt failed (rollover time set but no next
  notification exists)

Changes:
- DailyNotificationReactivationManager: Add detectAndProcessMissedRollovers()
  method and performActiveRolloverCheck() for app becoming active
- DailyNotificationReactivationManager: Enhance warm start scenario to check
  for missed rollovers
- DailyNotificationScheduler: Add forward calculation loop when next scheduled
  time is in the past
- DailyNotificationPlugin: Register observer for UIApplication.didBecomeActiveNotification
  to trigger rollover check when app becomes active

Fixes rollover scheduling for:
- App terminated: Rollover now detected and scheduled on next launch
- App inactive/backgrounded: Rollover detected when app becomes active
- Delayed recovery: Handles cases where app reopened after rollover interval
  has passed by calculating forward to next future time

All scenarios now properly schedule rollover notifications regardless of app
state when notification fires.
2026-01-09 20:02:40 +08:00
Jose Olarte III 243cbd08f1 docs(ios): add testing instructions for rollover interval
Add inline comments and documentation explaining how to temporarily
change rollover notification intervals from 24 hours to 2 minutes
for testing purposes. Comments specify exact line numbers and values
to change, making it easy to switch between production and testing
modes without losing context.

Changes:
- Add TESTING section to calculateNextScheduledTime() documentation
- Add inline TESTING comments at three change points:
  * Calendar date addition (24 hours → 2 minutes)
  * Fallback time calculation (24 hours → 2 minutes)
  * Duplicate prevention threshold (1 hour → 1 minute)

All code remains at production settings (24-hour intervals).
2026-01-08 21:25:37 +08:00
Jose Olarte III 7e93cbd771 fix(test-app): convert boolean pending to number in display
The pending field in NotificationStatus is a boolean, but the UI
was displaying it directly, causing "true" to appear instead of
a numeric count when notifications were scheduled.

Added a pendingCount computed property that converts boolean
values to numbers (true → 1, false → 0) while also handling
number types for future compatibility.
2026-01-08 19:00:55 +08:00
Jose Olarte III 6d64f71988 fix(ios): save rollover notification content to storage
Save notification content to storage immediately after scheduling
rollover notification so it can be retrieved when the notification
fires. Without this, processRollover fails to find the content
and cannot schedule the next notification.

The rollover flow creates a new notification with a new ID
(daily_rollover_*) but was only scheduling it with the system,
not saving it to storage. When the notification fired, the
lookup by ID failed because the content wasn't stored.

This matches the pattern used in DailyNotificationScheduleHelper
which saves content before scheduling.
2026-01-08 17:29:46 +08:00
Jose Olarte III 65379aedd6 refactor(test-app): extract reusable StatusList component
Created standardized StatusList component to eliminate duplicate status
display code across views. Standardized styling:
- Flexbox layout with space-between justification
- Border-bottom dividers (removed via :last-child)
- Optional status-based color coding via show-status-colors prop
- Consistent padding (12px 0) and spacing

Migrated HomeView and StatusView to use the new component:
- HomeView: Replaced inline status list, removed ~50 lines of duplicate CSS
- StatusView: Replaced diagnostics info items, removed ~25 lines of duplicate CSS
- Removed unused helper functions (getStatusType, getStatusDescription)
- Fixed TypeScript type assertions for status values
- Added diagnosticsItems computed property in StatusView

Reduces code duplication by ~75 lines and provides single source of truth
for status list styling across the application.
2026-01-07 21:20:49 +08:00
Jose Olarte III 66c7eca33d refactor(test-app): simplify System Status section layout
Replaced StatusCard components with simpler inline list layout:
- Removed card bounding boxes and side padding
- Added horizontal dividers between status items
- Title and value on same line using grid layout (left/right justified)
- Reduced padding and margins for more compact display
- Removed unused StatusCard import
2026-01-07 18:53:16 +08:00
Jose Olarte III d88978259d fix(ios): correct userInfo scope error in notification delivery handler
Fixed compilation error where userInfo was referenced outside its scope
in handleNotificationDelivery error logging. Changed to use
notification.userInfo directly.
2026-01-07 18:52:45 +08:00
Jose Olarte III 66cbe763fc fix(ios): add diagnostic logging for rollover notification flow
Add comprehensive logging to trace rollover notification handling
from AppDelegate delivery through to next notification scheduling.
This enables diagnosis of why rollover notifications fail to
schedule the next 24-hour notification.

Changes:
- Log observer registration on plugin load
- Log handler entry and data extraction in handleNotificationDelivery
- Log processing steps in processRollover including:
  * Missing scheduler/storage detection
  * Content lookup failures with available IDs
  * ScheduleNextNotification success/failure

These logs will help identify whether the issue is:
- Observer not receiving notifications
- Content missing from storage
- Scheduling logic failing silently
2026-01-07 16:51:40 +08:00
Jose Olarte III 766d56c661 feat(test-app): default notification time to current + 3 minutes
Replace hardcoded '09:00' default with dynamic calculation that sets
the notification time to 3 minutes from now (rounded up to next minute).
This makes it more convenient for users to quickly test notifications
without manually adjusting the time field.
2026-01-06 19:27:05 +08:00
Jose Olarte III f446362984 fix(ui): make notification countdown update reactively
The "Time Until" field in NotificationsView was not updating when
refresh was clicked or over time because the computed property used
Date.now() directly, which is evaluated once and doesn't trigger
reactive updates.

Changes:
- Add reactive currentTime property that updates every second
- Set up interval in mounted() to keep countdown live
- Clean up interval in beforeUnmount() to prevent memory leaks
- Update timeUntilNext computed to use reactive currentTime
- Update refreshNotifications() to immediately refresh currentTime

The countdown now updates automatically every second and immediately
when the refresh button is clicked, without requiring navigation away
and back to the view.
2026-01-06 17:38:59 +08:00
Jose Olarte III 20f15ebcea fix(ios): post notification delivery event to trigger rollover
The AppDelegate's willPresent method was not posting the
DailyNotificationDelivered notification event that the plugin
observes to trigger rollover scheduling. This caused rollover
notifications (scheduled 24 hours after the current notification)
to never be created, even though the rollover logic was fully
implemented in the plugin.

The fix extracts notification_id and scheduled_time from the
notification's userInfo and posts them via NotificationCenter using
the decoupled pattern. This allows the plugin to detect notification
delivery and automatically schedule the next day's notification.

Rollover now works correctly: when a notification is delivered,
the plugin schedules the next notification for 24 hours later,
and the NotificationsView properly displays the next notification
timestamp.
2026-01-06 17:19:18 +08:00
Jose Olarte III b230a8e7b5 feat(test-app): add emoji icons to platform and status badges
Add platform-specific emojis (🤖 Android, 🍎 iOS, 🌐 Web) and status
indicators (✅ Ready, ⚠️ Not Ready, ❓ Unknown) to improve visual
clarity in the home view welcome section.
2026-01-06 16:23:20 +08:00
Jose Olarte III f97b3bec5b feat(test-apps/daily-notification-test): implement notification status display in NotificationsView
Replace placeholder content with functional notification status viewer that
displays scheduled notifications and rollover information. Enables verification
of both manually scheduled notifications and automatic rollover scheduling
(24-hour recurrence).

Features:
- Display next scheduled notification time with formatted date/time
- Show time until next notification (days, hours, minutes)
- Display pending notification count
- Show last notification delivery time
- Display rollover status (enabled/disabled, last rollover time) when available
- Additional status info (enabled, scheduled, errors)
- Manual refresh button for status updates
- Loading and error states with platform detection

Uses typed plugin wrapper for type safety with fallback to raw plugin access
for rollover fields not in TypeScript interface (iOS-specific fields).
2026-01-05 20:57:15 +08:00
Jose Olarte III 911aabf671 fix(test-app): use Capacitor for platform detection in views
Replace hardcoded platform values and appStore.platform with
Capacitor.getPlatform() for accurate runtime platform detection.

Changes:
- HomeView: Use Capacitor.getPlatform() instead of appStore.platform
- StatusView: Use Capacitor.getPlatform() for initial diagnostics
- diagnostics-export: Replace hardcoded 'Android' with Capacitor detection
- StatusView: Fix timezone to use actual timezone instead of 'Unknown'
- diagnostics-export: Show 'N/A' for API Level on iOS/web (Android-specific)

Fixes platform badge showing "web" on iOS native and diagnostics
showing incorrect platform information.
2026-01-05 20:38:55 +08:00
Jose Olarte III 5ae63e6f6d fix(test-app): constrain JSON diagnostics output width
The Raw Diagnostics pre element was overflowing its container and
causing the entire page to require horizontal scrolling, making field
values in the diagnostics info section inaccessible.

Added min-width: 0 and overflow: hidden to .diagnostics-json container
to allow proper grid constraint propagation. Added max-width: 100%,
width: 100%, and box-sizing: border-box to .json-output to ensure
it respects container bounds while maintaining horizontal scroll
within the pre element itself.
2026-01-05 20:21:48 +08:00
Jose Olarte III edc4082f72 feat(ios): implement testAlarm method and fix plugin discovery
Add testAlarm() method to iOS plugin for quick notification testing.
Fix plugin method discovery by registering testAlarm in CAPBridgedPlugin
pluginMethods array. Add force-load code in AppDelegate to ensure plugin
is discovered by Capacitor's objc_getClassList scan.

Changes:
- Add testAlarm() implementation in DailyNotificationPlugin.swift
- Register testAlarm in pluginMethods array (required for Capacitor discovery)
- Add force-load code in test app AppDelegate (matches working ios-test-app)
- Add UNUserNotificationCenterDelegate to show notifications in foreground
- Add test notification button to ScheduleView with immediate feedback
- Add debug logging for method discovery and plugin loading

Fixes issue where testAlarm was implemented but returned "UNIMPLEMENTED"
because it wasn't registered in the pluginMethods array. Also ensures
plugin class is loaded before Capacitor's discovery phase.
2025-12-31 17:25:52 +08:00
Jose Olarte III c8919480d9 fix(test-app): conditionally call getExactAlarmStatus on Android only
getExactAlarmStatus() is an Android-only API and was causing
UNIMPLEMENTED errors on iOS. Now only calls the method on Android
platforms, with safe defaults for iOS.

- Check platform before calling getExactAlarmStatus()
- Use default values { enabled: false, supported: false } on iOS
- Add error handling for Android call failures
- Make exact alarm status logging conditional on Android
2025-12-31 14:27:08 +08:00
Jose Olarte III 2d353c877c feat(test-app): add dedicated Request Permissions view
Create a new RequestPermissionsView that provides a dedicated interface
for checking and requesting notification permissions, matching the
functionality found in the iOS test app.

The view includes:
- Status display with color-coded states (requesting/granted/error)
- Permission status grid showing notifications, exact alarm, and
  background refresh status
- Request Permissions button with same functionality as iOS test app
- Platform-specific settings access buttons
- Automatic status refresh on mount

Updated HomeView to navigate to the new view instead of calling
permission request function directly, providing better UX with
dedicated screen for permission management.
2025-12-31 14:20:49 +08:00
Jose Olarte III 2f0d733b10 feat(test-app): add back navigation and improve mobile layout
- Add back buttons to all sub-views (Schedule, Status, Notifications, History, Logs, Settings, UserZero, About)
- Fix router navigation by importing router instance directly (resolves TypeScript errors with vue-facing-decorator)
- Update back button styling: flex layout with page title, arrow-only label
- Fix "Check Status" action to navigate to StatusView instead of checking status inline
- Remove horizontal padding on mobile views (max-width 768px) for edge-to-edge layout
- Simplify badge styling in HomeView (remove padding and border-radius)
2025-12-31 14:04:42 +08:00