feat(receipt-import): enhance bread category detection and improve session management

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
Nils-Johan Gynther
2026-05-03 16:34:15 +02:00
parent a1c4a2f24d
commit fa7f225ee5
7 changed files with 299 additions and 12 deletions
@@ -66,6 +66,30 @@ class _ReceiptImportTabState extends ConsumerState<ReceiptImportTab> {
void initState() {
super.initState();
_loadProducts();
_restoreSession();
}
Future<void> _restoreSession() async {
final notifier = ref.read(receiptImportSessionProvider.notifier);
await notifier.restore();
final session = ref.read(receiptImportSessionProvider);
if (!mounted || session?.fileBytes == null) return;
final fileName =
session?.fileName ?? 'kvitto.${session?.fileExtension ?? 'pdf'}';
final bytes = session!.fileBytes!;
setState(() {
_pickedFile = PlatformFile(
name: fileName,
size: bytes.length,
bytes: bytes,
extension: session.fileExtension,
);
});
if (session.items != null) {
await _loadInventory();
}
}
int? _categoryIdForProduct(int? productId) {
@@ -244,11 +268,18 @@ class _ReceiptImportTabState extends ConsumerState<ReceiptImportTab> {
ref.read(receiptImportSessionProvider.notifier).setFile(
file.bytes!,
file.extension?.toLowerCase() ?? '',
fileName: file.name,
);
}
Future<void> _submit() async {
if (_pickedFile == null) return;
final session = ref.read(receiptImportSessionProvider);
final submitBytes = _pickedFile?.bytes ?? session?.fileBytes;
if (submitBytes == null) return;
final submitFileName =
_pickedFile?.name ?? session?.fileName ?? 'kvitto.${session?.fileExtension ?? 'pdf'}';
setState(() { _isLoading = true; });
// Obs: setFile() i _pickFile har redan placerat bytes i session; clear() behövs ej här
@@ -256,8 +287,8 @@ class _ReceiptImportTabState extends ConsumerState<ReceiptImportTab> {
final token = await ref.read(authStateProvider.future);
final repo = ref.read(importRepositoryProvider);
final items = await repo.importReceiptFile(
bytes: _pickedFile!.bytes!,
filename: _pickedFile!.name,
bytes: submitBytes,
filename: submitFileName,
token: token,
);
if (!mounted) return;
@@ -508,7 +539,12 @@ class _ReceiptImportTabState extends ConsumerState<ReceiptImportTab> {
}
}
bool get _canSubmit => !_isLoading && _pickedFile?.bytes != null;
bool get _canSubmit {
if (_isLoading) return false;
if (_pickedFile?.bytes != null) return true;
final session = ref.read(receiptImportSessionProvider);
return session?.fileBytes != null;
}
int get _selectedCount => _selected.values.where((v) => v).length;
// ── Kvittobild / PDF-förhandsvisning ───────────────────────────────────────
@@ -570,6 +606,9 @@ class _ReceiptImportTabState extends ConsumerState<ReceiptImportTab> {
final session = ref.watch(receiptImportSessionProvider);
final theme = Theme.of(context);
final items = session?.items;
final selectedFileName = _pickedFile?.name ?? session?.fileName;
final selectedFileSizeBytes =
_pickedFile?.size ?? session?.fileBytes?.length;
return SingleChildScrollView(
padding: const EdgeInsets.all(16),
@@ -584,12 +623,12 @@ class _ReceiptImportTabState extends ConsumerState<ReceiptImportTab> {
OutlinedButton.icon(
onPressed: _isLoading ? null : _pickFile,
icon: const Icon(Icons.attach_file),
label: Text(_pickedFile == null ? 'Välj kvittofil' : _pickedFile!.name),
label: Text(selectedFileName == null ? 'Välj kvittofil' : selectedFileName),
),
if (_pickedFile != null) ...[
if (selectedFileSizeBytes != null) ...[
const SizedBox(height: 8),
Text(
'${(_pickedFile!.size / 1024).round()} KB',
'${(selectedFileSizeBytes / 1024).round()} KB',
style: theme.textTheme.bodySmall?.copyWith(color: theme.colorScheme.outline),
),
],