import Foundation import SwiftData import WidgetKit /// 把 pinned 指标的最新值写进 App Group 快照,并请求 WidgetKit 刷新。 /// 调用时机:App 进后台 / 启动完成(RootView)。读库很轻(只取 pinned),无 AI、无网络。 /// App Group capability 未配置时整体静默 no-op,不影响主 App。 enum WidgetSnapshotRefresher { /// 每个系列(seriesKey,无则按 name)只取最新一条,最多 6 条。 @MainActor static func refresh(in ctx: ModelContext) { let pinnedPredicate = #Predicate { $0.pinned == true } var descriptor = FetchDescriptor( predicate: pinnedPredicate, sortBy: [SortDescriptor(\.capturedAt, order: .reverse)] ) descriptor.fetchLimit = 200 // pinned 总量不大,设上限只是兜底 guard let pinned = try? ctx.fetch(descriptor) else { return } var seenSeries = Set() var items: [WidgetSnapshot.Item] = [] for ind in pinned { // 已按 capturedAt 降序,首见即该系列最新 let key = ind.seriesKey ?? ind.name guard seenSeries.insert(key).inserted else { continue } items.append(.init( name: ind.name, value: ind.value, unit: ind.unit, statusRaw: ind.statusRaw, capturedAt: ind.capturedAt )) if items.count >= 6 { break } } let snapshot = WidgetSnapshot(updatedAt: .now, items: items) // 内容没变就不写、不刷新,省 WidgetKit 的刷新预算。 if let old = WidgetSnapshot.load(), old.items == snapshot.items { return } snapshot.save() WidgetCenter.shared.reloadAllTimelines() } }