forked from fritob/Camper-Monitor
App-Namen im iOS-Projekt auf VanControl vereinheitlichen
CamperMonitor (Haupt-Repo) und VanAligneiOS (aus dem gemergten solar-integration-Branch) liefen unter zwei verschiedenen internen Namen, obwohl die App nach aussen längst einheitlich "VanControl Pro" heisst. Jetzt durchgängig VanControl: - Ordner: CamperMonitor/, CamperMonitorWatch/, CamperMonitorComplication/, VanAligneiOSWidget/ → VanControl/, VanControlWatch/, VanControlComplication/, VanControlWidget/ - Xcode-Projekt: CamperMonitor.xcodeproj → VanControl.xcodeproj, alle Targets/Schemes/Produktnamen entsprechend umbenannt - Bundle-Identifier auf Wunsch mitgeändert: de.s0.fototeddy.VanControl* (App noch nicht veröffentlicht); dabei auch die WKCompanionAppBundleIdentifier-Werte korrigiert, die noch das alte de.fritob-Präfix statt des tatsächlichen de.s0.fototeddy-Präfixes trugen - Swift-Dateien/Typen: CamperMonitorApp → VanControlApp, VanAligneiOSWidget* → VanControlWidget* - Config/*-Info.plist umbenannt, README.md/Tools/README.md/run-tests.sh auf die neuen Pfade angepasst Bewusst unverändert: firmware/vanalign und alle Bezüge auf "VanAlign" als Namen der Neigungsmesser-Hardware (eigenständiges Produkt, kein App-Name) sowie der komplette Android/-Ordner. Build (App, Watch, Debug) und Protokoll-Testlauf grün. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
83ea85f3b8
commit
303a9735d0
@@ -0,0 +1,113 @@
|
||||
import SwiftUI
|
||||
|
||||
/// Zeigt die Neigung am Fahrzeug selbst, statt an einer abstrakten Blase.
|
||||
///
|
||||
/// Zwei Ansichten, jede um ihre Achse gekippt:
|
||||
///
|
||||
/// * **Seitenansicht** für die Längsneigung. Die Front zeigt nach links, das
|
||||
/// Heck nach rechts.
|
||||
/// * **Heckansicht** für die Querneigung. Sie teilt die Blickrichtung des
|
||||
/// Fahrers, links im Bild ist also links am Fahrzeug – bei einer
|
||||
/// Frontansicht wäre es seitenverkehrt.
|
||||
///
|
||||
/// In beiden Fällen wird gegen den mathematischen Drehsinn gekippt: Steht das
|
||||
/// Heck höher, muss die rechte Bildseite nach oben.
|
||||
struct VehicleTiltView: View {
|
||||
let pitch: Double?
|
||||
let roll: Double?
|
||||
var style: VehicleGraphicStyle = .vanster
|
||||
/// Für Querformat: beide Ansichten nebeneinander statt untereinander,
|
||||
/// kleinere Schrift, ohne Überhöhungs-Hinweis – muss ohne Scrollen in die
|
||||
/// Bildschirmhöhe passen.
|
||||
var compact = false
|
||||
/// Bildhöhe je Panel im Querformat – vom Aufrufer an die tatsächlich
|
||||
/// verfügbare Bildschirmhöhe angepasst, statt fest verdrahtet.
|
||||
var compactPanelHeight: CGFloat = 62
|
||||
|
||||
var body: some View {
|
||||
if compact {
|
||||
HStack(alignment: .top, spacing: 16) {
|
||||
tiltPanel(image: style.sideImageName, angle: pitch, title: "Längs",
|
||||
lowerLabel: "Front", upperLabel: "Heck", aspect: style.sideAspect)
|
||||
tiltPanel(image: style.rearImageName, angle: roll, title: "Quer",
|
||||
lowerLabel: "links", upperLabel: "rechts", aspect: style.rearAspect)
|
||||
}
|
||||
} else {
|
||||
VStack(spacing: 20) {
|
||||
tiltPanel(image: style.sideImageName, angle: pitch, title: "Längs",
|
||||
lowerLabel: "Front", upperLabel: "Heck", aspect: style.sideAspect)
|
||||
tiltPanel(image: style.rearImageName, angle: roll, title: "Quer",
|
||||
lowerLabel: "links", upperLabel: "rechts", aspect: style.rearAspect)
|
||||
|
||||
// Ohne diesen Hinweis nähme man den Bildwinkel für den echten.
|
||||
Text(String(format: "Neigung %.0f-fach überhöht dargestellt – "
|
||||
+ "sonst wäre sie kaum zu erkennen. Die Gradzahlen sind echt.",
|
||||
VehicleTilt.exaggeration))
|
||||
.font(.caption2)
|
||||
.foregroundStyle(.secondary)
|
||||
.multilineTextAlignment(.center)
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func tiltPanel(image: String,
|
||||
angle: Double?,
|
||||
title: String,
|
||||
lowerLabel: String,
|
||||
upperLabel: String,
|
||||
aspect: Double) -> some View {
|
||||
VStack(spacing: compact ? 4 : 8) {
|
||||
HStack {
|
||||
Text(title)
|
||||
.font(compact ? .caption2.weight(.medium) : .subheadline.weight(.medium))
|
||||
Spacer()
|
||||
Text(angle.map { String(format: "%.1f°", $0) } ?? "–")
|
||||
.font((compact ? Font.caption2 : .subheadline).weight(.semibold).monospacedDigit())
|
||||
.foregroundStyle(VehicleTilt.colour(for: angle))
|
||||
}
|
||||
|
||||
ZStack {
|
||||
// Waagerechte als Bezug – ohne sie ist eine kleine Neigung
|
||||
// nicht einzuschätzen.
|
||||
Rectangle()
|
||||
.fill(Color.secondary.opacity(0.35))
|
||||
.frame(height: 1)
|
||||
|
||||
Image(image)
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.foregroundStyle(VehicleTilt.colour(for: angle))
|
||||
.aspectRatio(aspect, contentMode: .fit)
|
||||
.rotationEffect(.degrees(-(angle ?? 0) * VehicleTilt.exaggeration))
|
||||
.animation(.spring(duration: 0.4), value: angle)
|
||||
.opacity(angle == nil ? 0.3 : 1)
|
||||
}
|
||||
.frame(height: compact ? compactPanelHeight : 110)
|
||||
|
||||
HStack {
|
||||
Text(lowerLabel)
|
||||
Spacer()
|
||||
Text(upperLabel)
|
||||
}
|
||||
.font(compact ? .system(size: 9) : .caption2)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// Umschalter zwischen den beiden Darstellungen, gemerkt über Starts hinweg.
|
||||
enum LevelDisplayStyle: String, CaseIterable, Identifiable {
|
||||
case bubble
|
||||
case vehicle
|
||||
|
||||
var id: String { rawValue }
|
||||
|
||||
var title: String {
|
||||
switch self {
|
||||
case .bubble: return "Libelle"
|
||||
case .vehicle: return "Fahrzeug"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user