feat(loading): Set-Kopf wird grün, wenn alle Komponenten geladen sind
Ein nicht-scanbarer Set-Kopf (Parent-Artikel) hat keinen eigenen Scan-Status. Sobald alle scanbaren, nicht entfernten Komponenten fertig (isDone) sind, wird der Kopf jetzt ebenfalls grün dargestellt (effectiveDone = isDone || setParentComplete) und zeigt statt des unterdrückten Hinweises ein grünes „Komplett geladen". Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@ -558,6 +558,17 @@ class _CustomerBody extends StatelessWidget {
|
|||||||
})
|
})
|
||||||
.map((it) => it.id)
|
.map((it) => it.id)
|
||||||
.toSet();
|
.toSet();
|
||||||
|
// Set-Kopf „komplett": alle scanbaren, nicht entfernten Komponenten fertig.
|
||||||
|
// Dann wird auch der (selbst nicht scanbare) Kopf grün dargestellt.
|
||||||
|
bool setParentComplete(DeliveryItem parent) {
|
||||||
|
final nr = artNrOf(parent);
|
||||||
|
if (nr == null) return false;
|
||||||
|
final comps = delivery.items.where((c) =>
|
||||||
|
c.parentArtikelNr == nr &&
|
||||||
|
!c.isRemoved &&
|
||||||
|
(details.articleOf(c.articleId)?.scannable ?? false));
|
||||||
|
return comps.isNotEmpty && comps.every((c) => c.isDone);
|
||||||
|
}
|
||||||
// Set-Köpfe je Lagergruppe (warehouseId → einzuhängende Köpfe) +
|
// Set-Köpfe je Lagergruppe (warehouseId → einzuhängende Köpfe) +
|
||||||
// gesammelte IDs, um sie aus der Dienstleistungs-Sektion zu entfernen.
|
// gesammelte IDs, um sie aus der Dienstleistungs-Sektion zu entfernen.
|
||||||
final injectedParentsByWarehouseId = <String, List<DeliveryItem>>{};
|
final injectedParentsByWarehouseId = <String, List<DeliveryItem>>{};
|
||||||
@ -686,6 +697,8 @@ class _CustomerBody extends StatelessWidget {
|
|||||||
details: details,
|
details: details,
|
||||||
onAction: (action) => onItemAction(item, action),
|
onAction: (action) => onItemAction(item, action),
|
||||||
suppressScanHint: setParentIds.contains(item.id),
|
suppressScanHint: setParentIds.contains(item.id),
|
||||||
|
setParentComplete: setParentIds.contains(item.id) &&
|
||||||
|
setParentComplete(item),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
// Gebuchte Dienstleistungen (nicht-scanbare Positionen ohne
|
// Gebuchte Dienstleistungen (nicht-scanbare Positionen ohne
|
||||||
@ -701,6 +714,8 @@ class _CustomerBody extends StatelessWidget {
|
|||||||
details: details,
|
details: details,
|
||||||
onAction: (action) => onItemAction(item, action),
|
onAction: (action) => onItemAction(item, action),
|
||||||
suppressScanHint: setParentIds.contains(item.id),
|
suppressScanHint: setParentIds.contains(item.id),
|
||||||
|
setParentComplete: setParentIds.contains(item.id) &&
|
||||||
|
setParentComplete(item),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
@ -807,6 +822,44 @@ class _ScanNotRequiredHint extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Grünes „Komplett geladen" für einen Set-Kopf (Parent-Artikel), dessen
|
||||||
|
/// (scanbare) Komponenten alle geladen sind. Ersetzt an dieser Stelle den
|
||||||
|
/// „Kein Scanvorgang notwendig"-Hinweis.
|
||||||
|
class _SetCompleteHint extends StatelessWidget {
|
||||||
|
const _SetCompleteHint();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final color = Colors.green.shade700;
|
||||||
|
return Container(
|
||||||
|
width: double.infinity,
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.green.withValues(alpha: 0.10),
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Icon(Icons.check_circle, size: 16, color: color),
|
||||||
|
const SizedBox(width: 6),
|
||||||
|
Flexible(
|
||||||
|
child: Text(
|
||||||
|
'Komplett geladen',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 13,
|
||||||
|
color: color,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Sektions-Kopf vor den Items eines Lagers. Visuell klar getrennt
|
/// Sektions-Kopf vor den Items eines Lagers. Visuell klar getrennt
|
||||||
/// (Standardlager vs. Filiale): Standardlager ist der primäre
|
/// (Standardlager vs. Filiale): Standardlager ist der primäre
|
||||||
/// Arbeitsplatz und damit neutral koloriert; Filial-Sections
|
/// Arbeitsplatz und damit neutral koloriert; Filial-Sections
|
||||||
@ -1166,6 +1219,7 @@ class _ItemRow extends StatelessWidget {
|
|||||||
required this.details,
|
required this.details,
|
||||||
required this.onAction,
|
required this.onAction,
|
||||||
this.suppressScanHint = false,
|
this.suppressScanHint = false,
|
||||||
|
this.setParentComplete = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
final DeliveryItem item;
|
final DeliveryItem item;
|
||||||
@ -1177,6 +1231,10 @@ class _ItemRow extends StatelessWidget {
|
|||||||
/// (scanbaren) Komponenten darunter sehr wohl gescannt werden.
|
/// (scanbaren) Komponenten darunter sehr wohl gescannt werden.
|
||||||
final bool suppressScanHint;
|
final bool suppressScanHint;
|
||||||
|
|
||||||
|
/// `true`, wenn dies ein Set-Kopf ist, dessen Komponenten alle fertig
|
||||||
|
/// geladen sind. Dann wird der (selbst nicht scanbare) Kopf grün dargestellt.
|
||||||
|
final bool setParentComplete;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
@ -1188,6 +1246,9 @@ class _ItemRow extends StatelessWidget {
|
|||||||
// Mengen-Zähler. Aus dem Artikel abgeleitet, damit ein in eine Lagergruppe
|
// Mengen-Zähler. Aus dem Artikel abgeleitet, damit ein in eine Lagergruppe
|
||||||
// eingehängter nicht-scanbarer Set-Kopf automatisch korrekt rendert.
|
// eingehängter nicht-scanbarer Set-Kopf automatisch korrekt rendert.
|
||||||
final scanNotRequired = !(article?.scannable ?? false);
|
final scanNotRequired = !(article?.scannable ?? false);
|
||||||
|
// Effektiv „fertig": eigener Scan-Status ODER (Set-Kopf, dessen Komponenten
|
||||||
|
// alle geladen sind) → der Kopf wird dann ebenfalls grün.
|
||||||
|
final effectiveDone = item.isDone || setParentComplete;
|
||||||
final isExternalWarehouse = warehouse != null && !warehouse.isStandard;
|
final isExternalWarehouse = warehouse != null && !warehouse.isStandard;
|
||||||
// Manueller Fallback-Button: nur für scanbare, noch offene Positionen
|
// Manueller Fallback-Button: nur für scanbare, noch offene Positionen
|
||||||
// (nicht done/entfernt/pausiert) — analog dazu, was ein Barcode-Scan
|
// (nicht done/entfernt/pausiert) — analog dazu, was ein Barcode-Scan
|
||||||
@ -1224,7 +1285,7 @@ class _ItemRow extends StatelessWidget {
|
|||||||
leadingIcon = Icons.pause_circle_outline;
|
leadingIcon = Icons.pause_circle_outline;
|
||||||
leadingIconColor = Colors.orange.shade800;
|
leadingIconColor = Colors.orange.shade800;
|
||||||
statusBadgeLabel = 'Pausiert';
|
statusBadgeLabel = 'Pausiert';
|
||||||
} else if (item.isDone) {
|
} else if (effectiveDone) {
|
||||||
cardColor = Colors.green.withValues(alpha: 0.07);
|
cardColor = Colors.green.withValues(alpha: 0.07);
|
||||||
borderColor = Colors.green.withValues(alpha: 0.35);
|
borderColor = Colors.green.withValues(alpha: 0.35);
|
||||||
titleColor = Colors.green.shade700;
|
titleColor = Colors.green.shade700;
|
||||||
@ -1413,11 +1474,14 @@ class _ItemRow extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
// Dienstleistung (nicht-scanbar): Hinweis statt Scan/Manuell-
|
// Set-Kopf, dessen Komponenten alle geladen sind → grünes
|
||||||
// Aktion. Steht an derselben Stelle wie der Manuell-Button.
|
// „Komplett geladen". Sonst (nicht-scanbare Position, KEIN
|
||||||
// Bei Set-Köpfen (Parent-Artikel) bewusst unterdrückt — dort
|
// Set-Kopf) der normale „Kein Scanvorgang notwendig"-Hinweis;
|
||||||
// wäre „kein Scanvorgang notwendig" irreführend.
|
// bei Set-Köpfen ist der unterdrückt (irreführend).
|
||||||
if (scanNotRequired && !suppressScanHint) ...[
|
if (scanNotRequired && setParentComplete) ...[
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
const _SetCompleteHint(),
|
||||||
|
] else if (scanNotRequired && !suppressScanHint) ...[
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
const _ScanNotRequiredHint(),
|
const _ScanNotRequiredHint(),
|
||||||
],
|
],
|
||||||
|
|||||||
Reference in New Issue
Block a user