Merge pull request #359 from nightah/refactor/calendar-selection-grouping

refactor(calendar): group calendars by accounts in settings
This commit is contained in:
Hariharan Mudaliar 2026-03-26 23:46:30 +05:30 • committed by GitHub
commit 8ff53e0d80
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 74 additions and 10 deletions

View file

@ -146,6 +146,7 @@ class CalendarService: CalendarServiceProviding {
extension CalendarModel { extension CalendarModel {
init(from calendar: EKCalendar) { init(from calendar: EKCalendar) {
self.init( self.init(
accountName: calendar.accountTitle,
id: calendar.calendarIdentifier, id: calendar.calendarIdentifier,
title: calendar.title, title: calendar.title,
color: calendar.color, color: calendar.color,
@ -267,7 +268,7 @@ extension Priority {
// MARK: - Helper Extensions // MARK: - Helper Extensions
private extension EKCalendar { extension EKCalendar {
var accountTitle: String { var accountTitle: String {
switch source.sourceType { switch source.sourceType {
case .local, .subscribed, .birthdays: case .local, .subscribed, .birthdays:

View file

@ -2905,18 +2905,48 @@ struct CalendarSettings: View {
} }
Section(header: Text("Select Calendars")) { Section(header: Text("Select Calendars")) {
ForEach(calendarManager.allCalendars, id: \.id) { calendar in let grouped = Dictionary(grouping: calendarManager.allCalendars, by: \.accountName)
Toggle(isOn: Binding( let sortedAccounts = grouped.keys.sorted()
get: { calendarManager.getCalendarSelected(calendar) },
set: { isSelected in ForEach(sortedAccounts, id: \.self) { account in
Task { let accountCalendars = grouped[account] ?? []
await calendarManager.setCalendarSelected(calendar, isSelected: isSelected) let allAccountSelected = accountCalendars.allSatisfy { calendarManager.getCalendarSelected($0) }
Section(header: HStack {
Text(account)
Spacer()
Toggle("", isOn: Binding(
get: { allAccountSelected },
set: { isSelected in
Task {
await calendarManager.setCalendarsSelected(accountCalendars, isSelected: isSelected)
}
} }
))
.labelsHidden()
.toggleStyle(.switch)
.controlSize(.mini)
.disabled(!showCalendar)
}) {
ForEach(accountCalendars, id: \.id) { calendar in
Toggle(isOn: Binding(
get: { calendarManager.getCalendarSelected(calendar) },
set: { isSelected in
Task {
await calendarManager.setCalendarSelected(calendar, isSelected: isSelected)
}
}
)) {
HStack(spacing: 8) {
Circle()
.fill(Color(calendar.color))
.frame(width: 8, height: 8)
Text(calendar.title)
}
}
.disabled(!showCalendar)
} }
)) {
Text(calendar.title)
} }
.disabled(!showCalendar)
} }
} }
} }

View file

@ -382,6 +382,36 @@ class CalendarManager: ObservableObject {
lastEventsFetchDate = Date() lastEventsFetchDate = Date()
} }
func setCalendarsSelected(_ calendars: [CalendarModel], isSelected: Bool) async {
var selectionState = Defaults[.calendarSelectionState]
let ids = Set(calendars.map { $0.id })
switch selectionState {
case .all:
if !isSelected {
let identifiers = Set(allCalendars.map { $0.id }).subtracting(ids)
selectionState = .selected(identifiers)
}
case .selected(var identifiers):
if isSelected {
identifiers.formUnion(ids)
} else {
identifiers.subtract(ids)
}
if identifiers.isEmpty || identifiers.count == allCalendars.count {
selectionState = .all
} else {
selectionState = .selected(identifiers)
}
}
Defaults[.calendarSelectionState] = selectionState
updateSelectedCalendars()
await updateEvents(force: true)
await updateLockScreenEvents(force: true)
}
func setReminderCompleted(reminderID: String, completed: Bool) async { func setReminderCompleted(reminderID: String, completed: Bool) async {
await calendarService.setReminderCompleted(reminderID: reminderID, completed: completed) await calendarService.setReminderCompleted(reminderID: reminderID, completed: completed)
await updateEvents(force: true) await updateEvents(force: true)

View file

@ -302,6 +302,7 @@ final class LockScreenWidgetPreviewManager: ObservableObject {
private func applyCalendarPreviewEvents() { private func applyCalendarPreviewEvents() {
let now = Date() let now = Date()
let reminderCalendar = CalendarModel( let reminderCalendar = CalendarModel(
accountName: "Preview",
id: "preview.reminders", id: "preview.reminders",
title: "Reminders", title: "Reminders",
color: .systemBlue, color: .systemBlue,
@ -327,6 +328,7 @@ final class LockScreenWidgetPreviewManager: ObservableObject {
) )
let eventCalendar = CalendarModel( let eventCalendar = CalendarModel(
accountName: "Preview",
id: "preview.calendar", id: "preview.calendar",
title: "Calendar", title: "Calendar",
color: .systemOrange, color: .systemOrange,

View file

@ -23,6 +23,7 @@
import Cocoa import Cocoa
struct CalendarModel: Identifiable, Hashable { struct CalendarModel: Identifiable, Hashable {
let accountName: String
let id: String let id: String
let title: String let title: String
let color: NSColor let color: NSColor