Lokaler Kalender in Rust mit CalDAV-Sync gegen Nextcloud (Linux, Windows, Android)
  • Rust 81.9%
  • Slint 14.5%
  • Kotlin 2%
  • Python 0.9%
  • Shell 0.7%
Find a file
audioprog 3d224f872f
All checks were successful
test / test (push) Successful in 24m37s
packages / debian (push) Successful in 10m57s
android / android (push) Successful in 15m35s
packages / opensuse (push) Successful in 12m3s
release / release (push) Successful in 14m45s
Bildschirmfotos fuer den englischen Ladeneintrag
Vier Motive, dieselben wie deutsch: Monat, Tag mit mehreren Terminen,
Woche, Nextcloud verbinden. Aufgenommen aus der Release-APK der Fassung
0.6.0 auf dem AVD ngencal_laden, 1080x1920 -- das Telefon-AVD hat 1080x2400
und waere mit 2,22:1 ueber Plays Grenze von 2:1.

Zwei Kleinigkeiten, die das Bild sonst verdorben haetten und die in
ladeneintrag-en.md notiert sind: ohne vorher erteilte Benachrichtigungs-
Erlaubnis steht unten eine rote Warnung, und das Kontoblatt gehoert ueber
die Monatsansicht, weil das deutsche 05 es so zeigt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 19:26:29 +02:00
.forgejo/workflows Geprueft wird jetzt gegen 34, weil die echte Instanz auf 34 laeuft 2026-08-31 14:09:24 +02:00
.vscode Umbenennung auf ngenNcCalendar 2026-08-15 07:59:47 +02:00
doc/iphone Die iPhone-Anleitung auch auf englisch 2026-09-14 11:38:23 +02:00
ngen_nc_cal_android Bildschirmfotos fuer den englischen Ladeneintrag 2026-09-14 19:26:29 +02:00
ngen_nc_cal_core Was zurueckgenommen wurde, laesst sich wiederherstellen 2026-09-14 16:01:10 +02:00
ngen_nc_cal_desktop Was zurueckgenommen wurde, laesst sich wiederherstellen 2026-09-14 16:01:10 +02:00
pruefung K-02 mit zwei echten Clients belegt 2026-08-20 16:21:17 +02:00
tests Geprueft wird jetzt gegen 34, weil die echte Instanz auf 34 laeuft 2026-08-31 14:09:24 +02:00
.gitignore Betriebsunterlagen des Demoservers bleiben draußen 2026-08-25 10:32:04 +02:00
ARCHITEKTUR.md Zweisprachigkeit und Wiederherstellen gehoeren zu 0.6.0 2026-09-14 16:15:55 +02:00
Cargo.lock Abhaengigkeiten auf den neuesten Stand gebracht 2026-09-14 13:20:33 +02:00
Cargo.toml Die Symbole fuer Play tragen jetzt wirklich eine Symboltabelle 2026-09-14 19:18:15 +02:00
check.sh Auch die Rust-Texte sprechen Englisch 2026-09-14 15:31:21 +02:00
CLAUDE.md Zweisprachigkeit und Wiederherstellen gehoeren zu 0.6.0 2026-09-14 16:15:55 +02:00
DATENSCHUTZ.md Datenschutzerklärung über die raw-Adresse 2026-08-20 15:49:15 +02:00
FORTSCHRITT.md Die Symbole fuer Play tragen jetzt wirklich eine Symboltabelle 2026-09-14 19:18:15 +02:00
GELERNT.md Uhrzeit-Knopf traegt ein Zifferblatt statt des Wortes 2026-09-14 15:39:41 +02:00
LICENSE Release-Workflow: ein Tag baut Linux und Windows 2026-08-11 16:50:37 +02:00
PRUEFLAUF.md Protokollierung im Schreibtisch-Client, Befund zurückgenommen 2026-08-20 16:40:36 +02:00
PRUEFPLAN.md Was zurueckgenommen wurde, laesst sich wiederherstellen 2026-09-14 16:01:10 +02:00
README.md Die iPhone-Anleitung auch auf englisch 2026-09-14 11:38:23 +02:00

