No description
  • HTML 76.8%
  • JavaScript 11.7%
  • Python 10.5%
  • Shell 1%
Find a file
2026-10-25 13:02:24 +01:00
.gitignore Stand vom 2026-10-25 2026-10-25 13:02:24 +01:00
app.html Stand vom 2026-10-25 2026-10-25 13:02:24 +01:00
COPYRIGHT Stand vom 2026-10-25 2026-10-25 13:02:24 +01:00
desktop_ui.js Stand vom 2026-10-25 2026-10-25 13:02:24 +01:00
finanzplan-desktop Stand vom 2026-10-25 2026-10-25 13:02:24 +01:00
finanzplan_desktop.py Stand vom 2026-10-25 2026-10-25 13:02:24 +01:00
fpsync.py Stand vom 2026-10-25 2026-10-25 13:02:24 +01:00
icon.svg Stand vom 2026-10-25 2026-10-25 13:02:24 +01:00
install.sh Stand vom 2026-10-25 2026-10-25 13:02:24 +01:00
LICENSE Stand vom 2026-10-25 2026-10-25 13:02:24 +01:00
README.md Stand vom 2026-10-25 2026-10-25 13:02:24 +01:00
requirements.txt Stand vom 2026-10-25 2026-10-25 13:02:24 +01:00
test_fpsync.py Stand vom 2026-10-25 2026-10-25 13:02:24 +01:00

Finanzplan — Desktop-Client (Linux)

Ein Desktop-Client für die Finanzplan-App, der dieselbe app.html wie die Android-App in einem nativen Fenster (WebKitGTK via pywebview) laufen lässt und sich per Partner-Sync direkt im WLAN mit dem Handy abgleicht.

  • Kein Server, keine Cloud. Der Abgleich geht ausschließlich direkt Desktop ↔ Handy im lokalen Netz, jede Nachricht AES-256-GCM-verschlüsselt. Das ist exakt dasselbe Protokoll wie zwischen zwei Telefonen (SyncManager.kt), nur in Python nachgebaut (fpsync.py).
  • Daten liegen lokal im WebView-Speicher unter ~/.local/share/finanzplan.
  • Kein Codewechsel an der App. app.html ist unverändert übernommen; sie blendet ihren eigenen Sync-Knopf aus, wenn keine Android-Bridge da ist – der Sync läuft hier stattdessen über das Fenstermenü.

Einrichten (Fedora / Hyprland)

Einmalig die System-Bausteine für WebKitGTK installieren (die kommen nicht aus pip):

sudo dnf install python3-gobject gtk3 webkit2gtk4.1

Dann starten – der erste Start legt automatisch eine .venv an und installiert die Python-Pakete hinein:

./finanzplan-desktop

Die venv wird mit --system-site-packages erstellt, damit sie das per dnf installierte PyGObject/WebKitGTK mitbenutzt; nur die reinen Python-Pakete (pywebview, cryptography, zeroconf, qrcode, secretstorage) landen in der venv.

In den App-Launcher / dmenu eintragen

Damit finanzplan-desktop überall aufrufbar ist und als Eintrag „Finanzplan" im App-Launcher (dmenu, dank shell, Wofi, …) auftaucht:

./install.sh

Das legt an:

  • einen Symlink ~/.local/bin/finanzplan-desktop → Start-Skript (der Ordner liegt im PATH),
  • einen .desktop-Eintrag ~/.local/share/applications/finanzplan-desktop.desktop,
  • das Icon unter ~/.local/share/icons/hicolor/scalable/apps/.

Rückgängig: ./install.sh --uninstall.

Warum nicht einfach den Ordner in den PATH legen? Dann kollidiert der Verzeichnisname finanzplan-desktop mit dem gleichnamigen Kommando – die Shell findet zuerst das Verzeichnis und meldet „keine Berechtigung". Der Symlink in ~/.local/bin löst genau das (das Start-Skript nutzt readlink -f und findet seinen Ordner auch über den Symlink).

In Hyprland alternativ per Keybind (hyprland.conf):

bind = $mainMod, F, exec, finanzplan-desktop

Skalierung & Diagramme (nur Desktop)

