From 45eff4a9ac46e104ce1c2895cb83e860746c60e6 Mon Sep 17 00:00:00 2001 From: Matthew Raymer Date: Wed, 5 Nov 2025 06:34:53 +0000 Subject: [PATCH] docs: add plugin state sync, time update logic, and component extraction - Update initialization to sync with plugin state on mount (checks for pre-existing schedules) - Add updateNotificationTime() method to update schedule when time changes (cancel old, schedule new) - Extract DailyNotificationSection into dedicated component using vue-facing-decorator - Update component architecture to show DailyNotificationSection.vue structure - Update Phase 2 tasks to reflect component creation and AccountViewView integration - Add acceptance criteria for plugin state sync and time update functionality - Update verification checklist with new requirements --- ...ly-notification-plugin-integration-plan.md | 211 ++++++++++++++---- 1 file changed, 166 insertions(+), 45 deletions(-) diff --git a/doc/daily-notification-plugin-integration-plan.md b/doc/daily-notification-plugin-integration-plan.md index 58606380..4637554f 100644 --- a/doc/daily-notification-plugin-integration-plan.md +++ b/doc/daily-notification-plugin-integration-plan.md @@ -255,18 +255,58 @@ export interface NativeFetcherConfig { #### Views Structure ``` src/views/ - └── AccountViewView.vue (existing - add Daily Notifications section) + └── AccountViewView.vue (existing - add DailyNotificationSection component) ``` -#### Supporting Components (Optional - Only if AccountViewView needs extraction) +#### Supporting Components ``` -src/components/notifications/ (optional) - ├── NotificationToggle.vue (optional - extract toggle if AccountViewView too long) - ├── NotificationTimePicker.vue (optional - extract time picker if needed) - └── NotificationStatusDisplay.vue (optional - extract status display if needed) +src/components/notifications/ + └── DailyNotificationSection.vue (required - extracted section component) ``` -**Note**: Supporting components should only be created if AccountViewView exceeds reasonable length limits (>200 lines). Keep everything in AccountViewView if possible. +**Component Structure**: `DailyNotificationSection.vue` will use vue-facing-decorator with ES6 classes + +```vue + + + +``` --- @@ -422,7 +462,7 @@ function getTimeFromInput(timeInput: string): string { ### Data Flow -#### 1. Initialization +#### 1. Initialization (Sync with Plugin State) ```typescript async initializeState() { @@ -440,13 +480,33 @@ async initializeState() { this.notificationsSupported = true; - // Load from settings - const nativeNotificationTime = settings.nativeNotificationTime || ""; - this.nativeNotificationEnabled = !!nativeNotificationTime; - this.nativeNotificationTimeStorage = nativeNotificationTime; - - if (nativeNotificationTime) { - this.nativeNotificationTime = formatTimeForDisplay(nativeNotificationTime); + // CRITICAL: Sync with plugin state first (source of truth) + // Plugin may have an existing schedule even if settings don't + if (status.isScheduled && status.scheduledTime) { + // Plugin has a scheduled notification - sync UI to match + this.nativeNotificationEnabled = true; + this.nativeNotificationTimeStorage = status.scheduledTime; + this.nativeNotificationTime = formatTimeForDisplay(status.scheduledTime); + + // Also sync settings to match plugin state + const settings = await this.$accountSettings(); + if (settings.nativeNotificationTime !== status.scheduledTime) { + await this.$saveSettings({ + nativeNotificationTime: status.scheduledTime, + nativeNotificationTitle: settings.nativeNotificationTitle || this.nativeNotificationTitle, + nativeNotificationMessage: settings.nativeNotificationMessage || this.nativeNotificationMessage, + }); + } + } else { + // No plugin schedule - check settings for user preference + const settings = await this.$accountSettings(); + const nativeNotificationTime = settings.nativeNotificationTime || ""; + this.nativeNotificationEnabled = !!nativeNotificationTime; + this.nativeNotificationTimeStorage = nativeNotificationTime; + + if (nativeNotificationTime) { + this.nativeNotificationTime = formatTimeForDisplay(nativeNotificationTime); + } } // Update UI with current status @@ -454,6 +514,12 @@ async initializeState() { } ``` +**Key Points**: +- `getDailyNotificationStatus()` is called on mount to check for pre-existing schedules +- Plugin state is the source of truth - if plugin has a schedule, UI syncs to match +- Settings are synced with plugin state if they differ +- If no plugin schedule exists, fall back to settings + #### 2. Enable Notification ```typescript @@ -529,18 +595,63 @@ async disableNativeNotification() { } ``` -#### 4. Edit Time +#### 4. Edit Time (Update Schedule) -**Approach**: Use inline HTML5 time input for quick edits +**Approach**: When time changes, immediately update the scheduled notification ```typescript async editNativeNotificationTime() { // Show inline HTML5 time input for quick changes this.showTimeEdit = true; } + +async updateNotificationTime(newTime: string) { + // newTime is in "HH:mm" format from HTML5 time input + if (!this.nativeNotificationEnabled) { + // If notification is disabled, just save the time preference + this.nativeNotificationTimeStorage = newTime; + this.nativeNotificationTime = formatTimeForDisplay(newTime); + await this.$saveSettings({ + nativeNotificationTime: newTime, + }); + return; + } + + // Notification is enabled - update the schedule + try { + const platformService = PlatformServiceFactory.getInstance(); + + // 1. Cancel existing notification + await platformService.cancelDailyNotification(); + + // 2. Schedule with new time + await platformService.scheduleDailyNotification({ + time: newTime, // "09:00" in local time + title: this.nativeNotificationTitle, + body: this.nativeNotificationMessage, + sound: true, + priority: 'high' + }); + + // 3. Update local state + this.nativeNotificationTimeStorage = newTime; + this.nativeNotificationTime = formatTimeForDisplay(newTime); + + // 4. Save to settings + await this.$saveSettings({ + nativeNotificationTime: newTime, + }); + + this.notify.success("Notification time updated successfully", TIMEOUTS.SHORT); + this.showTimeEdit = false; + } catch (error) { + logger.error("Failed to update notification time:", error); + this.notify.error("Failed to update notification time. Please try again.", TIMEOUTS.LONG); + } +} ``` -**Implementation Note**: HTML5 time input provides native mobile picker experience when shown inline, making it ideal for quick time adjustments in AccountViewView. +**Implementation Note**: HTML5 time input provides native mobile picker experience when shown inline, making it ideal for quick time adjustments. When the time changes, the notification schedule is immediately updated via PlatformService. ### Settings Schema @@ -643,39 +754,46 @@ interface Settings { **Goals**: Integrate notification scheduling into AccountViewView with optional supporting components #### Tasks -1. **Supporting Components (Optional)** - - [ ] Create supporting components only if AccountViewView exceeds length limits - - [ ] Consider: `NotificationToggle.vue`, `NotificationTimePicker.vue`, `NotificationStatusDisplay.vue` - - [ ] Follow project styling patterns - - [ ] Add TypeScript interfaces - - [ ] Keep components focused and reusable within AccountViewView context - -2. **AccountViewView Integration** ✅ **ACCEPTED** - - [ ] Add separate "Daily Notifications" section - - [ ] Check platform capabilities before showing UI (`v-if="notificationsSupported"`) - - [ ] Add computed property for platform capability detection +1. **DailyNotificationSection Component** + - [ ] Create `src/components/notifications/DailyNotificationSection.vue` + - [ ] Use vue-facing-decorator with ES6 class extending Vue + - [ ] Add PlatformServiceMixin to component + - [ ] Implement platform capability detection on mount + - [ ] Implement initialization that syncs with plugin state (checks for pre-existing schedules) - [ ] Add toggle switch for enabling/disabling notifications - [ ] Add HTML5 time input for scheduling time - [ ] Integrate with PlatformService via PlatformServiceFactory - - [ ] Save/load settings from `settings` table - [ ] Implement time format conversion (display vs storage) - [ ] Add enable/disable notification methods - - [ ] Add edit time functionality + - [ ] Add edit time functionality with schedule update (cancel old, schedule new) - [ ] Add permission request flow - [ ] Add error handling and user feedback + - [ ] Save/load settings from `settings` table + - [ ] Follow project styling patterns + - [ ] Add TypeScript interfaces + - [ ] Add file-level documentation + +2. **AccountViewView Integration** + - [ ] Import DailyNotificationSection component + - [ ] Add component to template (minimal integration) + - [ ] Verify component renders correctly + - [ ] Test component hiding on unsupported platforms #### Acceptance Criteria -- [ ] Supporting components created only if AccountViewView exceeds length limits -- [ ] AccountViewView has separate "Daily Notifications" section -- [ ] **AccountViewView notification section hidden on unsupported platforms** (`v-if="notificationsSupported"`) -- [ ] Notification section checks PlatformService capabilities before showing -- [ ] Toggle and time input functional in AccountViewView +- [ ] DailyNotificationSection component created using vue-facing-decorator +- [ ] Component extends Vue class with PlatformServiceMixin +- [ ] Component checks platform support on mount via `getDailyNotificationStatus()` +- [ ] Component syncs with plugin state on initialization (checks for pre-existing schedules) +- [ ] Component hidden on unsupported platforms (`v-if="notificationsSupported"`) +- [ ] Toggle and time input functional +- [ ] Time changes update notification schedule immediately (cancel old, schedule new) - [ ] Settings persist across app restarts -- [ ] Plugin state syncs with settings +- [ ] Plugin state syncs with settings on mount - [ ] All logging uses project logger - [ ] Error handling implemented - [ ] Loading states visible - [ ] UI matches existing design patterns +- [ ] AccountViewView integration is minimal (just imports and uses component) --- @@ -837,16 +955,16 @@ async mounted() { #### Components That Must Implement This Pattern -1. **AccountViewView.vue**: Daily Notifications section uses `v-if="notificationsSupported"` -2. **Supporting components** (if created): Must check support before rendering any scheduling UI -3. **Any component providing scheduling UI**: Must verify `getDailyNotificationStatus() !== null` before showing scheduling controls +1. **DailyNotificationSection.vue**: Daily Notifications section uses `v-if="notificationsSupported"` and checks `getDailyNotificationStatus()` on mount +2. **Any component providing scheduling UI**: Must verify `getDailyNotificationStatus() !== null` before showing scheduling controls #### Verification Checklist -- [ ] AccountViewView notification section hidden via `v-if` on unsupported platforms -- [ ] Supporting components (if created) check and hide on unsupported platforms -- [ ] All components tested on Web/Electron to verify hiding works +- [ ] DailyNotificationSection checks platform support on mount and hides on unsupported platforms +- [ ] DailyNotificationSection syncs with plugin state on initialization (checks for pre-existing schedules) +- [ ] Component tested on Web/Electron to verify hiding works - [ ] No console errors when components are hidden +- [ ] Time changes properly update notification schedule ### Code Quality Standards - **Logging**: Use `logger` from `@/utils/logger`, not `console.*` @@ -938,8 +1056,11 @@ await platformService.scheduleDailyNotification({ - [ ] Plugin integrated using PlatformService architecture - [ ] Feature works on Capacitor (Android/iOS) - [ ] Feature hidden/graceful on Web/Electron -- [ ] AccountViewView integration complete and functional -- [ ] **AccountViewView notification section hides itself on unsupported platforms** +- [ ] DailyNotificationSection component created and functional +- [ ] **DailyNotificationSection hides itself on unsupported platforms** +- [ ] Component syncs with plugin state on mount (checks for pre-existing schedules) +- [ ] Time changes update notification schedule immediately +- [ ] AccountViewView integration minimal (just imports component) - [ ] Settings persist across app restarts - [ ] Logging standardized (no console.*) - [ ] Error handling robust