first commit

This commit is contained in:
fototeddy
2026-09-04 21:30:51 +02:00
commit da64b1b6bd
160 changed files with 20664 additions and 0 deletions
+116
View File
@@ -0,0 +1,116 @@
import SwiftUI
struct DashboardView: View {
@Environment(DeviceStore.self) private var store
@Environment(BluetoothManager.self) private var bluetooth
@State private var isAddingDevice = false
@State private var isManagingProfiles = false
@State private var isShowingSettings = false
private let columns = [GridItem(.adaptive(minimum: 300), spacing: 16)]
var body: some View {
NavigationStack {
ScrollView {
if !bluetooth.isBluetoothReady {
statusBanner
}
if store.activeDevices.isEmpty {
emptyState
} else {
LazyVGrid(columns: columns, spacing: 16) {
ForEach(store.activeDevices) { device in
NavigationLink {
DeviceDetailView(device: device)
} label: {
DeviceCard(
device: device,
snapshot: bluetooth.snapshots[device.id],
linkState: bluetooth.linkStates[device.id] ?? .searching
)
}
.buttonStyle(.plain)
}
}
.padding(.horizontal)
.padding(.top, 8)
}
}
.background(Color(.systemGroupedBackground))
.navigationTitle(store.activeProfile?.name ?? "Camper")
.toolbar {
ToolbarItem(placement: .topBarLeading) {
profileMenu
}
ToolbarItem(placement: .primaryAction) {
Button("Gerät hinzufügen", systemImage: "plus") {
isAddingDevice = true
}
}
}
.sheet(isPresented: $isAddingDevice) {
AddDeviceView()
}
.sheet(isPresented: $isManagingProfiles) {
ProfilesView()
}
.sheet(isPresented: $isShowingSettings) {
SettingsView()
}
}
}
/// Umschalter zwischen den Fahrzeugen.
private var profileMenu: some View {
Menu {
Picker("Fahrzeug", selection: Binding(
get: { store.activeProfileID },
set: { id in
guard let profile = store.profiles.first(where: { $0.id == id }) else { return }
store.selectProfile(profile)
bluetooth.refreshConfiguration()
}
)) {
ForEach(store.profiles) { profile in
Label(profile.name, systemImage: profile.symbol).tag(profile.id)
}
}
Divider()
Button("Fahrzeuge verwalten…", systemImage: "car.2") {
isManagingProfiles = true
}
Button("Einstellungen…", systemImage: "gearshape") {
isShowingSettings = true
}
} label: {
Label(store.activeProfile?.name ?? "Fahrzeug",
systemImage: store.activeProfile?.symbol ?? "box.truck")
.labelStyle(.iconOnly)
}
}
private var statusBanner: some View {
Label(bluetooth.bluetoothStatusText, systemImage: "exclamationmark.triangle.fill")
.font(.callout)
.frame(maxWidth: .infinity, alignment: .leading)
.padding()
.background(.orange.opacity(0.15), in: .rect(cornerRadius: 12))
.padding(.horizontal)
.padding(.top, 8)
}
private var emptyState: some View {
ContentUnavailableView {
Label("Noch keine Geräte", systemImage: "antenna.radiowaves.left.and.right")
} description: {
Text("Füge \(store.activeProfile.map { "\($0.name)" } ?? "diesem Fahrzeug") "
+ "den Ladebooster, den Solarladeregler und das BMS hinzu.")
} actions: {
Button("Gerät suchen") { isAddingDevice = true }
.buttonStyle(.borderedProminent)
}
.padding(.top, 60)
}
}