← Alle Beiträge

Plainva 0.6.2: die mobile App, neu gebaut — und die Geste, die kein Test sehen konnte

8. August 2026

Die mobile App ist über acht Planungsrunden gewachsen. Für jede Desktop-Funktion ein Screen, für jede Rückfrage ein Sheet, für jede Fläche eigenes CSS. Keine Runde hat hinter der vorigen aufgeräumt.

Irgendwann habe ich gezählt: 24 Screens. 24 Sheets, an der schlimmsten Stelle vier tief gestapelt — vier Sheets, um eine Eigenschaft zu setzen. mobile.css war auf 3.361 Zeilen angewachsen, so groß wie das gesamte geteilte Stylesheet, das eigentlich beide Shells benutzen sollten. Von 25 geteilten UI-Bausteinen benutzte das Telefon zwei Klassen.

Das ist weder ein Design- noch ein Funktionsproblem. Es ist eine fehlende Schicht: Nichts entschied, wo etwas hingehört, also entschied es jeder Screen für sich.

Die deutlichste Einzelzahl: 26 Screens rendern die eine Kopfzeile, genau einer die andere — und das war der Startbildschirm. Jeder einzelne Navigationsschritt änderte also Titelgröße, Schriftgewicht, Kante und Schatten gleichzeitig. Die Kopfzeile, die eigentlich die der App sein sollte, mit ordentlicher Scroll-Erhebung, war toter Code.

Zwanzig Dinge, die das Telefon nicht konnte

Ich habe sie vor dem Neubau aufgeschrieben, weil „die mobile App fühlt sich schlechter an” nichts ist, was man beheben kann. Das hier schon:

Kein Import — wer von Notion umsteigen wollte, konnte am Telefon gar nicht anfangen. Keine Anhänge, kein Bildbetrachter, ein eingefügtes Foto war danach unsichtbar. Der Kalender war schreibgeschützt: kein Anlegen, kein Bearbeiten, keine Serien, keine Teilnehmer. Kein Allen-Antworten, kein Weiterleiten, keine Anhänge beim Versand, kein Entwurf — eine angefangene Mail war beim Verlassen des Bildschirms schlicht weg. Relationen nicht konfigurierbar. Kein Zeilenmenü in Datenbanken. Fünf von sieben Aufgaben-Filtern fehlten. Zwei Slash-Befehle, die im Menü standen und nichts taten.

Alle zwanzig sind mit diesem Release zu. Das Telefon fährt jetzt denselben Import mit denselben siebenundzwanzig Quellen, schreibt in den Kalender inklusive Serien und Teilnehmern, leitet Mail mit Anhängen weiter und lässt eine Datenbank bauen statt nur ansehen.

Die Struktur darunter: drei Flächen statt vierundzwanzig Screens — Navigator, Arbeitsfläche, Kontext. Das ist das Raummodell des Desktops, zeitlich statt räumlich. Und auf dem Tablet wird es wieder räumlich: das adaptive Layout ist das Desktop-Layout, drei Spalten nebeneinander.

Die Geste, die nie funktioniert hat

Der Teil, der mir nachgeht.

Die erste Interaktionsregel des neuen Entwurfs lautet: Tippen öffnet, Wischen führt die Zeilenaktion aus. Sie war gebaut. Sie war getestet. Sie war in den Screenshots.

Auf einem echten Telefon ist sie kein einziges Mal angesprungen.

Die Zeile deklarierte kein touch-action, also nahm der Browser jeden horizontalen Zug als Scroll-Geste, bevor der Zeiger-Handler ihn überhaupt sah. Eine fehlende CSS-Eigenschaft.

Was mich daran beschäftigt, ist nicht der Fehler. Es ist, warum er überlebt hat: Jede Prüfung, die ich fahre, fährt mit der Maus. Unit-Tests, Playwright, der Screenshot-Vergleich — eine Maus schaut touch-action gar nicht an. Die Eigenschaft ist für all das unsichtbar. Ich hatte 230 Aufnahmen von Flächen über fünf Themes, und keine einzige davon hätte mir sagen können, dass die tragende Geste der App tot ist.

