Files
Ai/HealthBridge/Utils/NotificationManager.swift
Claude b953908f58 Add HealthBridge iOS app for intelligent health data synchronization
Complete implementation of a SwiftUI iOS app that serves as a "Single Source
of Truth" for health data. The app reads from all Apple Health sources,
detects conflicts between devices, merges data using configurable strategies,
and writes cleaned data back.

Features:
- Phase 1: HealthKit integration with automatic source discovery
- Phase 2: DataReader with conflict detection (time-window based)
- Phase 3: RuleEngine with 8 merge strategies (exclusive, priority, higher wins, etc.)
- Phase 4: MergeEngine for conflict resolution + DataWriter for HealthKit writes
- Phase 5: SwiftUI UI for dashboard, conflicts, rules, and sources management
- Phase 6: Background sync with configurable intervals and push notifications
- Phase 7: Complete rule editor and polished UI components

Supported data types:
- Steps, Heart Rate, Blood Pressure, SpO2, Sleep
- Distance, Floors Climbed, Active Energy, HRV, Respiratory Rate

Architecture: SourceManager -> DataReader -> RuleEngine -> MergeEngine -> DataWriter
2025-12-25 16:59:48 +00:00

186 lines
5.1 KiB
Swift

import Foundation
import UserNotifications
@MainActor
class NotificationManager: ObservableObject {
static let shared = NotificationManager()
@Published var isAuthorized = false
@Published var pendingNotifications: [String] = []
private let center = UNUserNotificationCenter.current()
private init() {
Task {
await checkAuthorization()
}
}
// MARK: - Authorization
func requestAuthorization() async -> Bool {
do {
let granted = try await center.requestAuthorization(options: [.alert, .sound, .badge])
isAuthorized = granted
return granted
} catch {
print("Notification authorization failed: \(error)")
return false
}
}
func checkAuthorization() async {
let settings = await center.notificationSettings()
isAuthorized = settings.authorizationStatus == .authorized
}
// MARK: - Conflict Notifications
func sendConflictNotification(count: Int) async {
guard isAuthorized else { return }
let content = UNMutableNotificationContent()
content.title = "HealthBridge"
if count == 1 {
content.body = "1 neuer Konflikt erfordert Ihre Aufmerksamkeit"
} else {
content.body = "\(count) neue Konflikte erfordern Ihre Aufmerksamkeit"
}
content.sound = .default
content.badge = NSNumber(value: count)
content.categoryIdentifier = "CONFLICT"
let request = UNNotificationRequest(
identifier: "healthbridge.conflict.\(Date().timeIntervalSince1970)",
content: content,
trigger: nil
)
do {
try await center.add(request)
} catch {
print("Failed to send notification: \(error)")
}
}
// MARK: - Sync Notifications
func sendSyncCompleteNotification(
conflictsResolved: Int,
pendingConflicts: Int
) async {
guard isAuthorized else { return }
let content = UNMutableNotificationContent()
content.title = "Sync abgeschlossen"
if pendingConflicts > 0 {
content.body = "\(conflictsResolved) Konflikte gelöst, \(pendingConflicts) offen"
} else {
content.body = "Alle \(conflictsResolved) Konflikte wurden gelöst"
}
content.sound = .default
content.categoryIdentifier = "SYNC_COMPLETE"
let request = UNNotificationRequest(
identifier: "healthbridge.sync.\(Date().timeIntervalSince1970)",
content: content,
trigger: nil
)
do {
try await center.add(request)
} catch {
print("Failed to send notification: \(error)")
}
}
// MARK: - Scheduled Notifications
func scheduleReminder(at hour: Int, minute: Int) async {
guard isAuthorized else { return }
let content = UNMutableNotificationContent()
content.title = "HealthBridge Erinnerung"
content.body = "Vergessen Sie nicht, Ihre Gesundheitsdaten zu synchronisieren"
content.sound = .default
var dateComponents = DateComponents()
dateComponents.hour = hour
dateComponents.minute = minute
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
let request = UNNotificationRequest(
identifier: "healthbridge.reminder.daily",
content: content,
trigger: trigger
)
do {
try await center.add(request)
} catch {
print("Failed to schedule reminder: \(error)")
}
}
func cancelReminder() {
center.removePendingNotificationRequests(withIdentifiers: ["healthbridge.reminder.daily"])
}
// MARK: - Badge Management
func clearBadge() async {
do {
try await center.setBadgeCount(0)
} catch {
print("Failed to clear badge: \(error)")
}
}
func updateBadge(count: Int) async {
do {
try await center.setBadgeCount(count)
} catch {
print("Failed to update badge: \(error)")
}
}
// MARK: - Notification Categories
func registerCategories() {
// Conflict category with actions
let resolveAction = UNNotificationAction(
identifier: "RESOLVE_AUTO",
title: "Automatisch lösen",
options: []
)
let viewAction = UNNotificationAction(
identifier: "VIEW_CONFLICTS",
title: "Anzeigen",
options: [.foreground]
)
let conflictCategory = UNNotificationCategory(
identifier: "CONFLICT",
actions: [resolveAction, viewAction],
intentIdentifiers: [],
options: []
)
// Sync complete category
let syncCategory = UNNotificationCategory(
identifier: "SYNC_COMPLETE",
actions: [viewAction],
intentIdentifiers: [],
options: []
)
center.setNotificationCategories([conflictCategory, syncCategory])
}
}