iOS: Kassenzettel in den Scannen-Tab, Markenblau statt System-Blau, weisse Kacheln, luftigere Pruefen-Liste
- Kassenzettel-Kachel vom Listen- in den Scannen-Tab verschoben (passt thematisch). - App-Akzent auf Markenblau (#3F51B5/#7C8AE8, wie Web/App-Icon) via .tint; alle Color.accentColor -> Color.marke. System-Blau verschwindet. - Kachel-Buttons/Links auf .buttonStyle(.plain): weisse Schrift/Symbole statt getoentem Blau. - Kassenzettel-Pruefen-Liste: je Artikel eine eigene Section (insetGrouped) mit Artikel/Menge/Lagerort in eigenen Zeilen - klar gruppiert, nicht mehr gequetscht. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -503,12 +503,12 @@ struct KassenzettelMarkierenView: View {
|
||||
ZStack(alignment: .topLeading) {
|
||||
Image(uiImage: bild).resizable().scaledToFit()
|
||||
.frame(width: geo.size.width, height: geo.size.height)
|
||||
Rectangle().stroke(Color.accentColor, lineWidth: 2)
|
||||
.background(Color.accentColor.opacity(0.15))
|
||||
Rectangle().stroke(Color.marke, lineWidth: 2)
|
||||
.background(Color.marke.opacity(0.15))
|
||||
.frame(width: rect.width, height: rect.height)
|
||||
.offset(x: rect.minX, y: rect.minY)
|
||||
.gesture(zieh(resize: false))
|
||||
Rectangle().fill(Color.accentColor)
|
||||
Rectangle().fill(Color.marke)
|
||||
.frame(width: 26, height: 26)
|
||||
.offset(x: rect.maxX - 13, y: rect.maxY - 13)
|
||||
.gesture(zieh(resize: true))
|
||||
@@ -608,7 +608,14 @@ struct KassenzettelPruefenView: View {
|
||||
}.padding()
|
||||
} else {
|
||||
List {
|
||||
ForEach($zeilen) { $z in zeile($z) }
|
||||
ForEach($zeilen) { $z in
|
||||
Section {
|
||||
zeile($z)
|
||||
} header: {
|
||||
Text(z.text)
|
||||
.textCase(nil).font(.footnote).foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
Section {
|
||||
Button { Task { await einlagern() } } label: {
|
||||
HStack {
|
||||
@@ -620,6 +627,7 @@ struct KassenzettelPruefenView: View {
|
||||
Text("Nicht zugeordnete Zeilen werden übersprungen. Neue Artikel werden nicht angelegt.")
|
||||
}
|
||||
}
|
||||
.listStyle(.insetGrouped)
|
||||
}
|
||||
}
|
||||
.onAppear(perform: aufbauen)
|
||||
@@ -637,47 +645,49 @@ struct KassenzettelPruefenView: View {
|
||||
} message: { Text(meldung ?? "") }
|
||||
}
|
||||
|
||||
/// Drei Zeilen (Rows) je Artikel: Auswahl, Menge, Lagerort. In einer eigenen
|
||||
/// Section gruppiert – so ist klar, was zusammengehört, und nichts ist gequetscht.
|
||||
@ViewBuilder private func zeile(_ z: Binding<KassenzettelZeile>) -> some View {
|
||||
let zeile = z.wrappedValue
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
Text(zeile.text).font(.caption).foregroundStyle(.secondary).lineLimit(1)
|
||||
Menu {
|
||||
ForEach(zeile.kandidaten) { k in
|
||||
Button("\(k.name) · \(k.score) %") {
|
||||
z.wrappedValue.artikel = KassenzettelArtikel(id: k.productId, name: k.name, unit: k.checkInUnit)
|
||||
}
|
||||
}
|
||||
Divider()
|
||||
Button { sucheZiel = ZeilenRef(id: zeile.id) } label: { Label("Suchen…", systemImage: "magnifyingglass") }
|
||||
if zeile.artikel != nil {
|
||||
Button(role: .destructive) { z.wrappedValue.artikel = nil } label: {
|
||||
Label("Nicht zuordnen", systemImage: "xmark")
|
||||
}
|
||||
}
|
||||
} label: {
|
||||
HStack {
|
||||
Image(systemName: zeile.artikel == nil ? "questionmark.circle" : "checkmark.circle.fill")
|
||||
.foregroundStyle(zeile.artikel == nil ? Color.secondary : Color.green)
|
||||
Text(zeile.artikel?.name ?? "– Artikel wählen –")
|
||||
.foregroundStyle(zeile.artikel == nil ? Color.secondary : Color.primary)
|
||||
Spacer()
|
||||
Image(systemName: "chevron.up.chevron.down").font(.caption2).foregroundStyle(.secondary)
|
||||
// Artikel wählen
|
||||
Menu {
|
||||
ForEach(zeile.kandidaten) { k in
|
||||
Button("\(k.name) · \(k.score) %") {
|
||||
z.wrappedValue.artikel = KassenzettelArtikel(id: k.productId, name: k.name, unit: k.checkInUnit)
|
||||
}
|
||||
}
|
||||
HStack(spacing: 12) {
|
||||
Stepper("Menge \(Int(zeile.menge))", value: z.menge, in: 1...99).fixedSize()
|
||||
Divider()
|
||||
Button { sucheZiel = ZeilenRef(id: zeile.id) } label: { Label("Suchen…", systemImage: "magnifyingglass") }
|
||||
if zeile.artikel != nil {
|
||||
Button(role: .destructive) { z.wrappedValue.artikel = nil } label: {
|
||||
Label("Nicht zuordnen", systemImage: "xmark")
|
||||
}
|
||||
}
|
||||
} label: {
|
||||
HStack {
|
||||
Image(systemName: zeile.artikel == nil ? "questionmark.circle" : "checkmark.circle.fill")
|
||||
.foregroundStyle(zeile.artikel == nil ? Color.secondary : Color.green)
|
||||
Text(zeile.artikel?.name ?? "– Artikel wählen –")
|
||||
.foregroundStyle(zeile.artikel == nil ? Color.secondary : Color.primary)
|
||||
Spacer()
|
||||
Menu {
|
||||
Button("– ohne –") { z.wrappedValue.ortId = nil }
|
||||
ForEach(locations) { loc in Button(loc.name) { z.wrappedValue.ortId = loc.id } }
|
||||
} label: {
|
||||
Label(ortName(zeile.ortId), systemImage: "mappin.and.ellipse").font(.callout).lineLimit(1)
|
||||
}
|
||||
Button { scanZiel = ZeilenRef(id: zeile.id) } label: {
|
||||
Image(systemName: "qrcode.viewfinder")
|
||||
}.buttonStyle(.borderless)
|
||||
Image(systemName: "chevron.up.chevron.down").font(.caption2).foregroundStyle(.secondary)
|
||||
}
|
||||
}.padding(.vertical, 4)
|
||||
}
|
||||
// Menge
|
||||
Stepper("Menge: \(Int(zeile.menge))", value: z.menge, in: 1...99)
|
||||
// Lagerort + QR-Scan
|
||||
HStack {
|
||||
Menu {
|
||||
Button("– ohne –") { z.wrappedValue.ortId = nil }
|
||||
ForEach(locations) { loc in Button(loc.name) { z.wrappedValue.ortId = loc.id } }
|
||||
} label: {
|
||||
Label(ortName(zeile.ortId), systemImage: "mappin.and.ellipse")
|
||||
}
|
||||
Spacer()
|
||||
Button { scanZiel = ZeilenRef(id: zeile.id) } label: {
|
||||
Label("QR", systemImage: "qrcode.viewfinder")
|
||||
}.buttonStyle(.borderless)
|
||||
}
|
||||
}
|
||||
|
||||
private func ortName(_ id: String?) -> String {
|
||||
|
||||
Reference in New Issue
Block a user