ngenNcCalendar

Lokaler Kalender in Rust mit CalDAV-Anbindung an Nextcloud, für Linux, Windows und Android. Die Daten liegen lokal; der Server ist ein Replikat, nicht die Voraussetzung zum Arbeiten.

Dieses Projekt ist KI-Programmiert und vom Menschen geleitet.

Stand: v0.1.0 veröffentlicht, Meilensteine 1 bis 5 abgeschlossen — Monatsansicht, lokaler SQLite-Speicher, CalDAV in beide Richtungen, Konto-Einrichtung, Wiederholungsregeln, Zeitzonen samt Windows-Namen, Anlegen/Ändern/Löschen, Konfliktauflösung, selbsttätiger Abgleich, Erinnerungen als Systembenachrichtigung und ICS-Export. Alles gegen eine echte Nextcloud durchgespielt. Offen: Android.

Wo das Projekt liegt

Zuhause auf einem selbst betriebenen Forgejo, gespiegelt nach GitLab:

Quelle https://git.bg-ak.de/leonhard.suckau/ngenNcCalendar — hier laufen CI und Releases
Spiegel https://gitlab.com/audioprog/ngennccalendar — öffentlich erreichbar, trägt die Datenschutzerklärung für Google Play

Gespiegelt wird serverseitig: Forgejo schiebt bei jedem Push nach GitLab (Repo-Einstellungen → Mirror-Einstellungen). Lokal bleibt es bei einem einzigen Remote — zwei Push-Adressen am selben Remote wären der andere Weg, aber dann hinge der Spiegel an diesem einen Rechner, und ein Push von woanders käme dort nie an.

Der Spiegel überträgt Commits und Tags, keine Releases: die Archive und die APK liegen weiterhin nur am Forgejo.

Aufbau

ngen_nc_cal_core     Plattformunabhängiger Kern — kennt keine GUI und kein OS.
                  Domänenmodell, Kalenderrechnung, später iCalendar, SQLite,
                  CalDAV-Sync. Vollständig headless testbar.
ngen_nc_cal_desktop  Desktop-GUI (Slint), Binary `ngennccalendar`.
                  Hält nur den Ansichtszustand und füllt die Slint-Modelle.