Es gibt jetzt einen Touch-Wächter, der mit echten Zeiger-Ereignissen zieht, gegen das Produktions-Bündel. Er hat den Fehler beim ersten Lauf gefunden, als ich ihn zur Gegenprobe rückwärts geprüft habe.

Dieselbe Durchsicht förderte ein zweites Ding derselben Bauart zutage: das mobile Produktions-Bündel mountete überhaupt nicht. Kein langsamer Start — ein weißer Bildschirm. Die automatische Aufteilung hatte die CommonJS-Hülle von react-dom und den Interop-Aufruf von react-i18next in zwei Chunks gelegt, die einander referenzieren; der Aufrufer lief vor der Initialisierung. Lint grün. Typecheck grün. 556 Unit-Tests grün. Die komplette CI grün. Die App war beim Start tot.

Der Desktop hat nach dem weißen Fenster in 0.3.0 einen Produktions-Smoke bekommen. Mobile nie. Jetzt schon.

Zwei Namen, die eine Datei waren

Auch wer das Telefon nie anfasst, bekommt aus diesem Release etwas.

Google Drive löst Namensabfragen ohne Rücksicht auf Groß- und Kleinschreibung auf. Eine Abfrage von mobile App.md lieferte also auch Mobile App.md. Plainva nahm den ersten Treffer — womit ein Upload den Inhalt der anderen Notiz überschreiben konnte. Und das folgende Voll-Listing kannte nur noch einen der beiden Namen, also galt der Zwilling als remote gelöscht und wurde lokal entfernt. Nach jeder Wiederherstellung erneut.

Unter Windows und macOS ist es schlimmer: dort sind beide Namen eine Datei.

Plainva akzeptiert jetzt ausschließlich den byte-genauen Namen und meldet die Mehrdeutigkeit, statt zu raten — bei einem Beinahe-Treffer wird nichts geschrieben, umbenannt oder gelöscht.

Und der Sync hat den Unterschied zwischen „vorübergehend” und „endgültig” gelernt. Bisher wurde jeder Fehler zum Zustand error mit der rohen Anbieter-Meldung daneben; ein abgebrochener Aufruf, ein 503, ein Token mitten in der Rotation lasen sich exakt wie ein widerrufenes Konto. Und weil der Backoff innerhalb von fünf Minuten neu versucht, war die rote Meldung meist wieder weg, wenn jemand hinsah. Die sagen jetzt neutral, wann der nächste Versuch fällig ist. Rot wird erst der dritte Fehlschlag in Folge — ein widerrufenes Konto weiterhin sofort, denn ein unbekannter Fehler zählt als endgültig. Ein falsches „fatal” ist laut, ein falsches „vorübergehend” ist Stille, und Stille ist die Fehlerart, die Daten kostet.

Am Schreibtisch

Aufgaben lassen sich dort abhaken, wo man sie sieht — im Monatsraster, in der Agenda, im Ganztags-Streifen. Das klingt klein und war es nicht: Das Abhaken re-indiziert, stößt den Hintergrund-Worker an und erzeugt bei einer wiederkehrenden Aufgabe die nächste. Ein zweiter Handler im Kalender hätte bedeutet, dass es davon abhängt, wo man abhakt, ob die Kette weiterläuft.

Und Aufgaben bekommen die umgekehrte Zeitoptik der Termine. Ein vergangener Termin ist vorbei, also dimmt er. Eine überfällige Aufgabe ist dringender, also wird sie hervorgehoben — und eine künftige tritt zurück.


Plainva bleibt local-first: reines Markdown in einem Ordner, der Dir gehört, Obsidian-kompatibel, AGPL. Download · Changelog