feat: barcode scanning for shelf add + scan screen barcode option
- Add ShelfBarcodeScanScreen: scans barcode via mobile_scanner, looks up
product via GET /products/barcode/{barcode} (Open Food Facts fallback),
returns CatalogProduct to caller; loading overlay while looking up;
"Add manually" fallback in AppBar for unknown products
- Extract AddToShelfSheet to add_to_shelf_sheet.dart (was private in
product_search_screen.dart) so both search and scan screens can reuse it
- Add barcode icon button to ProductSearchScreen AppBar → opens scanner
- Add "Scan barcode" card (📷) to ScanScreen alongside receipt and photo modes
- Rename ScanScreen title: addFromReceiptOrPhoto → scanScreenTitle
("Сканировать" / "Scan & Recognize") to reflect all three modes
- Add 2 L10n keys (scanScreenTitle, barcodeScanSubtitle) across all 12 locales
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,9 @@ import 'package:go_router/go_router.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
|
||||
import '../../l10n/app_localizations.dart';
|
||||
import '../../shared/models/product.dart';
|
||||
import '../products/add_to_shelf_sheet.dart';
|
||||
import '../products/shelf_barcode_scan_screen.dart';
|
||||
import 'recognition_service.dart';
|
||||
|
||||
/// Entry screen — lets the user choose how to add products.
|
||||
@@ -19,7 +22,7 @@ class _ScanScreenState extends ConsumerState<ScanScreen> {
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text(l10n.addFromReceiptOrPhoto)),
|
||||
appBar: AppBar(title: Text(l10n.scanScreenTitle)),
|
||||
body: ListView(
|
||||
padding: const EdgeInsets.all(20),
|
||||
children: [
|
||||
@@ -43,11 +46,43 @@ class _ScanScreenState extends ConsumerState<ScanScreen> {
|
||||
subtitle: l10n.photoProductsSubtitle,
|
||||
onTap: () => _pickAndRecognize(context, _Mode.products),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_ModeCard(
|
||||
emoji: '📷',
|
||||
title: l10n.scanBarcode,
|
||||
subtitle: l10n.barcodeScanSubtitle,
|
||||
onTap: _openBarcode,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _openBarcode() {
|
||||
final messenger = ScaffoldMessenger.of(context);
|
||||
final addedText = AppLocalizations.of(context)!.productAddedToShelf;
|
||||
|
||||
Navigator.push<CatalogProduct>(
|
||||
context,
|
||||
MaterialPageRoute(builder: (_) => const ShelfBarcodeScanScreen()),
|
||||
).then((catalogProduct) {
|
||||
if (catalogProduct != null && mounted) {
|
||||
showModalBottomSheet<void>(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
builder: (_) => AddToShelfSheet(
|
||||
catalogProduct: catalogProduct,
|
||||
onAdded: () => messenger.showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('${catalogProduct.displayName} — $addedText'),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _pickAndRecognize(
|
||||
BuildContext context,
|
||||
_Mode mode,
|
||||
|
||||
Reference in New Issue
Block a user