import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:mobile_scanner/mobile_scanner.dart'; import '../../core/auth/auth_provider.dart'; import '../../l10n/app_localizations.dart'; import '../../shared/models/product.dart'; import 'food_product_service.dart'; import 'product_portion_sheet.dart'; /// Screen that activates the device camera to scan a barcode. /// On successful scan it looks up the catalog product and shows /// [ProductPortionSheet] to confirm the portion before adding to diary. class BarcodeScanScreen extends ConsumerStatefulWidget { const BarcodeScanScreen({ super.key, required this.mealType, required this.date, required this.onAdded, }); final String mealType; final String date; final VoidCallback onAdded; @override ConsumerState createState() => _BarcodeScanScreenState(); } class _BarcodeScanScreenState extends ConsumerState { bool _scanning = true; void _onBarcodeDetected(BarcodeCapture capture) async { if (!_scanning) return; final rawValue = capture.barcodes.firstOrNull?.rawValue; if (rawValue == null) return; setState(() => _scanning = false); final l10n = AppLocalizations.of(context)!; final service = FoodProductService(ref.read(apiClientProvider)); final catalogProduct = await service.getByBarcode(rawValue); if (!mounted) return; if (catalogProduct == null) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(l10n.productNotFound)), ); setState(() => _scanning = true); return; } _showPortionSheet(catalogProduct); } void _showPortionSheet(CatalogProduct catalogProduct) { showModalBottomSheet( context: context, isScrollControlled: true, builder: (_) => ProductPortionSheet( catalogProduct: catalogProduct, onConfirm: (portionGrams) => _addToDiary(catalogProduct, portionGrams), ), ).then((_) { if (mounted) setState(() => _scanning = true); }); } Future _addToDiary( CatalogProduct catalogProduct, double portionGrams) async { final l10n = AppLocalizations.of(context)!; try { await ref.read(apiClientProvider).post('/diary', data: { 'product_id': catalogProduct.id, 'portion_g': portionGrams, 'meal_type': widget.mealType, 'date': widget.date, 'source': 'barcode', }); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(catalogProduct.displayName)), ); widget.onAdded(); Navigator.pop(context); } } catch (_) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(l10n.addFailed)), ); } } } @override Widget build(BuildContext context) { final l10n = AppLocalizations.of(context)!; return Scaffold( appBar: AppBar(title: Text(l10n.scanBarcode)), body: MobileScanner( onDetect: _onBarcodeDetected, ), ); } }