forked from fritob/Camper-Monitor
169 lines
6.2 KiB
Swift
169 lines
6.2 KiB
Swift
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
|
|
}
|
|
}
|
|
}
|
|
}
|