summaryrefslogtreecommitdiff
path: root/DomainDig/LocalNotificationService.swift
diff options
context:
space:
mode:
Diffstat (limited to 'DomainDig/LocalNotificationService.swift')
-rw-r--r--DomainDig/LocalNotificationService.swift89
1 files changed, 89 insertions, 0 deletions
diff --git a/DomainDig/LocalNotificationService.swift b/DomainDig/LocalNotificationService.swift
new file mode 100644
index 0000000..450d844
--- /dev/null
+++ b/DomainDig/LocalNotificationService.swift
@@ -0,0 +1,89 @@
+import Foundation
+import UserNotifications
+
+@MainActor
+final class LocalNotificationService {
+ static let shared = LocalNotificationService()
+
+ private init() {}
+
+ func configureForegroundPresentation() {
+ UNUserNotificationCenter.current().delegate = NotificationCenterDelegate.shared
+ }
+
+ func requestAuthorizationIfNeeded() async -> Bool {
+ let center = UNUserNotificationCenter.current()
+ let settings = await center.notificationSettings()
+
+ switch settings.authorizationStatus {
+ case .authorized, .provisional, .ephemeral:
+ return true
+ case .notDetermined:
+ return (try? await center.requestAuthorization(options: [.alert, .badge, .sound])) ?? false
+ case .denied:
+ return false
+ @unknown default:
+ return false
+ }
+ }
+
+ func notifyDomainEvent(domain: String, message: String, severity: ChangeSeverity) async {
+ await schedule(
+ identifier: "domain-change-\(domain)",
+ title: domain,
+ body: message,
+ interruptionLevel: severity == .high ? .timeSensitive : .active
+ )
+ }
+
+ func notifyCertificateWarning(domain: String, daysRemaining: Int) async {
+ await schedule(
+ identifier: "cert-warning-\(domain)",
+ title: domain,
+ body: "Certificate expires in \(daysRemaining) days",
+ interruptionLevel: .timeSensitive
+ )
+ }
+
+ func notifySweepComplete(summary: BatchSweepSummary) async {
+ let body = "\(summary.changedDomains) changed, \(summary.warningDomains) warnings, \(summary.unchangedDomains) unchanged"
+ await schedule(
+ identifier: "sweep-complete",
+ title: summary.source == .watchlistRefresh ? "Check All Complete" : "Batch Complete",
+ body: body,
+ interruptionLevel: .active
+ )
+ }
+
+ private func schedule(
+ identifier: String,
+ title: String,
+ body: String,
+ interruptionLevel: UNNotificationInterruptionLevel
+ ) async {
+ let content = UNMutableNotificationContent()
+ content.title = title
+ content.body = body
+ content.sound = .default
+ content.interruptionLevel = interruptionLevel
+
+ let request = UNNotificationRequest(
+ identifier: identifier,
+ content: content,
+ trigger: UNTimeIntervalNotificationTrigger(timeInterval: 0.1, repeats: false)
+ )
+
+ try? await UNUserNotificationCenter.current().add(request)
+ }
+}
+
+private final class NotificationCenterDelegate: NSObject, UNUserNotificationCenterDelegate {
+ static let shared = NotificationCenterDelegate()
+
+ func userNotificationCenter(
+ _ center: UNUserNotificationCenter,
+ willPresent notification: UNNotification
+ ) async -> UNNotificationPresentationOptions {
+ [.banner, .list, .sound]
+ }
+}