Uhr: Nivellierung auf drei Seiten, Assistent passt ohne Scrollen

Alles auf einem Bildschirm hiess scrollen, und auf dieser Grösse ist das
der falsche Handgriff: Einen Wisch trifft man beim Rangieren auch ohne
hinzusehen, eine Scrollposition nicht. Was gerade zählt, hängt ausserdem
vom Arbeitsschritt ab.

Jetzt drei Seiten zum Wischen:

* Neigung – Fahrzeugansicht oder Libelle, was zu tun ist, Herkunft der
  Werte
* Keile – die Höhe je Rad. Fehlen Spurweite und Radstand, steht das dort,
  statt dass die Seite leer wirkt.
* Ausrichten – der Assistent, vorher hinter einem Knopf

Der Assistent ist dabei enger gesetzt: kleinere Zahl, zwei Zeilen Rat mit
Skalierung, kleinere Libelle, und kein ScrollView mehr. Beim Rangieren
schaut man kurz hin, da darf nichts ausserhalb des Bildes liegen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
BiasF
2026-08-31 21:59:52 +02:00
co-authored by Claude Opus 5
parent 82df240ebc
commit 8aa8658b5c
3 changed files with 126 additions and 60 deletions
+76 -14
View File
@@ -1,16 +1,45 @@
import SwiftUI
/// Nivellierung auf der Uhr.
/// Nivellierung auf der Uhr, aufgeteilt auf drei Seiten zum Wischen.
///
/// Auf einem Bildschirm dieser Grösse ist Wischen besser als Scrollen: Beim
/// Rangieren trifft man einen Wisch auch ohne hinzusehen, eine Scrollposition
/// dagegen nicht und was gerade wichtig ist, hängt vom Arbeitsschritt ab.
///
/// 1. **Neigung** wie das Fahrzeug steht, als Fahrzeugansicht oder Libelle.
/// 2. **Keile** wie hoch jedes Rad unterlegt werden muss.
/// 3. **Ausrichten** der Assistent fürs Rangieren, mit Vibration.
///
/// Die Werte kommen bevorzugt **direkt vom Sensor** (`WatchLevelRadio`); nur
/// wenn der gerade nicht erreichbar ist, tritt der zuletzt über das iPhone
/// gemeldete Stand an seine Stelle. Woher sie stammen, steht unten ein alter
/// Wert sieht sonst aus wie ein stillstehendes Fahrzeug.
/// gemeldete Stand an seine Stelle. Woher sie stammen, steht auf der ersten
/// Seite ein alter Wert sieht sonst aus wie ein stillstehendes Fahrzeug.
///
/// Kalibriert wird hier nichts. Das gehört einmalig ans iPhone, mit ebenem
/// Fahrzeug und Ruhe dafür; auf der Uhr wäre der Knopf nur eine Gelegenheit,
/// die Nullage aus Versehen zu verstellen.
struct WatchLevelView: View {
@State private var page = Page.reading
enum Page: Hashable {
case reading, wedges, align
}
var body: some View {
TabView(selection: $page) {
LevelReadingPage()
.tag(Page.reading)
WedgePage()
.tag(Page.wedges)
WatchAlignView()
.tag(Page.align)
}
.tabViewStyle(.page)
}
}
/// Erste Seite: wie das Fahrzeug steht.
struct LevelReadingPage: View {
@Environment(PhoneLink.self) private var link
@Environment(WatchLevelRadio.self) private var radio
@AppStorage("levelDisplayStyle") private var showsVehicle = true
@@ -36,16 +65,6 @@ struct WatchLevelView: View {
.multilineTextAlignment(.center)
.foregroundStyle(reading.state.isLevel ? .green : .primary)
if let lift, !lift.isNegligible {
WheelLiftPlan(lift: lift, isCompact: true)
.padding(.top, 2)
}
NavigationLink(value: WatchRoute.align) {
Label("Ausrichten", systemImage: "arrow.left.and.right")
}
.buttonStyle(.borderedProminent)
Button {
showsVehicle.toggle()
} label: {
@@ -58,7 +77,7 @@ struct WatchLevelView: View {
}
.padding(.horizontal, 4)
}
.navigationTitle("Nivellierung")
.navigationTitle("Neigung")
}
private func angle(_ title: String, _ value: Double?) -> some View {
@@ -71,6 +90,49 @@ struct WatchLevelView: View {
.foregroundStyle(.secondary)
}
}
}
/// Zweite Seite: die Keilhöhen, als Draufsicht auf die vier Räder.
struct WedgePage: View {
@Environment(PhoneLink.self) private var link
@Environment(WatchLevelRadio.self) private var radio
private var reading: WatchLevelReading { WatchLevelReading(radio: radio, phone: link) }
var body: some View {
ScrollView {
VStack(spacing: 8) {
if let lift, !lift.isNegligible {
WheelLiftPlan(lift: lift, isCompact: true)
Text("Zentimeter unter das jeweilige Rad. Das höchste bleibt liegen.")
.font(.system(size: 10))
.foregroundStyle(.secondary)
.multilineTextAlignment(.center)
} else if hasMeasurements {
Label("Keine Keile nötig", systemImage: "checkmark.circle.fill")
.font(.footnote)
.foregroundStyle(.green)
.padding(.top, 20)
} else {
// Ohne Fahrzeugmasse lässt sich nichts rechnen. Das gehört
// gesagt, sonst wirkt die Seite kaputt.
Label("Fahrzeugmasse fehlen", systemImage: "ruler")
.font(.footnote.weight(.medium))
Text("Spurweite und Radstand am iPhone im Fahrzeugprofil "
+ "hinterlegen, dann steht hier die Keilhöhe je Rad.")
.font(.system(size: 10))
.foregroundStyle(.secondary)
.multilineTextAlignment(.center)
}
}
.padding(.horizontal, 4)
}
.navigationTitle("Keile")
}
private var hasMeasurements: Bool {
link.payload?.profile.trackWidth != nil && link.payload?.profile.wheelbase != nil
}
/// Wie hoch jedes Rad unterlegt werden muss reine Geometrie, und nur zu
/// haben, wenn im Fahrzeugprofil Spurweite und Radstand stehen.