diff --git a/packages/smooth_app/ios/Podfile.lock b/packages/smooth_app/ios/Podfile.lock index 2d27689b1ae..6d6fdad6af8 100644 --- a/packages/smooth_app/ios/Podfile.lock +++ b/packages/smooth_app/ios/Podfile.lock @@ -308,6 +308,6 @@ SPEC CHECKSUMS: url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe webview_flutter_wkwebview: 0982481e3d9c78fd5c6f62a002fcd24fc791f1e4 -PODFILE CHECKSUM: 642d7227a22f6cf08664cf1937c611a52f51dfac +PODFILE CHECKSUM: 798cbe17fd0f5e52d4df92f6b2f3257201f5868e COCOAPODS: 1.16.2 diff --git a/packages/smooth_app/lib/pages/image/product_image_gallery_other_view.dart b/packages/smooth_app/lib/pages/image/product_image_gallery_other_view.dart index d52d3358313..d8eed0d80e3 100644 --- a/packages/smooth_app/lib/pages/image/product_image_gallery_other_view.dart +++ b/packages/smooth_app/lib/pages/image/product_image_gallery_other_view.dart @@ -154,6 +154,14 @@ class _RawGridGallery extends StatelessWidget { heroTag: heroTag!, language: language, ), + onLongPress: () async => _usePhotoAs( + context: context, + product: product, + rawImages: rawImages, + productImage: productImage, + heroTag: heroTag!, + language: language, + ), ), ), ), @@ -198,4 +206,19 @@ class _RawGridGallery extends StatelessWidget { ), ); } + + Future _usePhotoAs({ + required final BuildContext context, + required final Product product, + required final List rawImages, + required final ProductImage productImage, + required final String heroTag, + required final OpenFoodFactsLanguage language, + }) => + ProductImageOtherPage.usePhotoAs( + context: context, + product: product, + language: language, + productImage: productImage, + ); } diff --git a/packages/smooth_app/lib/pages/image/product_image_other_page.dart b/packages/smooth_app/lib/pages/image/product_image_other_page.dart index c2776eee386..16c4a7c5e72 100644 --- a/packages/smooth_app/lib/pages/image/product_image_other_page.dart +++ b/packages/smooth_app/lib/pages/image/product_image_other_page.dart @@ -37,6 +37,88 @@ class ProductImageOtherPage extends StatefulWidget { @override State createState() => _ProductImageOtherPageState(); + + static Future usePhotoAs({ + required final BuildContext context, + required final Product product, + required final OpenFoodFactsLanguage language, + required final ProductImage productImage, + }) async { + final AppLocalizations appLocalizations = AppLocalizations.of(context); + final SmoothColorsThemeExtension extension = + context.extension(); + + final List imageFields = [ + ImageField.FRONT, + ImageField.INGREDIENTS, + ImageField.NUTRITION, + ImageField.PACKAGING, + ]; + + final Widget existingPictureIcon = icons.Picture.checkAlt( + color: extension.success, + semanticLabel: appLocalizations.photo_already_exists, + ); + final Widget missingPictureIcon = icons.Picture.error( + color: extension.error, + semanticLabel: appLocalizations.photo_missing, + ); + + final ImageField? selectedImageField = + await showSmoothListOfChoicesModalSheet( + context: context, + title: appLocalizations.photo_viewer_use_picture_as_title( + Languages().getNameInLanguage(language), + ), + padding: const EdgeInsetsDirectional.only( + start: 15.0, + end: 19.0, + ), + labels: [ + appLocalizations.photo_field_front, + appLocalizations.photo_field_ingredients, + appLocalizations.photo_field_nutrition, + appLocalizations.photo_field_packaging, + ], + values: imageFields, + prefixIcons: [ + const icons.Milk.filled(), + const icons.Ingredients.alt(), + const icons.NutritionFacts(), + const icons.Recycling(), + ], + suffixIcons: imageFields.map((final ImageField imageField) { + final bool exists = TransientFile.fromProduct( + product, + imageField, + language, + ).isImageAvailable(); + return exists ? existingPictureIcon : missingPictureIcon; + }).toList(growable: false), + ); + + if (context.mounted && selectedImageField != null) { + final CropParameters? cropParameters = + await UploadedImageGallery.useExistingPhotoFor( + context: context, + rawImage: productImage, + barcode: product.barcode!, + imageField: selectedImageField, + isLoggedInMandatory: true, + productType: product.productType, + language: language, + ); + + if (cropParameters != null) { + return ProductImagePageResult( + cropParameters: cropParameters, + imageField: selectedImageField, + ); + } + } + + return null; + } } class _ProductImageOtherPageState extends State { @@ -122,76 +204,15 @@ class _ProductImageOtherPageState extends State { } Future _usePhotoAs() async { - final AppLocalizations appLocalizations = AppLocalizations.of(context); - final SmoothColorsThemeExtension extension = - context.extension(); - - final List imageFields = [ - ImageField.FRONT, - ImageField.INGREDIENTS, - ImageField.NUTRITION, - ImageField.PACKAGING, - ]; - - final Widget existingPictureIcon = icons.Picture.checkAlt( - color: extension.success, - semanticLabel: appLocalizations.photo_already_exists, - ); - final Widget missingPictureIcon = icons.Picture.error( - color: extension.error, - semanticLabel: appLocalizations.photo_missing, - ); - - final ImageField? selectedImageField = - await showSmoothListOfChoicesModalSheet( + final ProductImagePageResult? res = await ProductImageOtherPage.usePhotoAs( context: context, - title: appLocalizations.photo_viewer_use_picture_as_title( - Languages().getNameInLanguage(widget.language), - ), - padding: const EdgeInsetsDirectional.only( - start: 15.0, - end: 19.0, - ), - labels: [ - appLocalizations.photo_field_front, - appLocalizations.photo_field_ingredients, - appLocalizations.photo_field_nutrition, - appLocalizations.photo_field_packaging, - ], - values: imageFields, - prefixIcons: [ - const icons.Milk.filled(), - const icons.Ingredients.alt(), - const icons.NutritionFacts(), - const icons.Recycling(), - ], - suffixIcons: imageFields.map((final ImageField imageField) { - final bool exists = TransientFile.fromProduct( - widget.product, - imageField, - widget.language, - ).isImageAvailable(); - return exists ? existingPictureIcon : missingPictureIcon; - }).toList(growable: false), + product: widget.product, + language: widget.language, + productImage: widget.currentImage, ); - if (mounted && selectedImageField != null) { - final CropParameters? parameters = - await UploadedImageGallery.useExistingPhotoFor( - context: context, - rawImage: widget.currentImage, - barcode: widget.product.barcode!, - imageField: selectedImageField, - isLoggedInMandatory: true, - productType: widget.product.productType, - language: widget.language, - ); - - if (mounted && parameters != null) { - Navigator.of(context).pop( - ProductImagePageResult(parameters, selectedImageField), - ); - } + if (mounted && res != null) { + Navigator.of(context).pop(res); } } } @@ -488,7 +509,10 @@ class _ProductImagePageIndicator extends StatelessWidget { } class ProductImagePageResult { - ProductImagePageResult(this.cropParameters, this.imageField); + ProductImagePageResult({ + required this.cropParameters, + required this.imageField, + }); final CropParameters cropParameters; final ImageField imageField; diff --git a/packages/smooth_app/lib/pages/product/gallery_view/product_image_gallery_view.dart b/packages/smooth_app/lib/pages/product/gallery_view/product_image_gallery_view.dart index e50f6295fb1..89513b2789a 100644 --- a/packages/smooth_app/lib/pages/product/gallery_view/product_image_gallery_view.dart +++ b/packages/smooth_app/lib/pages/product/gallery_view/product_image_gallery_view.dart @@ -377,6 +377,10 @@ class _ProductImageGalleryFooterButtonState } void _handleScrollNotification(ScrollNotification notification) { + if (notification.metrics.axis == Axis.horizontal) { + return; + } + if (notification is ScrollStartNotification) { _scrollInitialPosition = notification.metrics.extentBefore; _scrollDirection = ScrollDirection.idle;