iOS: Mengen-Sheet auf Form-Ebene praesentieren (erstes Oeffnen bleibt offen)
Das Menge-hinzufuegen/umlagern/entfernen-Sheet ging beim ersten Antippen sofort wieder zu: das spaet fertige Laden der Entnahme-Statistik (.task im Abschnitt) riss das gerade praesentierte Sheet weg. ObjectStockSection ist jetzt zustands- los (bekommt removals + Sheet-Binding); Sheet und Statistik-Laden liegen in der Detailansicht auf der stabilen Form-Ebene bzw. im reload(). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -4,27 +4,29 @@ import SwiftUI
|
||||
/// Lebensmittel. Erlaubt Hinzufügen, Umlagern (ohne Grund) und Entfernen (mit
|
||||
/// Pflicht-Grund) und zeigt eine kleine Entnahme-Statistik. Wird als Abschnitt
|
||||
/// in die Produkt-Detailansicht eingebettet.
|
||||
/// Welches Mengen-Sheet gerade offen ist. Wird auf der stabilen Form-Ebene der
|
||||
/// Detailansicht präsentiert (nicht im Abschnitt selbst), sonst schloss sich das
|
||||
/// Fenster beim ersten Öffnen sofort wieder (das spät fertige Laden der
|
||||
/// Entnahme-Statistik hat das frische Sheet weggerissen).
|
||||
enum ObjectStockSheet: Identifiable {
|
||||
case add
|
||||
case relocate(from: String?)
|
||||
case remove(loc: String?)
|
||||
var id: String {
|
||||
switch self {
|
||||
case .add: return "add"
|
||||
case .relocate(let f): return "relocate-\(f ?? "none")"
|
||||
case .remove(let l): return "remove-\(l ?? "none")"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ObjectStockSection: View {
|
||||
let product: Product
|
||||
let locations: [StorageLocation]
|
||||
let lots: [Lot]
|
||||
var onChanged: () async -> Void
|
||||
|
||||
@State private var removals: RemovalSummary?
|
||||
@State private var sheet: StockSheet?
|
||||
|
||||
enum StockSheet: Identifiable {
|
||||
case add
|
||||
case relocate(from: String?)
|
||||
case remove(loc: String?)
|
||||
var id: String {
|
||||
switch self {
|
||||
case .add: return "add"
|
||||
case .relocate(let f): return "relocate-\(f ?? "none")"
|
||||
case .remove(let l): return "remove-\(l ?? "none")"
|
||||
}
|
||||
}
|
||||
}
|
||||
let removals: RemovalSummary?
|
||||
@Binding var sheet: ObjectStockSheet?
|
||||
|
||||
private var einheit: String { product.unitName.isEmpty ? "Stück" : product.unitName }
|
||||
private func ortName(_ id: String?) -> String {
|
||||
@@ -63,23 +65,6 @@ struct ObjectStockSection: View {
|
||||
.buttonStyle(.borderless)
|
||||
.font(.callout)
|
||||
}
|
||||
// Sheet an den Abschnitt hängen (nicht an die Group) – sonst ging das
|
||||
// Fenster bei manchen iOS-Versionen kurz auf und sofort wieder zu.
|
||||
.sheet(item: $sheet) { welche in
|
||||
NavigationStack {
|
||||
switch welche {
|
||||
case .add:
|
||||
ObjectAddSheet(product: product, locations: locations, einheit: einheit,
|
||||
perform: { await afterAction() })
|
||||
case .relocate(let from):
|
||||
ObjectRelocateSheet(product: product, locations: locations, initialFrom: from,
|
||||
perform: { await afterAction() })
|
||||
case .remove(let loc):
|
||||
ObjectRemoveSheet(product: product, locations: locations, einheit: einheit,
|
||||
initialLoc: loc, perform: { await afterAction() })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let removals, !removals.stats.isEmpty {
|
||||
Section("Bereits entnommen") {
|
||||
@@ -90,17 +75,6 @@ struct ObjectStockSection: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
.task(id: product.id) { await loadRemovals() }
|
||||
.onChange(of: lots) { _ in Task { await loadRemovals() } }
|
||||
}
|
||||
|
||||
private func loadRemovals() async {
|
||||
removals = try? await APIClient.shared.productRemovals(id: product.id)
|
||||
}
|
||||
|
||||
private func afterAction() async {
|
||||
await onChanged()
|
||||
await loadRemovals()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,10 @@ struct ProductDetailView: View {
|
||||
@State private var fieldValues: [String: String] = [:]
|
||||
|
||||
@State private var editLot: Lot?
|
||||
// Mengen-Bestand (Menge je Lagerort): Sheet + Entnahme-Statistik werden hier
|
||||
// gehalten und auf Form-Ebene präsentiert, damit das Sheet stabil aufgeht.
|
||||
@State private var objectSheet: ObjectStockSheet?
|
||||
@State private var objectRemovals: RemovalSummary?
|
||||
|
||||
private let labels = ["", "Glas", "Tüte", "Flasche", "Dose", "Tube", "Becher", "Beutel", "Karton"]
|
||||
|
||||
@@ -92,7 +96,7 @@ struct ProductDetailView: View {
|
||||
} else if current.isObject && !current.isBulk {
|
||||
// Menge je Lagerort (Verbrauchsgegenstände laufen als Charge, s.u.).
|
||||
ObjectStockSection(product: current, locations: locations, lots: lots,
|
||||
onChanged: { await reload() })
|
||||
removals: objectRemovals, sheet: $objectSheet)
|
||||
} else {
|
||||
// Lebensmittel und Verbrauchsgegenstände: Vorrat aus den Chargen.
|
||||
Section("Bestand") {
|
||||
@@ -287,6 +291,25 @@ struct ProductDetailView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Mengen-Sheets auf der stabilen Form-Ebene (nicht im Abschnitt), sonst
|
||||
// schloss sich das Fenster beim ersten Öffnen sofort wieder.
|
||||
.sheet(item: $objectSheet) { welche in
|
||||
NavigationStack {
|
||||
switch welche {
|
||||
case .add:
|
||||
ObjectAddSheet(product: current, locations: locations,
|
||||
einheit: current.unitName.isEmpty ? "Stück" : current.unitName,
|
||||
perform: { await reload() })
|
||||
case .relocate(let from):
|
||||
ObjectRelocateSheet(product: current, locations: locations, initialFrom: from,
|
||||
perform: { await reload() })
|
||||
case .remove(let loc):
|
||||
ObjectRemoveSheet(product: current, locations: locations,
|
||||
einheit: current.unitName.isEmpty ? "Stück" : current.unitName,
|
||||
initialLoc: loc, perform: { await reload() })
|
||||
}
|
||||
}
|
||||
}
|
||||
.task {
|
||||
fillForm()
|
||||
await reload()
|
||||
@@ -355,6 +378,12 @@ struct ProductDetailView: View {
|
||||
} else {
|
||||
fieldDefs = []
|
||||
}
|
||||
// Entnahme-Statistik nur für „Menge je Lagerort"-Gegenstände.
|
||||
if current.isObject && !current.isBulk && !current.isIndividual {
|
||||
objectRemovals = try? await APIClient.shared.productRemovals(id: current.id)
|
||||
} else {
|
||||
objectRemovals = nil
|
||||
}
|
||||
}
|
||||
|
||||
/// Verwaltungsart (individual/bulk) mitschicken, wenn sie umgestellt wurde.
|
||||
|
||||
Reference in New Issue
Block a user