diff --git a/SleepFocus/Models/HomeSummary.swift b/SleepFocus/Models/HomeSummary.swift index 5c51285..0edbc5e 100644 --- a/SleepFocus/Models/HomeSummary.swift +++ b/SleepFocus/Models/HomeSummary.swift @@ -17,7 +17,7 @@ nonisolated struct HomeSummaryMonthPayload: Decodable { let updatedAt: String } -nonisolated struct HomeSummary: Decodable { +nonisolated struct HomeSummary: Codable { let userId: String let selectedDate: String? let sleepQuality: SleepQualitySummary @@ -29,25 +29,25 @@ nonisolated struct HomeSummary: Decodable { let processing: ProcessingSummary? } -nonisolated struct SleepQualitySummary: Decodable { +nonisolated struct SleepQualitySummary: Codable { let score: Double? let maxScore: Double? let status: String? let source: String? } -nonisolated struct FocusPredictionSummary: Decodable { +nonisolated struct FocusPredictionSummary: Codable { let score: Int? let label: String? let source: String? } -nonisolated struct CircadianRhythmSummary: Decodable { +nonisolated struct CircadianRhythmSummary: Codable { let averageWakeTimeMinutes: Int let confidence: Double } -nonisolated struct ProcessingSummary: Decodable { +nonisolated struct ProcessingSummary: Codable { let state: String let lastJobId: String? let updatedAt: String? diff --git a/SleepFocus/Services/HomeSummaryStore.swift b/SleepFocus/Services/HomeSummaryStore.swift index 51a41ee..33cdfa3 100644 --- a/SleepFocus/Services/HomeSummaryStore.swift +++ b/SleepFocus/Services/HomeSummaryStore.swift @@ -34,7 +34,7 @@ final class HomeSummaryStore: ObservableObject { isWaitingForModel = false isSyncing = false - summary = monthSummariesByDay[selectedMonthKey]?[selectedDayKey] + summary = monthSummariesByDay[selectedMonthKey]?[selectedDayKey] ?? loadPersistedSummary(for: selectedDayKey) sleepMetrics = nil sleepStageBreakdown = nil @@ -56,6 +56,7 @@ final class HomeSummaryStore: ObservableObject { var resolvedSummary = monthSummariesByDay[selectedMonthKey]?[selectedDayKey] if let resolvedSummary { summary = resolvedSummary + cacheSummary(resolvedSummary, fallbackDate: selectedDate) } if resolvedSummary == nil { @@ -195,6 +196,25 @@ final class HomeSummaryStore: ObservableObject { var monthMap = monthSummariesByDay[monthKey] ?? [:] monthMap[dayKey] = summary monthSummariesByDay[monthKey] = monthMap + + persistSummary(summary, for: dayKey) + } + + private func loadPersistedSummary(for dayKey: String) -> HomeSummary? { + guard let data = UserDefaults.standard.data(forKey: Self.persistenceKey(for: dayKey)), + let decoded = try? JSONDecoder().decode(HomeSummary.self, from: data) else { + return nil + } + return decoded + } + + private func persistSummary(_ summary: HomeSummary, for dayKey: String) { + guard let data = try? JSONEncoder().encode(summary) else { return } + UserDefaults.standard.set(data, forKey: Self.persistenceKey(for: dayKey)) + } + + private static func persistenceKey(for dayKey: String) -> String { + "homeSummary.\(dayKey)" } // Ramp up polling to improve fetching performance without spamming backend