Andromida/Andromida/App/State/SettingsStore.swift

125 lines
3.5 KiB
Swift

import Foundation
import Observation
import Bedrock
import UserNotifications
@MainActor
@Observable
final class SettingsStore: CloudSyncable {
@ObservationIgnored private let cloudSync = CloudSyncManager<AppSettingsData>()
/// The current notification authorization status.
private(set) var notificationAuthStatus: UNAuthorizationStatus = .notDetermined
var remindersEnabled: Bool {
get { cloudSync.data.remindersEnabled }
set {
update { $0.remindersEnabled = newValue }
Task { await handleReminderToggle(enabled: newValue) }
}
}
var reminderHour: Int {
get { cloudSync.data.reminderHour }
set {
update { $0.reminderHour = newValue }
if remindersEnabled {
Task { await scheduleReminder() }
}
}
}
var reminderMinute: Int {
get { cloudSync.data.reminderMinute }
set {
update { $0.reminderMinute = newValue }
if remindersEnabled {
Task { await scheduleReminder() }
}
}
}
/// Returns a Date representing the reminder time for use with DatePicker.
var reminderTime: Date {
get {
var components = DateComponents()
components.hour = reminderHour
components.minute = reminderMinute
return Calendar.current.date(from: components) ?? Date()
}
set {
let components = Calendar.current.dateComponents([.hour, .minute], from: newValue)
reminderHour = components.hour ?? 8
reminderMinute = components.minute ?? 0
}
}
var hapticsEnabled: Bool {
get { cloudSync.data.hapticsEnabled }
set { update { $0.hapticsEnabled = newValue } }
}
var soundEnabled: Bool {
get { cloudSync.data.soundEnabled }
set { update { $0.soundEnabled = newValue } }
}
var ritualLengthDays: Double {
get { Double(cloudSync.data.ritualLengthDays) }
set { update { $0.ritualLengthDays = Int(newValue) } }
}
var iCloudAvailable: Bool { cloudSync.iCloudAvailable }
var iCloudEnabled: Bool {
get { cloudSync.iCloudEnabled }
set { cloudSync.iCloudEnabled = newValue }
}
var lastSyncDate: Date? { cloudSync.lastSyncDate }
var syncStatus: String { cloudSync.syncStatus }
var hasCompletedInitialSync: Bool { cloudSync.hasCompletedInitialSync }
init() {
Task { await refreshNotificationStatus() }
}
func forceSync() {
cloudSync.sync()
}
/// Refreshes the notification authorization status.
func refreshNotificationStatus() async {
notificationAuthStatus = await NotificationService.shared.authorizationStatus
}
private func update(_ transform: (inout AppSettingsData) -> Void) {
cloudSync.update { data in
transform(&data)
}
}
// MARK: - Notification Handling
private func handleReminderToggle(enabled: Bool) async {
if enabled {
await scheduleReminder()
} else {
NotificationService.shared.cancelAllReminders()
}
await refreshNotificationStatus()
}
private func scheduleReminder() async {
let components = cloudSync.data.reminderTimeComponents
await NotificationService.shared.scheduleDailyReminder(at: components)
await refreshNotificationStatus()
}
}
extension SettingsStore {
static var preview: SettingsStore {
SettingsStore()
}
}