diff --git a/ios/Plugin/DailyNotificationReactivationManager.swift b/ios/Plugin/DailyNotificationReactivationManager.swift index e55a4e6..e15d3df 100644 --- a/ios/Plugin/DailyNotificationReactivationManager.swift +++ b/ios/Plugin/DailyNotificationReactivationManager.swift @@ -458,11 +458,10 @@ class DailyNotificationReactivationManager { // Filter for missed notifications: // - scheduled_time < currentTime // - delivery_status != 'delivered' (if deliveryStatus property exists) - // Note: For Phase 1, we'll check if notification is past scheduled time - // In Phase 2, we'll add deliveryStatus tracking let missed = allNotifications.filter { notification in - notification.scheduledTime < currentTimeMs - // TODO: Add deliveryStatus check when property is added to NotificationContent + let isPastScheduledTime = notification.scheduledTime < currentTimeMs + let isNotDelivered = notification.deliveryStatus != "delivered" + return isPastScheduledTime && isNotDelivered } NSLog("\(Self.TAG): Detected \(missed.count) missed notifications") @@ -475,19 +474,15 @@ class DailyNotificationReactivationManager { * @param notification Notification to mark as missed */ private func markMissedNotification(_ notification: NotificationContent) async throws { - // Note: NotificationContent doesn't have deliveryStatus property yet - // For Phase 1, we'll save the notification with updated metadata - // In Phase 2, we'll add deliveryStatus tracking to NotificationContent + // Update delivery status and last delivery attempt + notification.deliveryStatus = "missed" + notification.lastDeliveryAttempt = Int64(Date().timeIntervalSince1970 * 1000) // Save to storage (notification already exists, this updates it) storage.saveNotificationContent(notification) // Record in history (if history table exists) - // Note: History recording may need to be implemented based on database structure NSLog("\(Self.TAG): Marked notification \(notification.id) as missed") - - // TODO: Add deliveryStatus property to NotificationContent in Phase 2 - // TODO: Add lastDeliveryAttempt property to NotificationContent in Phase 2 } // MARK: - Future Notification Verification diff --git a/ios/Plugin/NotificationContent.swift b/ios/Plugin/NotificationContent.swift index ec06051..a7d9b11 100644 --- a/ios/Plugin/NotificationContent.swift +++ b/ios/Plugin/NotificationContent.swift @@ -28,6 +28,10 @@ class NotificationContent: Codable { let payload: [String: Any]? let etag: String? + // Phase 2: Delivery tracking properties + var deliveryStatus: String? // e.g., "scheduled", "delivered", "missed", "error" + var lastDeliveryAttempt: Int64? // milliseconds since epoch (matches Android long) + // MARK: - Codable Support enum CodingKeys: String, CodingKey { @@ -39,6 +43,8 @@ class NotificationContent: Codable { case url case payload case etag + case deliveryStatus + case lastDeliveryAttempt } required init(from decoder: Decoder) throws { @@ -58,6 +64,8 @@ class NotificationContent: Codable { payload = nil } etag = try container.decodeIfPresent(String.self, forKey: .etag) + deliveryStatus = try container.decodeIfPresent(String.self, forKey: .deliveryStatus) + lastDeliveryAttempt = try container.decodeIfPresent(Int64.self, forKey: .lastDeliveryAttempt) } func encode(to encoder: Encoder) throws { @@ -75,6 +83,8 @@ class NotificationContent: Codable { try container.encode(payloadString, forKey: .payload) } try container.encodeIfPresent(etag, forKey: .etag) + try container.encodeIfPresent(deliveryStatus, forKey: .deliveryStatus) + try container.encodeIfPresent(lastDeliveryAttempt, forKey: .lastDeliveryAttempt) } // MARK: - Initialization @@ -90,6 +100,8 @@ class NotificationContent: Codable { * @param url URL for content fetching * @param payload Additional payload data * @param etag ETag for HTTP caching + * @param deliveryStatus Delivery status (optional, Phase 2) + * @param lastDeliveryAttempt Last delivery attempt timestamp (optional, Phase 2) */ init(id: String, title: String?, @@ -98,7 +110,9 @@ class NotificationContent: Codable { fetchedAt: Int64, url: String?, payload: [String: Any]?, - etag: String?) { + etag: String?, + deliveryStatus: String? = nil, + lastDeliveryAttempt: Int64? = nil) { self.id = id self.title = title @@ -108,6 +122,8 @@ class NotificationContent: Codable { self.url = url self.payload = payload self.etag = etag + self.deliveryStatus = deliveryStatus + self.lastDeliveryAttempt = lastDeliveryAttempt } // MARK: - Convenience Methods @@ -181,7 +197,7 @@ class NotificationContent: Codable { * @return Dictionary representation of notification content */ func toDictionary() -> [String: Any] { - return [ + var dict: [String: Any] = [ "id": id, "title": title ?? "", "body": body ?? "", @@ -191,6 +207,16 @@ class NotificationContent: Codable { "payload": payload ?? [:], "etag": etag ?? "" ] + + // Phase 2: Add delivery tracking properties if present + if let deliveryStatus = deliveryStatus { + dict["deliveryStatus"] = deliveryStatus + } + if let lastDeliveryAttempt = lastDeliveryAttempt { + dict["lastDeliveryAttempt"] = lastDeliveryAttempt + } + + return dict } /** @@ -223,6 +249,16 @@ class NotificationContent: Codable { return nil } + // Handle lastDeliveryAttempt (can be Int64 or Double/TimeInterval) + let lastDeliveryAttempt: Int64? + if let attempt = dict["lastDeliveryAttempt"] as? Int64 { + lastDeliveryAttempt = attempt + } else if let attempt = dict["lastDeliveryAttempt"] as? Double { + lastDeliveryAttempt = Int64(attempt) + } else { + lastDeliveryAttempt = nil + } + return NotificationContent( id: id, title: dict["title"] as? String, @@ -231,7 +267,9 @@ class NotificationContent: Codable { fetchedAt: fetchedAt, url: dict["url"] as? String, payload: dict["payload"] as? [String: Any], - etag: dict["etag"] as? String + etag: dict["etag"] as? String, + deliveryStatus: dict["deliveryStatus"] as? String, + lastDeliveryAttempt: lastDeliveryAttempt ) } }