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>
Routing the post-save reload through the manual sync button made a new Home
Assistant event appear, but at the cost of invalidateCache(), which drops the
cached events as well as the range bounds — so every event vanished and
reappeared for one new one. That reads as unfinished, and it is.
Only the range bounds have to go: nil bounds are what force the next fetch to
reach the server. The events can stay on screen until the fresh ones replace
them. Saving now does exactly that and nothing more; the menu's manual sync
keeps clearing everything, which is what a full refresh is for.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Saving ran loadEvents(force: true), which skips the isCached check but leaves
the existing cache in place. The manual reload button clears the cache first,
and that is the one that reliably shows a newly created Home Assistant event.
Rather than keep reasoning about why bypassing the cache is not enough, saving
now takes the path that demonstrably works — the only difference between the
two was invalidateCache().
reloadVisible had no callers left and is gone.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
An iCal subscription could be banished but never un-banished. The server has
always sent and accepted sidebar_hidden for subscriptions, but iOS left the
field off ICalSubscription entirely and omitted "ical" from
serverManagedSources, from setCalendarSidebarHidden and from both places that
reconcile the server's flag. So the key went into banishedCalendarKeys and
nothing ever took it out: refreshFromCache filters on that set as well as on
hiddenCalendarKeys, which is why showing the calendar again left its events
invisible and no amount of syncing helped. Closed on all four sides.
The account models are also no longer brittle about absent fields.
HomeAssistantAccount required auth_method, and CalDAVCalendar and
GoogleCalendar required sidebar_hidden, with no custom decoder — one missing
key threw, the `try?` at the call site turned that into an empty list, and the
reconciliation silently did not run, stranding calendars as banished in exactly
the same way. HACalendar already carried a lenient decoder for this reason; the
other three now do too.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The monorepo's Xcode project referenced ../CalendarrKit, but the package was
never brought across: it is the one repo that never had a remote, so it existed
only on one machine. Added as a subtree at the root, where that existing
relative path resolves, so the project needs no change. History is preserved —
the commits explaining why the snapshot colours sit flat on the wire and why
the package must stay Foundation-only are the kind of thing that cannot be
reconstructed later.
The iOS target also did not compile on beta, independent of any of this. The
attachments section combined a string title with a footer, and SwiftUI has no
initializer for that pair: the title then binds as the first positional
argument of Section(content:footer:), which is what the three misleading
"generic parameter 'Content'" errors were. Rewritten as header:/footer:, the
way the reminders section directly above already does it.
Carries over the pending change from the archived iOS repo: each calendar
source now reports its own failure instead of being swallowed by `try?`, so an
absent Home Assistant calendar can finally be diagnosed from the app.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
attachmentCount im Event-Parser, EventAttachment als Modell, API-Methoden
fuer Liste, Upload, Download, Thumbnail und Loeschen. Der Multipart-Body
ist von importICS uebernommen.
Die Detailansicht laedt die Liste beim Oeffnen und teilt eine Datei ueber
das System-Share-Sheet; der Editor staged neue Dateien und wendet sie
erst nach dem Speichern an, weil ein neuer Termin vorher keine UID hat.
EventAttachment liegt bewusst in CalEvent.swift statt in einer eigenen
Datei: eine hier angelegte .swift-Datei waere in keinem Xcode-Target
Mitglied und wuerde schlicht nicht mitkompiliert -- das faellt erst auf
dem Mac auf.
Die URL fuer das Share-Sheet steckt in einem kleinen Identifiable-Wrapper,
weil URL das nicht ist und eine nachtraegliche Konformitaet auf einen
Stdlib-Typ modulweit sichtbar waere.
Nicht kompiliert: auf diesem Rechner gibt es kein Xcode. Muss auf dem Mac
gebaut werden.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Calendarr-IOS wird mit vollstaendiger Historie als Unterverzeichnis
ios/ eingebunden. Damit liegen Server, Web, Android und iOS in einem
gemeinsamen Repo.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>