fix(ios): correct next notification time and improve rollover UI refresh
- Fix getNextNotificationTime() to find earliest scheduled notification instead of using first request (pendingNotificationRequests doesn't guarantee order) - Add comprehensive logging for rollover tracking with DNP-ROLLOVER prefix for Xcode console filtering - Reset all notifications and rollover state when scheduling new notification via scheduleDailyNotification() to ensure clean test state - Fix userInfo scope error in handleNotificationDelivery error handler - Update test app UI to refresh status every 5-10 seconds and immediately after notification delivery to reflect rollover changes - Add console logging in UI to debug getNotificationStatus() results This ensures the UI correctly displays the next notification time after rollover completes, and test notifications start with a clean slate.
This commit is contained in:
@@ -393,6 +393,10 @@ class DailyNotificationReactivationManager {
|
||||
}
|
||||
}
|
||||
|
||||
// Step 4.5: Check for delivered notifications and trigger rollover
|
||||
// This handles notifications that were delivered while app was not running
|
||||
await checkAndProcessDeliveredNotifications()
|
||||
|
||||
// Record recovery in history
|
||||
let result = RecoveryResult(
|
||||
missedCount: missedCount,
|
||||
@@ -1004,6 +1008,94 @@ class DailyNotificationReactivationManager {
|
||||
// Don't throw - this is best effort
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for delivered notifications and trigger rollover
|
||||
*
|
||||
* This ensures rollover happens on app launch if notifications were delivered
|
||||
* while the app was not running
|
||||
*/
|
||||
private func checkAndProcessDeliveredNotifications() async {
|
||||
NSLog("DNP-ROLLOVER: RECOVERY_CHECK_START")
|
||||
print("DNP-ROLLOVER: RECOVERY_CHECK_START")
|
||||
|
||||
// Get delivered notifications from system
|
||||
let deliveredNotifications = await notificationCenter.deliveredNotifications()
|
||||
NSLog("DNP-ROLLOVER: RECOVERY_FOUND delivered_count=\(deliveredNotifications.count)")
|
||||
print("DNP-ROLLOVER: RECOVERY_FOUND delivered_count=\(deliveredNotifications.count)")
|
||||
|
||||
// Get last processed rollover time from storage
|
||||
let lastProcessedTime = storage.getLastRolloverTime()
|
||||
let lastProcessedTimeStr = formatTime(lastProcessedTime)
|
||||
NSLog("DNP-ROLLOVER: RECOVERY_LAST_PROCESSED time=\(lastProcessedTimeStr)")
|
||||
print("DNP-ROLLOVER: RECOVERY_LAST_PROCESSED time=\(lastProcessedTimeStr)")
|
||||
|
||||
var processedCount = 0
|
||||
var skippedCount = 0
|
||||
|
||||
for notification in deliveredNotifications {
|
||||
let userInfo = notification.request.content.userInfo
|
||||
|
||||
guard let notificationId = userInfo["notification_id"] as? String,
|
||||
let scheduledTime = userInfo["scheduled_time"] as? Int64 else {
|
||||
continue
|
||||
}
|
||||
|
||||
let scheduledTimeStr = formatTime(scheduledTime)
|
||||
|
||||
// Only process if this notification hasn't been processed yet
|
||||
if scheduledTime > lastProcessedTime {
|
||||
NSLog("DNP-ROLLOVER: RECOVERY_PROCESS id=\(notificationId) scheduled_time=\(scheduledTimeStr)")
|
||||
print("DNP-ROLLOVER: RECOVERY_PROCESS id=\(notificationId) scheduled_time=\(scheduledTimeStr)")
|
||||
|
||||
// Get notification content
|
||||
guard let content = storage.getNotificationContent(id: notificationId) else {
|
||||
NSLog("DNP-ROLLOVER: RECOVERY_ERROR id=\(notificationId) content_not_found")
|
||||
print("DNP-ROLLOVER: RECOVERY_ERROR id=\(notificationId) content_not_found")
|
||||
continue
|
||||
}
|
||||
|
||||
// Trigger rollover
|
||||
let scheduled = await scheduler.scheduleNextNotification(
|
||||
content,
|
||||
storage: storage,
|
||||
fetcher: nil // TODO: Phase 2 - Add fetcher
|
||||
)
|
||||
|
||||
if scheduled {
|
||||
NSLog("DNP-ROLLOVER: RECOVERY_SUCCESS id=\(notificationId)")
|
||||
print("DNP-ROLLOVER: RECOVERY_SUCCESS id=\(notificationId)")
|
||||
// Update last processed time
|
||||
storage.saveLastRolloverTime(scheduledTime)
|
||||
processedCount += 1
|
||||
} else {
|
||||
NSLog("DNP-ROLLOVER: RECOVERY_FAILED id=\(notificationId)")
|
||||
print("DNP-ROLLOVER: RECOVERY_FAILED id=\(notificationId)")
|
||||
}
|
||||
} else {
|
||||
skippedCount += 1
|
||||
NSLog("DNP-ROLLOVER: RECOVERY_SKIP id=\(notificationId) already_processed scheduled_time=\(scheduledTimeStr)")
|
||||
print("DNP-ROLLOVER: RECOVERY_SKIP id=\(notificationId) already_processed scheduled_time=\(scheduledTimeStr)")
|
||||
}
|
||||
}
|
||||
|
||||
NSLog("DNP-ROLLOVER: RECOVERY_COMPLETE processed=\(processedCount) skipped=\(skippedCount)")
|
||||
print("DNP-ROLLOVER: RECOVERY_COMPLETE processed=\(processedCount) skipped=\(skippedCount)")
|
||||
}
|
||||
|
||||
/**
|
||||
* Format time for logging
|
||||
*
|
||||
* @param timestamp Timestamp in milliseconds
|
||||
* @return Formatted time string
|
||||
*/
|
||||
private func formatTime(_ timestamp: Int64) -> String {
|
||||
let date = Date(timeIntervalSince1970: Double(timestamp) / 1000.0)
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateStyle = .medium
|
||||
formatter.timeStyle = .short
|
||||
return formatter.string(from: date)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Supporting Types
|
||||
|
||||
Reference in New Issue
Block a user