Diese Trennung ist der Kern des Entwurfs: Android bekommt später ein eigenes Frontend auf demselben Kern — kein zweiter Sync-Pfad, kein zweites Datenmodell.

  • ngen_nc_cal_core/src/model.rs Kalender, Termine, die drei iCalendar-Zeitformen
  • ngen_nc_cal_core/src/month.rs 6×7-Monatsraster, Kalenderwoche, deutsche Datumsformate
  • ngen_nc_cal_core/src/source.rs EventSource: die Abfrage-Schnittstelle der Frontends
  • ngen_nc_cal_core/src/sqlite.rs lokale Datenbank: Schema, Migration, Bereichsabfrage
  • ngen_nc_cal_core/src/store.rs dieselbe Schnittstelle im Arbeitsspeicher (Tests, Beispieldaten)
  • ngen_nc_cal_core/src/ical.rs iCalendar lesen (RFC 5545)
  • ngen_nc_cal_core/src/icalwrite.rs iCalendar schreiben: neu anlegen, im Rohtext ändern
  • ngen_nc_cal_core/src/icalexport.rs einen ganzen Kalender als eine .ics ausgeben
  • ngen_nc_cal_core/src/projection.rs daraus die Zeilen für die Anzeige, in der Anzeigezone
  • ngen_nc_cal_core/src/recurrence.rs Wiederholungsregeln (RRULE) auswerten
  • ngen_nc_cal_core/src/search.rs Titel und Ort aus dem Rohtext, für die Suche und die Ortsliste
  • ngen_nc_cal_core/src/reminders.rs wann eine Erinnerung (VALARM) fällig ist
  • ngen_nc_cal_core/src/windowszones.rs Windows-Zonennamen auf IANA-Zonen abbilden
  • ngen_nc_cal_core/src/series.rs eine .ics für einen Zeitraum ausrechnen, samt Ausnahmen
  • ngen_nc_cal_core/src/caldav/ CalDAV-Client; xml.rs ist die serverfreie Hälfte
  • ngen_nc_cal_core/src/sync.rs der Abgleich: ctag → Delta → Vollabgleich als Rückfall
  • ngen_nc_cal_core/src/demo.rs Beispieldaten, solange kein Konto eingerichtet ist
  • ngen_nc_cal_desktop/ui/appwindow.slint die GUI
  • ngen_nc_cal_desktop/src/main.rs Verdrahtung Kern ↔ GUI
  • ngen_nc_cal_desktop/src/account.rs Anmeldung und Abgleich im Hintergrund-Thread
  • ngen_nc_cal_desktop/src/form.rs Termin-Formular: zwischen Textfeldern und Modell
  • ngen_nc_cal_desktop/src/secrets.rs App-Passwort: Schlüsselbund oder eigene Datei
  • ngen_nc_cal_desktop/src/paths.rs wo die Datenbank liegt (XDG bzw. %APPDATA%)
  • ngen_nc_cal_desktop/src/notify.rs fällige Erinnerung an den Benachrichtigungsdienst des Systems
  • ngen_nc_cal_desktop/src/update.rs Selbst-Aktualisierung über die Forgejo-Releases
  • ngen_nc_cal_desktop/ui/icon.svg Programmsymbol (Quelle); icon.ico ist das daraus gebaute Windows-Symbol

Veröffentlichen

Ein Tag vX.Y.Z auf main löst .forgejo/workflows/release.yml aus: Linux und Windows werden gebaut und als Release veröffentlicht. Die Version im Tag muss zur Workspace-Version in Cargo.toml passen — der Workflow bricht sonst ab, denn sonst böte die Selbst-Aktualisierung dasselbe Update endlos erneut an.

# Vor dem Tag: baut es überhaupt für Windows?
cargo check --target x86_64-pc-windows-gnu -p ngen_nc_cal_desktop

# Version in Cargo.toml anheben, committen, dann:
git tag v0.2.0 && git push origin v0.2.0

Der Windows-Check vor dem Tag ist kein Ritual. Der erste Release-Versuch scheiterte daran, dass notify_rust::Notification::hint() nur unter Unix existiert — hier fällt das nie auf, weil hier für Linux gebaut wird. Im Workflow kommt der Windows-Bau nach dem Linux-Bau, ein solcher Fehler kostet dort also erst eine Viertelstunde und dann einen verbrannten Tag. Bewusst nicht ins Tor von test.yml genommen: die Prüfung für ein zweites Ziel dauert rund zwölf Minuten und würde jeden Push ausbremsen.

Warum -gnu und nicht das CI-Ziel -msvc: für MSVC braucht cargo xwin noch llvm-lib und lld-link, die hier nicht installiert sind. Für diese Art Fehler genügt -gnu — beide Ziele sehen dieselben cfg(windows)-Zweige, sie unterscheiden sich erst in C-Laufzeit und Linker.

Je Release entstehen drei Assets:

Asset wofür
ngenNcCalendar-x86_64-unknown-linux-gnu.tar.gz Linux, mit Lizenz, Symbol und Desktop-Eintrag — das zieht der Updater
ngennccalendar-x86_64-unknown-linux-gnu dieselbe Binärdatei nackt: herunterladen, chmod +x, starten
ngenNcCalendar-x86_64-pc-windows-msvc.zip Windows

Ein Tag baut zusätzlich das Android-Paket (.forgejo/workflows/android.yml) und hängt zwei weitere Assets an:

Asset wofür
ngenNcCalendar-android.aab zum Hochladen in die Google Play Console
ngenNcCalendar-android.apk zum direkten Installieren, ohne Play

