import SwiftUI /// Fahrzeuge anlegen, umbenennen und entfernen. struct ProfilesView: View { @Environment(DeviceStore.self) private var store @Environment(BluetoothManager.self) private var bluetooth @Environment(\.dismiss) private var dismiss @State private var editing: Profile? @State private var pendingDeletion: Profile? var body: some View { NavigationStack { List { Section { ForEach(store.profiles) { profile in row(for: profile) } } footer: { Text("Jedes Fahrzeug hat seine eigenen Geräte. Die App liest immer " + "nur die des gewählten Fahrzeugs aus.") } Section { Button("Fahrzeug hinzufügen", systemImage: "plus") { let profile = store.addProfile(named: "Camper \(store.profiles.count + 1)") editing = profile } } } .navigationTitle("Fahrzeuge") .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .confirmationAction) { Button("Fertig") { dismiss() } } } .sheet(item: $editing) { profile in ProfileEditView(profile: profile) } .confirmationDialog("Fahrzeug entfernen?", isPresented: .init(get: { pendingDeletion != nil }, set: { if !$0 { pendingDeletion = nil } }), titleVisibility: .visible) { Button("Entfernen", role: .destructive) { if let pendingDeletion { store.removeProfile(pendingDeletion) bluetooth.refreshConfiguration() } pendingDeletion = nil } } message: { if let pendingDeletion { Text("„\(pendingDeletion.name)“ und die \(store.deviceCount(in: pendingDeletion)) " + "darin eingerichteten Geräte werden gelöscht.") } } } } private func row(for profile: Profile) -> some View { HStack { Label { VStack(alignment: .leading, spacing: 2) { Text(profile.name) Text(deviceSummary(for: profile)) .font(.caption) .foregroundStyle(.secondary) } } icon: { Image(systemName: profile.symbol) } Spacer() if profile.id == store.activeProfileID { Image(systemName: "checkmark") .foregroundStyle(.tint) .fontWeight(.semibold) } } .contentShape(.rect) .onTapGesture { store.selectProfile(profile) bluetooth.refreshConfiguration() } .swipeActions(edge: .trailing) { // Das letzte Fahrzeug muss bleiben, sonst hätten Geräte keinen Ort. if store.hasMultipleProfiles { Button("Entfernen", systemImage: "trash", role: .destructive) { pendingDeletion = profile } } Button("Bearbeiten", systemImage: "pencil") { editing = profile } .tint(.gray) } } private func deviceSummary(for profile: Profile) -> String { let count = store.deviceCount(in: profile) return count == 1 ? "1 Gerät" : "\(count) Geräte" } } /// Name und Symbol eines Fahrzeugs ändern. private struct ProfileEditView: View { let profile: Profile @Environment(DeviceStore.self) private var store @Environment(\.dismiss) private var dismiss @State private var name = "" @State private var symbol = "box.truck" private let columns = [GridItem(.adaptive(minimum: 60), spacing: 12)] var body: some View { NavigationStack { Form { Section("Name") { TextField("Name", text: $name) } Section("Symbol") { LazyVGrid(columns: columns, spacing: 12) { ForEach(Profile.symbols, id: \.self) { candidate in Button { symbol = candidate } label: { Image(systemName: candidate) .font(.title2) .frame(width: 52, height: 52) .background(symbol == candidate ? Color.accentColor.opacity(0.18) : Color.secondary.opacity(0.08), in: .rect(cornerRadius: 12)) .foregroundStyle(symbol == candidate ? Color.accentColor : Color.primary) } .buttonStyle(.plain) } } .padding(.vertical, 4) } } .navigationTitle("Fahrzeug") .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .cancellationAction) { Button("Abbrechen") { dismiss() } } ToolbarItem(placement: .confirmationAction) { Button("Sichern") { var updated = profile updated.name = name.trimmingCharacters(in: .whitespaces) updated.symbol = symbol store.update(updated) dismiss() } .disabled(name.trimmingCharacters(in: .whitespaces).isEmpty) } } .onAppear { name = profile.name symbol = profile.symbol } } } }