import Foundation /// 主 App → 桌面 Widget 的数据快照(经 App Group UserDefaults 传递)。 /// /// 为什么不让 Widget 直接读 SwiftData:store 在 App 沙盒且开了文件保护, /// extension 进程独立、锁屏时不可读;快照是「最后一次看到的值」,锁屏也能显示。 /// /// ⚠️ 同步契约:`KangkangWidget` extension 里有本结构的独立拷贝 /// (extension 不引主 App 代码,避免 Xcode target membership 配置成本)。 /// 改字段时两边一起改:KangkangWidget/PinnedIndicatorsWidget.swift。 struct WidgetSnapshot: Codable, Equatable { struct Item: Codable, Equatable { var name: String // "收缩压" var value: String // "128" var unit: String // "mmHg" var statusRaw: String // IndicatorStatus.rawValue: high|low|normal var capturedAt: Date } var updatedAt: Date var items: [Item] // MARK: - App Group 存取 /// App Group ID。两个 target 的 App Groups capability 都要勾这一个。 static let appGroupID = "group.com.xuhuayong.kangkang" static let storeKey = "kk.widget.snapshot.v1" /// App Group 未配置(capability 没加)时返回 nil → 调用方静默跳过,App 照常运行。 static var sharedDefaults: UserDefaults? { UserDefaults(suiteName: appGroupID) } func save(to defaults: UserDefaults? = WidgetSnapshot.sharedDefaults) { guard let defaults, let data = try? JSONEncoder().encode(self) else { return } defaults.set(data, forKey: Self.storeKey) } static func load(from defaults: UserDefaults? = WidgetSnapshot.sharedDefaults) -> WidgetSnapshot? { guard let defaults, let data = defaults.data(forKey: storeKey) else { return nil } return try? JSONDecoder().decode(WidgetSnapshot.self, from: data) } }