krz/domain-dig

an ios app for DNS & SSL analysis

clone: git clone https://gitbay.org/krz/domain-dig.git

main: Shared/DomainDigWidgetData.swift · raw

 1import Foundation
 2
 3/// App Group + snapshot shared between the app (writer) and the widget (reader).
 4///
 5/// Deliberately self-contained: it references no app-target types (TrackedDomain,
 6/// PortfolioSnapshot, DomainHealth, ) so it compiles unchanged into the widget
 7/// extension. The app maps its richer types into these DTOs.
 8enum DomainDigWidgetStore {
 9    static let appGroupID = "group.net.cleberg.DomainDig"
10    private static let key = "widgetData"
11
12    private static var defaults: UserDefaults? {
13        UserDefaults(suiteName: appGroupID)
14    }
15
16    static func write(_ data: DomainDigWidgetData) {
17        guard let defaults, let encoded = try? JSONEncoder().encode(data) else { return }
18        defaults.set(encoded, forKey: key)
19    }
20
21    static func read() -> DomainDigWidgetData? {
22        guard let defaults,
23              let encoded = defaults.data(forKey: key),
24              let data = try? JSONDecoder().decode(DomainDigWidgetData.self, from: encoded)
25        else { return nil }
26        return data
27    }
28}
29
30struct DomainDigWidgetData: Codable, Sendable {
31    var generatedAt: Date
32    var totalDomains: Int
33    var healthyCount: Int
34    var warningCount: Int
35    var criticalCount: Int
36    var expiringSoonCount: Int
37    var unreachableCount: Int
38    var domains: [DomainDigWidgetDomain]
39
40    static let placeholder = DomainDigWidgetData(
41        generatedAt: .distantPast,
42        totalDomains: 3,
43        healthyCount: 2,
44        warningCount: 1,
45        criticalCount: 0,
46        expiringSoonCount: 1,
47        unreachableCount: 0,
48        domains: [
49            DomainDigWidgetDomain(domain: "example.com", isPinned: true, status: .healthy, certDaysRemaining: 240, lastChange: nil),
50            DomainDigWidgetDomain(domain: "cleberg.net", isPinned: false, status: .warning, certDaysRemaining: 21, lastChange: nil),
51            DomainDigWidgetDomain(domain: "example.org", isPinned: false, status: .healthy, certDaysRemaining: 88, lastChange: nil)
52        ]
53    )
54
55    /// Empty state used before the app has written any data.
56    static let empty = DomainDigWidgetData(
57        generatedAt: .distantPast,
58        totalDomains: 0,
59        healthyCount: 0,
60        warningCount: 0,
61        criticalCount: 0,
62        expiringSoonCount: 0,
63        unreachableCount: 0,
64        domains: []
65    )
66}
67
68struct DomainDigWidgetDomain: Codable, Sendable, Identifiable {
69    var domain: String
70    var isPinned: Bool
71    var status: DomainDigWidgetStatus
72    var certDaysRemaining: Int?
73    var lastChange: Date?
74
75    var id: String { domain }
76}
77
78enum DomainDigWidgetStatus: String, Codable, Sendable {
79    case healthy
80    case warning
81    case critical
82}