You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

144 lines
5.7 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import SwiftUI
struct PersonsView: View {
@EnvironmentObject var store: Store
@State private var newName = ""
@FocusState private var newFocused: Bool
private let nameWidth: CGFloat = 220
private let genderWidth: CGFloat = 120
private let noteWidth: CGFloat = 180
private let checkWidth: CGFloat = 32
var body: some View {
VStack(alignment: .leading, spacing: 0) {
HStack(spacing: 10) {
TextField("Name der neuen Person", text: $newName)
.textFieldStyle(.roundedBorder)
.frame(width: 260)
.focused($newFocused)
.onSubmit(add)
Button("Hinzufügen", action: add).buttonStyle(.borderedProminent)
.disabled(newName.trimmingCharacters(in: .whitespaces).isEmpty)
Text("Häkchen = darf diese Aufgabe übernehmen. Wer mindestens eine Diener-Aufgabe hat, erscheint oben in der Übersicht, wer eine Schulungsaufgabe hat, unten.")
.font(.caption).foregroundStyle(Theme.muted)
.fixedSize(horizontal: false, vertical: true)
}
.padding(16)
ScrollView([.horizontal, .vertical]) {
VStack(alignment: .leading, spacing: 0) {
headerRow
ForEach(store.personsSorted) { p in
if let binding = store.binding(person: p.id) {
PersonRow(person: binding, widths: (nameWidth, genderWidth, noteWidth, checkWidth))
}
}
}
.padding([.horizontal, .bottom], 16)
}
}
}
private var headerRow: some View {
HStack(alignment: .bottom, spacing: 0) {
Text("Name").frame(width: nameWidth, alignment: .leading).padding(.leading, 4)
Text("Bruder/Schwester").frame(width: genderWidth, alignment: .leading)
Text("Notiz").frame(width: noteWidth, alignment: .leading)
ForEach(store.db.tasks) { t in
Text(t.name)
.lineLimit(1)
.fixedSize()
.rotationEffect(.degrees(-90))
.frame(width: checkWidth, height: 170, alignment: .center)
.background(Theme.soft(for: t.group))
.help(t.name)
}
Spacer().frame(width: 80)
}
.font(.caption.weight(.semibold))
.foregroundStyle(Theme.muted)
.padding(.bottom, 6)
.overlay(alignment: .bottom) { Rectangle().fill(Theme.line).frame(height: 1) }
}
private func add() {
if store.addPerson(named: newName) { newName = "" } else { NSSound.beep() }
newFocused = true
}
}
struct PersonRow: View {
@Binding var person: Person
let widths: (name: CGFloat, gender: CGFloat, note: CGFloat, check: CGFloat)
@EnvironmentObject var store: Store
@State private var name = ""
@FocusState private var focused: Bool
var body: some View {
HStack(spacing: 0) {
TextField("Name", text: $name)
.textFieldStyle(.roundedBorder)
.frame(width: widths.name - 12)
.padding(.trailing, 12)
.onAppear { name = person.name }
.focused($focused)
.onSubmit(commitName)
.onChange(of: focused) { _, now in if !now { commitName() } }
.onDisappear(perform: commitName)
Picker("", selection: $person.gender) {
Text("–").tag("")
Text("Bruder").tag("Bruder")
Text("Schwester").tag("Schwester")
}
.labelsHidden()
.frame(width: widths.gender - 12)
.padding(.trailing, 12)
TextField("", text: $person.note)
.textFieldStyle(.roundedBorder)
.frame(width: widths.note - 12)
.padding(.trailing, 12)
ForEach(store.db.tasks) { t in
Toggle("", isOn: Binding(
get: { person.tasks.contains(t.id) },
set: { on in
if on { if !person.tasks.contains(t.id) { person.tasks.append(t.id) } }
else { person.tasks.removeAll { $0 == t.id } }
}))
.toggleStyle(.checkbox)
.labelsHidden()
.frame(width: widths.check)
.help(t.name)
}
Button("Löschen", role: .destructive, action: delete)
.buttonStyle(.link)
.foregroundStyle(Theme.bengara)
.frame(width: 80)
}
.padding(.vertical, 5)
.overlay(alignment: .bottom) { Rectangle().fill(Theme.line).frame(height: 1) }
}
private func commitName() {
let n = name.trimmingCharacters(in: .whitespaces)
guard n != person.name else { return }
if n.isEmpty || store.db.persons.contains(where: { $0.id != person.id && $0.name.lowercased() == n.lowercased() }) {
NSSound.beep(); name = person.name; return
}
person.name = n
}
private func delete() {
let count = store.entryCount(person: person.id)
let alert = NSAlert()
alert.messageText = "\(person.name) löschen?"
alert.informativeText = count > 0
? "\(count) Einträge im Verlauf gehören zu dieser Person und werden ebenfalls gelöscht."
: "Die Person hat noch keine Einträge im Verlauf."
alert.addButton(withTitle: "Löschen").hasDestructiveAction = true
alert.addButton(withTitle: "Abbrechen")
guard alert.runModal() == .alertFirstButtonReturn else { return }
store.deletePerson(person.id)
}
}

Powered by TurnKey Linux.