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:
dbastrikin
2026-03-26 15:21:56 +02:00
parent 7b2f86c6a4
commit b2bdcbae6f
29 changed files with 537 additions and 277 deletions

View File

@@ -100,6 +100,8 @@
"navProducts": "المنتجات",
"navRecipes": "الوصفات",
"addFromReceiptOrPhoto": "إضافة من الإيصال أو الصورة",
"scanScreenTitle": "المسح والتعرف",
"barcodeScanSubtitle": "ابحث عن منتج بالباركود",
"chooseMethod": "اختر الطريقة",
"photoReceipt": "تصوير الإيصال",
"photoReceiptSubtitle": "التعرف على جميع المنتجات من الإيصال",

View File

@@ -100,6 +100,8 @@
"navProducts": "Produkte",
"navRecipes": "Rezepte",
"addFromReceiptOrPhoto": "Aus Kassenbon oder Foto hinzufügen",
"scanScreenTitle": "Scannen & Erkennen",
"barcodeScanSubtitle": "Produkt per Barcode finden",
"chooseMethod": "Methode wählen",
"photoReceipt": "Kassenbon fotografieren",
"photoReceiptSubtitle": "Alle Produkte vom Kassenbon erkennen",

View File

@@ -100,6 +100,8 @@
"navProducts": "Products",
"navRecipes": "Recipes",
"addFromReceiptOrPhoto": "Add from receipt or photo",
"scanScreenTitle": "Scan & Recognize",
"barcodeScanSubtitle": "Find a product by its barcode",
"chooseMethod": "Choose method",
"photoReceipt": "Photo of receipt",
"photoReceiptSubtitle": "Recognize all items from a receipt",

View File

@@ -100,6 +100,8 @@
"navProducts": "Productos",
"navRecipes": "Recetas",
"addFromReceiptOrPhoto": "Añadir desde recibo o foto",
"scanScreenTitle": "Escanear y Reconocer",
"barcodeScanSubtitle": "Encontrar un producto por su código de barras",
"chooseMethod": "Elegir método",
"photoReceipt": "Fotografiar recibo",
"photoReceiptSubtitle": "Reconocemos todos los productos del recibo",

View File

@@ -100,6 +100,8 @@
"navProducts": "Produits",
"navRecipes": "Recettes",
"addFromReceiptOrPhoto": "Ajouter depuis ticket ou photo",
"scanScreenTitle": "Scanner & Reconnaître",
"barcodeScanSubtitle": "Trouver un produit par son code-barres",
"chooseMethod": "Choisir la méthode",
"photoReceipt": "Photographier le ticket",
"photoReceiptSubtitle": "Reconnaissance de tous les produits du ticket",

View File

@@ -100,6 +100,8 @@
"navProducts": "उत्पाद",
"navRecipes": "रेसिपी",
"addFromReceiptOrPhoto": "रसीद या फ़ोटो से जोड़ें",
"scanScreenTitle": "स्कैन और पहचानें",
"barcodeScanSubtitle": "बारकोड से उत्पाद खोजें",
"chooseMethod": "तरीका चुनें",
"photoReceipt": "रसीद की फ़ोटो",
"photoReceiptSubtitle": "रसीद से सभी उत्पाद पहचानें",

View File

@@ -100,6 +100,8 @@
"navProducts": "Prodotti",
"navRecipes": "Ricette",
"addFromReceiptOrPhoto": "Aggiungi da scontrino o foto",
"scanScreenTitle": "Scansiona & Riconosci",
"barcodeScanSubtitle": "Trova un prodotto tramite il codice a barre",
"chooseMethod": "Scegli il metodo",
"photoReceipt": "Fotografa scontrino",
"photoReceiptSubtitle": "Riconosciamo tutti i prodotti dallo scontrino",

View File

@@ -100,6 +100,8 @@
"navProducts": "食品",
"navRecipes": "レシピ",
"addFromReceiptOrPhoto": "レシートや写真から追加",
"scanScreenTitle": "スキャン&認識",
"barcodeScanSubtitle": "バーコードで商品を探す",
"chooseMethod": "方法を選択",
"photoReceipt": "レシートを撮影",
"photoReceiptSubtitle": "レシートから全商品を認識",

View File

@@ -100,6 +100,8 @@
"navProducts": "식품",
"navRecipes": "레시피",
"addFromReceiptOrPhoto": "영수증 또는 사진으로 추가",
"scanScreenTitle": "스캔 및 인식",
"barcodeScanSubtitle": "바코드로 제품 찾기",
"chooseMethod": "방법 선택",
"photoReceipt": "영수증 촬영",
"photoReceiptSubtitle": "영수증의 모든 상품 인식",

View File

