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
+50 -44
View File
@@ -20,52 +20,58 @@ struct WatchAlignView: View {
private var state: LevelState? { reading.hasReading ? reading.state : nil }
var body: some View {
ScrollView {
VStack(spacing: 8) {
if let current = assistant.current {
Text(String(format: "%.1f°", current.deviation))
.font(.system(size: 40, weight: .semibold, design: .rounded))
.monospacedDigit()
.foregroundStyle(assistant.hasReachedTarget ? .green : .primary)
.contentTransition(.numericText())
} else {
ProgressView()
.padding(.vertical, 12)
}
Label(assistant.trend.text, systemImage: assistant.trend.symbol)
.font(.footnote.weight(.medium))
.foregroundStyle(trendColor)
Text(assistant.advice)
.font(.caption)
.multilineTextAlignment(.center)
.foregroundStyle(.secondary)
if let state {
HStack(spacing: 12) {
WatchBubble(pitch: state.pitch, roll: state.roll)
.frame(width: 56, height: 56)
VStack(alignment: .leading, spacing: 2) {
Text(String(format: "Längs %.1f°", state.pitch ?? 0))
Text(String(format: "Quer %.1f°", state.roll ?? 0))
}
.font(.caption2)
.monospacedDigit()
.foregroundStyle(.secondary)
}
.padding(.top, 2)
}
Button("Von vorn messen", systemImage: "arrow.counterclockwise") {
assistant.reset()
hasAnnouncedTarget = false
}
.font(.caption2)
.padding(.top, 4)
// Ohne ScrollView: Beim Rangieren schaut man kurz hin, da darf nichts
// ausserhalb des Bildes liegen. Alles ist deshalb so bemessen, dass es
// auch auf der kleinsten Uhr auf einen Blick passt.
VStack(spacing: 3) {
if let current = assistant.current {
Text(String(format: "%.1f°", current.deviation))
.font(.system(size: 30, weight: .semibold, design: .rounded))
.monospacedDigit()
.foregroundStyle(assistant.hasReachedTarget ? .green : .primary)
.contentTransition(.numericText())
} else {
ProgressView()
.padding(.vertical, 6)
}
.padding(.horizontal, 4)
Label(assistant.trend.text, systemImage: assistant.trend.symbol)
.font(.caption2.weight(.medium))
.foregroundStyle(trendColor)
Text(assistant.advice)
.font(.system(size: 11))
.multilineTextAlignment(.center)
.foregroundStyle(.secondary)
.lineLimit(2)
.minimumScaleFactor(0.8)
if let state {
HStack(spacing: 8) {
WatchBubble(pitch: state.pitch, roll: state.roll)
.frame(width: 40, height: 40)
VStack(alignment: .leading, spacing: 1) {
Text(String(format: "Längs %.1f°", state.pitch ?? 0))
Text(String(format: "Quer %.1f°", state.roll ?? 0))
}
.font(.system(size: 11))
.monospacedDigit()
.foregroundStyle(.secondary)
}
}
Button {
assistant.reset()
hasAnnouncedTarget = false
} label: {
Label("Von vorn", systemImage: "arrow.counterclockwise")
.font(.system(size: 10))
}
.buttonStyle(.borderless)
.foregroundStyle(.secondary)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.padding(.horizontal, 2)
.navigationTitle("Ausrichten")
.onChange(of: tilt, initial: true) { _, tilt in
guard let tilt else { return }