forked from fritob/Camper-Monitor
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:
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user