@@ -676,6 +676,18 @@ abstract class AppLocalizations {
/// **'Add from receipt or photo'**
String get addFromReceiptOrPhoto;
/// No description provided for @scanScreenTitle.
///
/// In en, this message translates to:
/// **'Scan & Recognize'**
String get scanScreenTitle;
/// No description provided for @barcodeScanSubtitle.
///
/// In en, this message translates to:
/// **'Find a product by its barcode'**
String get barcodeScanSubtitle;
/// No description provided for @chooseMethod.
///
/// In en, this message translates to:

View File

@@ -290,6 +290,12 @@ class AppLocalizationsAr extends AppLocalizations {
@override
String get addFromReceiptOrPhoto => 'إضافة من الإيصال أو الصورة';
@override
String get scanScreenTitle => 'المسح والتعرف';
@override
String get barcodeScanSubtitle => 'ابحث عن منتج بالباركود';
@override
String get chooseMethod => 'اختر الطريقة';

View File

@@ -291,6 +291,12 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get addFromReceiptOrPhoto => 'Aus Kassenbon oder Foto hinzufügen';
@override
String get scanScreenTitle => 'Scannen & Erkennen';
@override
String get barcodeScanSubtitle => 'Produkt per Barcode finden';
@override
String get chooseMethod => 'Methode wählen';

View File

@@ -290,6 +290,12 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get addFromReceiptOrPhoto => 'Add from receipt or photo';
@override
String get scanScreenTitle => 'Scan & Recognize';
@override
String get barcodeScanSubtitle => 'Find a product by its barcode';
@override
String get chooseMethod => 'Choose method';

View File

@@ -291,6 +291,13 @@ class AppLocalizationsEs extends AppLocalizations {
@override
String get addFromReceiptOrPhoto => 'Añadir desde recibo o foto';
@override
String get scanScreenTitle => 'Escanear y Reconocer';
@override
String get barcodeScanSubtitle =>
'Encontrar un producto por su código de barras';
@override
String get chooseMethod => 'Elegir método';

View File

@@ -291,6 +291,12 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String get addFromReceiptOrPhoto => 'Ajouter depuis ticket ou photo';
@override
String get scanScreenTitle => 'Scanner & Reconnaître';
@override
String get barcodeScanSubtitle => 'Trouver un produit par son code-barres';
@override
String get chooseMethod => 'Choisir la méthode';

View File

@@ -291,6 +291,12 @@ class AppLocalizationsHi extends AppLocalizations {
@override
String get addFromReceiptOrPhoto => 'रसीद या फ़ोटो से जोड़ें';
@override
String get scanScreenTitle => 'स्कैन और पहचानें';
@override
String get barcodeScanSubtitle => 'बारकोड से उत्पाद खोजें';
@override
String get chooseMethod => 'तरीका चुनें';

View File

@@ -291,6 +291,13 @@ class AppLocalizationsIt extends AppLocalizations {
@override
String get addFromReceiptOrPhoto => 'Aggiungi da scontrino o foto';
@override
String get scanScreenTitle => 'Scansiona & Riconosci';
@override
String get barcodeScanSubtitle =>
'Trova un prodotto tramite il codice a barre';
@override
String get chooseMethod => 'Scegli il metodo';

View File

@@ -289,6 +289,12 @@ class AppLocalizationsJa extends AppLocalizations {
@override
String get addFromReceiptOrPhoto => 'レシートや写真から追加';
@override
String get scanScreenTitle => 'スキャン&認識';
@override
String get barcodeScanSubtitle => 'バーコードで商品を探す';
@override
String get chooseMethod => '方法を選択';

View File

@@ -289,6 +289,12 @@ class AppLocalizationsKo extends AppLocalizations {
@override
String get addFromReceiptOrPhoto => '영수증 또는 사진으로 추가';
@override
String get scanScreenTitle => '스캔 및 인식';
@override
String get barcodeScanSubtitle => '바코드로 제품 찾기';
@override
String get chooseMethod => '방법 선택';

View File

@@ -291,6 +291,12 @@ class AppLocalizationsPt extends AppLocalizations {
@override
String get addFromReceiptOrPhoto => 'Adicionar de recibo ou foto';
@override
String get scanScreenTitle => 'Escanear & Reconhecer';
@override
String get barcodeScanSubtitle => 'Encontrar produto pelo código de barras';
@override
String get chooseMethod => 'Escolher método';

View File

@@ -290,6 +290,12 @@ class AppLocalizationsRu extends AppLocalizations {
@override
String get addFromReceiptOrPhoto => 'Добавить из чека или фото';
@override
String get scanScreenTitle => 'Сканировать';
@override
String get barcodeScanSubtitle => 'Найти продукт по штрихкоду';
@override
String get chooseMethod => 'Выберите способ';

View File

@@ -289,6 +289,12 @@ class AppLocalizationsZh extends AppLocalizations {
@override
String get addFromReceiptOrPhoto => '从收据或照片添加';
@override
String get scanScreenTitle => '扫描与识别';
@override
String get barcodeScanSubtitle => '通过条形码查找产品';
@override
String get chooseMethod => '选择方式';

View File

@@ -100,6 +100,8 @@
"navProducts": "Produtos",
"navRecipes": "Receitas",
"addFromReceiptOrPhoto": "Adicionar de recibo ou foto",
"scanScreenTitle": "Escanear & Reconhecer",
"barcodeScanSubtitle": "Encontrar produto pelo código de barras",
"chooseMethod": "Escolher método",
"photoReceipt": "Fotografar recibo",
"photoReceiptSubtitle": "Reconhecemos todos os produtos do recibo",

View File

@@ -100,6 +100,8 @@
"navProducts": "Продукты",
"navRecipes": "Рецепты",
"addFromReceiptOrPhoto": "Добавить из чека или фото",
"scanScreenTitle": "Сканировать",
"barcodeScanSubtitle": "Найти продукт по штрихкоду",
"chooseMethod": "Выберите способ",
"photoReceipt": "Сфотографировать чек",
"photoReceiptSubtitle": "Распознаем все продукты из чека",

View File

@@ -100,6 +100,8 @@
"navProducts": "食品",
"navRecipes": "食谱",
"addFromReceiptOrPhoto": "从收据或照片添加",
"scanScreenTitle": "扫描与识别",
"barcodeScanSubtitle": "通过条形码查找产品",
"chooseMethod": "选择方式",
"photoReceipt": "拍摄收据",
"photoReceiptSubtitle": "识别收据中的所有商品",