import Foundation /// Wetterlage, unabhängig von der Quelle. /// /// Eine eigene Aufzählung statt WeatherKits Typ: die Widget-Ebene soll nicht /// gegen ein Framework gebunden sein, das eine kostenpflichtige Mitgliedschaft /// und eine Entitlement voraussetzt. Fällt WeatherKit einmal weg, wird nur die /// Abbildung ausgetauscht. public enum WeatherCondition: String, Equatable, Sendable, CaseIterable { case clear case mostlyClear case partlyCloudy case cloudy case fog case drizzle case rain case heavyRain case sleet case snow case heavySnow case hail case thunderstorm case windy case hot case frigid case unknown } /// Der Ort, für den Wetter angezeigt wird. public enum WeatherPlace: Equatable, Sendable, Codable { /// Aktueller Standort über CoreLocation. case current /// Fester Ort, in den Widget-Einstellungen gewählt. case fixed(name: String, latitude: Double, longitude: Double) public var isCurrent: Bool { self == .current } } public struct HourlyPoint: Equatable, Sendable, Identifiable { public let date: Date public let temperature: Measurement public let condition: WeatherCondition public let precipitationChance: Double public var id: Date { date } public init(date: Date, temperature: Measurement, condition: WeatherCondition, precipitationChance: Double) { self.date = date self.temperature = temperature self.condition = condition self.precipitationChance = precipitationChance } } /// Was Apple bei Nutzung von WeatherKit sichtbar verlangt. /// /// Das ist keine Kür: die Nennung samt Link auf die Rechtshinweise ist /// Bedingung der Nutzung. Deshalb steht sie im Datenmodell und nicht in einer /// Notiz, die man beim Bauen der Oberfläche übersieht. public struct WeatherAttribution: Equatable, Sendable { public let name: String public let legalPageURL: URL public let logoURL: URL? public init(name: String, legalPageURL: URL, logoURL: URL?) { self.name = name self.legalPageURL = legalPageURL self.logoURL = logoURL } } public struct WeatherSnapshot: Equatable, Sendable { public let placeName: String public let temperature: Measurement public let apparentTemperature: Measurement public let condition: WeatherCondition public let isDaylight: Bool public let humidity: Double public let windSpeed: Measurement public let high: Measurement? public let low: Measurement? public let hourly: [HourlyPoint] public let asOf: Date public let attribution: WeatherAttribution? public init(placeName: String, temperature: Measurement, apparentTemperature: Measurement, condition: WeatherCondition, isDaylight: Bool, humidity: Double, windSpeed: Measurement, high: Measurement?, low: Measurement?, hourly: [HourlyPoint], asOf: Date, attribution: WeatherAttribution?) { self.placeName = placeName self.temperature = temperature self.apparentTemperature = apparentTemperature self.condition = condition self.isDaylight = isDaylight self.humidity = humidity self.windSpeed = windSpeed self.high = high self.low = low self.hourly = hourly self.asOf = asOf self.attribution = attribution } } /// Wie beim Kalender: jeder Fehlerfall bekommt eine eigene Antwort in der /// Oberfläche. „Keine Daten" ist keine. public enum WeatherState: Equatable, Sendable { case ready(WeatherSnapshot) /// Noch nie geladen. case idle case loading /// Ortungsberechtigung fehlt — betrifft nur `.current`. case locationDenied /// Kein Netz oder Dienst nicht erreichbar. Der letzte Stand bleibt sichtbar. case unavailable(lastKnown: WeatherSnapshot?, reason: String) }