125 lines
3.5 KiB
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()
|
|
}
|
|
}
|