krz/hutch

an ios client for sourcehut

clone: git clone https://gitbay.org/krz/hutch.git

main: Shared/SystemStatusWidgetSnapshot.swift · raw

 1import Foundation
 2#if canImport(WidgetKit)
 3import WidgetKit
 4#endif
 5
 6enum SystemStatusWidgetConfiguration {
 7    static let kind = "SystemStatusWidget"
 8}
 9
10struct SystemStatusWidgetSnapshot: Codable, Sendable {
11    let services: [ServiceEntry]
12    let hasDisruption: Bool
13    let overallStatusText: String
14    let bannerSummary: String
15    let updatedAt: Date
16
17    struct ServiceEntry: Codable, Sendable, Identifiable {
18        let id: String
19        let name: String
20        let status: String
21        let requiresAttention: Bool
22    }
23
24    static let unavailable = SystemStatusWidgetSnapshot(
25        services: [],
26        hasDisruption: false,
27        overallStatusText: "Unavailable",
28        bannerSummary: "",
29        updatedAt: .now
30    )
31}
32
33enum SystemStatusWidgetSnapshotStore {
34    private static let snapshotKey = "systemStatus.widgetSnapshot"
35
36    static func load(
37        accountID: String? = nil,
38        defaults: UserDefaults? = sharedDefaults()
39    ) -> SystemStatusWidgetSnapshot? {
40        guard let defaults,
41              let data = defaults.data(forKey: scopedKey(for: resolvedAccountID(accountID, defaults: defaults))) else {
42            return nil
43        }
44        return try? JSONDecoder().decode(SystemStatusWidgetSnapshot.self, from: data)
45    }
46
47    static func save(
48        _ snapshot: SystemStatusWidgetSnapshot,
49        accountID: String? = nil,
50        defaults: UserDefaults? = sharedDefaults()
51    ) {
52        guard let defaults,
53              let data = try? JSONEncoder().encode(snapshot) else {
54            return
55        }
56        defaults.set(data, forKey: scopedKey(for: resolvedAccountID(accountID, defaults: defaults)))
57        reloadWidgetTimelines()
58    }
59
60    static func clear(
61        accountID: String? = nil,
62        defaults: UserDefaults? = sharedDefaults()
63    ) {
64        guard let defaults else { return }
65        defaults.removeObject(forKey: scopedKey(for: resolvedAccountID(accountID, defaults: defaults)))
66        reloadWidgetTimelines()
67    }
68
69    private static func sharedDefaults() -> UserDefaults? {
70        UserDefaults(suiteName: HutchAppGroup.identifier)
71    }
72
73    private static func scopedKey(for accountID: String?) -> String {
74        guard let accountID, !accountID.isEmpty else { return snapshotKey }
75        return "\(snapshotKey).\(accountID)"
76    }
77
78    private static func resolvedAccountID(_ accountID: String?, defaults: UserDefaults) -> String? {
79        accountID ?? ActiveAccountContextStore.load(defaults: defaults)
80    }
81
82    private static func reloadWidgetTimelines() {
83        #if canImport(WidgetKit)
84        WidgetCenter.shared.reloadTimelines(ofKind: SystemStatusWidgetConfiguration.kind)
85        #endif
86    }
87}