mirror of
https://github.com/praktimarc/kst4contest.git
synced 2026-10-20 14:23:08 +02:00
Draw the whole interface in Compose
Etappen 3 to 6a of the migration (129 commits). Every window the operator sees is Compose; the JavaFX ones still exist beside them so the two could be compared against a live session, which is the only way the differences came to light. The toolchain first, then the settings window with its eleven tabs and 72 real preferences; then the multi-column table as a component, and with it the rules it needs -- stable row identity, a selection that survives a refresh, column order the operator can drag, and a repaint when the rows change rather than when the list instance does. Then the update and monitor windows, and the main window: 22 station columns, the filter bar, the selected-station panel, the message tabs, the priority bar, the sked controls, the status indicators and the timeline, assembled behind a splitter because Compose has none. The map stops being a WebView. A Compose canvas projects WebMercator tiles itself, with the clustering in core and an asynchronous fetcher in place of the local tile proxy; derive() becomes a pure Kotlin reimplementation instead of a reflection call into com.sun.javafx. Most of the volume here is parity the operator would notice rather than new behaviour: desktop density instead of Material's phone minimums, colours taken from the JavaFX stylesheets instead of Material's palette, row dividers, band columns, grid-square labels and their colours, the home marker and antenna beam, pinch-to-zoom under Wayland, and layouts that survive a window narrower than the chart they stack. Two lessons are worth more than the diff. A control bound to a value Compose cannot observe writes through and never redraws -- that one shipped repeatedly with a green build, because no test drew anything. And a layout that clips instead of wrapping is worse than one that is merely too narrow: half a word is the worst available outcome.
This commit is contained in:
173 files changed
+26500
-4305
No files matched your search
@@ -0,0 +1,91 @@
|
||||
# Umsetzungsplan Etappe 5 — Hauptfenster
|
||||
|
||||
Spezifikation: `docs/superpowers/specs/2026-09-25-compose-migration-design.md`, Etappe 5.
|
||||
|
||||
## Der Umfang, gemessen
|
||||
|
||||
| Teil | Zeilen | Besonderheit |
|
||||
|---|---|---|
|
||||
| Stationsliste `initChatMemberTable` | 854 | 22 Spalten, 13 Zellfabriken, 1 Zeilenfabrik, 4 Vergleicher |
|
||||
| Filterleiste | ~977 | 37 Bedienelemente, davon **25 Umschaltknöpfe** |
|
||||
| Infobereich `generateFurtherInfoAbtSelectedCallsignBP` | 881 | eigener Teiler mit gespeicherter Position |
|
||||
| Menüleiste (File, Options, Windows, Help) | ~343 | macOS-Systemmenüleiste |
|
||||
| `TimelineView` | 376 | eigene Datei, eigene Zeichnung |
|
||||
| Top-Prioritätenliste | 69 | |
|
||||
| Statusanzeigen | ~40 | Sked-Warnung, Verbindung, Band-Upgrade |
|
||||
|
||||
Über **3500 Zeilen**. Etappe 3 war kleiner und wurde geteilt.
|
||||
|
||||
**Der Infobereich ist so groß wie die Stationsliste.** In der Spezifikation steht er
|
||||
als einer von sieben Aufzählungspunkten; das untertreibt ihn um eine Größenordnung.
|
||||
|
||||
## Aufteilung in 5a, 5b und 5c
|
||||
|
||||
Nicht aus Ordnungsliebe, sondern weil eine Etappe lieferbar sein soll. Nach jedem
|
||||
Abschnitt läuft die Anwendung, und du kannst abnehmen, bevor der nächste anfängt.
|
||||
|
||||
### 5a — Stationsliste und Filterleiste
|
||||
|
||||
Der Kern. Die mehrspaltige Tabelle aus Etappe 4 wurde **für diese Liste** zugeschnitten
|
||||
und trägt hier ihre erste echte Last: 22 Spalten, Zellfärbung aus Zeile *und* Wert,
|
||||
Zeilenfärbung nach `getCurrentPriorityScore()` über vier Schwellen, eigene Vergleicher,
|
||||
23 gespeicherte Spaltenbreiten.
|
||||
|
||||
Die 25 Umschaltknöpfe der Filterleiste sind kein Formular, sondern Zustand mit Regeln —
|
||||
welche Filter einander ausschließen, welche sich stapeln. Die Regeln gehören in einen
|
||||
testbaren Zustand, bevor ein Knopf gezeichnet wird.
|
||||
|
||||
**Abnahme:** Die Liste zeigt dieselben Stationen in derselben Reihenfolge wie JavaFX,
|
||||
die Filter wirken gleich, Spaltenbreiten überleben den Neustart.
|
||||
|
||||
### 5b — Infobereich, Top-Prioritätenliste, Chat-Reiter
|
||||
|
||||
Der Infobereich hängt an der Auswahl der Liste aus 5a — deshalb danach und nicht
|
||||
davor. Sein Teiler wird hier einmal richtig gebaut; im Monitor-Fenster habe ich ihn
|
||||
bewusst weggelassen, statt ihn zweimal halb zu bauen.
|
||||
|
||||
**Abnahme:** Auswahl in der Liste füllt den Infobereich wie bisher, Teilerpositionen
|
||||
werden entprellt gespeichert.
|
||||
|
||||
### 5c — Menüleiste, Statusleiste, TimelineView, Profilwechsel
|
||||
|
||||
Die Menüleiste wird eine gemeinsame Composable-Funktion, die jedes Fenster aufruft —
|
||||
so verlangt es Compose, und so bekommen die Compose-Fenster auf macOS ihre
|
||||
Systemmenüleiste zurück, die sie seit Etappe 3b nicht haben.
|
||||
|
||||
**Der Profilwechsel ändert seine Natur.** Heute reißt er die Laufzeit ab und baut eine
|
||||
neue `Kst4ContestApplication` auf, weil viele Bedienelemente inline erzeugte
|
||||
Instanzfelder sind. Dieser Grund entfällt; der Wechsel wird zum Austausch des
|
||||
Zustandsobjekts. `shutdownRuntime()` bleibt trotzdem verantwortlich für alles, was eine
|
||||
Verbindung überdauert.
|
||||
|
||||
**Abnahme:** Profilwechsel im laufenden Betrieb, ohne doppelt angemeldete Zuhörer und
|
||||
ohne gehaltene Ressourcen. Auf macOS erscheint die Menüleiste bei jedem Fenster.
|
||||
|
||||
## Was aus Etappe 4 mitgenommen wird
|
||||
|
||||
Vier Fehler dieser Etappe kamen **ausschließlich** durch Hinsehen ans Licht, keiner
|
||||
durch einen Test, und der Prüfer fand nur einen Teil davon:
|
||||
|
||||
1. Ein Zwischenspeicher, der den Zustand nicht mehr las, und eine Tabelle, die deshalb
|
||||
nie wieder zeichnete.
|
||||
2. Eine Kopfzeile, die die ganze Tabellenhöhe nahm.
|
||||
3. Eine Liste, die bei jeder neuen Zeile vom Kopf wegdriftete.
|
||||
4. Ein Menüeintrag, der seinen Umschalter verloren hatte.
|
||||
|
||||
Daraus drei Regeln für diese Etappe:
|
||||
|
||||
- **Was gezeichnet wird, muss beim Lesen Zustand berühren.** Der `Snapshot.observe`-Test
|
||||
aus Etappe 4 fängt genau das und wird hier für jede neue Ansicht angelegt.
|
||||
- **Nach jedem sichtbaren Teil wird gestartet und hingesehen**, nicht erst am Ende des
|
||||
Abschnitts.
|
||||
- **Kein Verhalten wird weggelassen, um ein Darstellungsproblem zu umgehen.** Der
|
||||
verlorene Umschalter war genau dieser Tausch.
|
||||
|
||||
## Offene Punkte
|
||||
|
||||
1. Ob `Platform.setImplicitExit(false)` und `ApplicationRuntimeLauncher.exitApplication()`
|
||||
in der Compose-Fassung noch eine Entsprechung brauchen — laut Spezifikation nach
|
||||
Etappe 4 zu klären, also jetzt.
|
||||
2. Ob die Filterleiste ihre 25 Knöpfe behält oder ob mehrere davon derselbe Zustand
|
||||
sind. Vor dem Zeichnen zu lesen, nicht danach.
|
||||
Reference in new issue
Block a user