Files
jarvis/Jarvis/Notifications/NotificationSettings.swift
Robin Kutesa 595f21fb6c
Some checks failed
CI / Build · macos-14 · Debug (push) Has been cancelled
CI / Build · macos-15 · Debug (push) Has been cancelled
CI / Build · macos-14 · Release (push) Has been cancelled
CI / Build · macos-15 · Release (push) Has been cancelled
feat: East Africa + Southern Africa pills with regional sub-sections
- East Africa pill: merges Uganda + east-africa tags; Uganda pinned first via sub-sections
- Southern Africa pill: covers SA, Namibia, Botswana, Zimbabwe, Zambia, Mozambique; SA/Namibia/Botswana prioritized
- StoryStore.setPill now resets lastSyncedAt to bypass 30s rate-limit on filter switch
- sectionSupplement background fetch populates sparse regional sections in All digest
- SignalFeedView digestContent: flat hero+scroll path for pills without subSections (was showing max 5)
- Theme: removed standalone Uganda pill, wired new sub-section layouts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 02:33:33 +03:00

76 lines
3.5 KiB
Swift

// NotificationSettings.swift
// Jarvis persisted notification preferences: breaking alerts + morning/evening
// briefings with weather.
import Foundation
@MainActor
final class NotificationSettings: ObservableObject {
static let shared = NotificationSettings()
private let key = "jarvis_notifications_v1"
// Master intent (actual OS permission tracked by NotificationManager).
@Published var enabled: Bool { didSet { persist() } }
// Breaking / new-story alerts
@Published var breakingEnabled: Bool { didSet { persist() } }
@Published var breakingMinSignal: Int { didSet { persist() } }
// Morning briefing
@Published var morningEnabled: Bool { didSet { persist() } }
@Published var morningHour: Int { didSet { persist() } }
@Published var morningMinute: Int { didSet { persist() } }
// Evening briefing
@Published var eveningEnabled: Bool { didSet { persist() } }
@Published var eveningHour: Int { didSet { persist() } }
@Published var eveningMinute: Int { didSet { persist() } }
// Weather
@Published var weatherEnabled: Bool { didSet { persist() } }
@Published var locationName: String { didSet { persist() } }
@Published var latitude: Double? { didSet { persist() } }
@Published var longitude: Double? { didSet { persist() } }
@Published var resolvedPlace: String? { didSet { persist() } }
private struct Stored: Codable {
var enabled, breakingEnabled, morningEnabled, eveningEnabled, weatherEnabled: Bool
var breakingMinSignal, morningHour, morningMinute, eveningHour, eveningMinute: Int
var locationName: String
var latitude, longitude: Double?
var resolvedPlace: String?
}
private init() {
if let data = UserDefaults.standard.data(forKey: key),
let s = try? JSONDecoder().decode(Stored.self, from: data) {
enabled = s.enabled
breakingEnabled = s.breakingEnabled; breakingMinSignal = s.breakingMinSignal
morningEnabled = s.morningEnabled; morningHour = s.morningHour; morningMinute = s.morningMinute
eveningEnabled = s.eveningEnabled; eveningHour = s.eveningHour; eveningMinute = s.eveningMinute
weatherEnabled = s.weatherEnabled; locationName = s.locationName
latitude = s.latitude; longitude = s.longitude; resolvedPlace = s.resolvedPlace
} else {
enabled = true
breakingEnabled = true; breakingMinSignal = 65
morningEnabled = true; morningHour = 7; morningMinute = 0
eveningEnabled = true; eveningHour = 18; eveningMinute = 0
weatherEnabled = true; locationName = ""
latitude = nil; longitude = nil; resolvedPlace = nil
}
}
private func persist() {
let s = Stored(enabled: enabled, breakingEnabled: breakingEnabled,
morningEnabled: morningEnabled, eveningEnabled: eveningEnabled,
weatherEnabled: weatherEnabled, breakingMinSignal: breakingMinSignal,
morningHour: morningHour, morningMinute: morningMinute,
eveningHour: eveningHour, eveningMinute: eveningMinute,
locationName: locationName, latitude: latitude, longitude: longitude,
resolvedPlace: resolvedPlace)
if let data = try? JSONEncoder().encode(s) { UserDefaults.standard.set(data, forKey: key) }
}
var hasResolvedLocation: Bool { latitude != nil && longitude != nil }
}