import EventKit import Foundation class CalendarService: ObservableObject { private let eventStore = EKEventStore() @Published var events: [EKEvent] = [] @Published var selectedCalendars: Set = [] @Published var availableCalendars: [EKCalendar] = [] @Published var hasAccess = false init() { Task { await requestAccess() } setupNotificationObserver() } deinit { NotificationCenter.default.removeObserver(self) } private func setupNotificationObserver() { NotificationCenter.default.addObserver( forName: .EKEventStoreChanged, object: eventStore, queue: .main ) { [weak self] _ in self?.handleEventStoreChanged() } NotificationCenter.default.addObserver( forName: .NSCalendarDayChanged, object: nil, queue: .main ) { [weak self] _ in self?.handleDayChanged() } } @MainActor private func handleEventStoreChanged() { loadCalendars() loadEvents() } @MainActor private func handleDayChanged() { loadEvents() } @MainActor func requestAccess() async { do { let granted = try await eventStore.requestFullAccessToEvents() hasAccess = granted if granted { loadCalendars() loadDefaultSelectedCalendars() loadEvents() } } catch { print("Calendar access error: \(error)") hasAccess = false } } @MainActor func loadCalendars() { availableCalendars = eventStore.calendars(for: .event) } @MainActor func loadDefaultSelectedCalendars() { if let savedCalendars = UserDefaults.standard.array(forKey: "selectedCalendars") as? [String] { selectedCalendars = Set(savedCalendars) } else { selectedCalendars = Set(availableCalendars.map { $0.calendarIdentifier }) } } @MainActor func saveSelectedCalendars() { UserDefaults.standard.set(Array(selectedCalendars), forKey: "selectedCalendars") loadEvents() } @MainActor func loadEvents() { let calendar = Calendar.current let today = calendar.startOfDay(for: Date()) guard let startDate = calendar.date(byAdding: .day, value: -14, to: today), let endDate = calendar.date(byAdding: .day, value: 14, to: today) else { return } let calendars = availableCalendars.filter { selectedCalendars.contains($0.calendarIdentifier) } let predicate = eventStore.predicateForEvents(withStart: startDate, end: endDate, calendars: calendars) let fetchedEvents = eventStore.events(matching: predicate) events = fetchedEvents.sorted { $0.startDate < $1.startDate } } }