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:
Rsclub2_2 committed 2026-10-05 22:33:28 +02:00
1 parent a6fba12f01
commit cc8c90204e
173 files changed
+26500 -4305

No files matched your search

+32 -101
View File
@@ -52,39 +52,23 @@ jobs:
shell: pwsh
run: choco install wixtoolset --no-progress -y
- name: Build JAR and copy runtime dependencies
shell: pwsh
run: |
.\gradlew.bat -S :app-desktop:collectRuntime
$jar = Get-ChildItem -Path target -Filter 'praktiKST-*.jar' | Sort-Object LastWriteTime -Descending | Select-Object -First 1
if (-not $jar) {
throw "No project JAR produced"
}
Copy-Item $jar.FullName app-desktop/build/dist-libs/app.jar
- name: Build app-image with jpackage
- name: Build app-image
shell: pwsh
run: |
.\gradlew.bat -S :app-desktop:createDistributable
New-Item -ItemType Directory -Force -Path dist | Out-Null
$addModules = (Select-String -Path gradle.properties -Pattern '^jpackageAddModules=').Line.Split('=')[1]
if ($LASTEXITCODE -ne 0) { throw "Failed to resolve --add-modules from module-info.java" }
jpackage `
--type app-image `
--name praktiKST `
--icon packaging/icons/kst4contest.ico `
--input app-desktop/build/dist-libs `
--main-jar app.jar `
--main-class kst4contest.view.Main `
--add-modules $addModules `
--dest dist
# The next step reads dist/KST4Contest, so the Compose output goes
# there. The module list now lives in app-desktop/build.gradle.kts.
if (Test-Path dist/KST4Contest) { Remove-Item -Recurse -Force dist/KST4Contest }
Copy-Item -Recurse app-desktop/build/compose/binaries/main/app/KST4Contest dist/KST4Contest
- name: Create Windows ZIP
shell: pwsh
run: |
if (-not (Test-Path dist/praktiKST)) {
throw "No Windows app-image produced by jpackage"
if (-not (Test-Path dist/KST4Contest)) {
throw "No Windows app-image produced by createDistributable"
}
Compress-Archive -Path dist/praktiKST -DestinationPath "dist/$env:ASSET_BASENAME-windows-x64.zip" -Force
Compress-Archive -Path dist/KST4Contest -DestinationPath "dist/$env:ASSET_BASENAME-windows-x64.zip" -Force
- name: Upload Windows artifact
uses: actions/upload-artifact@v4.3.4
@@ -116,23 +100,14 @@ jobs:
- name: Ensure gradlew is executable
run: chmod +x gradlew
- name: Build JAR and copy runtime dependencies
run: |
./gradlew -S :app-desktop:collectRuntime
- name: Build app-image with jpackage
- name: Build app-image
run: |
./gradlew -S :app-desktop:createDistributable
mkdir -p dist
ADD_MODULES="$(grep -m1 '^jpackageAddModules=' gradle.properties | cut -d= -f2)"
jpackage \
--type app-image \
--name KST4Contest \
--icon packaging/icons/kst4contest.png \
--input app-desktop/build/dist-libs \
--main-jar app.jar \
--main-class kst4contest.view.Main \
--add-modules "$ADD_MODULES" \
--dest dist
# The following steps read dist/KST4Contest, so the Compose output goes
# there. The module list now lives in app-desktop/build.gradle.kts.
rm -rf dist/KST4Contest
cp -a app-desktop/build/compose/binaries/main/app/KST4Contest dist/
- name: Create AppDir metadata
run: |
@@ -203,27 +178,13 @@ jobs:
- name: Ensure gradlew is executable
run: chmod +x gradlew
- name: Build JAR and copy runtime dependencies
run: |
./gradlew -S :app-desktop:collectRuntime
- name: Build Debian package
run: |
./gradlew -S :app-desktop:packageDeb
mkdir -p dist
ADD_MODULES="$(grep -m1 '^jpackageAddModules=' gradle.properties | cut -d= -f2)"
jpackage \
--type deb \
--name KST4Contest \
--icon packaging/icons/kst4contest.png \
--input app-desktop/build/dist-libs \
--main-jar app.jar \
--main-class kst4contest.view.Main \
--add-modules "$ADD_MODULES" \
--linux-package-deps "libgstreamer1.0-0,libgstreamer-plugins-base1.0-0,gstreamer1.0-plugins-good" \
--dest dist
DEB="$(ls dist/*.deb | head -n 1)"
DEB="$(ls app-desktop/build/compose/binaries/main/deb/*.deb | head -n 1)"
if [ -z "$DEB" ]; then
echo "No DEB produced by jpackage" && exit 1
echo "No DEB produced by packageDeb" && exit 1
fi
mv "$DEB" "dist/${ASSET_BASENAME}-debian-amd64.deb"
@@ -262,27 +223,13 @@ jobs:
- name: Ensure gradlew is executable
run: chmod +x gradlew
- name: Build JAR and copy runtime dependencies
run: |
./gradlew -S :app-desktop:collectRuntime
- name: Build Fedora package
run: |
./gradlew -S :app-desktop:packageRpm
mkdir -p dist
ADD_MODULES="$(grep -m1 '^jpackageAddModules=' gradle.properties | cut -d= -f2)"
jpackage \
--type rpm \
--name KST4Contest \
--icon packaging/icons/kst4contest.png \
--input app-desktop/build/dist-libs \
--main-jar app.jar \
--main-class kst4contest.view.Main \
--add-modules "$ADD_MODULES" \
--linux-package-deps "gstreamer1,gstreamer1-plugins-base,gstreamer1-plugins-good" \
--dest dist
RPM="$(ls dist/*.rpm | head -n 1)"
RPM="$(ls app-desktop/build/compose/binaries/main/rpm/*.rpm | head -n 1)"
if [ -z "$RPM" ]; then
echo "No RPM produced by jpackage" && exit 1
echo "No RPM produced by packageRpm" && exit 1
fi
mv "$RPM" "dist/${ASSET_BASENAME}-fedora-x86_64.rpm"
@@ -323,23 +270,14 @@ jobs:
- name: Ensure gradlew is executable
run: chmod +x gradlew
- name: Build JAR and copy runtime dependencies
run: |
./gradlew -S :app-desktop:collectRuntime
- name: Build app-image with jpackage
- name: Build app-image
run: |
./gradlew -S :app-desktop:createDistributable
mkdir -p dist
ADD_MODULES="$(grep -m1 '^jpackageAddModules=' gradle.properties | cut -d= -f2)"
jpackage \
--type app-image \
--name KST4Contest \
--icon packaging/icons/kst4contest.png \
--input app-desktop/build/dist-libs \
--main-jar app.jar \
--main-class kst4contest.view.Main \
--add-modules "$ADD_MODULES" \
--dest dist
# The following steps read dist/KST4Contest, so the Compose output goes
# there. The module list now lives in app-desktop/build.gradle.kts.
rm -rf dist/KST4Contest
cp -a app-desktop/build/compose/binaries/main/app/KST4Contest dist/
- name: Build Arch Linux package artifact
run: |
@@ -445,20 +383,13 @@ jobs:
flatpak remote-add --user --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
flatpak --user install -y flathub org.freedesktop.Platform//24.08 org.freedesktop.Sdk//24.08
- name: Build app-image with jpackage
- name: Build app-image
run: |
./gradlew -S :app-desktop:collectRuntime
./gradlew -S :app-desktop:createDistributable
mkdir -p target/flatpak-src
ADD_MODULES="$(grep -m1 '^jpackageAddModules=' gradle.properties | cut -d= -f2)"
jpackage \
--type app-image \
--name KST4Contest \
--icon packaging/icons/kst4contest.png \
--input app-desktop/build/dist-libs \
--main-jar app.jar \
--main-class kst4contest.view.Main \
--add-modules "$ADD_MODULES" \
--dest target/flatpak-src
# The manifest's source is flatpak-src/KST4Contest.
rm -rf target/flatpak-src/KST4Contest
cp -a app-desktop/build/compose/binaries/main/app/KST4Contest target/flatpak-src/
- name: Create Flatpak manifest
run: |