Files
desktop-planer/README.md
2026-09-22 13:28:52 +02:00

7.3 KiB
Raw Blame History

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 Extension
    • extension.js – Layout auf dem Arbeitsbereich, Stapelung über Desktop-Icons
    • calendar.js – Monat, Woche (Drag), Tag, Termin-Popover
    • todos.js – Todo-Liste, Todo-Popover
    • notes.js – Ordnerbaum, Markdown-Anzeige, Inline-Editor, Kontextmenü
    • widgets.js – Popover (Grab, Esc, Tab, Klick daneben), Kontextmenü, Datums- und Zeitauswahl
    • markdown.js, dates.js – reine Logik, ohne Shell testbar
    • store.js – Ablage, Tombstones, Übernahme vom Server
    • sync.js – Abgleich mit dem Server (Soup, Timer)
  • backend/ – Sync-Server (FastAPI, SQLite), Dockerfile, docker-compose.yml
  • android/ – native Android-App mit denselben drei Bereichen, siehe android/README.md
  • dev/ – Test-Werkzeuge

Daten

~/.local/share/desktop-app/

  • events.json – Termine
  • todos.json – Todos
  • notes/ – 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öscht
  • folders.json – Ordner mit Zeitpunkt und deleted-Flag, damit auch leere Ordner mitlaufen
  • sync.json – Server-Zugang, siehe Sync
  • sync-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 seit since in den angefragten Sammlungen plus neuer cursor. Ohne Sammlungen kommen die vier ersten, files nur 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.