feat: enhance error dialogs with delete functionality and improve documentation
This commit is contained in:
@@ -3,7 +3,7 @@ import 'package:flutter/services.dart';
|
||||
|
||||
import '../../../core/l10n/l10n.dart';
|
||||
|
||||
/// Visar en dialogruta med ett felmeddelande och en kopieringsknapp.
|
||||
/// Visar en dialogruta med ett felmeddelande och knappar för kopiera och ta bort.
|
||||
void showErrorDialog(BuildContext context, String errorMessage) {
|
||||
showDialog(
|
||||
context: context,
|
||||
@@ -28,6 +28,7 @@ void showErrorDialog(BuildContext context, String errorMessage) {
|
||||
child: Text(context.l10n.errorDialogCopy),
|
||||
onPressed: () {
|
||||
Clipboard.setData(ClipboardData(text: errorMessage));
|
||||
Navigator.of(context).pop();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(context.l10n.errorDialogCopied)),
|
||||
);
|
||||
|
||||
@@ -460,6 +460,44 @@ class _ReceiptImportTabState extends ConsumerState<ReceiptImportTab> {
|
||||
);
|
||||
}
|
||||
|
||||
void _deleteItem(int index) {
|
||||
final items = _items;
|
||||
if (items == null || index < 0 || index >= items.length) return;
|
||||
|
||||
// Ta bort raden från items
|
||||
final remainingItems = <ParsedReceiptItem>[...items];
|
||||
remainingItems.removeAt(index);
|
||||
|
||||
// Re-index edits och selected i en enda pass
|
||||
final remainingEdits = <int, ItemEdit>{};
|
||||
final remainingSelected = <int, bool>{};
|
||||
var newIndex = 0;
|
||||
|
||||
for (var oldIndex = 0; oldIndex < items.length; oldIndex++) {
|
||||
if (oldIndex != index) {
|
||||
if (_edits.containsKey(oldIndex)) {
|
||||
remainingEdits[newIndex] = _edits[oldIndex]!;
|
||||
}
|
||||
if (_selected[oldIndex] == true) {
|
||||
remainingSelected[newIndex] = true;
|
||||
}
|
||||
newIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
final notifier = ref.read(receiptImportSessionProvider.notifier);
|
||||
if (remainingItems.isEmpty) {
|
||||
notifier.clear();
|
||||
} else {
|
||||
notifier.setImportedResult(
|
||||
items: remainingItems,
|
||||
edits: remainingEdits,
|
||||
selected: remainingSelected,
|
||||
);
|
||||
}
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
Future<void> _addSelected() async {
|
||||
final items = _items;
|
||||
if (items == null) return;
|
||||
@@ -572,9 +610,36 @@ class _ReceiptImportTabState extends ConsumerState<ReceiptImportTab> {
|
||||
SnackBar(content: Text(parts.join(', ') + '.')),
|
||||
);
|
||||
|
||||
// Avmarkera sparade rader och uppdatera inventariet
|
||||
// Ta bort de tillagda raderna från listan
|
||||
final addedIndexSet = toAdd.toSet();
|
||||
final remainingItems = <ParsedReceiptItem>[];
|
||||
final remainingEdits = <int, ItemEdit>{};
|
||||
final remainingSelected = <int, bool>{};
|
||||
|
||||
var newIndex = 0;
|
||||
for (var oldIndex = 0; oldIndex < items.length; oldIndex++) {
|
||||
if (!addedIndexSet.contains(oldIndex)) {
|
||||
remainingItems.add(items[oldIndex]);
|
||||
if (_edits.containsKey(oldIndex)) {
|
||||
remainingEdits[newIndex] = _edits[oldIndex]!;
|
||||
}
|
||||
if (_selected[oldIndex] == true) {
|
||||
remainingSelected[newIndex] = true;
|
||||
}
|
||||
newIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
final notifier = ref.read(receiptImportSessionProvider.notifier);
|
||||
notifier.setSelectedForIndexes(toAdd, false);
|
||||
if (remainingItems.isEmpty) {
|
||||
notifier.clear();
|
||||
} else {
|
||||
notifier.setImportedResult(
|
||||
items: remainingItems,
|
||||
edits: remainingEdits,
|
||||
selected: remainingSelected,
|
||||
);
|
||||
}
|
||||
setState(() {});
|
||||
await _loadInventory();
|
||||
} catch (e) {
|
||||
@@ -779,6 +844,7 @@ class _ReceiptImportTabState extends ConsumerState<ReceiptImportTab> {
|
||||
i,
|
||||
initialEntryMode: ImportProductEntryMode.create,
|
||||
),
|
||||
onDeleteRequested: () => _deleteItem(i),
|
||||
matchedViaBadgeBuilder: _buildMatchedViaBadge,
|
||||
);
|
||||
},
|
||||
@@ -811,6 +877,7 @@ class _ReceiptImportResultRow extends ConsumerWidget {
|
||||
final VoidCallback onEditRequested;
|
||||
final VoidCallback onSelectExistingRequested;
|
||||
final VoidCallback onCreateRequested;
|
||||
final VoidCallback onDeleteRequested;
|
||||
final Widget Function(ParsedReceiptItem item, ThemeData theme)
|
||||
matchedViaBadgeBuilder;
|
||||
|
||||
@@ -824,6 +891,7 @@ class _ReceiptImportResultRow extends ConsumerWidget {
|
||||
required this.onEditRequested,
|
||||
required this.onSelectExistingRequested,
|
||||
required this.onCreateRequested,
|
||||
required this.onDeleteRequested,
|
||||
required this.matchedViaBadgeBuilder,
|
||||
});
|
||||
|
||||
@@ -1019,14 +1087,29 @@ class _ReceiptImportResultRow extends ConsumerWidget {
|
||||
],
|
||||
],
|
||||
),
|
||||
trailing: Icon(
|
||||
hasProduct
|
||||
? Icons.check_circle
|
||||
: (isSuggested ? Icons.help_outline : Icons.error_outline),
|
||||
color: hasProduct
|
||||
? Colors.green
|
||||
: (isSuggested ? Colors.orange : theme.colorScheme.tertiary),
|
||||
size: 20,
|
||||
trailing: SizedBox(
|
||||
width: 80,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
hasProduct
|
||||
? Icons.check_circle
|
||||
: (isSuggested ? Icons.help_outline : Icons.error_outline),
|
||||
color: hasProduct
|
||||
? Colors.green
|
||||
: (isSuggested ? Colors.orange : theme.colorScheme.tertiary),
|
||||
size: 20,
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.delete_outline, size: 18, color: theme.colorScheme.error),
|
||||
onPressed: onDeleteRequested,
|
||||
tooltip: 'Ta bort rad',
|
||||
constraints: const BoxConstraints(minWidth: 40, minHeight: 40),
|
||||
padding: const EdgeInsets.all(4),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
onTap: onEditRequested,
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user