# Daily Notification Plugin: Alignment Outline **Purpose:** Checklist of changes/additions needed in this app to align with the test app (`daily-notification-plugin/test-apps/daily-notification-test`) so that: 1. **Rollover recovery** (and rollover itself) works. 2. **Notifications show when the app is in the foreground** (not only background/closed). 3. **Plugin loads at app launch** so recovery runs after reboot without the user opening notification UI. **Reference:** Test app at `/Users/aardimus/Sites/trentlarson/daily-notification-plugin_test/daily-notification-plugin/test-apps/daily-notification-test` --- ## 1. iOS AppDelegate **File:** `ios/App/App/AppDelegate.swift` ### 1.1 Add imports - [ ] `import UserNotifications` - [ ] Import the Daily Notification plugin framework (Swift module name: **TimesafariDailyNotificationPlugin** per this app’s Podfile; test app uses **DailyNotificationPlugin**) ### 1.2 Conform to `UNUserNotificationCenterDelegate` - [ ] Add `, UNUserNotificationCenterDelegate` to the class declaration: `class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate` ### 1.3 Force-load plugin at launch - [ ] In `application(_:didFinishLaunchingWithOptions:)`, **before** other setup, add logic to force-load the plugin class (e.g. `_ = DailyNotificationPlugin.self` or the class exposed by the TimesafariDailyNotificationPlugin pod) so that the plugin’s `load()` (and thus `performRecovery()`) runs at app launch, not only when JS first calls the plugin. ### 1.4 Set notification center delegate - [ ] In `didFinishLaunchingWithOptions`, set: `UNUserNotificationCenter.current().delegate = self` - [ ] In `applicationDidBecomeActive`, **re-set** the same delegate (in case Capacitor or another component clears it). ### 1.5 Implement `userNotificationCenter(_:willPresent:withCompletionHandler:)` - [ ] When a notification is delivered (including in foreground), read `notification_id` and `scheduled_time` from `notification.request.content.userInfo`. - [ ] Post rollover event: `NotificationCenter.default.post(name: NSNotification.Name("DailyNotificationDelivered"), object: nil, userInfo: ["notification_id": id, "scheduled_time": scheduledTime])` - [ ] Call completion handler with presentation options so the notification is shown in foreground, e.g. `completionHandler([.banner, .sound, .badge])` (use `.alert` on iOS 13 if needed). ### 1.6 Implement `userNotificationCenter(_:didReceive:withCompletionHandler:)` - [ ] Handle notification tap/interaction; call `completionHandler()` when done. --- ## 2. Android Manifest **File:** `android/app/src/main/AndroidManifest.xml` ### 2.1 Fix receiver placement - [ ] Move the two `` elements (**DailyNotificationReceiver** and **BootReceiver**) **inside** the `` block (e.g. after `...` and before `...`). - [ ] Remove the stray second `` so there is a single `...` containing activity, receivers, and provider. ### 2.2 (Optional) Add NotifyReceiver - [ ] If the plugin’s Android integration expects **NotifyReceiver** for alarm-based delivery, add a `` for `org.timesafari.dailynotification.NotifyReceiver` inside `` (see test app manifest for exact declaration). ### 2.3 (Optional) BootReceiver options - [ ] Consider aligning with test app: add `android:directBootAware="true"`, `android:exported="true"`, and intent-filter actions `LOCKED_BOOT_COMPLETED`, `MY_PACKAGE_REPLACED`, `PACKAGE_REPLACED` if you need the same boot/update behavior. --- ## 3. Capacitor / JS startup (optional but recommended) **File:** `src/main.capacitor.ts` (or the main entry used for native builds) ### 3.1 Load plugin at startup - [ ] Add a top-level import or an early call that touches the Daily Notification plugin so the JS side loads it at app startup (e.g. `import "@timesafari/daily-notification-plugin"` or a small init that calls `getRebootRecoveryStatus()` or `configure()`). This ensures the plugin is loaded as soon as the app runs; together with the iOS force-load in AppDelegate, recovery runs at launch. --- ## 4. Plugin configuration (optional) - [ ] If you use the native fetcher or need plugin config (db path, storage, etc.), call `DailyNotification.configure()` and/or `configureNativeFetcher()` when appropriate (e.g. after login or when notification UI is first used), similar to the test app’s `configureNativeFetcher()` in HomeView. --- ## 5. Summary table | Area | Change / addition | |-------------------------|------------------------------------------------------------------------------------| | **iOS AppDelegate** | Conform to `UNUserNotificationCenterDelegate`; set delegate; force-load plugin; implement `willPresent` (post `DailyNotificationDelivered` + show in foreground) and `didReceive`. | | **Android manifest** | Move DailyNotificationReceiver and BootReceiver inside ``; remove duplicate ``; optionally add NotifyReceiver and BootReceiver options. | | **main.capacitor.ts** | Optionally import or call plugin at startup so it (and recovery) load at launch. | | **Plugin config** | Optionally call `configure()` / `configureNativeFetcher()` where appropriate. | --- ## 6. Verification After making the changes: - [ ] **iOS:** Build and run; trigger a daily notification and confirm it appears when the app is in the foreground. - [ ] **iOS:** Confirm rollover (next day’s schedule) still occurs after a notification fires (check logs for `DNP-ROLLOVER` / `DailyNotificationDelivered`). - [ ] **iOS:** Restart the app (or reboot) and confirm recovery runs without opening the notification settings screen (e.g. logs show plugin load and recovery). - [ ] **Android:** Build and run; confirm receivers are registered (no manifest errors) and that notifications and boot recovery behave as expected.