7.3 KiB
Desktop
GNOME-Shell-Extension (GNOME 46, Ubuntu 24.04): Kalender, Todos und Notizen direkt auf dem Desktop, unter allen Fenstern, über dem Wallpaper.
Bedienung
- Woche: startet mit der aktuellen Uhrzeit in der Mitte, rote Linie markiert jetzt.
- Termin anlegen: in der Wochenansicht auf eine Stunde drücken und bis zur Endstunde ziehen, auch über mehrere Tage. Klick ohne Ziehen = eine Stunde. Ziehen in der Zeile „ganz“ = ganztägig. Oder Rechtsklick auf einen Tag (Monat), eine Stunde (Woche) oder die Tagesfläche: „Termin erstellen“. Popover: Titel, Von und Bis je mit Datum und Uhrzeit. Ohne Ende gilt eine Stunde, ohne Uhrzeit ganztägig.
- Todo anlegen: Rechtsklick ins Todo-Panel oder in den Kalender, „Todo erstellen“. Text plus Datum und Uhrzeit.
- Notiz: Rechtsklick irgendwo im Notiz-Panel, „Notiz erstellen“ fragt den Namen und öffnet den Editor. Klick in die Notizfläche bearbeitet. Mit Fokus steht der rohe Markdown-Text, ohne Fokus die formatierte Ansicht. Gespeichert wird alle 5 Sekunden und beim Klick woanders hin. Enter in einer Liste setzt den nächsten Punkt, Enter auf einem leeren Punkt beendet die Liste.
- Maustasten: links bearbeitet, Mitte hakt ein Todo ab oder benennt Notiz/Ordner um, rechts öffnet das Menü. Alle Popover öffnen am Mauszeiger.
- Rechtsklick auf freie Fläche: Erstellen (Todos, Tagesansicht, Notizbaum im Wurzelordner).
- Ordner: Klick klappt auf und zu, der Pfeil zeigt den Zustand wie in Obsidian.
- Rechtsklick auf Ordner: Notiz oder Unterordner darin erstellen, Umbenennen, Löschen.
- Rechtsklick auf Eintrag: Umbenennen, Löschen.
- Popover: Enter speichert, Esc oder Klick daneben bricht ab. Keine Buttons.
Aufbau
desktop@marha.de/– die Extensionextension.js– Layout auf dem Arbeitsbereich, Stapelung über Desktop-Iconscalendar.js– Monat, Woche (Drag), Tag, Termin-Popovertodos.js– Todo-Liste, Todo-Popovernotes.js– Ordnerbaum, Markdown-Anzeige, Inline-Editor, Kontextmenüwidgets.js– Popover (Grab, Esc, Tab, Klick daneben), Kontextmenü, Datums- und Zeitauswahlmarkdown.js,dates.js– reine Logik, ohne Shell testbarstore.js– Ablage, Tombstones, Übernahme vom Serversync.js– Abgleich mit dem Server (Soup, Timer)
backend/– Sync-Server (FastAPI, SQLite),Dockerfile,docker-compose.ymlandroid/– native Android-App mit denselben drei Bereichen, sieheandroid/README.mddev/– Test-Werkzeuge
Daten
~/.local/share/desktop-app/
events.json– Terminetodos.json– Todosnotes/– Notizen als.md, Ordner beliebig verschachtelt (Obsidian kann den Ordner öffnen)deleted-notes.json– gelöschte Notizen mit Zeitpunkt, damit der Sync sie auch woanders löschtfolders.json– Ordner mit Zeitpunkt und deleted-Flag, damit auch leere Ordner mitlaufensync.json– Server-Zugang, siehe Syncsync-state.json– letzter Server-Stand
Gelöschte Termine und Todos bleiben mit deleted: true in der Datei und werden nur ausgeblendet.
Sync
Der Server (backend/, FastAPI + SQLite) hält den Kern. Jedes Gerät gleicht regelmäßig ab und sofort
nach jeder eigenen Änderung: eigene Änderungen hoch, fremde Änderungen runter. Der Takt richtet sich nach
der Aktivität: nach einer Änderung (eigene oder vom Server) eine Minute lang jede Sekunde, dann alle
5 Sekunden, nach 5 Minuten Ruhe alle 10 Sekunden. Bei Konflikten gewinnt der Eintrag mit dem
neueren updated (Notizen: Änderungszeit der Datei, ganze Datei). Offline geht weiter, beim
Wiederverbinden wird nachgeliefert. Eine gerade offene Notiz wird nicht von außen überschrieben.
Claude-Code-Sitzungen (nur PCs)
Die Extension gleicht auch ~/.claude/projects/ ab, also Sitzungen und Memory von Claude Code.
Alle 10 Minuten prüft sie den Ordner. Hoch geht eine Datei, wenn sie sich geändert hat und seit
einer Stunde nicht angefasst wurde. Vom Server kommt sie, wenn sie dort neuer ist, mit ihrer
Änderungszeit. Gelöschte Dateien verschwinden auch auf dem anderen PC. Die App fragt diese
Dateien nie an. Bedingung: gleicher Pfad auf beiden PCs, der Ordnername enthält ihn.
"files": false in sync.json schaltet es ab, ein Pfad statt false ersetzt den Ordner.
make sync-files stößt den Abgleich sofort an und wartet, bis er durch ist.
Zugang auf jedem Gerät in ~/.local/share/desktop-app/sync.json:
{"url": "https://planer.marha.de", "token": "<SYNC_TOKEN aus .env>"}
Ohne diese Datei läuft die Extension rein lokal. Optional "interval": Ruhetakt in Sekunden statt 10.
Server-API (alle Aufrufe mit Authorization: Bearer <SYNC_TOKEN>):
POST /api/sync–{"since": <cursor>, "events": [...], "todos": [...], "notes": [...], "folders": [...], "files": [...]}; Antwort: Änderungen seitsincein den angefragten Sammlungen plus neuercursor. Ohne Sammlungen kommen die vier ersten,filesnur auf Anfrage.GET /api/events,/api/todos,/api/notes– aktueller Stand ohne Gelöschte, für andere Anwendungen
Server starten
cp .env.example .env # SYNC_TOKEN setzen
make dev # lokal, http://localhost:8040 (anderer Port: make dev PORT=8050)
make prod # auf dem Server: Docker Compose hinter Traefik, https://planer.marha.de
make stop | make logs | make down
make test # Server-Tests
make apk # Android-App bauen, make apk-install schickt sie aufs Handy (android/README.md)
Installation
cp .env.example .env # SYNC_TOKEN eintragen (derselbe wie auf dem Server)
make install # kopiert die Extension nach ~/.local/share/gnome-shell/extensions und aktiviert sie
make update # überschreibt eine installierte Extension mit dem Stand aus diesem Ordner
Beide legen ~/.local/share/desktop-app/sync.json aus der .env an, falls sie fehlt. Ohne .env
läuft die Extension rein lokal. Danach ab- und wieder anmelden. Unter Wayland lädt die Shell neuen
Code erst nach einem neuen Login. make update startet die Extension neu, damit ein neuer Sync-Zugang
sofort greift.
Voraussetzung: GNOME 46 (Ubuntu 24.04).
Entwicklung
gjs -m dev/tests/run.js # Unit-Tests für dates.js und markdown.js
dev/restart.sh # Test-Shell als Fenster starten (zum Selbst-Ausprobieren)
dev/restart.sh headless # Test-Shell unsichtbar, für simulierte Eingaben
dev/tests/input.sh # Ablauf-Tests mit echter Maus und Tastatur (headless)
dev/tests/sync.sh # Sync-Test: lokaler Server plus headless Shell, beide Richtungen
dev/eval.sh dev/seed.js # Testdaten einspielen
dev/eval.sh 'js' # JavaScript in der Test-Shell ausführen (oder Dateipfad)
dev/shot.sh [datei.png] # Screenshot der Test-Shell
dev/input.sh click X Y # Maus und Tastatur simulieren (nur headless gefahrlos)
dev/press.sh "Text" # Button mit diesem Text direkt auslösen
dev/stop.sh # Test-Shell beenden
Die Test-Shell läuft mit GSETTINGS_BACKEND=keyfile und eigenem XDG_DATA_HOME
unter /tmp/desktop-app-nested/. Die echte Session bleibt unberührt.
Im Fenstermodus (nested, X11-Backend) würden virtuelle Eingabegeräte auf dem echten Desktop
landen. Deshalb nutzt dev/input.sh nur den headless Modus (natives Backend).
dev/fake-ding.py startet ein Fenster wie Desktop Icons, um die Stapelung zu prüfen.