feat: aggrega duplicati nella lista della spesa con quantità

Quando si genera la lista dal piano pasti, gli alimenti ripetuti in
più giorni o slot vengono aggregati in un unico elemento con contatore.
Es. zucchine lunedì + mercoledì → "zucchine (x2)".

- ShoppingItem: aggiunto campo quantity (default 1, persistito in JSON)
- ShoppingListProvider.addAll: conta le occorrenze per nome
  (case-insensitive) e crea un ShoppingItem con quantity = conteggio
- ShoppingItemTile: mostra "(xN)" colorato in primary quando quantity > 1,
  diventa muted insieme al nome quando l'elemento è completato

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-16 18:54:22 +02:00
parent cba83c9559
commit 404a5f44ac
3 changed files with 51 additions and 17 deletions
@@ -49,16 +49,26 @@ class ShoppingListProvider extends ChangeNotifier {
void addAll(List<String> names) {
final existing = _items.map((i) => i.name.toLowerCase()).toSet();
final seen = <String>{};
final toAdd = <ShoppingItem>[];
// Conta le occorrenze mantenendo il nome nella sua forma originale (prima occorrenza)
final counts = <String, int>{};
final canonical = <String, String>{};
for (final name in names) {
final key = name.toLowerCase().trim();
if (key.isNotEmpty && !existing.contains(key) && seen.add(key)) {
toAdd.add(ShoppingItem(
id: '${DateTime.now().millisecondsSinceEpoch}_${seen.length}',
name: name.trim(),
));
}
if (key.isEmpty) continue;
counts[key] = (counts[key] ?? 0) + 1;
canonical.putIfAbsent(key, () => name.trim());
}
final toAdd = <ShoppingItem>[];
var i = 0;
for (final entry in counts.entries) {
if (existing.contains(entry.key)) continue;
toAdd.add(ShoppingItem(
id: '${DateTime.now().millisecondsSinceEpoch}_${i++}',
name: canonical[entry.key]!,
quantity: entry.value,
));
}
if (toAdd.isEmpty) return;
_items = [..._items, ...toAdd];