import SwiftUI import SwiftData import EventKit @MainActor final class SettingsViewModel: ObservableObject { @Published var availableCalendars: [EKCalendar] = [] @Published var showCalendarPermissionAlert: Bool = false @Published var showToast: Bool = false @Published var toastMessage: String = "" func loadCalendars() { availableCalendars = CalendarService.shared.availableCalendars() } @discardableResult func ensureValidCalendarSelection(settings: AppSettings) -> Bool { loadCalendars() guard !availableCalendars.isEmpty else { settings.calendarId = nil settings.syncEnabled = false showToastMessage(String(localized: "toast_calendar_unavailable")) return false } if let selected = settings.calendarId, availableCalendars.contains(where: { $0.calendarIdentifier == selected }) { return true } settings.calendarId = availableCalendars.first?.calendarIdentifier return true } func requestCalendarAccess() async -> Bool { let granted = await CalendarService.shared.requestAccess() if !granted { showCalendarPermissionAlert = true } else { loadCalendars() } return granted } func openSystemSettings() { if let url = URL(string: UIApplication.openSettingsURLString) { UIApplication.shared.open(url) } } func updateCalendarEvents(settings: AppSettings, plan: WeekPlan?) { guard let plan = plan, settings.syncEnabled else { return } CalendarService.shared.updateEventsTime( slots: plan.slots, weekStartDate: plan.weekStartDate, settings: settings ) } func resetAllData(context: ModelContext) { do { try deleteAll(of: MealSlot.self, in: context) try deleteAll(of: WeekPlan.self, in: context) try deleteAll(of: Dish.self, in: context) try deleteAll(of: Tag.self, in: context) DefaultDataService.createDefaultTags(context: context) let settingsDescriptor = FetchDescriptor() if let existingSettings = try context.fetch(settingsDescriptor).first { resetSettings(existingSettings) } else { DefaultDataService.createDefaultSettings(context: context) if let createdSettings = try context.fetch(settingsDescriptor).first { resetSettings(createdSettings) } } try context.save() } catch { #if DEBUG print("Failed to reset all data: \(error)") #endif } } private func deleteAll(of type: T.Type, in context: ModelContext) throws { let descriptor = FetchDescriptor() let models = try context.fetch(descriptor) for model in models { context.delete(model) } try context.save() } private func showToastMessage(_ message: String) { toastMessage = message withAnimation(.easeInOut(duration: 0.2)) { showToast = true } } private func resetSettings(_ settings: AppSettings) { let defaults = AppSettings() settings.mealWindows = defaults.mealWindows settings.includeWeekends = defaults.includeWeekends settings.language = defaults.language settings.calendarId = defaults.calendarId settings.syncEnabled = defaults.syncEnabled settings.syncMode = defaults.syncMode settings.lunchTime = defaults.lunchTime settings.dinnerTime = defaults.dinnerTime settings.eventDuration = defaults.eventDuration settings.eventPrefix = defaults.eventPrefix settings.reminderMinutesBefore = defaults.reminderMinutesBefore settings.iCloudSyncEnabled = false settings.onboardingCompleted = false } }