diff --git a/android/app/build.gradle b/android/app/build.gradle index c1cc5439..b1babb49 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -101,6 +101,13 @@ dependencies { implementation project(':capacitor-android') implementation project(':capacitor-community-sqlite') implementation "androidx.biometric:biometric:1.2.0-alpha05" + + // Daily Notification Plugin dependencies + implementation "androidx.room:room-runtime:2.6.1" + implementation "androidx.work:work-runtime-ktx:2.9.0" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3" + annotationProcessor "androidx.room:room-compiler:2.6.1" + testImplementation "junit:junit:$junitVersion" androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion" diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 46e22c04..37463376 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -52,6 +52,25 @@ + + + + + + + + + + + + + @@ -59,4 +78,11 @@ + + + + + + + diff --git a/android/app/src/main/java/app/timesafari/MainActivity.java b/android/app/src/main/java/app/timesafari/MainActivity.java index 387b6ac9..2e85dfea 100644 --- a/android/app/src/main/java/app/timesafari/MainActivity.java +++ b/android/app/src/main/java/app/timesafari/MainActivity.java @@ -67,6 +67,9 @@ public class MainActivity extends BridgeActivity { // Register SharedImage plugin registerPlugin(SharedImagePlugin.class); + // Register DailyNotification plugin + registerPlugin(com.timesafari.dailynotification.DailyNotificationPlugin.class); + // Initialize SQLite //registerPlugin(SQLite.class); diff --git a/doc/daily-notification-plugin-architecture.md b/doc/daily-notification-plugin-architecture.md new file mode 100644 index 00000000..c2dbe424 --- /dev/null +++ b/doc/daily-notification-plugin-architecture.md @@ -0,0 +1,312 @@ +# Daily Notification Plugin - Architecture Overview + +## System Architecture + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Vue Components │ +│ (PushNotificationPermission.vue, AccountViewView.vue, etc.) │ +└───────────────────────────┬─────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ NotificationService (Factory) │ +│ - Platform detection via Capacitor API │ +│ - Singleton pattern │ +│ - Returns appropriate implementation │ +└───────────────────────────┬─────────────────────────────────────┘ + │ + ┌───────────┴────────────┐ + ▼ ▼ +┌───────────────────────────┐ ┌────────────────────────────┐ +│ NativeNotificationService │ │ WebPushNotificationService │ +│ │ │ │ +│ iOS/Android │ │ Web/PWA │ +│ - UNUserNotificationCenter│ │ - Web Push API │ +│ - NotificationManager │ │ - Service Workers │ +│ - AlarmManager │ │ - VAPID keys │ +│ - Background tasks │ │ - Push server │ +└─────────────┬─────────────┘ └────────────┬───────────────┘ + │ │ + ▼ ▼ +┌─────────────────────────┐ ┌──────────────────────────────┐ +│ DailyNotificationPlugin│ │ Existing Web Push Logic │ +│ (Capacitor Plugin) │ │ (PushNotificationPermission)│ +│ │ │ │ +│ - Native iOS code │ │ - Service worker │ +│ - Native Android code │ │ - VAPID subscription │ +│ - SQLite storage │ │ - Push server integration │ +└─────────────────────────┘ └──────────────────────────────┘ +``` + +## Platform Decision Flow + +``` +User Action: Schedule Notification + │ + ▼ + NotificationService.getInstance() + │ + ├──> Check: Capacitor.isNativePlatform() + │ + ┌────┴─────┐ + │ │ + YES NO + │ │ + ▼ ▼ +Native Web/PWA +Service Service + │ │ + ▼ ▼ +Plugin Web Push +``` + +## Data Flow Example: Scheduling a Notification + +### Native Platform (iOS/Android) +``` +1. User clicks "Enable Notifications" + │ +2. PushNotificationPermission.vue + │ + └─> NotificationService.getInstance() + │ + └─> Returns NativeNotificationService (detected iOS/Android) + │ + └─> nativeService.requestPermissions() + │ + └─> DailyNotification.requestPermissions() [Capacitor Plugin] + │ + └─> Native code requests OS permissions + │ + └─> Returns: { granted: true/false } + +3. User sets time & message + │ +4. nativeService.scheduleDailyNotification({ time: '09:00', ... }) + │ + └─> DailyNotification.scheduleDailyReminder({ ... }) + │ + └─> Native code: + - Stores in SQLite + - Schedules AlarmManager (Android) or UNNotificationRequest (iOS) + - Returns: success/failure + +5. At 9:00 AM: + - Android: AlarmManager triggers → DailyNotificationReceiver + - iOS: UNUserNotificationCenter triggers notification + - Notification appears even if app is closed +``` + +### Web Platform +``` +1. User clicks "Enable Notifications" + │ +2. PushNotificationPermission.vue + │ + └─> NotificationService.getInstance() + │ + └─> Returns WebPushNotificationService (detected web) + │ + └─> webService.requestPermissions() + │ + └─> Notification.requestPermission() [Browser API] + │ + └─> Returns: 'granted'/'denied'/'default' + +3. User sets time & message + │ +4. webService.scheduleDailyNotification({ ... }) + │ + └─> [TODO] Subscribe to push service with VAPID + │ + └─> Send subscription to server with schedule time + │ + └─> Server sends push at scheduled time + │ + └─> Service worker receives → shows notification +``` + +## File Organization + +``` +src/ +├── plugins/ +│ └── DailyNotificationPlugin.ts [Plugin registration] +│ +├── services/ +│ └── notifications/ +│ ├── index.ts [Barrel export] +│ ├── NotificationService.ts [Factory + Interface] +│ ├── NativeNotificationService.ts [iOS/Android impl] +│ └── WebPushNotificationService.ts [Web impl stub] +│ +├── components/ +│ └── PushNotificationPermission.vue [UI - to be updated] +│ +└── views/ + └── AccountViewView.vue [Settings UI] +``` + +## Key Design Decisions + +### 1. **Unified Interface** +- Single `NotificationServiceInterface` for all platforms +- Consistent API regardless of underlying implementation +- Type-safe across TypeScript codebase + +### 2. **Runtime Platform Detection** +- No build-time configuration needed +- Same code bundle for all platforms +- Factory pattern selects implementation automatically + +### 3. **Coexistence Strategy** +- Web Push and Native run on different platforms +- No conflicts - mutually exclusive at runtime +- Allows gradual migration and testing + +### 4. **Singleton Pattern** +- One service instance per app lifecycle +- Efficient resource usage +- Consistent state management + +## Permission Flow + +### Android +``` +App Launch + ↓ +Check if POST_NOTIFICATIONS granted (API 33+) + │ + ├─> YES: Ready to schedule + │ + └─> NO: Request runtime permission + ↓ + Show system dialog + ↓ + User grants/denies + ↓ + Schedule notifications (if granted) +``` + +### iOS +``` +App Launch + ↓ +Check notification authorization status + │ + ├─> authorized: Ready to schedule + │ + ├─> notDetermined: Request permission + │ ↓ + │ Show system dialog + │ ↓ + │ User grants/denies + │ + └─> denied: Guide user to Settings +``` + +### Web +``` +App Load + ↓ +Check Notification.permission + │ + ├─> "granted": Ready to subscribe + │ + ├─> "default": Request permission + │ ↓ + │ Show browser prompt + │ ↓ + │ User grants/denies + │ + └─> "denied": Cannot show notifications +``` + +## Error Handling Strategy + +```typescript +// All methods return promises with success/failure +try { + const granted = await service.requestPermissions(); + if (granted) { + const success = await service.scheduleDailyNotification({...}); + if (success) { + // Show success message + } else { + // Show scheduling error + } + } else { + // Show permission denied message + } +} catch (error) { + // Log error and show generic error message + logger.error('Notification error:', error); +} +``` + +## Background Execution + +### Native (iOS/Android) +- ✅ Full background support +- ✅ Survives app termination +- ✅ Survives device reboot (with BootReceiver) +- ✅ Exact alarm scheduling +- ✅ Works offline + +### Web/PWA +- ⚠️ Limited background support +- ⚠️ Requires active service worker +- ⚠️ Browser/OS dependent +- ❌ Needs network for delivery +- ⚠️ iOS: Only on Home Screen PWAs (16.4+) + +## Storage + +### Native +``` +DailyNotificationPlugin + ↓ +SQLite Database (Room/Core Data) + ↓ +Stores: +- Schedule configurations +- Content cache +- Delivery history +- Callback registrations +``` + +### Web +``` +Web Push + ↓ +IndexedDB (via Dexie) + ↓ +Stores: +- Settings (notifyingNewActivityTime, etc.) +- Push subscription info +- VAPID keys +``` + +## Testing Strategy + +### Unit Testing +- Mock `Capacitor.isNativePlatform()` to test both paths +- Test factory returns correct implementation +- Test each service implementation independently + +### Integration Testing +- Test on actual devices (iOS/Android) +- Test in browsers (Chrome, Safari, Firefox) +- Verify notification delivery +- Test permission flows + +### E2E Testing +- Schedule notification → Wait → Verify delivery +- Test app restart scenarios +- Test device reboot scenarios +- Test permission denial recovery + +--- + +**Key Takeaway**: The architecture provides a clean separation between platforms while maintaining a unified API for Vue components. Platform detection happens automatically at runtime, and the appropriate notification system is used transparently. diff --git a/doc/daily-notification-plugin-checklist.md b/doc/daily-notification-plugin-checklist.md new file mode 100644 index 00000000..2d6024ee --- /dev/null +++ b/doc/daily-notification-plugin-checklist.md @@ -0,0 +1,341 @@ +# Daily Notification Plugin - Integration Checklist + +**Integration Date**: 2026-01-21 +**Plugin Version**: 1.0.11 +**Status**: Phase 1 Complete ✅ + +--- + +## Phase 1: Infrastructure Setup ✅ COMPLETE + +### Code Files +- [x] Created `src/plugins/DailyNotificationPlugin.ts` +- [x] Created `src/services/notifications/NotificationService.ts` +- [x] Created `src/services/notifications/NativeNotificationService.ts` +- [x] Created `src/services/notifications/WebPushNotificationService.ts` +- [x] Created `src/services/notifications/index.ts` + +### Android Configuration +- [x] Added permissions to `AndroidManifest.xml`: + - [x] `POST_NOTIFICATIONS` + - [x] `SCHEDULE_EXACT_ALARM` + - [x] `USE_EXACT_ALARM` + - [x] `RECEIVE_BOOT_COMPLETED` + - [x] `WAKE_LOCK` +- [x] Registered receivers in `AndroidManifest.xml`: + - [x] `DailyNotificationReceiver` + - [x] `BootReceiver` +- [x] Added dependencies to `build.gradle`: + - [x] Room (`androidx.room:room-runtime:2.6.1`) + - [x] WorkManager (`androidx.work:work-runtime-ktx:2.9.0`) + - [x] Coroutines (`org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3`) + - [x] Room Compiler (`androidx.room:room-compiler:2.6.1`) +- [x] Registered plugin in `MainActivity.java` + +### iOS Configuration +- [x] Added to `Info.plist`: + - [x] `UIBackgroundModes` (fetch, processing) + - [x] `BGTaskSchedulerPermittedIdentifiers` + - [x] `NSUserNotificationAlertStyle` +- [ ] ⚠️ **MANUAL STEP**: Xcode capabilities (see Phase 5) + +### Documentation +- [x] Created `doc/daily-notification-plugin-integration.md` +- [x] Created `doc/daily-notification-plugin-integration-summary.md` +- [x] Created `doc/daily-notification-plugin-architecture.md` +- [x] Created this checklist + +--- + +## Phase 2: UI Integration ⏳ TODO + +### Update Components +- [ ] Modify `PushNotificationPermission.vue`: + - [ ] Import `NotificationService` + - [ ] Replace direct web push calls with service methods + - [ ] Add platform-aware messaging + - [ ] Test permission flow + - [ ] Test notification scheduling + +### Update Views +- [ ] Update `AccountViewView.vue`: + - [ ] Use `NotificationService` for status checks + - [ ] Add platform indicator + - [ ] Test settings display + +### Settings Integration +- [ ] Verify settings save/load correctly: + - [ ] `notifyingNewActivityTime` for native + - [ ] `notifyingReminderMessage` for native + - [ ] `notifyingReminderTime` for native + - [ ] Existing web push settings preserved + +--- + +## Phase 3: Web Push Integration ⏳ TODO + +### Wire WebPushNotificationService +- [ ] Extract subscription logic from `PushNotificationPermission.vue` +- [ ] Implement `scheduleDailyNotification()` method +- [ ] Implement `cancelDailyNotification()` method +- [ ] Implement `getStatus()` method +- [ ] Test web platform notification flow + +### Server Integration +- [ ] Verify web push server endpoints still work +- [ ] Test subscription/unsubscription +- [ ] Test scheduled message delivery + +--- + +## Phase 4: Testing ⏳ TODO + +### Desktop Development +- [ ] Code compiles without errors +- [ ] ESLint passes +- [ ] TypeScript types are correct +- [ ] Platform detection works in browser console + +### Android Emulator +- [ ] App builds successfully +- [ ] Plugin loads without errors +- [ ] Can open app and navigate +- [ ] No JavaScript console errors + +### Android Device (Real) +- [ ] Request permissions dialog appears +- [ ] Permissions can be granted +- [ ] Schedule notification succeeds +- [ ] Notification appears at scheduled time +- [ ] Notification survives app close +- [ ] Notification survives device reboot +- [ ] Notification can be cancelled + +### iOS Simulator +- [ ] App builds successfully +- [ ] Plugin loads without errors +- [ ] Can open app and navigate +- [ ] No JavaScript console errors + +### iOS Device (Real) +- [ ] Request permissions dialog appears +- [ ] Permissions can be granted +- [ ] Schedule notification succeeds +- [ ] Notification appears at scheduled time +- [ ] Background fetch works +- [ ] Notification survives app close +- [ ] Notification can be cancelled + +### Web Browser +- [ ] Existing web push still works +- [ ] No JavaScript errors +- [ ] Platform detection selects web service +- [ ] Permission flow works +- [ ] Subscription works + +--- + +## Phase 5: iOS Xcode Setup ⚠️ MANUAL REQUIRED + +### Open Xcode Project +```bash +cd ios +open App/App.xcodeproj +``` + +### Configure Capabilities +- [ ] Select "App" target in project navigator +- [ ] Go to "Signing & Capabilities" tab +- [ ] Click "+ Capability" button +- [ ] Add "Background Modes": + - [ ] Enable "Background fetch" + - [ ] Enable "Background processing" +- [ ] Click "+ Capability" button again +- [ ] Add "Push Notifications" (if using remote notifications) + +### Install CocoaPods +```bash +cd ios +pod install +cd .. +``` +- [ ] Run `pod install` successfully +- [ ] Verify `CapacitorDailyNotification` pod is installed + +### Verify Configuration +- [ ] Build succeeds in Xcode +- [ ] No capability warnings +- [ ] No pod errors +- [ ] Can run on simulator + +--- + +## Phase 6: Build & Deploy ⏳ TODO + +### Sync Capacitor +```bash +npx cap sync +``` +- [ ] Sync completes without errors +- [ ] Plugin files copied to native projects + +### Build Android +```bash +npm run build:android:debug +``` +- [ ] Build succeeds +- [ ] APK/AAB generated +- [ ] Can install on device/emulator + +### Build iOS +```bash +npm run build:ios:debug +``` +- [ ] Build succeeds +- [ ] IPA generated (if release) +- [ ] Can install on device/simulator + +### Test Production Builds +- [ ] Android release build works +- [ ] iOS release build works +- [ ] Notifications work in production + +--- + +## Troubleshooting Checklist + +### Android Issues + +#### Notifications Not Appearing +- [ ] Verified `DailyNotificationReceiver` is in AndroidManifest.xml +- [ ] Checked logcat for errors: `adb logcat | grep DailyNotification` +- [ ] Verified permissions granted in app settings +- [ ] Checked "Exact alarms" permission (Android 12+) +- [ ] Verified notification channel is created + +#### Build Errors +- [ ] Verified all dependencies in build.gradle +- [ ] Ran `./gradlew clean` and rebuilt +- [ ] Verified Kotlin version compatibility +- [ ] Checked for conflicting dependencies + +### iOS Issues + +#### Notifications Not Appearing +- [ ] Verified Background Modes enabled in Xcode +- [ ] Checked Xcode console for errors +- [ ] Verified permissions granted in Settings app +- [ ] Tested on real device (not just simulator) +- [ ] Checked BGTaskScheduler identifiers match Info.plist + +#### Build Errors +- [ ] Ran `pod install` successfully +- [ ] Verified deployment target is iOS 13.0+ +- [ ] Checked for pod conflicts +- [ ] Cleaned build folder (Xcode → Product → Clean Build Folder) + +### Web Issues + +#### Web Push Not Working +- [ ] Verified service worker is registered +- [ ] Checked browser console for errors +- [ ] Verified VAPID keys are correct +- [ ] Tested in supported browser (Chrome 42+, Firefox) +- [ ] Checked push server is running + +#### Permission Issues +- [ ] Verified permissions not blocked in browser +- [ ] Checked site settings in browser +- [ ] Verified HTTPS connection (required for web push) + +--- + +## Verification Commands + +### Check Plugin is Installed +```bash +npm list @timesafari/daily-notification-plugin +``` + +### Check Capacitor Sync +```bash +npx cap ls +``` + +### Check Android Build +```bash +cd android +./gradlew clean +./gradlew assembleDebug +``` + +### Check iOS Build +```bash +cd ios +pod install +xcodebuild -workspace App/App.xcworkspace -scheme App -configuration Debug build +``` + +### Check TypeScript +```bash +npm run type-check +``` + +### Check Linting +```bash +npm run lint +``` + +--- + +## Next Immediate Actions + +1. **Run Capacitor Sync**: + ```bash + npx cap sync + ``` + +2. **For iOS Development**: + ```bash + cd ios + open App/App.xcodeproj + # Enable Background Modes capability + pod install + cd .. + ``` + +3. **Test on Emulator/Simulator**: + ```bash + npm run build:android:debug # For Android + npm run build:ios:debug # For iOS + ``` + +4. **Update UI Components**: + - Start with `PushNotificationPermission.vue` + - Import and use `NotificationService` + +--- + +## Success Criteria + +- [x] **Phase 1**: All files created and configurations applied +- [ ] **Phase 2**: Components use NotificationService +- [ ] **Phase 3**: Web push integrated with service +- [ ] **Phase 4**: All tests pass on all platforms +- [ ] **Phase 5**: iOS capabilities configured in Xcode +- [ ] **Phase 6**: Production builds work on real devices + +--- + +## Questions or Issues? + +See documentation: +- Full guide: `doc/daily-notification-plugin-integration.md` +- Architecture: `doc/daily-notification-plugin-architecture.md` +- Summary: `doc/daily-notification-plugin-integration-summary.md` + +Plugin docs: `node_modules/@timesafari/daily-notification-plugin/README.md` + +--- + +**Current Status**: Ready for Phase 2 (UI Integration) 🚀 diff --git a/doc/daily-notification-plugin-integration-summary.md b/doc/daily-notification-plugin-integration-summary.md new file mode 100644 index 00000000..4c3c8075 --- /dev/null +++ b/doc/daily-notification-plugin-integration-summary.md @@ -0,0 +1,193 @@ +# Daily Notification Plugin Integration - Summary + +**Date**: 2026-01-21 +**Status**: ✅ Phase 1 Complete +**Next Phase**: UI Integration + +--- + +## What Was Completed + +### ✅ Plugin Infrastructure +1. **Plugin Registration**: `src/plugins/DailyNotificationPlugin.ts` + - Capacitor plugin registered with full TypeScript types + - Native-only (iOS/Android) + +2. **Service Abstraction**: `src/services/notifications/` + - `NotificationService.ts` - Platform detection & factory + - `NativeNotificationService.ts` - Native implementation + - `WebPushNotificationService.ts` - Web stub (for future) + - `index.ts` - Barrel export + +3. **Android Configuration**: + - ✅ Permissions added to `AndroidManifest.xml` + - ✅ Receivers registered (DailyNotificationReceiver, BootReceiver) + - ✅ Dependencies added to `build.gradle` (Room, WorkManager, Coroutines) + - ✅ Plugin registered in `MainActivity.java` + +4. **iOS Configuration**: + - ✅ Background modes added to `Info.plist` + - ✅ BGTaskScheduler identifiers configured + - ⚠️ **Requires manual Xcode setup** (capabilities) + +5. **Documentation**: `doc/daily-notification-plugin-integration.md` + +--- + +## Platform Support + +| Platform | Notification System | Status | +|----------|---------------------|--------| +| **iOS** | Native (UNUserNotificationCenter) | ✅ Configured | +| **Android** | Native (NotificationManager + AlarmManager) | ✅ Configured | +| **Web/PWA** | Web Push (existing) | 🔄 Coexists, not yet wired | +| **Electron** | Native (via Capacitor) | ✅ Ready | + +**Key Feature**: Both systems coexist using runtime platform detection. + +--- + +## Quick Start Usage + +```typescript +import { NotificationService } from '@/services/notifications'; + +// Automatically uses native on iOS/Android, web push on web +const service = NotificationService.getInstance(); + +// Request permissions +const granted = await service.requestPermissions(); + +if (granted) { + // Schedule daily notification at 9 AM + await service.scheduleDailyNotification({ + time: '09:00', + title: 'Daily Check-In', + body: 'Time to check your TimeSafari activity' + }); +} + +// Check status +const status = await service.getStatus(); +console.log('Notifications enabled:', status.enabled); +``` + +--- + +## Next Steps + +### Immediate (Phase 2) +1. **Update UI Components**: + - Modify `PushNotificationPermission.vue` to use `NotificationService` + - Add platform-aware messaging + - Test on simulator/emulator + +2. **iOS Xcode Setup** (Required): + ```bash + cd ios + open App/App.xcodeproj + ``` + - Enable "Background Modes" capability + - Enable "Push Notifications" capability + - Run `pod install` + +### Short-term (Phase 3) +3. **Wire Web Push**: Connect `WebPushNotificationService` to existing web push logic +4. **Test on Devices**: Real iOS and Android devices +5. **Update Settings**: Ensure notification preferences save correctly + +--- + +## Build & Sync + +```bash +# Sync native projects with web code +npx cap sync + +# Build for Android +npm run build:android:debug + +# Build for iOS (after Xcode setup) +cd ios && pod install && cd .. +npm run build:ios:debug +``` + +--- + +## Important Notes + +### ⚠️ Critical Requirements + +**Android**: +- `DailyNotificationReceiver` must be in AndroidManifest.xml (✅ done) +- Runtime permissions needed for Android 13+ (API 33+) +- Exact alarm permission for Android 12+ (API 31+) + +**iOS**: +- Background Modes capability must be enabled in Xcode (⚠️ manual) +- BGTaskScheduler identifiers must match Info.plist (✅ done) +- Test on real device (simulators have limitations) + +**Web**: +- Existing Web Push continues to work unchanged +- No conflicts - platform detection ensures correct system + +--- + +## Files Created/Modified + +### Created (8 files) +- `src/plugins/DailyNotificationPlugin.ts` +- `src/services/notifications/NotificationService.ts` +- `src/services/notifications/NativeNotificationService.ts` +- `src/services/notifications/WebPushNotificationService.ts` +- `src/services/notifications/index.ts` +- `doc/daily-notification-plugin-integration.md` +- `doc/daily-notification-plugin-integration-summary.md` + +### Modified (4 files) +- `android/app/src/main/AndroidManifest.xml` - Permissions + Receivers +- `android/app/build.gradle` - Dependencies +- `android/app/src/main/java/app/timesafari/MainActivity.java` - Plugin registration +- `ios/App/App/Info.plist` - Background modes + BGTaskScheduler + +--- + +## Testing Checklist + +### Before Device Testing +- [ ] Code compiles without errors +- [ ] Platform detection logic verified +- [ ] Service factory creates correct implementation + +### Android Device +- [ ] Request permissions (Android 13+) +- [ ] Schedule notification +- [ ] Notification appears at scheduled time +- [ ] Notification survives app close +- [ ] Notification survives device reboot + +### iOS Device +- [ ] Xcode capabilities enabled +- [ ] Request permissions +- [ ] Schedule notification +- [ ] Notification appears at scheduled time +- [ ] Background fetch works +- [ ] Notification survives app close + +### Web/PWA +- [ ] Existing web push still works +- [ ] No errors in console +- [ ] Platform detection selects web implementation + +--- + +## Questions? + +See full documentation: `doc/daily-notification-plugin-integration.md` + +Plugin README: `node_modules/@timesafari/daily-notification-plugin/README.md` + +--- + +**Status**: Ready for Phase 2 (UI Integration) 🚀 diff --git a/doc/daily-notification-plugin-integration.md b/doc/daily-notification-plugin-integration.md new file mode 100644 index 00000000..b5ac8a2f --- /dev/null +++ b/doc/daily-notification-plugin-integration.md @@ -0,0 +1,237 @@ +# Daily Notification Plugin Integration + +**Date**: 2026-01-21 +**Status**: ✅ Phase 1 Complete - Native Infrastructure +**Integration Type**: Native + Web Coexistence + +## Overview + +The Daily Notification Plugin has been integrated to provide native notification functionality for iOS and Android while maintaining existing Web Push for web/PWA builds. The integration uses platform detection to automatically select the appropriate notification system at runtime. + +## What Was Implemented + +### 1. **Plugin Registration** ✅ +- **File**: `src/plugins/DailyNotificationPlugin.ts` +- Registered Capacitor plugin with proper TypeScript types +- Native-only (no web implementation) + +### 2. **Service Abstraction Layer** ✅ +Created unified notification service with platform-specific implementations: + +- **`NotificationService.ts`**: Factory that selects implementation based on platform +- **`NativeNotificationService.ts`**: Wraps DailyNotificationPlugin for iOS/Android +- **`WebPushNotificationService.ts`**: Stub for future Web Push integration + +**Location**: `src/services/notifications/` + +**Key Features**: +- Unified interface (`NotificationServiceInterface`) +- Automatic platform detection via `Capacitor.isNativePlatform()` +- Type-safe implementation +- Singleton pattern for efficiency + +### 3. **Android Configuration** ✅ + +**Modified Files**: +- `android/app/src/main/AndroidManifest.xml` +- `android/app/build.gradle` +- `android/app/src/main/java/app/timesafari/MainActivity.java` + +**Changes**: +- ✅ Added notification permissions (POST_NOTIFICATIONS, SCHEDULE_EXACT_ALARM, etc.) +- ✅ Registered `DailyNotificationReceiver` (critical for alarm delivery) +- ✅ Registered `BootReceiver` (restores schedules after device restart) +- ✅ Added Room, WorkManager, and Coroutines dependencies +- ✅ Registered plugin in MainActivity + +### 4. **iOS Configuration** ✅ + +**Modified Files**: +- `ios/App/App/Info.plist` + +**Changes**: +- ✅ Added `UIBackgroundModes` (fetch, processing) +- ✅ Added `BGTaskSchedulerPermittedIdentifiers` for background tasks +- ✅ Added `NSUserNotificationAlertStyle` for alert-style notifications + +**Still Required** (Manual in Xcode): +- ⚠️ Enable "Background Modes" capability in Xcode + - Background fetch + - Background processing +- ⚠️ Enable "Push Notifications" capability (if using remote notifications) + +## Platform Behavior + +| Platform | Implementation | Status | +|----------|---------------|--------| +| **iOS** | DailyNotificationPlugin (native) | ✅ Configured | +| **Android** | DailyNotificationPlugin (native) | ✅ Configured | +| **Web/PWA** | Web Push (existing) | 🔄 Not yet wired up | +| **Electron** | Would use native | ✅ Ready | + +## Usage Example + +```typescript +import { NotificationService } from '@/services/notifications/NotificationService'; + +// Get the appropriate service for current platform +const notificationService = NotificationService.getInstance(); + +// Check platform +console.log('Platform:', NotificationService.getPlatform()); +console.log('Is native:', NotificationService.isNative()); + +// Request permissions +const granted = await notificationService.requestPermissions(); + +if (granted) { + // Schedule daily notification + await notificationService.scheduleDailyNotification({ + time: '09:00', + title: 'Daily Check-In', + body: 'Time to check your TimeSafari activity', + priority: 'normal' + }); +} + +// Check status +const status = await notificationService.getStatus(); +console.log('Enabled:', status.enabled); +console.log('Time:', status.scheduledTime); +``` + +## Next Steps + +### Phase 2: UI Integration +- [ ] Update `PushNotificationPermission.vue` to use `NotificationService` +- [ ] Add platform-aware UI messaging +- [ ] Update settings storage to work with both systems +- [ ] Test notification scheduling UI + +### Phase 3: Web Push Integration +- [ ] Wire `WebPushNotificationService` to existing PushNotificationPermission logic +- [ ] Extract web push subscription code into service methods +- [ ] Test web platform notification flow + +### Phase 4: Testing & Polish +- [ ] Test on real iOS device +- [ ] Test on real Android device (API 23+, API 33+) +- [ ] Test permission flows +- [ ] Test notification delivery +- [ ] Test app restart/reboot scenarios +- [ ] Verify background notification delivery + +### Phase 5: Xcode Configuration (iOS Only) +- [ ] Open `ios/App/App.xcodeproj` in Xcode +- [ ] Select App target → Signing & Capabilities +- [ ] Click "+ Capability" → Add "Background Modes" + - Enable "Background fetch" + - Enable "Background processing" +- [ ] Click "+ Capability" → Add "Push Notifications" (if using remote) +- [ ] Run `pod install` in `ios/` directory +- [ ] Build and test on device + +## Build Commands + +### Sync Capacitor +```bash +npx cap sync +# or +npx cap sync android +npx cap sync ios +``` + +### Build Android +```bash +npm run build:android +# or +npm run build:android:debug +``` + +### Build iOS +```bash +npm run build:ios +# or after Xcode setup: +cd ios && pod install && cd .. +npm run build:ios:debug +``` + +## Important Notes + +### Android +- **Critical**: `DailyNotificationReceiver` must be in AndroidManifest.xml +- Android 12+ (API 31+) requires `SCHEDULE_EXACT_ALARM` permission +- Android 13+ (API 33+) requires runtime `POST_NOTIFICATIONS` permission +- BootReceiver restores schedules after device restart + +### iOS +- **Critical**: Background modes must be enabled in Xcode capabilities +- iOS 13.0+ supported (already compatible with your deployment target) +- Background tasks use `BGTaskScheduler` +- User must grant notification permissions in Settings + +### Web +- Existing Web Push continues to work +- No conflicts with native implementation +- Platform detection ensures correct system is used + +## Files Modified + +### Created +- `src/plugins/DailyNotificationPlugin.ts` +- `src/services/notifications/NotificationService.ts` +- `src/services/notifications/NativeNotificationService.ts` +- `src/services/notifications/WebPushNotificationService.ts` + +### Modified +- `android/app/src/main/AndroidManifest.xml` +- `android/app/build.gradle` +- `android/app/src/main/java/app/timesafari/MainActivity.java` +- `ios/App/App/Info.plist` + +## Troubleshooting + +### Android: Notifications Not Appearing +1. Check that `DailyNotificationReceiver` is registered in AndroidManifest.xml +2. Verify permissions are requested at runtime (Android 13+) +3. Check that notification channel is created +4. Enable "Exact alarms" in app settings (Android 12+) + +### iOS: Background Tasks Not Running +1. Ensure Background Modes capability is enabled in Xcode +2. Check that BGTaskScheduler identifiers match Info.plist +3. Test on real device (simulator has limitations) +4. Check iOS Settings → Notifications → TimeSafari + +### Permission Issues +1. Request permissions before scheduling: `requestPermissions()` +2. Check permission status: `checkPermissions()` +3. Guide users to system settings if denied + +## Plugin Documentation + +For complete plugin documentation, see: +- Plugin README: `node_modules/@timesafari/daily-notification-plugin/README.md` +- Plugin version: 1.0.11 +- Repository: https://gitea.anomalistdesign.com/trent_larson/daily-notification-plugin + +## Testing Checklist + +- [ ] Android: Notification appears at scheduled time +- [ ] Android: Notification survives app close +- [ ] Android: Notification survives device reboot +- [ ] iOS: Notification appears at scheduled time +- [ ] iOS: Background fetch works +- [ ] iOS: Notification survives app close +- [ ] Web: Existing web push still works +- [ ] Platform detection works correctly +- [ ] Permission requests work on all platforms +- [ ] Status retrieval works correctly + +## Current Status + +✅ **Phase 1 Complete**: Native infrastructure configured +🔄 **Phase 2 In Progress**: Ready for UI integration +⏳ **Phase 3 Pending**: Web Push service integration +⏳ **Phase 4 Pending**: Testing and validation +⏳ **Phase 5 Pending**: Xcode capabilities setup diff --git a/ios/App/App/Info.plist b/ios/App/App/Info.plist index 5e3527b2..7e8cb33f 100644 --- a/ios/App/App/Info.plist +++ b/ios/App/App/Info.plist @@ -58,5 +58,17 @@ + UIBackgroundModes + + fetch + processing + + BGTaskSchedulerPermittedIdentifiers + + com.timesafari.dailynotification.content-fetch + com.timesafari.dailynotification.notification-delivery + + NSUserNotificationAlertStyle + alert diff --git a/src/plugins/DailyNotificationPlugin.ts b/src/plugins/DailyNotificationPlugin.ts new file mode 100644 index 00000000..a7ad7513 --- /dev/null +++ b/src/plugins/DailyNotificationPlugin.ts @@ -0,0 +1,38 @@ +/** + * Daily Notification Capacitor Plugin + * Provides native notification functionality for iOS and Android + * + * @see https://gitea.anomalistdesign.com/trent_larson/daily-notification-plugin + */ + +import { registerPlugin } from "@capacitor/core"; + +/** + * Type definitions for the Daily Notification Plugin + * Re-exported from the plugin package + */ +export type { + DailyNotificationPlugin, + DailyReminderOptions, + DailyReminderInfo, + PermissionStatusResult, + NotificationStatus, +} from "@timesafari/daily-notification-plugin"; + +// Import the plugin type +import type { DailyNotificationPlugin as DailyNotificationPluginType } from "@timesafari/daily-notification-plugin"; + +/** + * Register the Daily Notification plugin + * This plugin is only available on native platforms (iOS/Android) + * No web implementation - use Web Push for web/PWA builds + */ +const DailyNotification = registerPlugin( + "DailyNotification", + { + // No web implementation - native platforms only + // Web builds will use the existing Web Push system + }, +); + +export { DailyNotification }; diff --git a/src/services/notifications/NativeNotificationService.ts b/src/services/notifications/NativeNotificationService.ts new file mode 100644 index 00000000..518adf6e --- /dev/null +++ b/src/services/notifications/NativeNotificationService.ts @@ -0,0 +1,197 @@ +/** + * Native Notification Service + * + * Implementation of notification service using the DailyNotificationPlugin + * for native iOS and Android platforms. Provides full native notification + * capabilities including background delivery, exact alarm scheduling, and + * offline operation. + * + * @author Matthew Raymer + * @version 1.0.0 + * @since 2026-01-21 + */ + +import { DailyNotification } from "@/plugins/DailyNotificationPlugin"; +import type { + NotificationServiceInterface, + DailyNotificationOptions, + NotificationStatus, + PermissionStatus, +} from "./NotificationService"; +import { logger } from "@/utils/logger"; + +/** + * Native notification implementation using DailyNotificationPlugin + * Used for iOS and Android builds + * + * Features: + * - Full background notification support + * - Survives app restarts and device reboots + * - Exact alarm scheduling (Android 12+) + * - No network dependency for delivery + * - Native OS notification UI + */ +export class NativeNotificationService implements NotificationServiceInterface { + private readonly reminderId = "timesafari_daily_reminder"; + private readonly platformName = "native"; + + /** + * Native notifications are always supported on iOS/Android + */ + isSupported(): boolean { + return true; + } + + /** + * Request notification permissions from the OS + * Shows native permission dialog on first call + */ + async requestPermissions(): Promise { + try { + logger.debug("[NativeNotificationService] Requesting permissions"); + + const result = await DailyNotification.requestPermissions(); + + logger.debug("[NativeNotificationService] Permission result:", { + notificationsEnabled: result.notificationsEnabled, + allPermissionsGranted: result.allPermissionsGranted, + }); + + return result.allPermissionsGranted; + } catch (error) { + logger.error( + "[NativeNotificationService] Permission request failed:", + error, + ); + return false; + } + } + + /** + * Check current permission status without prompting + */ + async checkPermissions(): Promise { + try { + const status = await DailyNotification.checkPermissionStatus(); + + return { + granted: status.allPermissionsGranted, + details: { + notifications: status.notificationsEnabled, + exactAlarm: status.exactAlarmEnabled, + backgroundRefresh: true, // Native always has background capability + }, + }; + } catch (error) { + logger.error( + "[NativeNotificationService] Permission check failed:", + error, + ); + return { + granted: false, + details: { + notifications: false, + exactAlarm: false, + backgroundRefresh: false, + }, + }; + } + } + + /** + * Schedule a daily notification using native alarms + */ + async scheduleDailyNotification( + options: DailyNotificationOptions, + ): Promise { + try { + logger.info( + "[NativeNotificationService] Scheduling daily notification:", + { + time: options.time, + title: options.title, + }, + ); + + await DailyNotification.scheduleDailyReminder({ + id: this.reminderId, + title: options.title, + body: options.body, + time: options.time, // HH:mm format + repeatDaily: true, + sound: true, + vibration: true, + priority: options.priority || "normal", + }); + + logger.info( + "[NativeNotificationService] Daily notification scheduled successfully", + ); + return true; + } catch (error) { + logger.error("[NativeNotificationService] Schedule failed:", error); + return false; + } + } + + /** + * Cancel the daily notification + */ + async cancelDailyNotification(): Promise { + try { + logger.info("[NativeNotificationService] Cancelling daily notification"); + await DailyNotification.cancelDailyReminder(this.reminderId); + logger.info( + "[NativeNotificationService] Daily notification cancelled successfully", + ); + } catch (error) { + logger.error("[NativeNotificationService] Cancel failed:", error); + // Don't throw - cancellation failures are non-critical + } + } + + /** + * Get current notification status from the plugin + */ + async getStatus(): Promise { + try { + const reminders = await DailyNotification.getScheduledReminders(); + const reminder = reminders.reminders.find( + (r) => r.id === this.reminderId, + ); + + if (reminder) { + logger.debug("[NativeNotificationService] Found active reminder:", { + time: reminder.time, + isScheduled: reminder.isScheduled, + }); + + return { + enabled: reminder.isScheduled, + scheduledTime: reminder.time, + message: reminder.body, + notificationType: "native", + }; + } + + logger.debug("[NativeNotificationService] No active reminder found"); + return { + enabled: false, + notificationType: "native", + }; + } catch (error) { + logger.error("[NativeNotificationService] Get status failed:", error); + return { + enabled: false, + notificationType: "native", + }; + } + } + + /** + * Get platform identifier + */ + getPlatformName(): string { + return this.platformName; + } +} diff --git a/src/services/notifications/NotificationService.ts b/src/services/notifications/NotificationService.ts new file mode 100644 index 00000000..7d9090da --- /dev/null +++ b/src/services/notifications/NotificationService.ts @@ -0,0 +1,220 @@ +/** + * Unified Notification Service + * + * Provides a platform-agnostic interface for managing notifications across + * web and native platforms. Automatically delegates to the appropriate + * implementation based on the runtime platform: + * + * - Native platforms (iOS/Android): Uses DailyNotificationPlugin + * - Web/PWA: Uses Web Push with service workers and VAPID + * + * @author Matthew Raymer + * @version 1.0.0 + * @since 2026-01-21 + */ + +import { Capacitor } from "@capacitor/core"; +import { NativeNotificationService } from "./NativeNotificationService"; +import { WebPushNotificationService } from "./WebPushNotificationService"; + +/** + * Options for scheduling a daily notification + */ +export interface DailyNotificationOptions { + /** + * Time to send notification in HH:mm format (24-hour) + * Example: "09:00" for 9 AM, "17:30" for 5:30 PM + */ + time: string; + + /** + * Notification title + */ + title: string; + + /** + * Notification body/message + */ + body: string; + + /** + * Optional notification priority + * @default 'normal' + */ + priority?: "low" | "normal" | "high"; +} + +/** + * Current notification status + */ +export interface NotificationStatus { + /** + * Whether notifications are currently enabled + */ + enabled: boolean; + + /** + * Scheduled time in HH:mm format, if any + */ + scheduledTime?: string; + + /** + * Current notification message, if any + */ + message?: string; + + /** + * Platform-specific notification type identifier + */ + notificationType?: string; +} + +/** + * Permission status result + */ +export interface PermissionStatus { + /** + * Whether notification permissions are granted + */ + granted: boolean; + + /** + * Additional platform-specific permission details + */ + details?: { + notifications?: boolean; + exactAlarm?: boolean; + backgroundRefresh?: boolean; + }; +} + +/** + * Unified notification service interface + * All platform-specific implementations must conform to this interface + */ +export interface NotificationServiceInterface { + /** + * Check if notifications are supported on current platform + * @returns true if notifications are supported + */ + isSupported(): boolean; + + /** + * Request notification permissions from the user + * Shows system permission dialog on first call + * @returns Promise that resolves to true if permissions granted + */ + requestPermissions(): Promise; + + /** + * Check current notification permission status + * @returns Promise with permission status + */ + checkPermissions(): Promise; + + /** + * Schedule a daily notification/reminder + * @param options Notification configuration + * @returns Promise that resolves to true if scheduling succeeded + */ + scheduleDailyNotification( + options: DailyNotificationOptions, + ): Promise; + + /** + * Cancel all daily notifications + * @returns Promise that resolves when cancellation is complete + */ + cancelDailyNotification(): Promise; + + /** + * Get current notification status + * @returns Promise with current notification state + */ + getStatus(): Promise; + + /** + * Get the platform name for this service + * @returns Platform identifier (e.g., 'native', 'web') + */ + getPlatformName(): string; +} + +/** + * Notification Service Factory + * + * Singleton factory that creates and manages the appropriate notification + * service implementation based on the current platform. + * + * @example + * ```typescript + * const notificationService = NotificationService.getInstance(); + * const granted = await notificationService.requestPermissions(); + * if (granted) { + * await notificationService.scheduleDailyNotification({ + * time: '09:00', + * title: 'Daily Check-In', + * body: 'Time to check your TimeSafari activity' + * }); + * } + * ``` + */ +export class NotificationService { + private static instance: NotificationServiceInterface | null = null; + private static instanceCreated = false; + + /** + * Get the singleton notification service instance + * Creates the appropriate platform-specific implementation on first call + * + * @returns NotificationServiceInterface implementation for current platform + */ + static getInstance(): NotificationServiceInterface { + if (!this.instance) { + const platform = Capacitor.getPlatform(); + + if (!this.instanceCreated) { + // Log initialization for debugging (only happens once per app lifecycle) + // eslint-disable-next-line no-console + console.log( + `[NotificationService] Creating ${this.isNative() ? "native" : "web"} notification service for platform: ${platform}`, + ); + this.instanceCreated = true; + } + + if (this.isNative()) { + // iOS/Android: Use native plugin + this.instance = new NativeNotificationService(); + } else { + // Web/PWA: Use web push + this.instance = new WebPushNotificationService(); + } + } + return this.instance; + } + + /** + * Check if running on a native platform (iOS/Android) + * @returns true if running on iOS or Android + */ + static isNative(): boolean { + return Capacitor.isNativePlatform(); + } + + /** + * Get the current platform name + * @returns Platform identifier: 'ios', 'android', 'web', 'electron' + */ + static getPlatform(): string { + return Capacitor.getPlatform(); + } + + /** + * Reset the singleton instance (for testing purposes) + * @internal + */ + static reset(): void { + this.instance = null; + this.instanceCreated = false; + } +} diff --git a/src/services/notifications/WebPushNotificationService.ts b/src/services/notifications/WebPushNotificationService.ts new file mode 100644 index 00000000..fbc4bae3 --- /dev/null +++ b/src/services/notifications/WebPushNotificationService.ts @@ -0,0 +1,212 @@ +/** + * Web Push Notification Service + * + * Implementation of notification service using Web Push API with service workers + * for web/PWA builds. This is a wrapper around the existing PushNotificationPermission + * component logic, providing a consistent interface with the native notification service. + * + * @author Matthew Raymer + * @version 1.0.0 + * @since 2026-01-21 + */ + +import type { + NotificationServiceInterface, + DailyNotificationOptions, + NotificationStatus, + PermissionStatus, +} from "./NotificationService"; +import { logger } from "@/utils/logger"; + +/** + * Web Push notification implementation for web/PWA builds + * + * Features: + * - Uses Web Push API with VAPID authentication + * - Service worker-based message delivery + * - Requires server-side push infrastructure + * - Limited background support (browser-dependent) + * + * Limitations: + * - Requires active service worker + * - iOS: Limited to Home Screen PWAs on iOS 16.4+ + * - Android: Works in Chrome 42+ + * - Requires network connection for delivery + * + * @note This is currently a stub implementation that will be fully integrated + * with the existing PushNotificationPermission.vue component logic in a + * future update. For now, it provides the interface structure. + */ +export class WebPushNotificationService + implements NotificationServiceInterface +{ + private readonly platformName = "web"; + + /** + * Check if Web Push is supported in the current browser + */ + isSupported(): boolean { + const supported = + "serviceWorker" in navigator && + "PushManager" in window && + "Notification" in window; + + if (!supported) { + logger.warn( + "[WebPushNotificationService] Web Push is not supported in this browser", + ); + } + + return supported; + } + + /** + * Request notification permissions via browser API + */ + async requestPermissions(): Promise { + try { + if (!this.isSupported()) { + logger.error("[WebPushNotificationService] Web Push not supported"); + return false; + } + + logger.debug( + "[WebPushNotificationService] Requesting browser notification permissions", + ); + + const permission = await Notification.requestPermission(); + const granted = permission === "granted"; + + logger.debug( + "[WebPushNotificationService] Permission result:", + permission, + ); + + return granted; + } catch (error) { + logger.error( + "[WebPushNotificationService] Permission request failed:", + error, + ); + return false; + } + } + + /** + * Check current browser notification permission status + */ + async checkPermissions(): Promise { + if (!this.isSupported()) { + return { + granted: false, + details: { + notifications: false, + }, + }; + } + + const granted = window.Notification?.permission === "granted"; + + return { + granted, + details: { + notifications: granted, + }, + }; + } + + /** + * Schedule a daily notification via Web Push + * + * @note This is a stub implementation. The actual scheduling will be + * integrated with the existing PushNotificationPermission.vue component + * and web push server infrastructure. + * + * @param options Notification configuration + * @returns Promise that resolves to true if scheduling succeeded + */ + async scheduleDailyNotification( + options: DailyNotificationOptions, + ): Promise { + try { + logger.info("[WebPushNotificationService] Schedule requested:", { + time: options.time, + title: options.title, + }); + + // TODO: Integrate with existing PushNotificationPermission.vue logic + // This will involve: + // 1. Subscribing to push service with VAPID key + // 2. Sending subscription to server with schedule time + // 3. Server will send push messages at scheduled time + + logger.warn( + "[WebPushNotificationService] Scheduling not yet implemented - use PushNotificationPermission.vue component directly", + ); + + return false; + } catch (error) { + logger.error("[WebPushNotificationService] Schedule failed:", error); + return false; + } + } + + /** + * Cancel daily web push notifications + * + * @note This is a stub implementation. Will be integrated with existing + * web push unsubscribe logic. + */ + async cancelDailyNotification(): Promise { + try { + logger.info("[WebPushNotificationService] Cancel requested"); + + // TODO: Integrate with existing unsubscribe logic from App.vue + // This will involve: + // 1. Getting current service worker subscription + // 2. Calling subscription.unsubscribe() + // 3. Notifying server to stop sending push messages + + logger.warn( + "[WebPushNotificationService] Cancellation not yet implemented - use existing App.vue logic", + ); + } catch (error) { + logger.error("[WebPushNotificationService] Cancel failed:", error); + } + } + + /** + * Get current web push notification status + * + * @note This is a stub implementation. Will be integrated with existing + * settings retrieval logic. + */ + async getStatus(): Promise { + try { + // TODO: Integrate with existing settings from database + // Check settings.notifyingNewActivityTime and settings.notifyingReminderTime + + logger.debug( + "[WebPushNotificationService] Status check - stub implementation", + ); + + return { + enabled: false, + notificationType: "web-push", + }; + } catch (error) { + logger.error("[WebPushNotificationService] Get status failed:", error); + return { + enabled: false, + notificationType: "web-push", + }; + } + } + + /** + * Get platform identifier + */ + getPlatformName(): string { + return this.platformName; + } +} diff --git a/src/services/notifications/index.ts b/src/services/notifications/index.ts new file mode 100644 index 00000000..8f1283e4 --- /dev/null +++ b/src/services/notifications/index.ts @@ -0,0 +1,25 @@ +/** + * Notification Services Barrel Export + * + * Central export point for all notification-related services. + * Use this instead of importing from individual files. + * + * @example + * ```typescript + * import { NotificationService } from '@/services/notifications'; + * + * const service = NotificationService.getInstance(); + * await service.scheduleDailyNotification({ ... }); + * ``` + */ + +export { NotificationService } from "./NotificationService"; +export { NativeNotificationService } from "./NativeNotificationService"; +export { WebPushNotificationService } from "./WebPushNotificationService"; + +export type { + NotificationServiceInterface, + DailyNotificationOptions, + NotificationStatus, + PermissionStatus, +} from "./NotificationService";