diff --git a/packages/smooth_app/lib/background/background_task_barcode.dart b/packages/smooth_app/lib/background/background_task_barcode.dart index 4a70933d400..dcc36e0d1d4 100644 --- a/packages/smooth_app/lib/background/background_task_barcode.dart +++ b/packages/smooth_app/lib/background/background_task_barcode.dart @@ -1,7 +1,9 @@ import 'package:flutter/foundation.dart'; +import 'package:openfoodfacts/openfoodfacts.dart'; import 'package:smooth_app/background/background_task.dart'; import 'package:smooth_app/database/local_database.dart'; import 'package:smooth_app/pages/product/common/product_refresher.dart'; +import 'package:smooth_app/query/product_query.dart'; /// Abstract background task that involves a single barcode. abstract class BackgroundTaskBarcode extends BackgroundTask { @@ -11,20 +13,28 @@ abstract class BackgroundTaskBarcode extends BackgroundTask { super.language, required super.stamp, required this.barcode, + required this.productType, }); BackgroundTaskBarcode.fromJson(super.json) : barcode = json[_jsonTagBarcode] as String, + productType = + ProductType.fromOffTag(json[_jsonTagProductType] as String?) ?? + // for legacy reason (not refreshed products = no product type) + ProductType.food, super.fromJson(); final String barcode; + final ProductType productType; static const String _jsonTagBarcode = 'barcode'; + static const String _jsonTagProductType = 'productType'; @override Map toJson() { final Map result = super.toJson(); result[_jsonTagBarcode] = barcode; + result[_jsonTagProductType] = productType.offTag; return result; } @@ -45,4 +55,9 @@ abstract class BackgroundTaskBarcode extends BackgroundTask { barcode: barcode, localDatabase: localDatabase, ); + + @override + UriProductHelper get uriProductHelper => ProductQuery.getUriProductHelper( + productType: productType, + ); } diff --git a/packages/smooth_app/lib/background/background_task_crop.dart b/packages/smooth_app/lib/background/background_task_crop.dart index ed3327dc9ff..39adcd16d97 100644 --- a/packages/smooth_app/lib/background/background_task_crop.dart +++ b/packages/smooth_app/lib/background/background_task_crop.dart @@ -16,6 +16,7 @@ class BackgroundTaskCrop extends BackgroundTaskUpload { required super.processName, required super.uniqueId, required super.barcode, + required super.productType, required super.language, required super.stamp, required super.imageField, @@ -48,6 +49,7 @@ class BackgroundTaskCrop extends BackgroundTaskUpload { /// Adds the background task about uploading a product image. static Future addTask( final String barcode, { + required final ProductType? productType, required final OpenFoodFactsLanguage language, required final int imageId, required final ImageField imageField, @@ -67,6 +69,7 @@ class BackgroundTaskCrop extends BackgroundTaskUpload { final BackgroundTaskBarcode task = _getNewTask( language, barcode, + productType ?? ProductType.food, imageId, imageField, croppedFile, @@ -95,6 +98,7 @@ class BackgroundTaskCrop extends BackgroundTaskUpload { static BackgroundTaskCrop _getNewTask( final OpenFoodFactsLanguage language, final String barcode, + final ProductType productType, final int imageId, final ImageField imageField, final File croppedFile, @@ -108,6 +112,7 @@ class BackgroundTaskCrop extends BackgroundTaskUpload { BackgroundTaskCrop._( uniqueId: uniqueId, barcode: barcode, + productType: productType, processName: _operationType.processName, imageId: imageId, imageField: imageField.offTag, @@ -158,6 +163,7 @@ class BackgroundTaskCrop extends BackgroundTaskUpload { await BackgroundTaskRefreshLater.addTask( barcode, localDatabase: localDatabase, + productType: productType, ); } } diff --git a/packages/smooth_app/lib/background/background_task_details.dart b/packages/smooth_app/lib/background/background_task_details.dart index dcfc0bf8c4e..2ea3418a3e8 100644 --- a/packages/smooth_app/lib/background/background_task_details.dart +++ b/packages/smooth_app/lib/background/background_task_details.dart @@ -13,6 +13,7 @@ import 'package:smooth_app/database/local_database.dart'; /// /// With that stamp, we can de-duplicate similar tasks. enum BackgroundTaskDetailsStamp { + productType('product_type'), basicDetails('basic_details'), otherDetails('other_details'), ocrIngredients('ocr_ingredients'), @@ -38,6 +39,7 @@ class BackgroundTaskDetails extends BackgroundTaskBarcode required super.processName, required super.uniqueId, required super.barcode, + required super.productType, required super.stamp, required this.inputMap, }); @@ -70,6 +72,7 @@ class BackgroundTaskDetails extends BackgroundTaskBarcode required final BuildContext context, required final BackgroundTaskDetailsStamp stamp, final bool showSnackBar = true, + required final ProductType? productType, }) async { final LocalDatabase localDatabase = context.read(); final String uniqueId = await _operationType.getNewKey( @@ -80,6 +83,7 @@ class BackgroundTaskDetails extends BackgroundTaskBarcode minimalistProduct, uniqueId, stamp, + productType ?? ProductType.food, ); if (!context.mounted) { return; @@ -104,11 +108,13 @@ class BackgroundTaskDetails extends BackgroundTaskBarcode final Product minimalistProduct, final String uniqueId, final BackgroundTaskDetailsStamp stamp, + final ProductType productType, ) => BackgroundTaskDetails._( uniqueId: uniqueId, processName: _operationType.processName, barcode: minimalistProduct.barcode!, + productType: productType, inputMap: jsonEncode(minimalistProduct.toJson()), stamp: getStamp(minimalistProduct.barcode!, stamp.tag), ); diff --git a/packages/smooth_app/lib/background/background_task_hunger_games.dart b/packages/smooth_app/lib/background/background_task_hunger_games.dart index 283297599ac..e2508072629 100644 --- a/packages/smooth_app/lib/background/background_task_hunger_games.dart +++ b/packages/smooth_app/lib/background/background_task_hunger_games.dart @@ -13,6 +13,7 @@ class BackgroundTaskHungerGames extends BackgroundTaskBarcode { required super.processName, required super.uniqueId, required super.barcode, + required super.productType, required super.stamp, required this.insightId, required this.insightAnnotation, @@ -80,6 +81,8 @@ class BackgroundTaskHungerGames extends BackgroundTaskBarcode { processName: _operationType.processName, uniqueId: uniqueId, barcode: barcode, + // not really relevant for Robotoff + productType: ProductType.food, stamp: _getStamp(barcode, insightId), insightId: insightId, insightAnnotation: insightAnnotation, diff --git a/packages/smooth_app/lib/background/background_task_image.dart b/packages/smooth_app/lib/background/background_task_image.dart index 9c5ebbf221c..3fc83a5fb76 100644 --- a/packages/smooth_app/lib/background/background_task_image.dart +++ b/packages/smooth_app/lib/background/background_task_image.dart @@ -22,6 +22,7 @@ class BackgroundTaskImage extends BackgroundTaskUpload { required super.processName, required super.uniqueId, required super.barcode, + required super.productType, required super.language, required super.stamp, required super.imageField, @@ -58,6 +59,7 @@ class BackgroundTaskImage extends BackgroundTaskUpload { /// Adds the background task about uploading a product image. static Future addTask( final String barcode, { + required final ProductType? productType, required final OpenFoodFactsLanguage language, required final ImageField imageField, required final File fullFile, @@ -77,6 +79,7 @@ class BackgroundTaskImage extends BackgroundTaskUpload { final BackgroundTaskBarcode task = _getNewTask( language, barcode, + productType ?? ProductType.food, imageField, fullFile, croppedFile, @@ -105,6 +108,7 @@ class BackgroundTaskImage extends BackgroundTaskUpload { static BackgroundTaskImage _getNewTask( final OpenFoodFactsLanguage language, final String barcode, + final ProductType productType, final ImageField imageField, final File fullFile, final File croppedFile, @@ -118,6 +122,7 @@ class BackgroundTaskImage extends BackgroundTaskUpload { BackgroundTaskImage._( uniqueId: uniqueId, barcode: barcode, + productType: productType, processName: _operationType.processName, imageField: imageField.offTag, fullPath: fullFile.path, @@ -176,6 +181,7 @@ class BackgroundTaskImage extends BackgroundTaskUpload { await BackgroundTaskRefreshLater.addTask( barcode, localDatabase: localDatabase, + productType: productType, ); } } diff --git a/packages/smooth_app/lib/background/background_task_refresh_later.dart b/packages/smooth_app/lib/background/background_task_refresh_later.dart index cf21b6792a4..e9f259689bd 100644 --- a/packages/smooth_app/lib/background/background_task_refresh_later.dart +++ b/packages/smooth_app/lib/background/background_task_refresh_later.dart @@ -1,5 +1,6 @@ import 'package:flutter/painting.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:openfoodfacts/openfoodfacts.dart'; import 'package:smooth_app/background/background_task_barcode.dart'; import 'package:smooth_app/background/operation_type.dart'; import 'package:smooth_app/database/local_database.dart'; @@ -14,6 +15,7 @@ class BackgroundTaskRefreshLater extends BackgroundTaskBarcode { required super.processName, required super.uniqueId, required super.barcode, + required super.productType, required super.stamp, required this.timestamp, }); @@ -49,12 +51,17 @@ class BackgroundTaskRefreshLater extends BackgroundTaskBarcode { static Future addTask( final String barcode, { required final LocalDatabase localDatabase, + required final ProductType productType, }) async { final String uniqueId = await _operationType.getNewKey( localDatabase, barcode: barcode, ); - final BackgroundTaskBarcode task = _getNewTask(barcode, uniqueId); + final BackgroundTaskBarcode task = _getNewTask( + barcode, + uniqueId, + productType, + ); await task.addToManager(localDatabase); } @@ -67,11 +74,13 @@ class BackgroundTaskRefreshLater extends BackgroundTaskBarcode { static BackgroundTaskRefreshLater _getNewTask( final String barcode, final String uniqueId, + final ProductType productType, ) => BackgroundTaskRefreshLater._( uniqueId: uniqueId, processName: _operationType.processName, barcode: barcode, + productType: productType, timestamp: LocalDatabase.nowInMillis(), stamp: _getStamp(barcode), ); diff --git a/packages/smooth_app/lib/background/background_task_unselect.dart b/packages/smooth_app/lib/background/background_task_unselect.dart index 689d0d23583..3266bb6380a 100644 --- a/packages/smooth_app/lib/background/background_task_unselect.dart +++ b/packages/smooth_app/lib/background/background_task_unselect.dart @@ -19,6 +19,7 @@ class BackgroundTaskUnselect extends BackgroundTaskBarcode required super.uniqueId, required OpenFoodFactsLanguage super.language, required super.barcode, + required super.productType, required super.stamp, required this.imageField, }); @@ -43,6 +44,7 @@ class BackgroundTaskUnselect extends BackgroundTaskBarcode /// Adds the background task about unselecting a product image. static Future addTask( final String barcode, { + required final ProductType? productType, required final ImageField imageField, required final BuildContext context, required final OpenFoodFactsLanguage language, @@ -54,6 +56,7 @@ class BackgroundTaskUnselect extends BackgroundTaskBarcode ); final BackgroundTaskBarcode task = _getNewTask( barcode, + productType ?? ProductType.food, imageField, uniqueId, language, @@ -75,6 +78,7 @@ class BackgroundTaskUnselect extends BackgroundTaskBarcode /// Returns a new background task about unselecting a product image. static BackgroundTaskUnselect _getNewTask( final String barcode, + final ProductType productType, final ImageField imageField, final String uniqueId, final OpenFoodFactsLanguage language, @@ -82,6 +86,7 @@ class BackgroundTaskUnselect extends BackgroundTaskBarcode BackgroundTaskUnselect._( uniqueId: uniqueId, barcode: barcode, + productType: productType, language: language, processName: _operationType.processName, imageField: imageField.offTag, @@ -116,6 +121,7 @@ class BackgroundTaskUnselect extends BackgroundTaskBarcode await BackgroundTaskRefreshLater.addTask( barcode, localDatabase: localDatabase, + productType: productType, ); } } diff --git a/packages/smooth_app/lib/background/background_task_upload.dart b/packages/smooth_app/lib/background/background_task_upload.dart index 112446f49fb..603fb948fe1 100644 --- a/packages/smooth_app/lib/background/background_task_upload.dart +++ b/packages/smooth_app/lib/background/background_task_upload.dart @@ -16,6 +16,7 @@ abstract class BackgroundTaskUpload extends BackgroundTaskBarcode required super.processName, required super.uniqueId, required super.barcode, + required super.productType, required super.language, required super.stamp, required this.imageField, diff --git a/packages/smooth_app/lib/cards/data_cards/product_image_carousel_item.dart b/packages/smooth_app/lib/cards/data_cards/product_image_carousel_item.dart index d25e8afec69..6ce8405bd0d 100644 --- a/packages/smooth_app/lib/cards/data_cards/product_image_carousel_item.dart +++ b/packages/smooth_app/lib/cards/data_cards/product_image_carousel_item.dart @@ -45,6 +45,7 @@ class _ProductImageCarouselItemState extends State { onPressed: () async => confirmAndUploadNewPicture( context, barcode: widget.product.barcode!, + productType: widget.product.productType, imageField: widget.productImageData.imageField, language: ProductQuery.getLanguage(), isLoggedInMandatory: true, diff --git a/packages/smooth_app/lib/data_models/up_to_date_changes.dart b/packages/smooth_app/lib/data_models/up_to_date_changes.dart index 050964bdd47..82031153d3b 100644 --- a/packages/smooth_app/lib/data_models/up_to_date_changes.dart +++ b/packages/smooth_app/lib/data_models/up_to_date_changes.dart @@ -51,6 +51,9 @@ class UpToDateChanges { /// * [BackgroundTaskDetails] /// * [BackgroundTaskImage] Product _overwrite(final Product initial, final Product change) { + if (change.productType != null) { + initial.productType = change.productType; + } if (change.productName != null) { initial.productName = change.productName; } diff --git a/packages/smooth_app/lib/l10n/app_en.arb b/packages/smooth_app/lib/l10n/app_en.arb index db3fb6e6722..2887e976840 100644 --- a/packages/smooth_app/lib/l10n/app_en.arb +++ b/packages/smooth_app/lib/l10n/app_en.arb @@ -1769,6 +1769,25 @@ } } }, + "product_type_label_food": "Food", + "product_type_label_beauty": "Personal care", + "product_type_label_pet_food": "Pet food", + "product_type_label_product": "Other", + "product_type_selection_title": "Product type", + "product_type_selection_subtitle": "Select the type of this product", + "product_type_selection_empty": "You need to select a product type first!", + "@product_type_selection_empty": { + "description": "Error message about product type that needs to be set" + }, + "product_type_selection_already": "You cannot change the product type ({productType})!", + "@product_type_selection_already": { + "description": "Error message about product type that cannot be set again", + "placeholders": { + "productType": { + "type": "String" + } + } + }, "prices_app_dev_mode_flag": "Shortcut to Prices app on product page", "prices_app_button": "Go to Prices app", "prices_generic_title": "Prices", diff --git a/packages/smooth_app/lib/pages/image/uploaded_image_gallery.dart b/packages/smooth_app/lib/pages/image/uploaded_image_gallery.dart index 60634d851f0..4a4e63185dc 100644 --- a/packages/smooth_app/lib/pages/image/uploaded_image_gallery.dart +++ b/packages/smooth_app/lib/pages/image/uploaded_image_gallery.dart @@ -90,6 +90,7 @@ class UploadedImageGallery extends StatelessWidget { isLoggedInMandatory: isLoggedInMandatory, cropHelper: ProductCropAgainHelper( barcode: barcode, + productType: productType, imageField: imageField, imageId: int.parse(rawImage.imgid!), language: language, diff --git a/packages/smooth_app/lib/pages/image_crop_page.dart b/packages/smooth_app/lib/pages/image_crop_page.dart index 98056485b21..b53bcdc5f7e 100644 --- a/packages/smooth_app/lib/pages/image_crop_page.dart +++ b/packages/smooth_app/lib/pages/image_crop_page.dart @@ -257,6 +257,7 @@ Future confirmAndUploadNewPicture( final BuildContext context, { required final ImageField imageField, required final String barcode, + required final ProductType? productType, required final OpenFoodFactsLanguage language, required final bool isLoggedInMandatory, }) async => @@ -266,6 +267,7 @@ Future confirmAndUploadNewPicture( imageField: imageField, language: language, barcode: barcode, + productType: productType, ), isLoggedInMandatory: isLoggedInMandatory, ); diff --git a/packages/smooth_app/lib/pages/product/add_basic_details_page.dart b/packages/smooth_app/lib/pages/product/add_basic_details_page.dart index 5822fe3fa14..8a18e9cfff9 100644 --- a/packages/smooth_app/lib/pages/product/add_basic_details_page.dart +++ b/packages/smooth_app/lib/pages/product/add_basic_details_page.dart @@ -296,6 +296,7 @@ class _AddBasicDetailsPageState extends State { minimalistProduct, context: context, stamp: BackgroundTaskDetailsStamp.basicDetails, + productType: _product.productType, ); return true; diff --git a/packages/smooth_app/lib/pages/product/add_new_product_page.dart b/packages/smooth_app/lib/pages/product/add_new_product_page.dart index 92a54dab66f..47706058c9c 100644 --- a/packages/smooth_app/lib/pages/product/add_new_product_page.dart +++ b/packages/smooth_app/lib/pages/product/add_new_product_page.dart @@ -4,6 +4,7 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:matomo_tracker/matomo_tracker.dart'; import 'package:openfoodfacts/openfoodfacts.dart'; import 'package:provider/provider.dart'; +import 'package:smooth_app/background/background_task_details.dart'; import 'package:smooth_app/data_models/product_image_data.dart'; import 'package:smooth_app/data_models/product_list.dart'; import 'package:smooth_app/data_models/up_to_date_mixin.dart'; @@ -42,6 +43,7 @@ class AddNewProductPage extends StatefulWidget { EditProductAction.nutritionFacts: AnalyticsEvent.nutritionNewProductPage, }, + displayProductType = true, displayPictures = true, displayMisc = true, isLoggedInMandatory = false; @@ -61,10 +63,12 @@ class AddNewProductPage extends StatefulWidget { EditProductAction.nutritionFacts: AnalyticsEvent.nutritionFastTrackProductPage, }, + displayProductType = false, displayPictures = false, displayMisc = false; final Product product; + final bool displayProductType; final bool displayPictures; final bool displayMisc; final bool isLoggedInMandatory; @@ -81,6 +85,7 @@ class _AddNewProductPageState extends State int _totalPages = 0; double _progress = 0.0; bool _isLastPage = false; + ProductType? _inputProductType; late ColorScheme _colorScheme; late DaoProductList _daoProductList; @@ -107,6 +112,8 @@ class _AddNewProductPageState extends State bool _ecoscoreExpanded = false; + int get _pageNumber => _pageController.page!.round(); + @override String get actionName => 'Opened add_new_product_page'; @@ -152,14 +159,16 @@ class _AddNewProductPageState extends State widget.events[EditProductAction.openPage]!, barcode: barcode, ); - _totalPages = - 3 + (widget.displayMisc ? 1 : 0) + (widget.displayPictures ? 1 : 0); + _totalPages = 3 + + (widget.displayProductType ? 1 : 0) + + (widget.displayMisc ? 1 : 0) + + (widget.displayPictures ? 1 : 0); _progress = 1 / _totalPages; _pageController.addListener(() { setState(() { - _progress = (_pageController.page!.round() + 1) / _totalPages; - _isLastPage = (_pageController.page!.round() + 1) == _totalPages; + _progress = (_pageNumber + 1) / _totalPages; + _isLastPage = (_pageNumber + 1) == _totalPages; }); }); } @@ -212,6 +221,7 @@ class _AddNewProductPageState extends State _colorScheme = Theme.of(context).colorScheme; context.watch(); refreshUpToDate(); + _inputProductType ??= upToDateProduct.productType; _addToHistory(); for (final AnalyticsProductTracker tracker in _trackers) { @@ -248,6 +258,8 @@ class _AddNewProductPageState extends State child: PageView( controller: _pageController, children: [ + if (widget.displayProductType) + _buildCard(_getProductTypes(context)), if (widget.displayPictures) _buildCard(_getImageRows(context)), _buildCard(_getNutriscoreRows(context)), @@ -335,6 +347,7 @@ class _AddNewProductPageState extends State } Widget _getButtons() { + final AppLocalizations appLocalizations = AppLocalizations.of(context); return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ @@ -346,20 +359,37 @@ class _AddNewProductPageState extends State borderRadius: ROUNDED_BORDER_RADIUS, ), ), - onPressed: () { - if ((_pageController.page ?? 0.0) < 1.0) { + onPressed: () async { + if (_pageNumber == 0) { Navigator.of(context).maybePop(); - } else { - _pageController.previousPage( - duration: SmoothAnimationsDuration.short, - curve: Curves.easeOut, + return; + } + if (widget.displayProductType && _pageNumber == 1) { + return showDialog( + context: context, + builder: (final BuildContext context) => SmoothAlertDialog( + title: appLocalizations.product_type_selection_title, + body: Text( + appLocalizations.product_type_selection_already( + upToDateProduct.productType!.getLabel(appLocalizations), + ), + ), + positiveAction: SmoothActionButton( + text: appLocalizations.okay, + onPressed: () => Navigator.of(context).pop(), + ), + ), ); } + _pageController.previousPage( + duration: SmoothAnimationsDuration.short, + curve: Curves.easeOut, + ); }, child: Text( - (_pageController.hasClients ? _pageController.page! : 0.0) >= 1.0 - ? AppLocalizations.of(context).previous_label - : AppLocalizations.of(context).cancel, + (_pageController.hasClients ? _pageNumber : 0) >= 1 + ? appLocalizations.previous_label + : appLocalizations.cancel, style: const TextStyle( color: Colors.black, fontSize: 20.0, @@ -376,20 +406,41 @@ class _AddNewProductPageState extends State borderRadius: ROUNDED_BORDER_RADIUS, ), ), - onPressed: () { + onPressed: () async { if (_isLastPage) { Navigator.of(context).pop(); - } else { - _pageController.nextPage( - duration: SmoothAnimationsDuration.short, - curve: Curves.easeOut, + return; + } + if (widget.displayProductType && _pageNumber == 0) { + if (_inputProductType == null) { + return showDialog( + context: context, + builder: (final BuildContext context) => SmoothAlertDialog( + title: appLocalizations.product_type_selection_title, + body: Text( + appLocalizations.product_type_selection_empty, + ), + positiveAction: SmoothActionButton( + text: appLocalizations.okay, + onPressed: () => Navigator.of(context).pop(), + ), + ), + ); + } + await BackgroundTaskDetails.addTask( + Product(barcode: barcode)..productType = _inputProductType, + context: context, + stamp: BackgroundTaskDetailsStamp.productType, + productType: _inputProductType, ); } + _pageController.nextPage( + duration: SmoothAnimationsDuration.short, + curve: Curves.easeOut, + ); }, child: Text( - _isLastPage - ? AppLocalizations.of(context).finish - : AppLocalizations.of(context).next_label, + _isLastPage ? appLocalizations.finish : appLocalizations.next_label, style: const TextStyle( color: Colors.white, fontSize: 20.0, @@ -411,7 +462,7 @@ class _AddNewProductPageState extends State const SizedBox(height: 15.0), _buildCategoriesButton(context), AddNewProductButton( - AppLocalizations.of(context).nutritional_facts_input_button_label, + appLocalizations.nutritional_facts_input_button_label, Icons.filter_2, // deactivated when the categories were not set beforehand !_categoryEditor.isPopulated(upToDateProduct) @@ -547,6 +598,31 @@ class _AddNewProductPageState extends State ]; } + List _getProductTypes(final BuildContext context) { + final AppLocalizations appLocalizations = AppLocalizations.of(context); + + final List rows = []; + rows.add( + AddNewProductTitle(appLocalizations.product_type_selection_subtitle), + ); + + for (final ProductType productType in ProductType.values) { + rows.add( + RadioListTile( + title: Text(productType.getLabel(appLocalizations)), + onChanged: (ProductType? value) { + if (value != null) { + setState(() => _inputProductType = value); + } + }, + value: productType, + groupValue: _inputProductType, + ), + ); + } + return rows; + } + List _getImageRows(final BuildContext context) { final AppLocalizations appLocalizations = AppLocalizations.of(context); final List rows = []; @@ -597,6 +673,7 @@ class _AddNewProductPageState extends State await confirmAndUploadNewPicture( context, barcode: barcode, + productType: upToDateProduct.productType, imageField: ImageField.OTHER, language: ProductQuery.getLanguage(), isLoggedInMandatory: widget.isLoggedInMandatory, diff --git a/packages/smooth_app/lib/pages/product/add_other_details_page.dart b/packages/smooth_app/lib/pages/product/add_other_details_page.dart index 23565fa5be5..5ff14cbb004 100644 --- a/packages/smooth_app/lib/pages/product/add_other_details_page.dart +++ b/packages/smooth_app/lib/pages/product/add_other_details_page.dart @@ -141,6 +141,7 @@ class _AddOtherDetailsPageState extends State { _getMinimalistProduct(), context: context, stamp: BackgroundTaskDetailsStamp.otherDetails, + productType: _product.productType, ); return true; diff --git a/packages/smooth_app/lib/pages/product/common/product_dialog_helper.dart b/packages/smooth_app/lib/pages/product/common/product_dialog_helper.dart index 1bbd5070b0d..d30a1a9b39e 100644 --- a/packages/smooth_app/lib/pages/product/common/product_dialog_helper.dart +++ b/packages/smooth_app/lib/pages/product/common/product_dialog_helper.dart @@ -1,10 +1,7 @@ -import 'dart:math' as math; - import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:openfoodfacts/openfoodfacts.dart'; -import 'package:smooth_app/cards/category_cards/svg_cache.dart'; import 'package:smooth_app/data_models/fetched_product.dart'; import 'package:smooth_app/database/dao_product.dart'; import 'package:smooth_app/database/local_database.dart'; @@ -60,16 +57,6 @@ class ProductDialogHelper { void _openProductNotFoundDialog() => showDialog( context: context, builder: (BuildContext context) { - final double availableWidth = MediaQuery.sizeOf(context).width - - SmoothAlertDialog.defaultMargin.horizontal - - SmoothAlertDialog.defaultContentPadding(context).horizontal; - - /// The nutriscore logo is 240*130 - final double svgHeight = math.min( - (availableWidth * 0.4) / 240.0 * 130.0, - 175.0, - ); - final double heightMultiplier = switch (context.deviceType) { DeviceType.small => 1, DeviceType.smartphone => 2, @@ -101,33 +88,6 @@ class ProductDialogHelper { appLocalizations.barcode_barcode(barcode), textAlign: TextAlign.center, ), - SizedBox(height: MEDIUM_SPACE * heightMultiplier), - Semantics( - label: appLocalizations - .new_product_dialog_illustration_description, - excludeSemantics: true, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - flex: 4, - child: SvgCache( - unknownSvgNutriscore, - height: svgHeight, - ), - ), - const Spacer(), - Expanded( - flex: 4, - child: SvgCache( - unknownSvgEcoscore, - height: svgHeight, - ), - ), - ], - ), - ), SizedBox(height: SMALL_SPACE * heightMultiplier), Text( appLocalizations.new_product_dialog_description, diff --git a/packages/smooth_app/lib/pages/product/edit_new_packagings.dart b/packages/smooth_app/lib/pages/product/edit_new_packagings.dart index cfe8cef68f5..43012191485 100644 --- a/packages/smooth_app/lib/pages/product/edit_new_packagings.dart +++ b/packages/smooth_app/lib/pages/product/edit_new_packagings.dart @@ -176,6 +176,7 @@ class _EditNewPackagingsState extends State context, imageField: ImageField.OTHER, barcode: barcode, + productType: upToDateProduct.productType, language: ProductQuery.getLanguage(), isLoggedInMandatory: widget.isLoggedInMandatory, ), @@ -302,6 +303,7 @@ class _EditNewPackagingsState extends State changedProduct, context: context, stamp: BackgroundTaskDetailsStamp.structuredPackaging, + productType: upToDateProduct.productType, ); return true; } diff --git a/packages/smooth_app/lib/pages/product/edit_ocr/edit_ocr_page.dart b/packages/smooth_app/lib/pages/product/edit_ocr/edit_ocr_page.dart index d78a52cce5e..eb2d8be4583 100644 --- a/packages/smooth_app/lib/pages/product/edit_ocr/edit_ocr_page.dart +++ b/packages/smooth_app/lib/pages/product/edit_ocr/edit_ocr_page.dart @@ -126,6 +126,7 @@ class _EditOcrPageState extends State with UpToDateMixin { changedProduct, context: context, stamp: _helper.getStamp(), + productType: upToDateProduct.productType, ); return; } @@ -383,6 +384,7 @@ class _EditOcrPageState extends State with UpToDateMixin { context, imageField: ImageField.OTHER, barcode: widget.product.barcode!, + productType: upToDateProduct.productType, language: language, isLoggedInMandatory: widget.isLoggedInMandatory, ), diff --git a/packages/smooth_app/lib/pages/product/nutrition_page_loaded.dart b/packages/smooth_app/lib/pages/product/nutrition_page_loaded.dart index 6fed13681ec..7822e6d40e9 100644 --- a/packages/smooth_app/lib/pages/product/nutrition_page_loaded.dart +++ b/packages/smooth_app/lib/pages/product/nutrition_page_loaded.dart @@ -430,6 +430,7 @@ class _NutritionPageLoadedState extends State changedProduct, context: context, stamp: BackgroundTaskDetailsStamp.nutrition, + productType: widget.product.productType, ); return true; } diff --git a/packages/smooth_app/lib/pages/product/product_image_button.dart b/packages/smooth_app/lib/pages/product/product_image_button.dart index 2c6352d9f24..fbcaef5a540 100644 --- a/packages/smooth_app/lib/pages/product/product_image_button.dart +++ b/packages/smooth_app/lib/pages/product/product_image_button.dart @@ -85,6 +85,7 @@ enum ProductImageButtonType { ), ProductImageButtonType.unselect => ProductImageUnselectButton( product: product, + productType: product.productType, imageField: imageField, language: language, isLoggedInMandatory: isLoggedInMandatory, diff --git a/packages/smooth_app/lib/pages/product/product_image_crop_button.dart b/packages/smooth_app/lib/pages/product/product_image_crop_button.dart index 3164e89430e..5510220456c 100644 --- a/packages/smooth_app/lib/pages/product/product_image_crop_button.dart +++ b/packages/smooth_app/lib/pages/product/product_image_crop_button.dart @@ -122,6 +122,7 @@ class ProductImageCropButton extends ProductImageButton { cropHelper: ProductCropAgainHelper( language: language, barcode: barcode, + productType: productType, imageField: _imageData.imageField, imageId: imageId, ), @@ -144,6 +145,7 @@ class ProductImageCropButton extends ProductImageButton { cropHelper: ProductCropNewHelper( language: language, barcode: barcode, + productType: product.productType, imageField: _imageData.imageField, ), ), diff --git a/packages/smooth_app/lib/pages/product/product_image_gallery_view.dart b/packages/smooth_app/lib/pages/product/product_image_gallery_view.dart index 101797b386a..0ad9c6ccf09 100644 --- a/packages/smooth_app/lib/pages/product/product_image_gallery_view.dart +++ b/packages/smooth_app/lib/pages/product/product_image_gallery_view.dart @@ -73,6 +73,7 @@ class _ProductImageGalleryViewState extends State barcode: barcode, language: ProductQuery.getLanguage(), isLoggedInMandatory: true, + productType: upToDateProduct.productType, ); }, label: Text(appLocalizations.add_photo_button_label), diff --git a/packages/smooth_app/lib/pages/product/product_image_local_button.dart b/packages/smooth_app/lib/pages/product/product_image_local_button.dart index 049cffa4291..b362a6e0739 100644 --- a/packages/smooth_app/lib/pages/product/product_image_local_button.dart +++ b/packages/smooth_app/lib/pages/product/product_image_local_button.dart @@ -40,6 +40,7 @@ class ProductImageLocalButton extends ProductImageButton { context, imageField: imageField, barcode: barcode, + productType: product.productType, language: language, isLoggedInMandatory: isLoggedInMandatory, ); diff --git a/packages/smooth_app/lib/pages/product/product_image_unselect_button.dart b/packages/smooth_app/lib/pages/product/product_image_unselect_button.dart index f5e00fd953e..172a507975d 100644 --- a/packages/smooth_app/lib/pages/product/product_image_unselect_button.dart +++ b/packages/smooth_app/lib/pages/product/product_image_unselect_button.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:openfoodfacts/openfoodfacts.dart'; import 'package:provider/provider.dart'; import 'package:smooth_app/background/background_task_unselect.dart'; import 'package:smooth_app/database/local_database.dart'; @@ -14,9 +15,12 @@ class ProductImageUnselectButton extends ProductImageButton { required super.imageField, required super.language, required super.isLoggedInMandatory, + required this.productType, super.borderWidth, }); + final ProductType? productType; + @override IconData getIconData() => Icons.do_disturb_on; @@ -70,6 +74,7 @@ class ProductImageUnselectButton extends ProductImageButton { imageField: imageField, context: context, language: language, + productType: productType, ); localDatabase.notifyListeners(); if (!context.mounted) { diff --git a/packages/smooth_app/lib/pages/product/product_image_viewer.dart b/packages/smooth_app/lib/pages/product/product_image_viewer.dart index f92e8ece55c..5803ea100f7 100644 --- a/packages/smooth_app/lib/pages/product/product_image_viewer.dart +++ b/packages/smooth_app/lib/pages/product/product_image_viewer.dart @@ -119,6 +119,7 @@ class _ProductImageViewerState extends State context, imageField: widget.imageField, barcode: barcode, + productType: upToDateProduct.productType, language: widget.language, isLoggedInMandatory: true, ); diff --git a/packages/smooth_app/lib/pages/product/simple_input_page.dart b/packages/smooth_app/lib/pages/product/simple_input_page.dart index 2055aab2102..073714e16f5 100644 --- a/packages/smooth_app/lib/pages/product/simple_input_page.dart +++ b/packages/smooth_app/lib/pages/product/simple_input_page.dart @@ -190,6 +190,7 @@ class _SimpleInputPageState extends State { context: context, stamp: entry.key, showSnackBar: first, + productType: widget.product.productType, ); first = false; } diff --git a/packages/smooth_app/lib/pages/product/simple_input_page_helpers.dart b/packages/smooth_app/lib/pages/product/simple_input_page_helpers.dart index 0087300211f..e4f73be9525 100644 --- a/packages/smooth_app/lib/pages/product/simple_input_page_helpers.dart +++ b/packages/smooth_app/lib/pages/product/simple_input_page_helpers.dart @@ -130,6 +130,7 @@ abstract class AbstractSimpleInputPageHelper extends ChangeNotifier { context, imageField: ImageField.OTHER, barcode: product.barcode!, + productType: product.productType, language: ProductQuery.getLanguage(), // we're already logged in if needed isLoggedInMandatory: false, diff --git a/packages/smooth_app/lib/pages/product_crop_helper.dart b/packages/smooth_app/lib/pages/product_crop_helper.dart index 956949330c1..24a86c999c9 100644 --- a/packages/smooth_app/lib/pages/product_crop_helper.dart +++ b/packages/smooth_app/lib/pages/product_crop_helper.dart @@ -21,11 +21,13 @@ abstract class ProductCropHelper extends CropHelper { required this.imageField, required this.language, required this.barcode, + required this.productType, }); final ImageField imageField; final OpenFoodFactsLanguage language; final String barcode; + final ProductType? productType; @override String getPageTitle(final AppLocalizations appLocalizations) => @@ -56,6 +58,7 @@ class ProductCropNewHelper extends ProductCropHelper { required super.imageField, required super.language, required super.barcode, + required super.productType, }); @override @@ -88,6 +91,7 @@ class ProductCropNewHelper extends ProductCropHelper { } await BackgroundTaskImage.addTask( barcode, + productType: productType, language: language, imageField: imageField, fullFile: fullFile, @@ -117,6 +121,7 @@ class ProductCropAgainHelper extends ProductCropHelper { required super.imageField, required super.language, required super.barcode, + required super.productType, required this.imageId, }); @@ -143,6 +148,7 @@ class ProductCropAgainHelper extends ProductCropHelper { final Rect cropRect = _getServerCropRect(controller, image); await BackgroundTaskCrop.addTask( barcode, + productType: productType, language: language, imageField: imageField, imageId: imageId, diff --git a/packages/smooth_app/lib/query/product_query.dart b/packages/smooth_app/lib/query/product_query.dart index af0902ec1e6..5a892f89e1f 100644 --- a/packages/smooth_app/lib/query/product_query.dart +++ b/packages/smooth_app/lib/query/product_query.dart @@ -301,6 +301,10 @@ extension ProductTypeExtension on ProductType { ProductType.product => 'openproductsfacts', }; - // TODO(monsieurtanuki): localize with very short names, or use icons instead - String getLabel(final AppLocalizations appLocalizations) => name; + String getLabel(final AppLocalizations appLocalizations) => switch (this) { + ProductType.food => appLocalizations.product_type_label_food, + ProductType.beauty => appLocalizations.product_type_label_beauty, + ProductType.petFood => appLocalizations.product_type_label_pet_food, + ProductType.product => appLocalizations.product_type_label_product, + }; }