/** * NotificationContent.swift * * Data structure for notification content * * @author Matthew Raymer * @version 1.0.0 */ import Foundation /** * Data structure representing notification content * * This class encapsulates all the information needed for a notification * including scheduling, content, and metadata. */ class NotificationContent { // MARK: - Properties let id: String let title: String? let body: String? let scheduledTime: TimeInterval // milliseconds since epoch let fetchedAt: TimeInterval // milliseconds since epoch let url: String? let payload: [String: Any]? let etag: String? // MARK: - Initialization /** * Initialize notification content * * @param id Unique notification identifier * @param title Notification title * @param body Notification body text * @param scheduledTime When notification should fire (milliseconds since epoch) * @param fetchedAt When content was fetched (milliseconds since epoch) * @param url URL for content fetching * @param payload Additional payload data * @param etag ETag for HTTP caching */ init(id: String, title: String?, body: String?, scheduledTime: TimeInterval, fetchedAt: TimeInterval, url: String?, payload: [String: Any]?, etag: String?) { self.id = id self.title = title self.body = body self.scheduledTime = scheduledTime self.fetchedAt = fetchedAt self.url = url self.payload = payload self.etag = etag } // MARK: - Convenience Methods /** * Get scheduled time as Date * * @return Scheduled time as Date object */ func getScheduledTimeAsDate() -> Date { return Date(timeIntervalSince1970: scheduledTime / 1000) } /** * Get fetched time as Date * * @return Fetched time as Date object */ func getFetchedTimeAsDate() -> Date { return Date(timeIntervalSince1970: fetchedAt / 1000) } /** * Check if notification is scheduled for today * * @return true if scheduled for today */ func isScheduledForToday() -> Bool { let scheduledDate = getScheduledTimeAsDate() let today = Date() let calendar = Calendar.current return calendar.isDate(scheduledDate, inSameDayAs: today) } /** * Check if notification is scheduled for tomorrow * * @return true if scheduled for tomorrow */ func isScheduledForTomorrow() -> Bool { let scheduledDate = getScheduledTimeAsDate() let tomorrow = Calendar.current.date(byAdding: .day, value: 1, to: Date()) ?? Date() let calendar = Calendar.current return calendar.isDate(scheduledDate, inSameDayAs: tomorrow) } /** * Check if notification is in the future * * @return true if scheduled time is in the future */ func isInTheFuture() -> Bool { return scheduledTime > Date().timeIntervalSince1970 * 1000 } /** * Get age of content at scheduled time * * @return Age in seconds at scheduled time */ func getAgeAtScheduledTime() -> TimeInterval { return (scheduledTime - fetchedAt) / 1000 } /** * Convert to dictionary representation * * @return Dictionary representation of notification content */ func toDictionary() -> [String: Any] { return [ "id": id, "title": title ?? "", "body": body ?? "", "scheduledTime": scheduledTime, "fetchedAt": fetchedAt, "url": url ?? "", "payload": payload ?? [:], "etag": etag ?? "" ] } /** * Create from dictionary representation * * @param dict Dictionary representation * @return NotificationContent instance */ static func fromDictionary(_ dict: [String: Any]) -> NotificationContent? { guard let id = dict["id"] as? String, let scheduledTime = dict["scheduledTime"] as? TimeInterval, let fetchedAt = dict["fetchedAt"] as? TimeInterval else { return nil } return NotificationContent( id: id, title: dict["title"] as? String, body: dict["body"] as? String, scheduledTime: scheduledTime, fetchedAt: fetchedAt, url: dict["url"] as? String, payload: dict["payload"] as? [String: Any], etag: dict["etag"] as? String ) } }