Bisher standen dort zwei Angaben nebeneinander, etwa "rechts 8 cm" und "vorne 4 cm". Das liest sich wie zwei Aufgaben, ist aber eine: Unter "rechts" liegen zwei Räder, unter "vorne" auch, und eines davon ist dasselbe. Ausführen lässt sich das so nicht. Gerechnet wird jetzt über alle vier Aufstandspunkte auf einmal. Aus Spurweite, Radstand und den beiden Winkeln ergeben sich deren Höhen; angehoben wird auf das höchststehende Rad, das liegen bleibt. Aus dem Beispiel oben werden damit 12 cm vorne rechts, 8 cm hinten rechts, 4 cm vorne links und nichts hinten links – dieselbe Geometrie, nur richtig zusammengesetzt. Angezeigt wird das als Draufsicht auf das Fahrzeug (WheelLiftPlan), auf iPhone und Uhr dieselbe Ansicht, auf der Uhr kompakt. LevelingWedge entfällt. Abgesichert in run-tests.sh: reine Querneigung, reine Längsneigung, beides zusammen (16,1 / 9,2 / 7,0 / 0 cm), gespiegelte Vorzeichen und die Fälle ohne Fahrzeugmasse. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
75 lines
2.8 KiB
Swift
75 lines
2.8 KiB
Swift
import SwiftUI
|
||
|
||
/// Die Keilhöhen als Draufsicht auf das Fahrzeug.
|
||
///
|
||
/// Vier Zahlen an vier Rädern, statt zweier Angaben „rechts" und „vorne", die
|
||
/// sich nicht getrennt ausführen lassen. Oben ist vorne; links im Bild ist
|
||
/// links am Fahrzeug, aus Sicht des Fahrers.
|
||
///
|
||
/// Das höchststehende Rad bekommt nichts – es bleibt liegen, die anderen
|
||
/// werden auf seine Höhe gebracht.
|
||
struct WheelLiftPlan: View {
|
||
let lift: LevelingLift
|
||
/// Für die Uhr: kleinere Schrift, engerer Aufbau.
|
||
var isCompact = false
|
||
|
||
var body: some View {
|
||
VStack(spacing: isCompact ? 2 : 6) {
|
||
Text("vorne")
|
||
.font(labelFont)
|
||
.foregroundStyle(.secondary)
|
||
|
||
HStack(spacing: isCompact ? 6 : 12) {
|
||
VStack(spacing: isCompact ? 6 : 14) {
|
||
badge(.frontLeft)
|
||
badge(.rearLeft)
|
||
}
|
||
body_
|
||
VStack(spacing: isCompact ? 6 : 14) {
|
||
badge(.frontRight)
|
||
badge(.rearRight)
|
||
}
|
||
}
|
||
|
||
Text("hinten")
|
||
.font(labelFont)
|
||
.foregroundStyle(.secondary)
|
||
}
|
||
.accessibilityElement(children: .combine)
|
||
.accessibilityLabel(accessibilityText)
|
||
}
|
||
|
||
/// Der Umriss dazwischen macht aus vier Zahlen ein Fahrzeug.
|
||
private var body_: some View {
|
||
RoundedRectangle(cornerRadius: isCompact ? 4 : 8)
|
||
.strokeBorder(Color.secondary.opacity(0.4), lineWidth: 1)
|
||
.frame(width: isCompact ? 26 : 48, height: isCompact ? 44 : 84)
|
||
}
|
||
|
||
private func badge(_ wheel: LevelingLift.Wheel) -> some View {
|
||
let value = lift.centimetres(wheel)
|
||
let needed = value >= 1
|
||
return Text(needed ? String(format: "%.0f", value) : "–")
|
||
.font(valueFont)
|
||
.monospacedDigit()
|
||
.foregroundStyle(needed ? .primary : .secondary)
|
||
.frame(width: isCompact ? 26 : 42, height: isCompact ? 20 : 30)
|
||
.background(needed ? Color.orange.opacity(0.25) : Color.secondary.opacity(0.12),
|
||
in: .rect(cornerRadius: isCompact ? 4 : 6))
|
||
}
|
||
|
||
private var labelFont: Font { isCompact ? .system(size: 9) : .caption2 }
|
||
private var valueFont: Font {
|
||
isCompact ? .system(size: 12, weight: .semibold) : .callout.weight(.semibold)
|
||
}
|
||
|
||
private var accessibilityText: String {
|
||
let parts = LevelingLift.Wheel.allCases.compactMap { wheel -> String? in
|
||
let value = lift.centimetres(wheel)
|
||
guard value >= 1 else { return nil }
|
||
return String(format: "%@ %.0f Zentimeter", wheel.text, value)
|
||
}
|
||
return parts.isEmpty ? "Keine Keile nötig" : "Unterlegen: " + parts.joined(separator: ", ")
|
||
}
|
||
}
|