Auf dem großen Bildschirm blendet der Client eine kleine Leiste unten links ein:

  • Zoom – Knöpfe − / Prozent / +, oder per Tastatur Strg + / Strg − / Strg 0 (zurücksetzen), oder Strg + Mausrad. Die Stufe wird gemerkt (localStorage, nur auf diesem Rechner – wandert nicht in den Sync). Skaliert wird über WebKit selbst, genau wie der Zoom eines Browsers.

  • 📊 Diagramme – ein Overlay in zwei Abschnitten (Esc schließt):

    • Anteile (Ringe): anstehende Ausgaben nach Kategorie, Nötig/Optional, laufende Kosten pro Monat, Ausgegeben-Log des laufenden Jahres. Kategorien zählen auf ihrer obersten Ebene (Freizeit/Kino → Freizeit), wie in der App; hineindrillen kann man dort.
    • Verlauf: Balken für Monatsportionen — Ausgegeben/Erhalten je Monat und Bleibt übrig je Monat (dieselbe Zahl wie die Monatssaldo-Karte, ohne Projektion). Linien für Stände und Entwicklungen — Kontostand (die eingetragenen Überträge über zwei Jahre), Laufende Kosten je Monat (macht schleichende Erhöhungen sichtbar) und der Jahresvergleich (aufgelaufene Ausgaben, laufendes Jahr gegen Vorjahr). Zum Schluss die Budget-Stände. Ohne Werteachse, dafür Werte im Tooltip und die Eckwerte in der Legende.

    Beim Kontostand gilt: gemessen ist nur, was eingetragen wurde. Monate ohne Übertrag bekommen keinen Punkt, die Überbrückung ist gestrichelt, und der fortgeschriebene „heute"-Punkt ist hohl statt gefüllt. Die Linien-Achse beginnt bei null – sähe eine Kurve sonst dramatisch aus, wäre das nur der Maßstab, nicht die Sache.

    Karten ohne Daten fallen weg. Gerechnet wird mit den Funktionen der App (monatSaldo, currentRecs, spentSum, …), nicht mit Nachbauten – ein eigener Nachbau wird beim nächsten Schema-Schritt still falsch.

Diese Extras stecken in desktop_ui.js und werden nach dem Laden in die unveränderte app.html injiziert – die App-Datei selbst bleibt also byteidentisch zur Android-Version und kann bei einem Update weiter einfach überkopiert werden.

Injiziert wird als new Function("…") mit dem Quelltext als JSON-Zeichenkette. Das ist nötig, weil pywebview WebKit die Skriptlänge in Zeichen meldet, WebKit aber in Bytes rechnet: mit Umlauten oder Emoji im Skript schneidet WebKit hinten ab und wirft SyntaxError: Unexpected end of script – dann fehlt die Leiste ersatzlos. Als JSON ist die Zusendung reines ASCII.

Beenden

Fenster zu, Menü „Programm“ → Beenden, Strg + Q, oder Strg + C im Terminal – alles vier beendet den Client.

Früher ging keins davon: der Client las das Erscheinungsbild erst beim Schließen per evaluate_js aus der Seite. Dieser Aufruf läuft im GTK-Haupt- faden und wartet dort auf eine Antwort, die nur derselbe – gerade blockierte – Faden liefern könnte. Das Fenster blieb hängen und half nur noch kill. Heute meldet die Seite jede Änderung sofort (desktop_ui.js → pywebview.api.theme), und Strg + C hängt über GLib.unix_signal_add in der GTK-Schleife.

Wenn das Fenster zäh wirkt

WebKitGTK ist nicht auf jeder Treiber-/Compositor-Kombination gleich flott. Zum Eingrenzen:

FP_KEIN_DMABUF=1 finanzplan-desktop   # ohne DMABUF-Pfad (setzt WEBKIT_DISABLE_DMABUF_RENDERER)
FP_DEBUG=1 finanzplan-desktop         # Rechtsklick → „Element untersuchen“ zum Nachmessen

Der Client selbst schaltet enable-smooth-scrolling ein (WebKit hat das ab Werk aus, das Mausrad springt sonst in groben Stufen) und hängt den wheel-Horcher fürs Strg-Zoomen nur an, solange Strg gedrückt ist – ein dauerhaft nicht-passiver Horcher nimmt WebKit das nebenläufige Scrollen weg.

