Commit Graph

544 Commits

Author SHA1 Message Date
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
1dc0052b39 remove references to USE_EXACT_ALARM for Android 2026-03-06 21:11:27 -07: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
Matthew
dd55c6b4e1 fix(ios): use wrapper script for pod install in cap:sync:ios
The cap:sync:ios npm script was failing with "pod: command not found"
because npm scripts don't inherit the same PATH environment as shell
scripts, preventing detection of pod installed via rbenv shims.

Added pod-install.sh wrapper script that:
- Detects pod via command -v or rbenv shims ($HOME/.rbenv/shims/pod)
- Executes pod install with the found command
- Matches the pod detection logic used in build-native.sh

Updated cap:sync:ios script to use the wrapper instead of calling
pod install directly, ensuring consistent pod detection across
all build contexts.
2026-01-15 23:05:45 -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