feat(ios): Kalender des Geraets anzeigen und bespielen
Die Kalenderveroeffentlichung in Outlook ist oft von der IT gesperrt, und iCloud laesst sich nicht ueber einen ICS-Link einbinden. Das iPhone kennt beide Konten aber bereits, also liest die App sie per EventKit direkt. Die Termine bleiben auf dem Geraet und gehen nie an den Server. Im Web und auf anderen Geraeten erscheinen sie deshalb nicht — dafuer braucht es keine fremden Zugangsdaten und keine Kopie fremder Termindaten in unserer Datenbank. Standardmaessig aus: der Schalter steht unter Konten, und erst beim Einschalten fragt EventKit nach Zugriff. Wer die Funktion nicht will, sieht keine Berechtigungsabfrage. Kaum neuer Code noetig, weil CalEvent schon source/calendarId/readOnly hat und die Sichtbarkeits-, Sortier- und Ausblendlogik an calendarKey(source:calendarId:) haengt: die Quelle "device" rutscht ohne Umbau hinein. WritableCalendar bekommt nur ein deviceId, weil EventKit Zeichenketten statt Zeilen-IDs vergibt. Lesen, Anlegen, Aendern und Loeschen gehen ueber dieselben Ansichten wie bei allen anderen Quellen. Nur die Gruppenansicht bleibt aussen vor, die ist serverseitig zusammengesetzt. Statt den Store durch zwei Views zu reichen, damit der Kalender nach dem Einschalten nachlaedt, zaehlt der Dienst eine Generation hoch; ein abweichender Stand gilt im Cache als Treffer-Fehlschlag. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
2db4b42fa1
commit
c811486ea7
@@ -30,6 +30,8 @@ struct AccountsView: View {
|
||||
@State private var birthdayNotify = -1
|
||||
|
||||
@AppStorage("appLanguage") private var appLang = "system"
|
||||
@AppStorage(DeviceCalendarService.enabledKey) private var deviceCalendarsEnabled = false
|
||||
@State private var deviceCalendarAccessGranted = false
|
||||
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
@@ -42,6 +44,7 @@ struct AccountsView: View {
|
||||
caldavSection
|
||||
localSection
|
||||
birthdayContactsSection
|
||||
deviceCalendarSection
|
||||
icalSection
|
||||
googleSection
|
||||
haSection
|
||||
@@ -235,6 +238,30 @@ struct AccountsView: View {
|
||||
localCalendars.first { $0.isBirthday && $0.owned }
|
||||
}
|
||||
|
||||
/// Calendars the phone already has (iCloud, Outlook/Exchange, Google).
|
||||
/// They stay on the device — the server never sees them — so this is the
|
||||
/// way in when publishing an Outlook calendar is blocked by company policy.
|
||||
@ViewBuilder var deviceCalendarSection: some View {
|
||||
Section {
|
||||
Toggle(L10n.t("device.calendars.enable", appLang), isOn: $deviceCalendarsEnabled)
|
||||
if deviceCalendarsEnabled && !deviceCalendarAccessGranted {
|
||||
Text(L10n.t("device.calendars.denied", appLang))
|
||||
.font(.caption).foregroundStyle(.secondary)
|
||||
}
|
||||
} header: {
|
||||
Text(L10n.t("device.calendars.header", appLang))
|
||||
} footer: {
|
||||
Text(L10n.t("device.calendars.desc", appLang))
|
||||
}
|
||||
.onChange(of: deviceCalendarsEnabled) { _, on in
|
||||
guard on else { return }
|
||||
// Granting access bumps the service generation, which makes the
|
||||
// calendar reload instead of serving its pre-device cache.
|
||||
Task { deviceCalendarAccessGranted = await DeviceCalendarService.shared.requestAccess() }
|
||||
}
|
||||
.task { deviceCalendarAccessGranted = DeviceCalendarService.shared.hasAccess }
|
||||
}
|
||||
|
||||
@ViewBuilder var birthdayContactsSection: some View {
|
||||
Section {
|
||||
if let cal = birthdayCalendar {
|
||||
|
||||
Reference in New Issue
Block a user