Dunkelmodus

Der Dunkelmodus kommt aus der App selbst (ab v2.9.0): Menü → Erscheinungsbild schaltet durch Folgt dem System · Immer hell · Immer dunkel, die Wahl liegt im localStorage dieses Rechners. Zwei Dinge macht nur der Desktop-Client:

  • die Ring-Diagramme lesen die Wahl am data-theme des <html> ab (statt das System zu fragen) und wechseln damit auf die dunkle Palette,
  • die Wahl wird bei jedem Umschalten nach ~/.local/share/finanzplan/theme geschrieben (die Seite meldet sie über pywebview.api.theme); daraus setzt der nächste Start die Fensterfarbe, sonst blitzt ein weißes Fenster auf, bevor die Seite steht. Ohne diese Datei entscheidet gsettings … color-scheme.

Koppeln & Synchronisieren

Alles im Menü „Partner-Sync“ des Fensters:

  1. Koppeln — Code zeigen → ein QR erscheint. Am Handy „Mit Partner teilen“ → „Code scannen“ wählen und den QR scannen. Der 32-Byte-Schlüssel wandert nur über den Bildschirm, nie über ein Netz. (Genauso funktioniert es zwischen zwei Handys – nur zeigt hier der Desktop den Code und das Handy scannt.)
  2. Danach im selben WLAN abgleichen:
    • Ein Gerät wählt Empfangen, das andere Senden.
    • Beim Senden werden wartende Partner automatisch gefunden (mDNS) – oder man tippt die IP:Port ein, die das empfangende Gerät anzeigt.
    • Nach einem Round-Trip haben beide Seiten denselben, gemergten Stand (Last-Write-Wins pro Eintrag + Tombstones – dieselbe Logik wie in der App).

Schlüssel-Ablage

Der Sync-Schlüssel wird bevorzugt im Secret Service (GNOME-Keyring/KWallet über D-Bus) abgelegt, sofern unter der Sitzung erreichbar; sonst in einer Datei ~/.local/share/finanzplan/sync_key.bin mit Rechten 0600. Kein Passphrase-Prompt beim Start. Welche Ablage aktiv ist, steht im Kopplungs-Dialog.

Unter Hyprland läuft nicht immer ein Secret Service. Wer den Keyring will, startet z. B. gnome-keyring-daemon mit; ansonsten greift automatisch der Datei-Fallback. Der Schlüssel erlaubt einem Mitleser im selben WLAN höchstens, die Ausgabenliste zu lesen.

Daten sichern

  • Im Fenstermenü „Daten“: Backup exportieren / Backup einlesen (native Dateidialoge).
  • Oder in der App selbst über ⋯ → Sichern/Einlesen – der In-App-Export nutzt den Browser-Download (landet im Download-Ordner) und kann das Backup passphrase-verschlüsseln.

Dateien

Datei Zweck
finanzplan-desktop Start-Skript (venv-Einrichtung + Start)
finanzplan_desktop.py pywebview-Fenster, Menü, QR-/Sende-/Empfangs-Dialoge
desktop_ui.js Desktop-Extras (Zoom + Diagramme), in app.html injiziert
fpsync.py Krypto, Frame-Protokoll, Client/Server, mDNS, Schlüssel
app.html die unveränderte App-Oberfläche (aus dem Finanzplan-Repo)
install.sh Symlink + .desktop-Eintrag + Icon für den App-Launcher
icon.svg App-Icon
test_fpsync.py Selbsttest für Krypto/Protokoll (ohne GUI)

Test: python3 test_fpsync.py

Grenzen / Hinweise

  • Getestet sind der Sync-/Krypto-Kern (per Loopback, siehe test_fpsync.py) und das Fenster selbst unter Xvfb (Injektion der Extras, Zoom-Brücke, Theme-Meldung, Beenden per Strg+C/Strg+Q). Der echte Abgleich mit dem Handy muss auf dem Zielrechner im WLAN ausprobiert werden.
  • app.html ist eine Kopie. Bei einem App-Update die Datei neu aus Finanzplan/app/src/main/assets/app.html herüberkopieren.
  • Falls die pywebview-Version das Fenstermenü nicht darstellt: bitte melden – dann rüsten wir einen In-App-Sync-Knopf nach.