Nicht beides auf demselben Gerät. Play signiert die verteilte App mit seinem eigenen Schlüssel neu; die APK hier trägt den Upload-Schlüssel. Android hält das für zwei verschiedene Apps und verweigert die Aktualisierung („App nicht installiert"). Der Wechsel ginge nur über Deinstallieren — und das löscht die lokale Datenbank samt allem, was noch nicht beim Server ist. Einen Weg wählen und dabei bleiben; siehe GELERNT.md.

Dafür braucht es vier Secrets — ANDROID_KEYSTORE_BASE64, ANDROID_KEYSTORE_PASSWORD, ANDROID_KEY_ALIAS, ANDROID_KEY_PASSWORD —, sonst bricht der Lauf gleich am Anfang ab statt nach zwanzig Minuten.

Die Namen sind Vertrag mit ngen_nc_cal_desktop/src/update.rs: gesucht wird per Target-Triple nach einem Asset, dessen Name auch ngenNcCalendar enthält, mit ngennccalendar im Wurzelverzeichnis des Archivs. Die nackte Binärdatei ist deshalb klein geschrieben — so fällt sie aus der Auswahl des Updaters heraus und kann dem Archiv nicht den Rang ablaufen. asset_for nimmt nämlich den ersten Treffer, nicht den besten. Ein Test in update.rs liest die Workflow-Datei und schlägt fehl, wenn jemand daran dreht. Voraussetzung ist ein Secret PACKAGES_TOKEN mit Scope write:repository.

Die Datenbank liegt unter ~/.local/share/ngennccalendar/ngennccalendar.sqlite (Windows: %APPDATA%\ngenNcCalendar\). Die Statuszeile im Fenster nennt den Pfad und sagt, ob gerade echte Daten oder Beispieldaten zu sehen sind.

Distributionspakete

Derselbe Tag löst zusätzlich .forgejo/workflows/packages.yml aus: ein .deb und ein .rpm, beide in der Paketregistry von Forgejo — nicht als Release-Asset. Die Asset-Namen im Release sind Vertrag mit der Selbst-Aktualisierung; zwei weitere Dateien dort, deren Namen zufällig x86_64 enthalten, wären ein Risiko ohne Gegenwert.

Die Registry-Seite in Forgejo zeigt dieselben Zeilen mit $distribution und $component — das sind Platzhalter, keine Shell-Variablen. Kopiert man sie unverändert in eine Shell, werden sie zu nichts, und apt meldet „Missgestalteter Eintrag … (Suite)": eine Meldung, die aufs Format zeigt und nicht auf die Ursache. Hier stehen die Werte deshalb ausgeschrieben.

Die Quelle heißt nach dem Registry-Eigentümer, nicht nach diesem Projekt. Unter leonhard.suckau/debian liegen alle Pakete dieses Kontos, ngenAudioRecord eingeschlossen. Wer je Projekt eine eigene .list anlegt, hat zweimal dieselbe Quelle mit womöglich verschiedenen Schlüsselpfaden — und apt verweigert dann den Dienst komplett: „Widersprüchliche Werte gesetzt für Option Signed-By".

# Debian, Ubuntu und Verwandte
sudo install -d /etc/apt/keyrings
curl -fsSL https://git.bg-ak.de/api/packages/leonhard.suckau/debian/repository.key \
  | sudo tee /etc/apt/keyrings/forgejo-leonhard.suckau.asc >/dev/null
echo "deb [signed-by=/etc/apt/keyrings/forgejo-leonhard.suckau.asc] https://git.bg-ak.de/api/packages/leonhard.suckau/debian bookworm main" \
  | sudo tee /etc/apt/sources.list.d/forgejo-leonhard.suckau.list
sudo apt update && sudo apt install ngennccalendar

Der Schlüssel wird ASCII-armiert ausgeliefert; signed-by kommt mit .asc unmittelbar zurecht, ein gpg --dearmor ist unnötig.

# openSUSE
# Der Schlüssel muss VOR dem Hinzufügen eingelesen werden: Forgejo signiert die
# repomd.xml, und zypper bricht sonst mit „Signature verification failed" ab und
# überspringt die Quelle stillschweigend — die Installation scheitert dann mit
# „No provider of 'ngennccalendar' found", was wie ein fehlendes Paket aussieht.
sudo rpm --import https://git.bg-ak.de/api/packages/leonhard.suckau/rpm/repository.key
# Auch hier der Eigentümer als Name der Quelle, nicht das Projekt:
sudo zypper ar https://git.bg-ak.de/api/packages/leonhard.suckau/rpm/leap16 forgejo-leonhard.suckau
sudo zypper in ngennccalendar

Jedes Paket wird in einem Container seiner Zieldistribution gebaut, nicht einmal gebaut und zweimal verpackt. Das ist keine Sorgfaltsgeste: bookworm bringt glibc 2.36, Leap 16.0 bringt 2.40 (nachgemessen). Ein auf Leap gebautes Programm verlangt Symbole, die bookworm nicht kennt — das Paket ließe sich installieren und stürbe beim ersten Start. Aus demselben Grund heißt die zypper-Gruppe leap16 und nicht stable: ein späteres Tumbleweed-Paket gehört in eine eigene, nicht in dieselbe.

Die Abhängigkeiten stehen zur Hälfte von Hand da. dpkg-shlibdeps und find-requires lesen die SONAMEs aus dem ELF-Header, sehen also nur, was der Linker eingetragen hat. Beim ersten Bau kamen genau zwei Einträge heraus: libc6 und libfontconfig1. Alles Weitere — X11, Wayland, EGL, GL, xkbcommon — holt sich Slint zur Laufzeit per dlopen, und davon steht nichts im Header. Das Paket hätte sich installieren lassen und wäre beim Start gescheitert. Die Liste in ngen_nc_cal_desktop/Cargo.toml stammt deshalb aus dem Binary selbst:

strings -a target/release/ngennccalendar \
  | grep -oE 'lib[A-Za-z0-9_+-]+\.so(\.[0-9]+)?' | sort -u

Beim .deb stehen dort Debian-Paketnamen, beim .rpm die SONAMEs als Capability — openSUSE benennt seine Pakete anders, aber jedes RPM stellt den SONAMEn bereit, den es mitbringt. Die automatische Hälfte bleibt trotzdem eingeschaltet, deshalb sind dpkg-dev und rpm-build im Container Pflicht.

Beides ist am 31.08.2026 gegen die Registry durchgespielt worden, jeweils in einem leeren Container: apt-get install ngennccalendar zieht unter bookworm und unter Ubuntu 26.04 alle zwölf Bibliotheken mit, zypper in ngennccalendar löst die SONAMEs unter Leap 16.0 auf openSUSE-eigene Paketnamen auf (Mesa-libEGL1, Mesa-libGL1 …) und installiert 56 Pakete. Das ist der Grund für die SONAME-Schreibweise: eine Liste geratener openSUSE-Paketnamen wäre hier falsch gewesen.

Aus dem Paket installiert heißt: kein Selbst-Ersetzen. Liegt die Binärdatei unter /usr/bin, verweigert der Aktualisieren-Knopf die Arbeit und nennt stattdessen apt upgrade bzw. zypper up. Erkannt wird das am Pfad, nicht am Schreibrecht — als root dürfte das Programm nach /usr/bin schreiben und täte damit genau das Falsche: dpkg und rpm führen Buch über jede Datei, die sie angelegt haben.

Voraussetzung ist, dass PACKAGES_TOKEN zusätzlich den Scope write:package trägt. Für release.yml genügt write:repository; die Registry ist ein eigener Scope. Der erste Schritt jedes Paketjobs prüft das Recht, bevor eine Viertelstunde Bauzeit verbrannt ist.

Entwicklung

cargo run                                        # Desktop-GUI starten
cargo test -p ngen_nc_cal_core                      # Kern ohne Netz und ohne HTTP-Stack
cargo test -p ngen_nc_cal_core --features caldav    # zusätzlich CalDAV und Abgleich

Der Netzzugriff steckt hinter dem Feature caldav. Ohne das Feature hat ngen_nc_cal_core keinen HTTP-Stack — das hält die Kern-Tests schnell und den späteren Android-Build klein. Die CI prüft beide Varianten.

Klemmt die Verbindung zum Server, zerlegt dieses Werkzeug die Kette in Namensauflösung, TCP zu jeder gefundenen Adresse und die echte Anfrage:

cargo run -p ngen_nc_cal_core --features caldav --example connection -- cloud.example.de

Klemmt es erst beim Abgleich, geht dieses Werkzeug mit dem eingerichteten Konto den ganzen CalDAV-Ablauf durch — nur lesend, und ohne das App-Passwort auszugeben:

cargo run -p ngen_nc_cal_core --features caldav --example sync

Gegen eine echte Nextcloud prüfen lässt sich der ganze Ablauf mit dem Integrationstest. Er schreibt, deshalb läuft er nur mit ausdrücklich gesetzter Kalender-Adresse und legt ausschließlich Dateien mit dem Präfix ngencal-test- an, die er hinterher wieder löscht — trotzdem gehört dafür ein eigens angelegter Testkalender:

export NGENNCCAL_TEST_CALENDAR=https://cloud.example.de/remote.php/dav/calendars/leo/test/
export NGENNCCAL_TEST_USER=leo
export NGENNCCAL_TEST_PASSWORD=<App-Passwort>
cargo test -p ngen_nc_cal_core --features caldav --test nextcloud -- --nocapture

Statt eines vorhandenen Kalenders geht auch nur die Server-Adresse — dann legt sich der Test seinen Kalender selbst an und entfernt ihn wieder:

export NGENNCCAL_TEST_SERVER=https://cloud.example.de

Ohne diese Variablen überspringt er sich selbst; die CI braucht also keinen Server. Für einen Lauf ohne fremde Instanz liegt in tests/ eine Container-Beschreibung bereit:

podman-compose -f tests/nextcloud-compose.yml up -d
./tests/nextcloud-wait.sh
export NGENNCCAL_TEST_SERVER=http://127.0.0.1:8081
export NGENNCCAL_TEST_USER=admin NGENNCCAL_TEST_PASSWORD=admin-passwort
cargo test -p ngen_nc_cal_core --features caldav --test nextcloud -- --nocapture
podman-compose -f tests/nextcloud-compose.yml down

Das läuft rootless und ohne Sonderrechte; warum Host-Netz statt Port-Weiterleitung benutzt wird, steht in der Compose-Datei.

Die .slint-Datei lässt sich ohne Rust-Code vorschauen (lädt bei jedem Speichern neu):

slint-viewer --auto-reload ngen_nc_cal_desktop/ui/appwindow.slint

Ohne Daten aus Rust bleibt das Raster dabei leer — die Vorschau dient dem Layout, nicht dem Inhalt.

Bedienung

  • / oder Pfeiltasten links/rechts — Monat blättern

  • Heute oder T — zurück zum aktuellen Monat

  • Mehrtägige Termine laufen als durchgehender Balken über die Tage, in jeder Zelle auf derselben Höhe.

  • Klick auf einen Tag — Termine des Tages in der rechten Spalte; ein Klick auf einen Randtag blättert in dessen Monat

  • Konto einrichten — Adresse der Nextcloud eintragen, im Browser bestätigen

  • Abgleichen — von Hand; von selbst passiert es kurz nach dem Start und danach alle 15 Minuten

  • + Neuer Termin in der Tagesspalte, Klick auf einen Termin zum Ändern. Titel, Ort, Beschreibung, Zeitraum, Wiederholung und Erinnerung stehen im Dialog. Bringt die Datei eine ungewöhnliche Erinnerung mit, steht sie zusätzlich in der Liste; was sich nicht schreiben lässt — mehrere, per E-Mail, zu einem festen Zeitpunkt —, bleibt unangetastet.

  • Suchen — über Titel, Ort und Beschreibung. Passt nur die Beschreibung, steht der Ausschnitt um die Fundstelle unter dem Treffer; sonst wüsste man nicht, warum er dasteht.

  • Symbol im Benachrichtigungsfeld — sofern der Schreibtisch eines anzeigt. Dann schließt der ✕ das Fenster nur weg: das Programm läuft weiter und erinnert weiter, das Menü am Symbol öffnet es wieder, gleicht ab oder beendet. Der Kurzhinweis am Symbol nennt den nächsten Termin. Zeigt der Schreibtisch kein Benachrichtigungsfeld, gibt es auch kein Symbol — dann beendet der ✕ das Programm wie zuvor, statt es unsichtbar weiterlaufen zu lassen.

    Unter XFCE fehlt das Feld oft nur in der Leiste: Rechtsklick auf die Leiste → Neue Elemente hinzufügenStatus Tray-Erweiterung. Datum und Uhrzeit werden getippt (TT.MM.JJJJ, HH:MM); 1.8.26 und 9:00 gehen auch. Änderungen sind sofort im Kalender und gehen gleich zum Server — ohne Netz warten sie in der Warteschlange

Wenn zwei Geräte denselben Termin ändern

Dann gewinnt niemand. Die Fassung des Servers steht im Kalender, die eigene daneben — mit Warnzeichen, eigenem Rand und dem Hinweis, dass sie nur lokal existiert. Ein Klick darauf öffnet sie mit zwei Möglichkeiten:

  • Meine übernehmen — sie geht gegen den aktuellen Stand erneut zum Server.
  • Meine verwerfen — nur die lokale Kopie verschwindet.

Darunter steht, worin sich beide unterscheiden — je Feld der Wert vom Server und ein Knopf, der ihn übernimmt. Die Zeile verschwindet dabei, so sieht man, was noch offen ist. Am Ende gilt, was im Formular steht: den Titel von der einen Fassung, den Ort von der anderen, ein Klick je Feld.

Automatisch zusammengeführt wird nichts, denn bei zwei verschiedenen Uhrzeiten gäbe es keine richtige Wahl.

Konto verbinden

Es muss kein App-Passwort von Hand angelegt werden: die App fragt eines an, der Browser öffnet sich zur einmaligen Bestätigung, danach kommt das fertige App-Passwort zurück. Das Kennwort des Kontos selbst sieht das Programm nie, und das App-Passwort lässt sich in Nextcloud jederzeit einzeln zurückziehen.

Wo das App-Passwort liegt, entscheidest du im selben Panel:

  • Schlüsselbund des Systems — Secret Service unter Linux, Credential Manager unter Windows.
  • Selbst speichern — eine Datei im Datenverzeichnis, unter Unix mit 0600. Nötig ohne Schlüsselbund (headless Linux), sonst eine bewusste Wahl.

Die getroffene Wahl steht im Panel, damit niemand über die Ablage seines Passworts im Unklaren ist.

iPhone und iPad

Für iOS gibt es ngenNcCalendar nicht, und das bleibt vorerst so: iOS spricht CalDAV selbst, und ein Nextcloud-Kalender landet dort mit ein paar Handgriffen im System-Kalender — samt Siri, Uhr und allem, was daran hängt. Eine eigene App wäre dagegen ein Rückschritt.

Die Anleitung dafür, mit dem Konfigurationsprofil der offiziellen Nextcloud-App: doc/iphone/English.

Warum kein fertiger Client

Die Entscheidung, unter Android nicht den System-Kalender und DAVx⁵ zu benutzen, sondern eine eigenständige App zu bauen, ist bewusst getroffen — Begründung und Konsequenzen stehen in ARCHITEKTUR.md, Abschnitt „Android".