From 1f9caa2b0c1cd2e516584f9221bc9b2a36df5e2c Mon Sep 17 00:00:00 2001 From: Pierre Slamich Date: Mon, 22 Jul 2024 09:19:19 +0200 Subject: [PATCH 01/24] ci: Update crowdin.yml --- crowdin.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/crowdin.yml b/crowdin.yml index 2a1c9fb1819..0a1c3d77355 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -2,6 +2,7 @@ project_id_env: CROWDIN_PROJECT_ID api_token_env: CROWDIN_PERSONAL_TOKEN pull_request_title: "chore: New translations to review and merge" pull_request_body: '### What\n- Automated pull request pulling in new or updated translations from Crowdin (https://translate.openfoodfacts.org).\n## Checklist\n- [ ] Check that they are no bad translations. If there are, correct them directly in Crowdin so that they are not resynced again. Then you can correct them here as well, or wait 24 hours for the sync to happen automatically.\n- [ ] Put extra attention on Acholi, which is used mistakenly as a sandbox by people discovering the self-service translation button on Open Food Facts\n- [ ] Once you are happy, that automated checks pass, you can approve the PR and merge it.\n### Part of\n- Translations' +pull_request_labels : 'translations' files: - source: /packages/smooth_app/lib/l10n/app_en.arb dist: /packages/smooth_app/lib/l10n/app_en.arb From a9e216c72d467533da9ea815eb69131f5cc909bf Mon Sep 17 00:00:00 2001 From: Edouard Marquez Date: Mon, 22 Jul 2024 10:50:43 +0200 Subject: [PATCH 02/24] feat: Popup Menu now uses the iOS actions sheet (#5494) * iOS popup menu (cherry picked from commit 493f3d2ebbf444579f8c03ff0ac7d5f8b9db55e7) * Reorder mandatory fields --- packages/smooth_app/lib/l10n/app_en.arb | 4 + .../lib/pages/personalized_ranking_page.dart | 9 +- .../common/product_list_item_popup_items.dart | 18 ++- .../product/common/product_list_page.dart | 11 +- .../common/product_list_popup_items.dart | 18 ++- .../lib/widgets/smooth_menu_button.dart | 118 ++++++++++++++++++ packages/smooth_app/macos/Podfile.lock | 2 +- 7 files changed, 157 insertions(+), 23 deletions(-) create mode 100644 packages/smooth_app/lib/widgets/smooth_menu_button.dart diff --git a/packages/smooth_app/lib/l10n/app_en.arb b/packages/smooth_app/lib/l10n/app_en.arb index 4950480c499..01a2f992a77 100644 --- a/packages/smooth_app/lib/l10n/app_en.arb +++ b/packages/smooth_app/lib/l10n/app_en.arb @@ -2960,5 +2960,9 @@ "prices_feedback_form": "Click here to send us your feedback about this new feature!", "@prices_feedback_form": { "description": "A button to send feedback about the prices feature" + }, + "menu_button_list_actions": "Select an action", + "@menu_button_list_actions": { + "description": "Button to select an action in a list (eg: Share, Delete, …)" } } \ No newline at end of file diff --git a/packages/smooth_app/lib/pages/personalized_ranking_page.dart b/packages/smooth_app/lib/pages/personalized_ranking_page.dart index 4b6d42ea9d8..8441d94c516 100644 --- a/packages/smooth_app/lib/pages/personalized_ranking_page.dart +++ b/packages/smooth_app/lib/pages/personalized_ranking_page.dart @@ -16,6 +16,7 @@ import 'package:smooth_app/pages/product/common/loading_status.dart'; import 'package:smooth_app/pages/product/common/product_list_item_simple.dart'; import 'package:smooth_app/pages/product_list_user_dialog_helper.dart'; import 'package:smooth_app/widgets/smooth_app_bar.dart'; +import 'package:smooth_app/widgets/smooth_menu_button.dart'; import 'package:smooth_app/widgets/smooth_scaffold.dart'; class PersonalizedRankingPage extends StatefulWidget { @@ -97,13 +98,13 @@ class _PersonalizedRankingPageState extends State appBar: SmoothAppBar( title: Text(widget.title, overflow: TextOverflow.fade), actions: [ - PopupMenuButton( + SmoothPopupMenuButton( onSelected: _handlePopUpClick, itemBuilder: (BuildContext context) { - return >[ - PopupMenuItem( + return >[ + SmoothPopupMenuItem( value: 'add_to_list', - child: Text(appLocalizations.user_list_button_add_product), + label: appLocalizations.user_list_button_add_product, ), ]; }, diff --git a/packages/smooth_app/lib/pages/product/common/product_list_item_popup_items.dart b/packages/smooth_app/lib/pages/product/common/product_list_item_popup_items.dart index b97f58f32b0..ed67bb929bd 100644 --- a/packages/smooth_app/lib/pages/product/common/product_list_item_popup_items.dart +++ b/packages/smooth_app/lib/pages/product/common/product_list_item_popup_items.dart @@ -10,6 +10,7 @@ import 'package:smooth_app/generic_lib/dialogs/smooth_alert_dialog.dart'; import 'package:smooth_app/pages/personalized_ranking_page.dart'; import 'package:smooth_app/pages/product/compare_products3_page.dart'; import 'package:smooth_app/pages/product/ordered_nutrients_cache.dart'; +import 'package:smooth_app/widgets/smooth_menu_button.dart'; /// Popup menu item entries for the product list page, for selected items. enum ProductListItemPopupMenuEntry { @@ -26,6 +27,9 @@ abstract class ProductListItemPopupItem { /// IconData of the popup menu item. IconData getIconData(); + /// Is-it a destructive action? + bool isDestructive() => false; + /// Action of the popup menu item. /// /// Returns true if the caller must refresh (setState) (e.g. after deleting). @@ -37,17 +41,16 @@ abstract class ProductListItemPopupItem { }); /// Returns the popup menu item. - PopupMenuItem getMenuItem( + SmoothPopupMenuItem getMenuItem( final AppLocalizations appLocalizations, final bool enabled, ) => - PopupMenuItem( + SmoothPopupMenuItem( value: this, + icon: getIconData(), + label: getTitle(appLocalizations), enabled: enabled, - child: ListTile( - leading: Icon(getIconData()), - title: Text(getTitle(appLocalizations)), - ), + type: isDestructive() ? SmoothPopupMenuItemType.destructive : null, ); } @@ -139,6 +142,9 @@ class ProductListItemPopupDelete extends ProductListItemPopupItem { @override IconData getIconData() => Icons.delete; + @override + bool isDestructive() => true; + @override Future doSomething({ required final ProductList productList, diff --git a/packages/smooth_app/lib/pages/product/common/product_list_page.dart b/packages/smooth_app/lib/pages/product/common/product_list_page.dart index 59d9b4e671a..2336258b8a8 100644 --- a/packages/smooth_app/lib/pages/product/common/product_list_page.dart +++ b/packages/smooth_app/lib/pages/product/common/product_list_page.dart @@ -31,6 +31,7 @@ import 'package:smooth_app/pages/product_list_user_dialog_helper.dart'; import 'package:smooth_app/pages/scan/carousel/scan_carousel_manager.dart'; import 'package:smooth_app/query/product_query.dart'; import 'package:smooth_app/widgets/smooth_app_bar.dart'; +import 'package:smooth_app/widgets/smooth_menu_button.dart'; import 'package:smooth_app/widgets/smooth_scaffold.dart'; import 'package:smooth_app/widgets/will_pop_scope.dart'; @@ -181,7 +182,7 @@ class _ProductListPageState extends State } }, ), - PopupMenuButton( + SmoothPopupMenuButton( onSelected: (final ProductListPopupItem action) async { final ProductList? differentProductList = await action.doSomething( @@ -193,8 +194,7 @@ class _ProductListPageState extends State setState(() => productList = differentProductList); } }, - itemBuilder: (BuildContext context) => - >[ + itemBuilder: (_) => >[ if (enableRename) _rename.getMenuItem(appLocalizations), _share.getMenuItem(appLocalizations), _openInWeb.getMenuItem(appLocalizations), @@ -215,7 +215,7 @@ class _ProductListPageState extends State }, actionModeTitle: Text('${_selectedBarcodes.length}'), actionModeActions: [ - PopupMenuButton( + SmoothPopupMenuButton( onSelected: (final ProductListItemPopupItem action) async { final bool andThenSetState = await action.doSomething( productList: productList, @@ -229,8 +229,7 @@ class _ProductListPageState extends State } } }, - itemBuilder: (BuildContext context) => - >[ + itemBuilder: (_) => >[ if (userPreferences.getFlag(UserPreferencesDevMode .userPreferencesFlagBoostedComparison) == true) diff --git a/packages/smooth_app/lib/pages/product/common/product_list_popup_items.dart b/packages/smooth_app/lib/pages/product/common/product_list_popup_items.dart index 8fdcbd345d9..fbbd20e1796 100644 --- a/packages/smooth_app/lib/pages/product/common/product_list_popup_items.dart +++ b/packages/smooth_app/lib/pages/product/common/product_list_popup_items.dart @@ -8,6 +8,7 @@ import 'package:smooth_app/generic_lib/dialogs/smooth_alert_dialog.dart'; import 'package:smooth_app/helpers/analytics_helper.dart'; import 'package:smooth_app/helpers/temp_product_list_share_helper.dart'; import 'package:smooth_app/pages/product_list_user_dialog_helper.dart'; +import 'package:smooth_app/widgets/smooth_menu_button.dart'; import 'package:url_launcher/url_launcher.dart'; /// Popup menu item entries for the product list page. @@ -30,6 +31,9 @@ abstract class ProductListPopupItem { /// Popup menu entry of the popup menu item. ProductListPopupMenuEntry getEntry(); + /// Is-it a destructive action? + bool isDestructive() => false; + /// Action of the popup menu item. /// /// Returns a different product list if there are changes, else null. @@ -40,15 +44,14 @@ abstract class ProductListPopupItem { }); /// Returns the popup menu item. - PopupMenuItem getMenuItem( + SmoothPopupMenuItem getMenuItem( final AppLocalizations appLocalizations, ) => - PopupMenuItem( + SmoothPopupMenuItem( value: this, - child: ListTile( - leading: Icon(getIconData()), - title: Text(getTitle(appLocalizations)), - ), + icon: getIconData(), + label: getTitle(appLocalizations), + type: isDestructive() ? SmoothPopupMenuItemType.destructive : null, ); } @@ -64,6 +67,9 @@ class ProductListPopupClear extends ProductListPopupItem { @override ProductListPopupMenuEntry getEntry() => ProductListPopupMenuEntry.clear; + @override + bool isDestructive() => true; + @override Future doSomething({ required final ProductList productList, diff --git a/packages/smooth_app/lib/widgets/smooth_menu_button.dart b/packages/smooth_app/lib/widgets/smooth_menu_button.dart new file mode 100644 index 00000000000..0485b522183 --- /dev/null +++ b/packages/smooth_app/lib/widgets/smooth_menu_button.dart @@ -0,0 +1,118 @@ +import 'dart:io'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + +/// A Button similar to a [PopupMenuButton] for non Apple platforms. +/// On iOS and macOS, it's still an [IconButton], but that opens a +/// [CupertinoActionSheet]. +class SmoothPopupMenuButton extends StatefulWidget { + const SmoothPopupMenuButton({ + required this.onSelected, + required this.itemBuilder, + this.actionsTitle, + this.buttonIcon, + this.buttonLabel, + }) : assert(buttonLabel == null || buttonLabel.length > 0), + assert(actionsTitle == null || actionsTitle.length > 0); + + final void Function(T value) onSelected; + final Iterable> Function(BuildContext context) + itemBuilder; + final Icon? buttonIcon; + final String? buttonLabel; + final String? actionsTitle; + + @override + State> createState() => + _SmoothPopupMenuButtonState(); +} + +class _SmoothPopupMenuButtonState extends State> { + @override + Widget build(BuildContext context) { + if (Platform.isIOS || Platform.isMacOS) { + return IconButton( + icon: widget.buttonIcon ?? Icon(Icons.adaptive.more), + tooltip: widget.buttonLabel ?? + MaterialLocalizations.of(context).showMenuTooltip, + onPressed: _openModalSheet, + ); + } else { + return PopupMenuButton( + icon: widget.buttonIcon ?? Icon(Icons.adaptive.more), + tooltip: widget.buttonLabel ?? + MaterialLocalizations.of(context).showMenuTooltip, + onSelected: widget.onSelected, + itemBuilder: (BuildContext context) { + return widget.itemBuilder(context).map((SmoothPopupMenuItem item) { + return PopupMenuItem( + value: item.value, + enabled: item.enabled, + child: ListTile( + leading: Icon(item.icon), + title: Text(item.label), + ), + ); + }).toList(growable: false); + }, + ); + } + } + + // iOS and macOS behavior + void _openModalSheet() { + showCupertinoModalPopup( + context: context, + builder: (BuildContext context) { + return CupertinoActionSheet( + title: Text( + widget.actionsTitle ?? + AppLocalizations.of(context).menu_button_list_actions, + ), + actions: widget + .itemBuilder(context) + .where((SmoothPopupMenuItem item) => item.enabled) + .map((SmoothPopupMenuItem item) { + return CupertinoActionSheetAction( + isDefaultAction: + item.type == SmoothPopupMenuItemType.highlighted, + isDestructiveAction: + item.type == SmoothPopupMenuItemType.destructive, + onPressed: () { + widget.onSelected(item.value); + Navigator.of(context).maybePop(); + }, + child: Text(item.label), + ); + }).toList(growable: false), + ); + }); + } +} + +class SmoothPopupMenuItem { + const SmoothPopupMenuItem({ + required this.value, + required this.label, + this.icon, + this.type, + this.enabled = true, + }) : assert(label.length > 0); + + final T value; + final String label; + final IconData? icon; + final SmoothPopupMenuItemType? type; + final bool enabled; +} + +/// The style of an item in the menu +/// On Material platforms, all values behave the same. +/// On iOS, the [highlighted] value is in black and [destructive] in red. +enum SmoothPopupMenuItemType { + normal, + highlighted, + destructive, +} diff --git a/packages/smooth_app/macos/Podfile.lock b/packages/smooth_app/macos/Podfile.lock index a01e826ae0d..c802b6a34ca 100644 --- a/packages/smooth_app/macos/Podfile.lock +++ b/packages/smooth_app/macos/Podfile.lock @@ -114,7 +114,7 @@ SPEC CHECKSUMS: FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 in_app_review: a850789fad746e89bce03d4aeee8078b45a53fd0 mobile_scanner: 54ceceae0c8da2457e26a362a6be5c61154b1829 - package_info_plus: 02d7a575e80f194102bef286361c6c326e4c29ce + package_info_plus: fa739dd842b393193c5ca93c26798dff6e3d0e0c path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 ReachabilitySwift: 2128f3a8c9107e1ad33574c6e58e8285d460b149 rive_common: cf5ab646aa576b2d742d0e2d528126fbf032c856 From a797ebde6de4d0d2a1496e0a8145618d836346cb Mon Sep 17 00:00:00 2001 From: Edouard Marquez Date: Mon, 22 Jul 2024 12:13:01 +0200 Subject: [PATCH 03/24] feat: Add the outdated indicator to the photo grid (#5491) * Add the outdated indicator to the photo grid * Add some comments --- .../lib/data_models/product_image_data.dart | 2 + .../lib/database/transient_file.dart | 43 ++++--- .../lib/helpers/product_cards_helper.dart | 2 + packages/smooth_app/lib/l10n/app_en.arb | 7 ++ .../lib/pages/image/product_image_helper.dart | 23 ++++ .../lib/pages/image/product_image_widget.dart | 7 +- .../product/product_image_gallery_view.dart | 108 +++++++++++------- 7 files changed, 133 insertions(+), 59 deletions(-) create mode 100644 packages/smooth_app/lib/pages/image/product_image_helper.dart diff --git a/packages/smooth_app/lib/data_models/product_image_data.dart b/packages/smooth_app/lib/data_models/product_image_data.dart index c11f2bc1e25..9aaa20fd227 100644 --- a/packages/smooth_app/lib/data_models/product_image_data.dart +++ b/packages/smooth_app/lib/data_models/product_image_data.dart @@ -2,11 +2,13 @@ import 'package:openfoodfacts/openfoodfacts.dart'; class ProductImageData { const ProductImageData({ + required this.imageId, required this.imageField, required this.imageUrl, required this.language, }); + final String? imageId; final ImageField imageField; final String? imageUrl; final OpenFoodFactsLanguage? language; diff --git a/packages/smooth_app/lib/database/transient_file.dart b/packages/smooth_app/lib/database/transient_file.dart index dedaa7436d8..90714684c12 100644 --- a/packages/smooth_app/lib/database/transient_file.dart +++ b/packages/smooth_app/lib/database/transient_file.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:openfoodfacts/openfoodfacts.dart'; import 'package:smooth_app/data_models/product_image_data.dart'; @@ -11,34 +12,48 @@ class TransientFile { TransientFile( this.imageField, this.barcode, - this.language, - ) : url = null; + this.language, [ + this.uploadedDate, + ]) : url = null; TransientFile.fromProductImageData( final ProductImageData productImageData, this.barcode, - this.language, - ) : imageField = productImageData.imageField, + this.language, [ + this.uploadedDate, + ]) : imageField = productImageData.imageField, url = productImageData.imageUrl; - TransientFile.fromProduct( + factory TransientFile.fromProduct( final Product product, final ImageField imageField, final OpenFoodFactsLanguage language, - ) : this.fromProductImageData( - getProductImageData( - product, - imageField, - language, - ), - product.barcode!, - language, - ); + ) { + final ProductImageData productImageData = getProductImageData( + product, + imageField, + language, + ); + + return TransientFile.fromProductImageData( + productImageData, + product.barcode!, + language, + product + .getRawImages() + ?.firstWhereOrNull( + (final ProductImage productImage) => + productImage.imgid == productImageData.imageId, + ) + ?.uploaded, + ); + } final ImageField imageField; final String barcode; final OpenFoodFactsLanguage language; final String? url; + final DateTime? uploadedDate; /// {File "key": file path} map. static final Map _transientFiles = {}; diff --git a/packages/smooth_app/lib/helpers/product_cards_helper.dart b/packages/smooth_app/lib/helpers/product_cards_helper.dart index cf8553433f3..c229ad58177 100644 --- a/packages/smooth_app/lib/helpers/product_cards_helper.dart +++ b/packages/smooth_app/lib/helpers/product_cards_helper.dart @@ -266,6 +266,7 @@ ProductImageData getProductImageData( if (productImage != null) { // we found a localized version for this image return ProductImageData( + imageId: productImage.imgid, imageField: imageField, imageUrl: productImage.getUrl( product.barcode!, @@ -281,6 +282,7 @@ ProductImageData getProductImageData( ProductImageData getEmptyProductImageData(final ImageField imageField) => ProductImageData( imageField: imageField, + imageId: null, imageUrl: null, language: null, ); diff --git a/packages/smooth_app/lib/l10n/app_en.arb b/packages/smooth_app/lib/l10n/app_en.arb index 01a2f992a77..fac43512480 100644 --- a/packages/smooth_app/lib/l10n/app_en.arb +++ b/packages/smooth_app/lib/l10n/app_en.arb @@ -514,6 +514,13 @@ "@front_photo": { "description": "Button label: For adding a picture of the front of a product" }, + "outdated_image_accessibility_label": "{imageType} (this image may be outdated)", + "@outdated_image_accessibility_label": { + "description": "Accessibility label for images that are outdated (image type may be front/ingredients/nutrition…)", + "placeholders": { + "imageType": {} + } + }, "ingredients": "Ingredients", "@ingredients": {}, "ingredients_editing_instructions": "Keep the original order. Indicate the percentage when specified. Separate with a comma or hyphen, use parentheses for ingredients of an ingredient, and indicate allergens between underscores.", diff --git a/packages/smooth_app/lib/pages/image/product_image_helper.dart b/packages/smooth_app/lib/pages/image/product_image_helper.dart new file mode 100644 index 00000000000..6ef986950f0 --- /dev/null +++ b/packages/smooth_app/lib/pages/image/product_image_helper.dart @@ -0,0 +1,23 @@ +import 'package:openfoodfacts/openfoodfacts.dart'; +import 'package:smooth_app/database/transient_file.dart'; + +class _ProductImageHelper { + const _ProductImageHelper._(); + + /// An image is considered outdated/expired after 1 year. + /// Note: the value will be sent in the future by the backend. + static bool isExpired(final DateTime? uploadedDate) { + if (uploadedDate == null) { + return false; + } + return DateTime.now().difference(uploadedDate).inDays > 365; + } +} + +extension ProductImageExtension on ProductImage { + bool get expired => _ProductImageHelper.isExpired(uploaded); +} + +extension TransientFileExtension on TransientFile { + bool get expired => _ProductImageHelper.isExpired(uploadedDate); +} diff --git a/packages/smooth_app/lib/pages/image/product_image_widget.dart b/packages/smooth_app/lib/pages/image/product_image_widget.dart index 50dd84ded55..7393a6bd841 100644 --- a/packages/smooth_app/lib/pages/image/product_image_widget.dart +++ b/packages/smooth_app/lib/pages/image/product_image_widget.dart @@ -6,8 +6,9 @@ import 'package:openfoodfacts/openfoodfacts.dart'; import 'package:smooth_app/generic_lib/design_constants.dart'; import 'package:smooth_app/generic_lib/widgets/images/smooth_image.dart'; import 'package:smooth_app/generic_lib/widgets/smooth_card.dart'; +import 'package:smooth_app/pages/image/product_image_helper.dart'; import 'package:smooth_app/query/product_query.dart'; -import 'package:smooth_app/resources/app_icons.dart'; +import 'package:smooth_app/resources/app_icons.dart' as icons; import 'package:smooth_app/themes/smooth_theme_colors.dart'; /// Displays a product image thumbnail with the upload date on top. @@ -52,7 +53,7 @@ class ProductImageWidget extends StatelessWidget { if (uploaded == null) { return image; } - final bool expired = DateTime.now().difference(uploaded).inDays > 365; + final bool expired = productImage.expired; final String date = dateFormat.format(uploaded); return Semantics( @@ -94,7 +95,7 @@ class ProductImageWidget extends StatelessWidget { end: 0.0, height: 20.0, textDirection: Directionality.of(context), - child: Outdated( + child: icons.Outdated( size: 18.0, color: colors.red, ), 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 26197d46234..c517696c74e 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 @@ -13,11 +13,13 @@ import 'package:smooth_app/helpers/analytics_helper.dart'; import 'package:smooth_app/helpers/image_field_extension.dart'; import 'package:smooth_app/helpers/product_cards_helper.dart'; import 'package:smooth_app/pages/image/product_image_gallery_other_view.dart'; +import 'package:smooth_app/pages/image/product_image_helper.dart'; import 'package:smooth_app/pages/image_crop_page.dart'; import 'package:smooth_app/pages/product/common/product_refresher.dart'; import 'package:smooth_app/pages/product/product_image_swipeable_view.dart'; import 'package:smooth_app/query/product_query.dart'; import 'package:smooth_app/resources/app_animations.dart'; +import 'package:smooth_app/resources/app_icons.dart' as icons; import 'package:smooth_app/widgets/slivers.dart'; import 'package:smooth_app/widgets/smooth_scaffold.dart'; @@ -193,50 +195,72 @@ class _PhotoRow extends StatelessWidget { final ImageField imageField = _getImageField(position); final TransientFile transientFile = _getTransientFile(imageField); - return Padding( - padding: const EdgeInsets.only( - top: SMALL_SPACE, - ), - child: InkWell( - onTap: () => _openImage( - context: context, - initialImageIndex: position, + final bool expired = transientFile.expired; + + final AppLocalizations appLocalizations = AppLocalizations.of(context); + final String label = imageField.getProductImageTitle(appLocalizations); + + return Semantics( + image: true, + button: true, + label: expired + ? appLocalizations.product_image_outdated_accessibility_label(label) + : label, + excludeSemantics: true, + child: Padding( + padding: const EdgeInsets.only( + top: SMALL_SPACE, ), - child: Column( - children: [ - Stack( - children: [ - AspectRatio( - aspectRatio: 1.0, - child: SmoothImage( - rounded: false, - imageProvider: transientFile.getImageProvider(), - ), - ), - if (transientFile.isImageAvailable() && - !transientFile.isServerImage()) - Positioned.directional( - textDirection: Directionality.of(context), - bottom: VERY_SMALL_SPACE, - end: VERY_SMALL_SPACE, - child: const CloudUploadAnimation.circle(size: 30.0), + child: InkWell( + onTap: () => _openImage( + context: context, + initialImageIndex: position, + ), + child: Column( + children: [ + Stack( + children: [ + AspectRatio( + aspectRatio: 1.0, + child: SmoothImage( + rounded: false, + imageProvider: transientFile.getImageProvider(), + ), ), - ], - ), - Expanded( - child: Center( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - imageField - .getProductImageTitle(AppLocalizations.of(context)), - style: Theme.of(context).textTheme.headlineMedium, - textAlign: TextAlign.center, + if (transientFile.isImageAvailable() && + !transientFile.isServerImage()) + const Center( + child: CloudUploadAnimation.circle(size: 30.0), + ), + if (expired) + Positioned.directional( + textDirection: Directionality.of(context), + bottom: VERY_SMALL_SPACE, + end: VERY_SMALL_SPACE, + child: const icons.Outdated( + color: Colors.black87, + shadow: Shadow( + color: Colors.white38, + blurRadius: 2.0, + ), + ), + ), + ], + ), + Expanded( + child: Center( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + label, + style: Theme.of(context).textTheme.headlineMedium, + textAlign: TextAlign.center, + ), ), ), ), - ), - ], + ], + ), ), ), ); @@ -261,9 +285,9 @@ class _PhotoRow extends StatelessWidget { TransientFile _getTransientFile( final ImageField imageField, ) => - TransientFile.fromProductImageData( - getProductImageData(product, imageField, language), - product.barcode!, + TransientFile.fromProduct( + product, + imageField, language, ); From 71ccd1f3e44601fe0a1f69682315280bd67e212e Mon Sep 17 00:00:00 2001 From: Edouard Marquez Date: Tue, 23 Jul 2024 09:53:54 +0200 Subject: [PATCH 04/24] Migrate actions to Java 17 (#5500) --- .github/workflows/postsubmit.yml | 2 +- .github/workflows/waldo_sessions.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/postsubmit.yml b/.github/workflows/postsubmit.yml index 6c1dced4743..3ba797c1cda 100644 --- a/.github/workflows/postsubmit.yml +++ b/.github/workflows/postsubmit.yml @@ -19,7 +19,7 @@ jobs: uses: actions/setup-java@v4.2.1 with: distribution: 'zulu' - java-version: 11 + java-version: 17 # Get the flutter version from ./flutter-version.txt - run: echo "FLUTTER_VERSION=$(cat flutter-version.txt)" >> $GITHUB_OUTPUT diff --git a/.github/workflows/waldo_sessions.yml b/.github/workflows/waldo_sessions.yml index 0a0a7cadb07..d6765be39df 100644 --- a/.github/workflows/waldo_sessions.yml +++ b/.github/workflows/waldo_sessions.yml @@ -30,7 +30,7 @@ jobs: uses: actions/setup-java@v4.2.1 with: distribution: 'zulu' - java-version: 11 + java-version: 17 # Get the flutter version from ./flutter-version.txt - run: echo "FLUTTER_VERSION=$(cat flutter-version.txt)" >> $GITHUB_OUTPUT From 9cbcf75d5ddc27e4237fb7cf44dc008c2c85ed42 Mon Sep 17 00:00:00 2001 From: Edouard Marquez Date: Tue, 23 Jul 2024 09:54:25 +0200 Subject: [PATCH 05/24] feat: Disallow emojis on brand name (#5461) * Disallow emojis on brand name * Fix Lint warning --- .../lib/generic_lib/widgets/smooth_text_form_field.dart | 8 ++++++++ packages/smooth_app/lib/helpers/strings_helper.dart | 4 ++++ .../lib/pages/input/smooth_autocomplete_text_field.dart | 8 ++++++++ .../lib/pages/product/add_basic_details_page.dart | 1 + 4 files changed, 21 insertions(+) diff --git a/packages/smooth_app/lib/generic_lib/widgets/smooth_text_form_field.dart b/packages/smooth_app/lib/generic_lib/widgets/smooth_text_form_field.dart index ce4d0fc6166..0c2acb0bb9e 100644 --- a/packages/smooth_app/lib/generic_lib/widgets/smooth_text_form_field.dart +++ b/packages/smooth_app/lib/generic_lib/widgets/smooth_text_form_field.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:smooth_app/generic_lib/design_constants.dart'; +import 'package:smooth_app/helpers/strings_helper.dart'; enum TextFieldTypes { PLAIN_TEXT, @@ -25,6 +27,7 @@ class SmoothTextFormField extends StatefulWidget { this.autofocus, this.focusNode, this.spellCheckConfiguration, + this.allowEmojis = true, }); final TextFieldTypes type; @@ -42,6 +45,7 @@ class SmoothTextFormField extends StatefulWidget { final bool? autofocus; final FocusNode? focusNode; final SpellCheckConfiguration? spellCheckConfiguration; + final bool allowEmojis; @override State createState() => _SmoothTextFormFieldState(); @@ -90,6 +94,10 @@ class _SmoothTextFormFieldState extends State { onFieldSubmitted: widget.onFieldSubmitted, style: TextStyle(fontSize: textSize), cursorHeight: textSize * (textStyle.height ?? 1.4), + inputFormatters: [ + if (!widget.allowEmojis) + FilteringTextInputFormatter.deny(TextHelper.emojiRegex), + ], decoration: InputDecoration( contentPadding: const EdgeInsets.symmetric( horizontal: LARGE_SPACE, diff --git a/packages/smooth_app/lib/helpers/strings_helper.dart b/packages/smooth_app/lib/helpers/strings_helper.dart index 055db2cb4db..2d84a6827e8 100644 --- a/packages/smooth_app/lib/helpers/strings_helper.dart +++ b/packages/smooth_app/lib/helpers/strings_helper.dart @@ -48,6 +48,10 @@ extension StringExtensions on String { class TextHelper { const TextHelper._(); + /// From [https://github.com/duocnguyen6799/remove_emoji_input_formatter/blob/main/lib/src/constant.dart] + static final RegExp emojiRegex = RegExp( + '/\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62(?:\uDB40\uDC77\uDB40\uDC6C\uDB40\uDC73|\uDB40\uDC73\uDB40\uDC63\uDB40\uDC74|\uDB40\uDC65\uDB40\uDC6E\uDB40\uDC67)\uDB40\uDC7F|(?:\uD83E\uDDD1\uD83C\uDFFF\u200D\u2764(?:\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?|\u200D(?:\uD83D\uDC8B\u200D)?)\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69])|\uD83E\uDEF1\uD83C\uDFFF\u200D\uD83E\uDEF2)(?:\uD83C[\uDFFB-\uDFFE])|(?:\uD83E\uDDD1\uD83C\uDFFE\u200D\u2764(?:\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?|\u200D(?:\uD83D\uDC8B\u200D)?)\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69])|\uD83E\uDEF1\uD83C\uDFFE\u200D\uD83E\uDEF2)(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFD\u200D\u2764(?:\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?|\u200D(?:\uD83D\uDC8B\u200D)?)\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69])|\uD83E\uDEF1\uD83C\uDFFD\u200D\uD83E\uDEF2)(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFC\u200D\u2764(?:\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?|\u200D(?:\uD83D\uDC8B\u200D)?)\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69])|\uD83E\uDEF1\uD83C\uDFFC\u200D\uD83E\uDEF2)(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFB\u200D\u2764(?:\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?|\u200D(?:\uD83D\uDC8B\u200D)?)\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69])|\uD83E\uDEF1\uD83C\uDFFB\u200D\uD83E\uDEF2)(?:\uD83C[\uDFFC-\uDFFF])|\uD83D\uDC68(?:\uD83C\uDFFB(?:\u200D(?:\u2764(?:\uFE0F\u200D(?:\uD83D\uDC8B\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF]))|\u200D(?:\uD83D\uDC8B\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF])))|\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFC-\uDFFF])|[\u2695\u2696\u2708]\uFE0F|[\u2695\u2696\u2708]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))?|(?:\uD83C[\uDFFC-\uDFFF])\u200D\u2764(?:\uFE0F\u200D(?:\uD83D\uDC8B\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF]))|\u200D(?:\uD83D\uDC8B\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF])))|\u200D(?:\u2764(?:\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?|\u200D(?:\uD83D\uDC8B\u200D)?)\uD83D\uDC68|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFE])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])\uFE0F|\u200D(?:(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D[\uDC66\uDC67])|\uD83D[\uDC66\uDC67])|\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC|\u200D[\u2695\u2696\u2708])?|(?:\uD83D\uDC69(?:\uD83C\uDFFB\u200D\u2764(?:\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69]))|(?:\uD83C[\uDFFC-\uDFFF])\u200D\u2764(?:\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])))|\uD83E\uDDD1(?:\uD83C[\uDFFB-\uDFFF])\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1)(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC69(?:\u200D(?:\u2764(?:\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69]))|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83E\uDDD1(?:\u200D(?:\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D[\uDC66\uDC67])|\uD83D\uDC69\u200D\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|(?:\uD83D\uDC41\uFE0F?\u200D\uD83D\uDDE8|\uD83E\uDDD1(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|\uD83D\uDC69(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|\uD83D\uDE36\u200D\uD83C\uDF2B|\uD83C\uDFF3\uFE0F?\u200D\u26A7|\uD83D\uDC3B\u200D\u2744|(?:(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC6F|\uD83E[\uDDDE\uDDDF])\u200D[\u2640\u2642]|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642]|\u200D[\u2640\u2642])|\uD83C\uDFF4\u200D\u2620|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3C-\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])\u200D[\u2640\u2642]|[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23ED-\u23EF\u23F1\u23F2\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692\u2694-\u2697\u2699\u269B\u269C\u26A0\u26A7\u26AA\u26B0\u26B1\u26BD\u26BE\u26C4\u26C8\u26CF\u26D1\u26D3\u26E9\u26F0-\u26F5\u26F7\u26F8\u26FA\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D\u2721\u2733\u2734\u2744\u2747\u2757\u2763\u27A1\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDD70\uDD71\uDD7E\uDD7F\uDE02\uDE37\uDF21\uDF24-\uDF2C\uDF36\uDF7D\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F\uDFCD\uDFCE\uDFD4-\uDFDF\uDFF5\uDFF7]|\uD83D[\uDC3F\uDCFD\uDD49\uDD4A\uDD6F\uDD70\uDD73\uDD76-\uDD79\uDD87\uDD8A-\uDD8D\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA\uDECB\uDECD-\uDECF\uDEE0-\uDEE5\uDEE9\uDEF0\uDEF3])\uFE0F|\uD83D\uDC41\uFE0F?\u200D\uD83D\uDDE8|\uD83E\uDDD1(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|\uD83D\uDC69(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|\uD83C\uDFF3\uFE0F?\u200D\uD83C\uDF08|\uD83D\uDC69\u200D\uD83D\uDC67|\uD83D\uDC69\u200D\uD83D\uDC66|\uD83D\uDE36\u200D\uD83C\uDF2B|\uD83C\uDFF3\uFE0F?\u200D\u26A7|\uD83D\uDE35\u200D\uD83D\uDCAB|\uD83D\uDE2E\u200D\uD83D\uDCA8|\uD83D\uDC15\u200D\uD83E\uDDBA|\uD83E\uDEF1(?:\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC|\uD83C\uDFFB)?|\uD83E\uDDD1(?:\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC|\uD83C\uDFFB)?|\uD83D\uDC69(?:\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC|\uD83C\uDFFB)?|\uD83D\uDC3B\u200D\u2744|(?:(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC6F|\uD83E[\uDDDE\uDDDF])\u200D[\u2640\u2642]|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642]|\u200D[\u2640\u2642])|\uD83C\uDFF4\u200D\u2620|\uD83C\uDDFD\uD83C\uDDF0|\uD83C\uDDF6\uD83C\uDDE6|\uD83C\uDDF4\uD83C\uDDF2|\uD83D\uDC08\u200D\u2B1B|\u2764(?:\uFE0F\u200D(?:\uD83D\uDD25|\uD83E\uDE79)|\u200D(?:\uD83D\uDD25|\uD83E\uDE79))|\uD83D\uDC41\uFE0F?|\uD83C\uDFF3\uFE0F?|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3C-\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])\u200D[\u2640\u2642]|\uD83C\uDDFF(?:\uD83C[\uDDE6\uDDF2\uDDFC])|\uD83C\uDDFE(?:\uD83C[\uDDEA\uDDF9])|\uD83C\uDDFC(?:\uD83C[\uDDEB\uDDF8])|\uD83C\uDDFB(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA])|\uD83C\uDDFA(?:\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF])|\uD83C\uDDF9(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF])|\uD83C\uDDF8(?:\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF])|\uD83C\uDDF7(?:\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC])|\uD83C\uDDF5(?:\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE])|\uD83C\uDDF3(?:\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF])|\uD83C\uDDF2(?:\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF])|\uD83C\uDDF1(?:\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE])|\uD83C\uDDF0(?:\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF])|\uD83C\uDDEF(?:\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5])|\uD83C\uDDEE(?:\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9])|\uD83C\uDDED(?:\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA])|\uD83C\uDDEC(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE])|\uD83C\uDDEB(?:\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7])|\uD83C\uDDEA(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA])|\uD83C\uDDE9(?:\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF])|\uD83C\uDDE8(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF])|\uD83C\uDDE7(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF])|\uD83C\uDDE6(?:\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF])|[#*0-9]\uFE0F?\u20E3|\uD83E\uDD3C(?:\uD83C[\uDFFB-\uDFFF])|\u2764\uFE0F?|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?|\uD83C\uDFF4|(?:[\u270A\u270B]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5\uDEC3-\uDEC5\uDEF0\uDEF2-\uDEF6])(?:\uD83C[\uDFFB-\uDFFF])|(?:[\u261D\u270C\u270D]|\uD83D[\uDD74\uDD90])(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])|[\u261D\u270A-\u270D]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC08\uDC15\uDC3B\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD74\uDD7A\uDD90\uDD95\uDD96\uDE2E\uDE35\uDE36\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1F\uDD30-\uDD34\uDD36\uDD3C\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5\uDEC3-\uDEC5\uDEF0\uDEF2-\uDEF6]|\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD]|\uD83D\uDC6F|\uD83E[\uDDDE\uDDDF]|[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23ED-\u23EF\u23F1\u23F2\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692\u2694-\u2697\u2699\u269B\u269C\u26A0\u26A7\u26AA\u26B0\u26B1\u26BD\u26BE\u26C4\u26C8\u26CF\u26D1\u26D3\u26E9\u26F0-\u26F5\u26F7\u26F8\u26FA\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D\u2721\u2733\u2734\u2744\u2747\u2757\u2763\u27A1\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDD70\uDD71\uDD7E\uDD7F\uDE02\uDE37\uDF21\uDF24-\uDF2C\uDF36\uDF7D\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F\uDFCD\uDFCE\uDFD4-\uDFDF\uDFF5\uDFF7]|\uD83D[\uDC3F\uDCFD\uDD49\uDD4A\uDD6F\uDD70\uDD73\uDD76-\uDD79\uDD87\uDD8A-\uDD8D\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA\uDECB\uDECD-\uDECF\uDEE0-\uDEE5\uDEE9\uDEF0\uDEF3]|[\u23E9-\u23EC\u23F0\u23F3\u25FD\u2693\u26A1\u26AB\u26C5\u26CE\u26D4\u26EA\u26FD\u2705\u2728\u274C\u274E\u2753-\u2755\u2795-\u2797\u27B0\u27BF\u2B50]|\uD83C[\uDCCF\uDD8E\uDD91-\uDD9A\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF84\uDF86-\uDF93\uDFA0-\uDFC1\uDFC5\uDFC6\uDFC8\uDFC9\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC07\uDC09-\uDC14\uDC16-\uDC3A\uDC3C-\uDC3E\uDC40\uDC44\uDC45\uDC51-\uDC65\uDC6A\uDC79-\uDC7B\uDC7D-\uDC80\uDC84\uDC88-\uDC8E\uDC90\uDC92-\uDCA9\uDCAB-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDDA4\uDDFB-\uDE2D\uDE2F-\uDE34\uDE37-\uDE44\uDE48-\uDE4A\uDE80-\uDEA2\uDEA4-\uDEB3\uDEB7-\uDEBF\uDEC1-\uDEC5\uDED0-\uDED2\uDED5-\uDED7\uDEDD-\uDEDF\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB\uDFF0]|\uD83E[\uDD0D\uDD0E\uDD10-\uDD17\uDD20-\uDD25\uDD27-\uDD2F\uDD3A\uDD3F-\uDD45\uDD47-\uDD76\uDD78-\uDDB4\uDDB7\uDDBA\uDDBC-\uDDCC\uDDD0\uDDE0-\uDDFF\uDE70-\uDE74\uDE78-\uDE7C\uDE80-\uDE86\uDE90-\uDEAC\uDEB0-\uDEBA\uDEC0-\uDEC2\uDED0-\uDED9\uDEE0-\uDEE7]'); + /// Split the text into parts. /// Eg: with the symbol '*' /// 'Hello *world*!' => [('Hello ', defaultStyle), ('world', highlightedStyle), ('!', defaultStyle)] diff --git a/packages/smooth_app/lib/pages/input/smooth_autocomplete_text_field.dart b/packages/smooth_app/lib/pages/input/smooth_autocomplete_text_field.dart index 251643e6c2c..478bd00201f 100644 --- a/packages/smooth_app/lib/pages/input/smooth_autocomplete_text_field.dart +++ b/packages/smooth_app/lib/pages/input/smooth_autocomplete_text_field.dart @@ -2,8 +2,10 @@ import 'dart:async'; import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:openfoodfacts/openfoodfacts.dart'; import 'package:smooth_app/generic_lib/design_constants.dart'; +import 'package:smooth_app/helpers/strings_helper.dart'; import 'package:smooth_app/pages/product/autocomplete.dart'; /// Autocomplete text field. @@ -16,6 +18,7 @@ class SmoothAutocompleteTextField extends StatefulWidget { required this.constraints, required this.manager, this.minLengthForSuggestions = 1, + this.allowEmojis = true, }); final FocusNode focusNode; @@ -25,6 +28,7 @@ class SmoothAutocompleteTextField extends StatefulWidget { final BoxConstraints constraints; final int minLengthForSuggestions; final AutocompleteManager? manager; + final bool allowEmojis; @override State createState() => @@ -73,6 +77,10 @@ class _SmoothAutocompleteTextFieldState TextField( controller: widget.controller, onChanged: (_) => setState(() => _selectedSearch = null), + inputFormatters: [ + if (!widget.allowEmojis) + FilteringTextInputFormatter.deny(TextHelper.emojiRegex), + ], decoration: InputDecoration( filled: true, border: const OutlineInputBorder( 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 c59d5fdd03d..75480b7b753 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 @@ -194,6 +194,7 @@ class _AddBasicDetailsPageState extends State { focusNode: _focusNode, controller: _brandNameController, autocompleteKey: _autocompleteKey, + allowEmojis: false, hintText: appLocalizations.brand_name, constraints: constraints, manager: AutocompleteManager( From fe0313910b2149fd1e9e323929ca0c1bc5a90a64 Mon Sep 17 00:00:00 2001 From: Edouard Marquez Date: Tue, 23 Jul 2024 09:54:45 +0200 Subject: [PATCH 06/24] chore: Upgrade dependencies (#5490) * Upgrade dependencies * Downgrade audioplayers * Remove Lint warning * Bring back pupspec.lock * Also bring devtools_options.yaml --- packages/app_store/uri_store/pubspec.yaml | 2 +- packages/smooth_app/devtools_options.yaml | 3 + .../smooth_app/lib/query/product_query.dart | 2 +- packages/smooth_app/pubspec.lock | 112 +++++++++--------- packages/smooth_app/pubspec.yaml | 22 ++-- 5 files changed, 72 insertions(+), 69 deletions(-) create mode 100644 packages/smooth_app/devtools_options.yaml diff --git a/packages/app_store/uri_store/pubspec.yaml b/packages/app_store/uri_store/pubspec.yaml index 1e661bdb92a..ef0e35cefff 100644 --- a/packages/app_store/uri_store/pubspec.yaml +++ b/packages/app_store/uri_store/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: app_store_shared: path: ../shared - url_launcher: 6.1.3 + url_launcher: 6.3.0 dev_dependencies: flutter_test: diff --git a/packages/smooth_app/devtools_options.yaml b/packages/smooth_app/devtools_options.yaml new file mode 100644 index 00000000000..fa0b357c4f4 --- /dev/null +++ b/packages/smooth_app/devtools_options.yaml @@ -0,0 +1,3 @@ +description: This file stores settings for Dart & Flutter DevTools. +documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states +extensions: diff --git a/packages/smooth_app/lib/query/product_query.dart b/packages/smooth_app/lib/query/product_query.dart index 49bc51770d4..4f636f519bd 100644 --- a/packages/smooth_app/lib/query/product_query.dart +++ b/packages/smooth_app/lib/query/product_query.dart @@ -145,7 +145,7 @@ abstract class ProductQuery { } OpenFoodAPIConfiguration.uuid = uuid; await Sentry.configureScope((Scope scope) { - scope.setExtra('uuid', OpenFoodAPIConfiguration.uuid); + scope.contexts['uuid'] = OpenFoodAPIConfiguration.uuid; scope.setUser(SentryUser(username: OpenFoodAPIConfiguration.uuid)); }); } diff --git a/packages/smooth_app/pubspec.lock b/packages/smooth_app/pubspec.lock index 4eb4e3e3ea6..31d9c599402 100644 --- a/packages/smooth_app/pubspec.lock +++ b/packages/smooth_app/pubspec.lock @@ -209,34 +209,34 @@ packages: dependency: transitive description: name: camera_android - sha256: b350ac087f111467e705b2b76cc1322f7f5bdc122aa83b4b243b0872f390d229 + sha256: eacc70b6c81fa5e17921302fc17a1ae5983d94ce1d76c71e4869abdc615d35d2 url: "https://pub.dev" source: hosted - version: "0.10.9+2" + version: "0.10.9+8" camera_avfoundation: dependency: transitive description: name: camera_avfoundation - sha256: "7d021e8cd30d9b71b8b92b4ad669e80af432d722d18d6aac338572754a786c15" + sha256: b5093a82537b64bb88d4244f8e00b5ba69e822a5994f47b31d11400e1db975e5 url: "https://pub.dev" source: hosted - version: "0.9.16" + version: "0.9.17+1" camera_platform_interface: dependency: transitive description: name: camera_platform_interface - sha256: a250314a48ea337b35909a4c9d5416a208d736dcb01d0b02c6af122be66660b0 + sha256: b3ede1f171532e0d83111fe0980b46d17f1aa9788a07a2fbed07366bbdbb9061 url: "https://pub.dev" source: hosted - version: "2.7.4" + version: "2.8.0" camera_web: dependency: transitive description: name: camera_web - sha256: "9e9aba2fbab77ce2472924196ff8ac4dd8f9126c4f9a3096171cd1d870d6b26c" + sha256: b9235ec0a2ce949daec546f1f3d86f05c3921ed31c7d9ab6b7c03214d152fc2d url: "https://pub.dev" source: hosted - version: "0.3.3" + version: "0.3.4" carousel_slider: dependency: "direct main" description: @@ -417,10 +417,10 @@ packages: dependency: "direct main" description: name: email_validator - sha256: e9a90f27ab2b915a27d7f9c2a7ddda5dd752d6942616ee83529b686fc086221b + sha256: b19aa5d92fdd76fbc65112060c94d45ba855105a28bb6e462de7ff03b12fa1fb url: "https://pub.dev" source: hosted - version: "2.1.17" + version: "3.0.0" fake_async: dependency: transitive description: @@ -571,10 +571,10 @@ packages: dependency: "direct main" description: name: flutter_image_compress - sha256: "4edadb0ca2f957b85190e9c3aa728569b91b64b6e06e0eec5b622d47a8692ab2" + sha256: "45a3071868092a61b11044c70422b04d39d4d9f2ef536f3c5b11fb65a1e7dd90" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.3.0" flutter_image_compress_common: dependency: transitive description: @@ -648,18 +648,18 @@ packages: dependency: "direct main" description: name: flutter_native_splash - sha256: edf39bcf4d74aca1eb2c1e43c3e445fd9f494013df7f0da752fefe72020eedc0 + sha256: aa06fec78de2190f3db4319dd60fdc8d12b2626e93ef9828633928c2dcaea840 url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.1" flutter_plugin_android_lifecycle: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: "8cf40eebf5dec866a6d1956ad7b4f7016e6c0cc69847ab946833b7d43743809f" + sha256: c6b0b4c05c458e1c01ad9bcc14041dd7b1f6783d487be4386f793f47a8a4d03e url: "https://pub.dev" source: hosted - version: "2.0.19" + version: "2.0.20" flutter_secure_storage: dependency: "direct main" description: @@ -730,10 +730,10 @@ packages: dependency: "direct main" description: name: flutter_widget_from_html_core - sha256: e8f4f8b461a140ffb7c71f938bc76efc758893e7468843d9dbf70cb0b9e900cb + sha256: "23c72f8ce7ba1fd6f8fbdc107f07e04fe152ffd587be1b012938904bfda31950" url: "https://pub.dev" source: hosted - version: "0.8.5+3" + version: "0.8.3+1" fuchsia_remote_debug_protocol: dependency: transitive description: flutter @@ -767,18 +767,18 @@ packages: dependency: "direct main" description: name: go_router - sha256: c247a4f76071c3b97bb5ae8912968870d5565644801c5e09f3bc961b4d874895 + sha256: "39dd52168d6c59984454183148dc3a5776960c61083adfc708cc79a7b3ce1ba8" url: "https://pub.dev" source: hosted - version: "12.1.1" + version: "14.2.1" graphs: dependency: transitive description: name: graphs - sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 + sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" hive: dependency: "direct main" description: @@ -823,26 +823,26 @@ packages: dependency: "direct main" description: name: image - sha256: "4c68bfd5ae83e700b5204c1e74451e7bf3cf750e6843c6e158289cf56bda018e" + sha256: "2237616a36c0d69aef7549ab439b833fb7f9fb9fc861af2cc9ac3eedddd69ca8" url: "https://pub.dev" source: hosted - version: "4.1.7" + version: "4.2.0" image_picker: dependency: "direct main" description: name: image_picker - sha256: "33974eca2e87e8b4e3727f1b94fa3abcb25afe80b6bc2c4d449a0e150aedf720" + sha256: "021834d9c0c3de46bf0fe40341fa07168407f694d9b2bb18d532dc1261867f7a" url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" image_picker_android: dependency: transitive description: name: image_picker_android - sha256: "0f57fee1e8bfadf8cc41818bbcd7f72e53bb768a54d9496355d5e8a5681a19f1" + sha256: cea2bd5b9fcff039a4901d3b13c67fe747f940be9ba76bde1bcd218d168eeb7f url: "https://pub.dev" source: hosted - version: "0.8.12+1" + version: "0.8.12+6" image_picker_for_web: dependency: transitive description: @@ -996,10 +996,10 @@ packages: dependency: transitive description: name: logger - sha256: af05cc8714f356fd1f3888fb6741cbe9fbe25cdb6eedbab80e1a6db21047d4a4 + sha256: "697d067c60c20999686a0add96cf6aba723b3aa1f83ecf806a8097231529ec32" url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.4.0" logging: dependency: transitive description: @@ -1157,10 +1157,10 @@ packages: dependency: transitive description: name: path_provider_android - sha256: a248d8146ee5983446bf03ed5ea8f6533129a12b11f12057ad1b4a67a2b3b41d + sha256: "30c5aa827a6ae95ce2853cdc5fe3971daaac00f6f081c419c013f7f57bff2f5e" url: "https://pub.dev" source: hosted - version: "2.2.4" + version: "2.2.7" path_provider_foundation: dependency: transitive description: @@ -1189,10 +1189,10 @@ packages: dependency: transitive description: name: path_provider_windows - sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.3.0" permission_handler: dependency: "direct main" description: @@ -1317,10 +1317,10 @@ packages: dependency: transitive description: name: qr - sha256: "64957a3930367bf97cc211a5af99551d630f2f4625e38af10edd6b19131b64b3" + sha256: "5a1d2586170e172b8a8c8470bbbffd5eb0cd38a66c0d77155ea138d3af3a4445" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" qr_code_scanner: dependency: transitive description: @@ -1370,18 +1370,18 @@ packages: dependency: transitive description: name: sentry - sha256: "7342ef4c18932881730ac941a07a6e4cf76fe99cd1ea3bef06e53a6a1402dec0" + sha256: cbc29cbdd8a047aab3df42f826daf07e58dfb2e1d550895d1021a6d4e618b00d url: "https://pub.dev" source: hosted - version: "8.3.0" + version: "8.4.0" sentry_flutter: dependency: "direct main" description: name: sentry_flutter - sha256: "475cf49682e4d1eb48caa2577502721bcfdcbb63f215de57b3b246d52f4f7914" + sha256: "96ce085e1be6c9963d93d42d6ba5c67484c076c59d25c94a7ba906549dc6c635" url: "https://pub.dev" source: hosted - version: "8.3.0" + version: "8.4.0" share_plus: dependency: "direct main" description: @@ -1410,10 +1410,10 @@ packages: dependency: transitive description: name: shared_preferences_android - sha256: "1ee8bf911094a1b592de7ab29add6f826a7331fb854273d55918693d5364a1f2" + sha256: "93d0ec9dd902d85f326068e6a899487d1f65ffcd5798721a95330b26c8131577" url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "2.2.3" shared_preferences_foundation: dependency: transitive description: @@ -1434,10 +1434,10 @@ packages: dependency: transitive description: name: shared_preferences_platform_interface - sha256: "22e2ecac9419b4246d7c22bfbbda589e3acf5c0351137d87dd2939d984d37c3b" + sha256: "034650b71e73629ca08a0bd789fd1d83cc63c2d1e405946f7cef7bc37432f93a" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.4.0" shared_preferences_web: dependency: transitive description: @@ -1615,26 +1615,26 @@ packages: dependency: "direct main" description: name: url_launcher - sha256: f118f30f4301453d155c236a17d9ba53ec02a342591290aff91ae0fda4dc5428 + sha256: "21b704ce5fa560ea9f3b525b43601c678728ba46725bab9b01187b4831377ed3" url: "https://pub.dev" source: hosted - version: "6.1.3" + version: "6.3.0" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: "17cd5e205ea615e2c6ea7a77323a11712dffa0720a8a90540db57a01347f9ad9" + sha256: "95d8027db36a0e52caf55680f91e33ea6aa12a3ce608c90b06f4e429a21067ac" url: "https://pub.dev" source: hosted - version: "6.3.2" + version: "6.3.5" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: "7068716403343f6ba4969b4173cbf3b84fc768042124bc2c011e5d782b24fe89" + sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e url: "https://pub.dev" source: hosted - version: "6.3.0" + version: "6.3.1" url_launcher_linux: dependency: transitive description: @@ -1759,10 +1759,10 @@ packages: dependency: "direct main" description: name: webview_flutter - sha256: "25e1b6e839e8cbfbd708abc6f85ed09d1727e24e08e08c6b8590d7c65c9a8932" + sha256: "6869c8786d179f929144b4a1f86e09ac0eddfe475984951ea6c634774c16b522" url: "https://pub.dev" source: hosted - version: "4.7.0" + version: "4.8.0" webview_flutter_android: dependency: "direct main" description: @@ -1783,18 +1783,18 @@ packages: dependency: "direct main" description: name: webview_flutter_wkwebview - sha256: f12f8d8a99784b863e8b85e4a9a5e3cf1839d6803d2c0c3e0533a8f3c5a992a7 + sha256: "9c62cc46fa4f2d41e10ab81014c1de470a6c6f26051a2de32111b2ee55287feb" url: "https://pub.dev" source: hosted - version: "3.13.0" + version: "3.14.0" win32: dependency: transitive description: name: win32 - sha256: "0eaf06e3446824099858367950a813472af675116bf63f008a4c2a75ae13e9cb" + sha256: a79dbe579cb51ecd6d30b17e0cae4e0ea15e2c0e66f69ad4198f22a6789e94f4 url: "https://pub.dev" source: hosted - version: "5.5.0" + version: "5.5.1" win32_registry: dependency: transitive description: diff --git a/packages/smooth_app/pubspec.yaml b/packages/smooth_app/pubspec.yaml index f0619116fbd..affe85f10e5 100644 --- a/packages/smooth_app/pubspec.yaml +++ b/packages/smooth_app/pubspec.yaml @@ -13,21 +13,21 @@ dependencies: sdk: flutter async: 2.11.0 - go_router: 12.1.1 + go_router: 14.2.1 barcode_widget: 2.0.4 carousel_slider: 4.2.1 cupertino_icons: 1.0.8 flutter_svg: 2.0.10+1 flutter_map: 6.1.0 html: 0.15.4 - flutter_widget_from_html_core: 0.8.5+3 + flutter_widget_from_html_core: 0.8.3+1 fwfh_selectable_text: 0.8.3+1 flutter_secure_storage: 9.2.2 hive: 2.2.3 hive_flutter: 1.1.0 http: 1.2.0 http_parser: 4.0.2 - image_picker: 1.1.1 + image_picker: 1.1.2 iso_countries: 2.2.0 latlong2: 0.9.1 matomo_tracker: 4.1.1 @@ -37,10 +37,10 @@ dependencies: photo_view: 0.15.0 uuid: 3.0.7 provider: 6.1.2 - sentry_flutter: 8.3.0 + sentry_flutter: 8.4.0 sqflite: 2.3.3+1 sqflite_common_ffi: 2.3.3 - url_launcher: 6.1.3 + url_launcher: 6.3.0 visibility_detector: 0.4.0+2 app_settings: 5.1.1 diacritic: 0.1.5 @@ -48,8 +48,8 @@ dependencies: path: ../app_store/shared audioplayers: 5.2.1 flutter_email_sender: 6.0.3 - flutter_native_splash: 2.4.0 - image: 4.1.7 + flutter_native_splash: 2.4.1 + image: 4.2.0 auto_size_text: 3.0.0 crop_image: 1.0.13 shared_preferences: 2.2.3 @@ -61,16 +61,16 @@ dependencies: fimber: 0.7.0 shimmer: ^3.0.0 rive: 0.13.4 - webview_flutter: 4.7.0 + webview_flutter: 4.8.0 webview_flutter_android: 3.16.4 - webview_flutter_wkwebview: 3.13.0 + webview_flutter_wkwebview: 3.14.0 flutter_custom_tabs: 2.1.0 - flutter_image_compress: 2.2.0 + flutter_image_compress: 2.3.0 connectivity_plus: 5.0.2 dart_ping: 9.0.1 dart_ping_ios: 4.0.2 flutter_animation_progress_bar: 2.3.1 - email_validator: 2.1.17 + email_validator: 3.0.0 sliver_tools: 0.2.12 # According to the build variant, only one "app store" implementation must be added when building a release From 4404eb6b45d816768f41310ff6c8dc6cba847f68 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 Jul 2024 10:40:44 +0200 Subject: [PATCH 07/24] chore(deps): bump crowdin/github-action from 2.0.0 to 2.1.0 (#5508) Bumps [crowdin/github-action](https://github.com/crowdin/github-action) from 2.0.0 to 2.1.0. - [Release notes](https://github.com/crowdin/github-action/releases) - [Commits](https://github.com/crowdin/github-action/compare/v2.0.0...v2.1.0) --- updated-dependencies: - dependency-name: crowdin/github-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/crowdin.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/crowdin.yml b/.github/workflows/crowdin.yml index 8718d5b05ea..ba53a02f798 100644 --- a/.github/workflows/crowdin.yml +++ b/.github/workflows/crowdin.yml @@ -13,7 +13,7 @@ jobs: uses: actions/checkout@v4 - name: crowdin action - uses: crowdin/github-action@v2.0.0 + uses: crowdin/github-action@v2.1.0 continue-on-error: true with: # Upload sources to Crowdin From cc3756df59ebb895a1ceaee001b7f51e7fb25133 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 27 Jul 2024 18:40:14 +0200 Subject: [PATCH 08/24] chore(deps): bump crowdin/github-action from 2.1.0 to 2.1.1 (#5513) Bumps [crowdin/github-action](https://github.com/crowdin/github-action) from 2.1.0 to 2.1.1. - [Release notes](https://github.com/crowdin/github-action/releases) - [Commits](https://github.com/crowdin/github-action/compare/v2.1.0...v2.1.1) --- updated-dependencies: - dependency-name: crowdin/github-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/crowdin.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/crowdin.yml b/.github/workflows/crowdin.yml index ba53a02f798..4393100fc57 100644 --- a/.github/workflows/crowdin.yml +++ b/.github/workflows/crowdin.yml @@ -13,7 +13,7 @@ jobs: uses: actions/checkout@v4 - name: crowdin action - uses: crowdin/github-action@v2.1.0 + uses: crowdin/github-action@v2.1.1 continue-on-error: true with: # Upload sources to Crowdin From 9ad38875771ee301cea14ad5a12353716bb843c3 Mon Sep 17 00:00:00 2001 From: Edouard Marquez Date: Tue, 30 Jul 2024 08:54:05 +0200 Subject: [PATCH 09/24] An attempt to fix the blank external page (#5514) --- .../lib/pages/navigator/external_page.dart | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/packages/smooth_app/lib/pages/navigator/external_page.dart b/packages/smooth_app/lib/pages/navigator/external_page.dart index 4c5cef2ce6c..d28bd9bb2b0 100644 --- a/packages/smooth_app/lib/pages/navigator/external_page.dart +++ b/packages/smooth_app/lib/pages/navigator/external_page.dart @@ -8,6 +8,7 @@ import 'package:path/path.dart' as path; import 'package:smooth_app/helpers/launch_url_helper.dart'; import 'package:smooth_app/pages/navigator/app_navigator.dart'; import 'package:smooth_app/query/product_query.dart'; +import 'package:smooth_app/services/smooth_services.dart'; /// This screen is only used for deep links! /// @@ -58,19 +59,24 @@ class _ExternalPageState extends State { url = '$url?lc=${language.offTag}'; } - if (Platform.isAndroid) { - await tabs.launchUrl( - Uri.parse(url), - customTabsOptions: const tabs.CustomTabsOptions( - showTitle: true, - ), - ); - } else { - await LaunchUrlHelper.launchURL(url); - } - - if (mounted) { - AppNavigator.of(context).pop(); + try { + if (Platform.isAndroid) { + WidgetsFlutterBinding.ensureInitialized(); + await tabs.launchUrl( + Uri.parse(url), + customTabsOptions: const tabs.CustomTabsOptions( + showTitle: true, + ), + ); + } else { + await LaunchUrlHelper.launchURL(url); + } + } catch (e) { + Logs.e('Unable to open an external link', ex: e); + } finally { + if (mounted) { + AppNavigator.of(context).pop(); + } } }); } From ddb127d4cd9f08b852cc4746f9d98782d244bc58 Mon Sep 17 00:00:00 2001 From: Edouard Marquez Date: Tue, 30 Jul 2024 08:54:18 +0200 Subject: [PATCH 10/24] Remove flutter map attribution (#5511) --- .../knowledge_panels/knowledge_panel_world_map_card.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/smooth_app/lib/knowledge_panel/knowledge_panels/knowledge_panel_world_map_card.dart b/packages/smooth_app/lib/knowledge_panel/knowledge_panels/knowledge_panel_world_map_card.dart index 28e15cfebf3..a352587fd53 100644 --- a/packages/smooth_app/lib/knowledge_panel/knowledge_panels/knowledge_panel_world_map_card.dart +++ b/packages/smooth_app/lib/knowledge_panel/knowledge_panels/knowledge_panel_world_map_card.dart @@ -71,6 +71,7 @@ class KnowledgePanelWorldMapCard extends StatelessWidget { RichAttributionWidget( popupInitialDisplayDuration: const Duration(seconds: 5), animationConfig: const ScaleRAWA(), + showFlutterMapAttribution: false, attributions: [ TextSourceAttribution( 'OpenStreetMap contributors', From a1274f96a84884fa315837e64db8d2b8118403c9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Jul 2024 08:54:58 +0200 Subject: [PATCH 11/24] chore(deps): bump fastlane in /packages/smooth_app/android (#5516) Bumps [fastlane](https://github.com/fastlane/fastlane) from 2.221.1 to 2.222.0. - [Release notes](https://github.com/fastlane/fastlane/releases) - [Changelog](https://github.com/fastlane/fastlane/blob/master/CHANGELOG.latest.md) - [Commits](https://github.com/fastlane/fastlane/compare/fastlane/2.221.1...fastlane/2.222.0) --- updated-dependencies: - dependency-name: fastlane dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- packages/smooth_app/android/Gemfile.lock | 32 ++++++++++++------------ 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/smooth_app/android/Gemfile.lock b/packages/smooth_app/android/Gemfile.lock index c2fcdce8648..cd96c783d17 100644 --- a/packages/smooth_app/android/Gemfile.lock +++ b/packages/smooth_app/android/Gemfile.lock @@ -11,25 +11,25 @@ GEM base64 nkf rexml - addressable (2.8.6) - public_suffix (>= 2.0.2, < 6.0) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) artifactory (3.0.17) atomos (0.1.3) aws-eventstream (1.3.0) - aws-partitions (1.945.0) - aws-sdk-core (3.197.1) + aws-partitions (1.958.0) + aws-sdk-core (3.201.3) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.8) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.85.0) - aws-sdk-core (~> 3, >= 3.197.0) - aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.152.3) - aws-sdk-core (~> 3, >= 3.197.0) + aws-sdk-kms (1.88.0) + aws-sdk-core (~> 3, >= 3.201.0) + aws-sigv4 (~> 1.5) + aws-sdk-s3 (1.156.0) + aws-sdk-core (~> 3, >= 3.201.0) aws-sdk-kms (~> 1) - aws-sigv4 (~> 1.8) - aws-sigv4 (1.8.0) + aws-sigv4 (~> 1.5) + aws-sigv4 (1.9.0) aws-eventstream (~> 1, >= 1.0.2) babosa (1.0.4) base64 (0.2.0) @@ -44,7 +44,7 @@ GEM domain_name (0.6.20240107) dotenv (2.8.1) emoji_regex (3.2.3) - excon (0.110.0) + excon (0.111.0) faraday (1.10.3) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) @@ -66,7 +66,7 @@ GEM faraday-httpclient (1.0.1) faraday-multipart (1.0.4) multipart-post (~> 2) - faraday-net_http (1.0.1) + faraday-net_http (1.0.2) faraday-net_http_persistent (1.2.0) faraday-patron (1.0.0) faraday-rack (1.0.0) @@ -74,7 +74,7 @@ GEM faraday_middleware (1.2.0) faraday (~> 1.0) fastimage (2.3.1) - fastlane (2.221.1) + fastlane (2.222.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.8, < 3.0.0) artifactory (~> 3.0) @@ -162,7 +162,7 @@ GEM json (2.7.2) jwt (2.8.2) base64 - mini_magick (4.13.1) + mini_magick (4.13.2) mini_mime (1.1.5) multi_json (1.15.0) multipart-post (2.4.1) @@ -172,7 +172,7 @@ GEM optparse (0.5.0) os (1.1.4) plist (3.7.1) - public_suffix (5.1.1) + public_suffix (6.0.1) rake (13.2.1) representable (3.2.0) declarative (< 0.1.0) From 41be2eca5e5f532d288e7321fbb4603b25560201 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Jul 2024 08:55:21 +0200 Subject: [PATCH 12/24] chore(deps): bump fastlane in /packages/smooth_app/ios (#5515) Bumps [fastlane](https://github.com/fastlane/fastlane) from 2.221.1 to 2.222.0. - [Release notes](https://github.com/fastlane/fastlane/releases) - [Changelog](https://github.com/fastlane/fastlane/blob/master/CHANGELOG.latest.md) - [Commits](https://github.com/fastlane/fastlane/compare/fastlane/2.221.1...fastlane/2.222.0) --- updated-dependencies: - dependency-name: fastlane dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- packages/smooth_app/ios/Gemfile.lock | 32 ++++++++++++++-------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/smooth_app/ios/Gemfile.lock b/packages/smooth_app/ios/Gemfile.lock index 6c82f499c3b..ac033ddb6f3 100644 --- a/packages/smooth_app/ios/Gemfile.lock +++ b/packages/smooth_app/ios/Gemfile.lock @@ -11,25 +11,25 @@ GEM base64 nkf rexml - addressable (2.8.6) - public_suffix (>= 2.0.2, < 6.0) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) artifactory (3.0.17) atomos (0.1.3) aws-eventstream (1.3.0) - aws-partitions (1.945.0) - aws-sdk-core (3.197.1) + aws-partitions (1.958.0) + aws-sdk-core (3.201.3) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.8) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.85.0) - aws-sdk-core (~> 3, >= 3.197.0) - aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.152.3) - aws-sdk-core (~> 3, >= 3.197.0) + aws-sdk-kms (1.88.0) + aws-sdk-core (~> 3, >= 3.201.0) + aws-sigv4 (~> 1.5) + aws-sdk-s3 (1.156.0) + aws-sdk-core (~> 3, >= 3.201.0) aws-sdk-kms (~> 1) - aws-sigv4 (~> 1.8) - aws-sigv4 (1.8.0) + aws-sigv4 (~> 1.5) + aws-sigv4 (1.9.0) aws-eventstream (~> 1, >= 1.0.2) babosa (1.0.4) base64 (0.2.0) @@ -45,7 +45,7 @@ GEM domain_name (0.6.20240107) dotenv (2.8.1) emoji_regex (3.2.3) - excon (0.110.0) + excon (0.111.0) faraday (1.10.3) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) @@ -67,7 +67,7 @@ GEM faraday-httpclient (1.0.1) faraday-multipart (1.0.4) multipart-post (~> 2) - faraday-net_http (1.0.1) + faraday-net_http (1.0.2) faraday-net_http_persistent (1.2.0) faraday-patron (1.0.0) faraday-rack (1.0.0) @@ -75,7 +75,7 @@ GEM faraday_middleware (1.2.0) faraday (~> 1.0) fastimage (2.3.1) - fastlane (2.221.1) + fastlane (2.222.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.8, < 3.0.0) artifactory (~> 3.0) @@ -163,7 +163,7 @@ GEM json (2.7.2) jwt (2.8.2) base64 - mini_magick (4.13.1) + mini_magick (4.13.2) mini_mime (1.1.5) multi_json (1.15.0) multipart-post (2.4.1) @@ -173,7 +173,7 @@ GEM optparse (0.5.0) os (1.1.4) plist (3.7.1) - public_suffix (5.1.1) + public_suffix (6.0.1) rake (13.2.1) representable (3.2.0) declarative (< 0.1.0) From b938153f592662c53d3d47d158b2c42387d9ca2c Mon Sep 17 00:00:00 2001 From: Edouard Marquez Date: Fri, 2 Aug 2024 17:32:57 +0200 Subject: [PATCH 13/24] Fix UK flag (#5518) --- packages/smooth_app/lib/pages/prices/emoji_helper.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/smooth_app/lib/pages/prices/emoji_helper.dart b/packages/smooth_app/lib/pages/prices/emoji_helper.dart index 5b56715dccf..57a5d2b6aff 100644 --- a/packages/smooth_app/lib/pages/prices/emoji_helper.dart +++ b/packages/smooth_app/lib/pages/prices/emoji_helper.dart @@ -17,7 +17,10 @@ class EmojiHelper { static String? getEmojiByCountryCode(final String countryCode) { if (countryCode.isEmpty) { return null; + } else if (countryCode.toUpperCase() == 'UK') { + return _getCountryEmojiFromUnicode('GB'); } + return _getCountryEmojiFromUnicode(countryCode); } From 344518d048a9e5f9291055978ae2f9e06e62a079 Mon Sep 17 00:00:00 2001 From: Edouard Marquez Date: Fri, 2 Aug 2024 17:36:02 +0200 Subject: [PATCH 14/24] feat: Photo gallery for "Others" (#5501) * Photo gallery for "Others" * Error + loading * Photo details * Fix weird animation --- packages/smooth_app/ios/Podfile.lock | 316 --------------- packages/smooth_app/lib/l10n/app_en.arb | 45 +++ .../product_image_gallery_other_view.dart | 15 +- .../pages/image/product_image_other_page.dart | 363 +++++++++++++++++- .../lib/pages/image/product_image_widget.dart | 3 + packages/smooth_app/macos/Podfile.lock | 131 ------- 6 files changed, 402 insertions(+), 471 deletions(-) delete mode 100644 packages/smooth_app/ios/Podfile.lock delete mode 100644 packages/smooth_app/macos/Podfile.lock diff --git a/packages/smooth_app/ios/Podfile.lock b/packages/smooth_app/ios/Podfile.lock deleted file mode 100644 index d81cc120361..00000000000 --- a/packages/smooth_app/ios/Podfile.lock +++ /dev/null @@ -1,316 +0,0 @@ -PODS: - - app_settings (5.1.1): - - Flutter - - audioplayers_darwin (0.0.1): - - Flutter - - camera_avfoundation (0.0.1): - - Flutter - - connectivity_plus (0.0.1): - - Flutter - - ReachabilitySwift - - device_info_plus (0.0.1): - - Flutter - - Flutter (1.0.0) - - flutter_custom_tabs_ios (2.0.0): - - Flutter - - flutter_email_sender (0.0.1): - - Flutter - - flutter_icmp_ping (0.0.1): - - Flutter - - flutter_image_compress_common (1.0.0): - - Flutter - - Mantle - - SDWebImage - - SDWebImageWebPCoder - - flutter_native_splash (0.0.1): - - Flutter - - flutter_secure_storage (6.0.0): - - Flutter - - GoogleDataTransport (9.4.1): - - GoogleUtilities/Environment (~> 7.7) - - nanopb (< 2.30911.0, >= 2.30908.0) - - PromisesObjC (< 3.0, >= 1.2) - - GoogleMLKit/BarcodeScanning (4.0.0): - - GoogleMLKit/MLKitCore - - MLKitBarcodeScanning (~> 3.0.0) - - GoogleMLKit/MLKitCore (4.0.0): - - MLKitCommon (~> 9.0.0) - - GoogleToolboxForMac/DebugUtils (2.3.2): - - GoogleToolboxForMac/Defines (= 2.3.2) - - GoogleToolboxForMac/Defines (2.3.2) - - GoogleToolboxForMac/Logger (2.3.2): - - GoogleToolboxForMac/Defines (= 2.3.2) - - "GoogleToolboxForMac/NSData+zlib (2.3.2)": - - GoogleToolboxForMac/Defines (= 2.3.2) - - "GoogleToolboxForMac/NSDictionary+URLArguments (2.3.2)": - - GoogleToolboxForMac/DebugUtils (= 2.3.2) - - GoogleToolboxForMac/Defines (= 2.3.2) - - "GoogleToolboxForMac/NSString+URLArguments (= 2.3.2)" - - "GoogleToolboxForMac/NSString+URLArguments (2.3.2)" - - GoogleUtilities/Environment (7.13.3): - - GoogleUtilities/Privacy - - PromisesObjC (< 3.0, >= 1.2) - - GoogleUtilities/Logger (7.13.3): - - GoogleUtilities/Environment - - GoogleUtilities/Privacy - - GoogleUtilities/Privacy (7.13.3) - - GoogleUtilities/UserDefaults (7.13.3): - - GoogleUtilities/Logger - - GoogleUtilities/Privacy - - GoogleUtilitiesComponents (1.1.0): - - GoogleUtilities/Logger - - GTMSessionFetcher/Core (2.3.0) - - image_picker_ios (0.0.1): - - Flutter - - in_app_review (0.2.0): - - Flutter - - integration_test (0.0.1): - - Flutter - - iso_countries (0.0.1): - - Flutter - - libwebp (1.3.2): - - libwebp/demux (= 1.3.2) - - libwebp/mux (= 1.3.2) - - libwebp/sharpyuv (= 1.3.2) - - libwebp/webp (= 1.3.2) - - libwebp/demux (1.3.2): - - libwebp/webp - - libwebp/mux (1.3.2): - - libwebp/demux - - libwebp/sharpyuv (1.3.2) - - libwebp/webp (1.3.2): - - libwebp/sharpyuv - - Mantle (2.2.0): - - Mantle/extobjc (= 2.2.0) - - Mantle/extobjc (2.2.0) - - MLImage (1.0.0-beta4) - - MLKitBarcodeScanning (3.0.0): - - MLKitCommon (~> 9.0) - - MLKitVision (~> 5.0) - - MLKitCommon (9.0.0): - - GoogleDataTransport (~> 9.0) - - GoogleToolboxForMac/Logger (~> 2.1) - - "GoogleToolboxForMac/NSData+zlib (~> 2.1)" - - "GoogleToolboxForMac/NSDictionary+URLArguments (~> 2.1)" - - GoogleUtilities/UserDefaults (~> 7.0) - - GoogleUtilitiesComponents (~> 1.0) - - GTMSessionFetcher/Core (< 3.0, >= 1.1) - - MLKitVision (5.0.0): - - GoogleToolboxForMac/Logger (~> 2.1) - - "GoogleToolboxForMac/NSData+zlib (~> 2.1)" - - GTMSessionFetcher/Core (< 3.0, >= 1.1) - - MLImage (= 1.0.0-beta4) - - MLKitCommon (~> 9.0) - - mobile_scanner (3.5.6): - - Flutter - - GoogleMLKit/BarcodeScanning (~> 4.0.0) - - MTBBarcodeScanner (5.0.11) - - nanopb (2.30910.0): - - nanopb/decode (= 2.30910.0) - - nanopb/encode (= 2.30910.0) - - nanopb/decode (2.30910.0) - - nanopb/encode (2.30910.0) - - package_info_plus (0.4.5): - - Flutter - - path_provider_foundation (0.0.1): - - Flutter - - FlutterMacOS - - permission_handler_apple (9.3.0): - - Flutter - - PromisesObjC (2.4.0) - - qr_code_scanner (0.2.0): - - Flutter - - MTBBarcodeScanner - - ReachabilitySwift (5.2.2) - - rive_common (0.0.1): - - Flutter - - SDWebImage (5.19.2): - - SDWebImage/Core (= 5.19.2) - - SDWebImage/Core (5.19.2) - - SDWebImageWebPCoder (0.14.6): - - libwebp (~> 1.0) - - SDWebImage/Core (~> 5.17) - - Sentry/HybridSDK (8.21.0): - - SentryPrivate (= 8.21.0) - - sentry_flutter (0.0.1): - - Flutter - - FlutterMacOS - - Sentry/HybridSDK (= 8.21.0) - - SentryPrivate (8.21.0) - - share_plus (0.0.1): - - Flutter - - shared_preferences_foundation (0.0.1): - - Flutter - - FlutterMacOS - - sqflite (0.0.3): - - Flutter - - FlutterMacOS - - url_launcher_ios (0.0.1): - - Flutter - - webview_flutter_wkwebview (0.0.1): - - Flutter - -DEPENDENCIES: - - app_settings (from `.symlinks/plugins/app_settings/ios`) - - audioplayers_darwin (from `.symlinks/plugins/audioplayers_darwin/ios`) - - camera_avfoundation (from `.symlinks/plugins/camera_avfoundation/ios`) - - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`) - - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - - Flutter (from `Flutter`) - - flutter_custom_tabs_ios (from `.symlinks/plugins/flutter_custom_tabs_ios/ios`) - - flutter_email_sender (from `.symlinks/plugins/flutter_email_sender/ios`) - - flutter_icmp_ping (from `.symlinks/plugins/flutter_icmp_ping/ios`) - - flutter_image_compress_common (from `.symlinks/plugins/flutter_image_compress_common/ios`) - - flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`) - - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) - - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) - - in_app_review (from `.symlinks/plugins/in_app_review/ios`) - - integration_test (from `.symlinks/plugins/integration_test/ios`) - - iso_countries (from `.symlinks/plugins/iso_countries/ios`) - - mobile_scanner (from `.symlinks/plugins/mobile_scanner/ios`) - - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) - - qr_code_scanner (from `.symlinks/plugins/qr_code_scanner/ios`) - - rive_common (from `.symlinks/plugins/rive_common/ios`) - - sentry_flutter (from `.symlinks/plugins/sentry_flutter/ios`) - - share_plus (from `.symlinks/plugins/share_plus/ios`) - - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - - sqflite (from `.symlinks/plugins/sqflite/darwin`) - - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - - webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/ios`) - -SPEC REPOS: - trunk: - - GoogleDataTransport - - GoogleMLKit - - GoogleToolboxForMac - - GoogleUtilities - - GoogleUtilitiesComponents - - GTMSessionFetcher - - libwebp - - Mantle - - MLImage - - MLKitBarcodeScanning - - MLKitCommon - - MLKitVision - - MTBBarcodeScanner - - nanopb - - PromisesObjC - - ReachabilitySwift - - SDWebImage - - SDWebImageWebPCoder - - Sentry - - SentryPrivate - -EXTERNAL SOURCES: - app_settings: - :path: ".symlinks/plugins/app_settings/ios" - audioplayers_darwin: - :path: ".symlinks/plugins/audioplayers_darwin/ios" - camera_avfoundation: - :path: ".symlinks/plugins/camera_avfoundation/ios" - connectivity_plus: - :path: ".symlinks/plugins/connectivity_plus/ios" - device_info_plus: - :path: ".symlinks/plugins/device_info_plus/ios" - Flutter: - :path: Flutter - flutter_custom_tabs_ios: - :path: ".symlinks/plugins/flutter_custom_tabs_ios/ios" - flutter_email_sender: - :path: ".symlinks/plugins/flutter_email_sender/ios" - flutter_icmp_ping: - :path: ".symlinks/plugins/flutter_icmp_ping/ios" - flutter_image_compress_common: - :path: ".symlinks/plugins/flutter_image_compress_common/ios" - flutter_native_splash: - :path: ".symlinks/plugins/flutter_native_splash/ios" - flutter_secure_storage: - :path: ".symlinks/plugins/flutter_secure_storage/ios" - image_picker_ios: - :path: ".symlinks/plugins/image_picker_ios/ios" - in_app_review: - :path: ".symlinks/plugins/in_app_review/ios" - integration_test: - :path: ".symlinks/plugins/integration_test/ios" - iso_countries: - :path: ".symlinks/plugins/iso_countries/ios" - mobile_scanner: - :path: ".symlinks/plugins/mobile_scanner/ios" - package_info_plus: - :path: ".symlinks/plugins/package_info_plus/ios" - path_provider_foundation: - :path: ".symlinks/plugins/path_provider_foundation/darwin" - permission_handler_apple: - :path: ".symlinks/plugins/permission_handler_apple/ios" - qr_code_scanner: - :path: ".symlinks/plugins/qr_code_scanner/ios" - rive_common: - :path: ".symlinks/plugins/rive_common/ios" - sentry_flutter: - :path: ".symlinks/plugins/sentry_flutter/ios" - share_plus: - :path: ".symlinks/plugins/share_plus/ios" - shared_preferences_foundation: - :path: ".symlinks/plugins/shared_preferences_foundation/darwin" - sqflite: - :path: ".symlinks/plugins/sqflite/darwin" - url_launcher_ios: - :path: ".symlinks/plugins/url_launcher_ios/ios" - webview_flutter_wkwebview: - :path: ".symlinks/plugins/webview_flutter_wkwebview/ios" - -SPEC CHECKSUMS: - app_settings: 017320c6a680cdc94c799949d95b84cb69389ebc - audioplayers_darwin: 877d9a4d06331c5c374595e46e16453ac7eafa40 - camera_avfoundation: 759172d1a77ae7be0de08fc104cfb79738b8a59e - connectivity_plus: bf0076dd84a130856aa636df1c71ccaff908fa1d - device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6 - Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - flutter_custom_tabs_ios: a651b18786388923b62de8c0537607de87c2eccf - flutter_email_sender: 10a22605f92809a11ef52b2f412db806c6082d40 - flutter_icmp_ping: 2b159955eee0c487c766ad83fec224ae35e7c935 - flutter_image_compress_common: ec1d45c362c9d30a3f6a0426c297f47c52007e3e - flutter_native_splash: edf599c81f74d093a4daf8e17bd7a018854bc778 - flutter_secure_storage: d33dac7ae2ea08509be337e775f6b59f1ff45f12 - GoogleDataTransport: 6c09b596d841063d76d4288cc2d2f42cc36e1e2a - GoogleMLKit: 2bd0dc6253c4d4f227aad460f69215a504b2980e - GoogleToolboxForMac: 8bef7c7c5cf7291c687cf5354f39f9db6399ad34 - GoogleUtilities: ea963c370a38a8069cc5f7ba4ca849a60b6d7d15 - GoogleUtilitiesComponents: 679b2c881db3b615a2777504623df6122dd20afe - GTMSessionFetcher: 3a63d75eecd6aa32c2fc79f578064e1214dfdec2 - image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1 - in_app_review: 318597b3a06c22bb46dc454d56828c85f444f99d - integration_test: ce0a3ffa1de96d1a89ca0ac26fca7ea18a749ef4 - iso_countries: eb09d40f388e4c65e291e0bb36a701dfe7de6c74 - libwebp: 1786c9f4ff8a279e4dac1e8f385004d5fc253009 - Mantle: c5aa8794a29a022dfbbfc9799af95f477a69b62d - MLImage: 7bb7c4264164ade9bf64f679b40fb29c8f33ee9b - MLKitBarcodeScanning: 04e264482c5f3810cb89ebc134ef6b61e67db505 - MLKitCommon: c1b791c3e667091918d91bda4bba69a91011e390 - MLKitVision: 8baa5f46ee3352614169b85250574fde38c36f49 - mobile_scanner: 38dcd8a49d7d485f632b7de65e4900010187aef2 - MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb - nanopb: 438bc412db1928dac798aa6fd75726007be04262 - package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85 - path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 - permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2 - PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 - qr_code_scanner: bb67d64904c3b9658ada8c402e8b4d406d5d796e - ReachabilitySwift: 2128f3a8c9107e1ad33574c6e58e8285d460b149 - rive_common: cbbac3192af00d7341f19dae2f26298e9e37d99e - SDWebImage: dfe95b2466a9823cf9f0c6d01217c06550d7b29a - SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380 - Sentry: ebc12276bd17613a114ab359074096b6b3725203 - sentry_flutter: dff1df05dc39c83d04f9330b36360fc374574c5e - SentryPrivate: d651efb234cf385ec9a1cdd3eff94b5e78a0e0fe - share_plus: c3fef564749587fc939ef86ffb283ceac0baf9f5 - shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 - sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec - url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe - webview_flutter_wkwebview: be0f0d33777f1bfd0c9fdcb594786704dbf65f36 - -PODFILE CHECKSUM: 31bd95b3ebe08a1371aec307f223993946c837a3 - -COCOAPODS: 1.15.2 diff --git a/packages/smooth_app/lib/l10n/app_en.arb b/packages/smooth_app/lib/l10n/app_en.arb index fac43512480..bfad1e2f3de 100644 --- a/packages/smooth_app/lib/l10n/app_en.arb +++ b/packages/smooth_app/lib/l10n/app_en.arb @@ -775,6 +775,7 @@ } } }, + "product_image_outdated": "This image may be outdated", "homepage_main_card_logo_description": "Welcome to Open Food Facts", "@homepage_main_card_logo_description": { "description": "Description for accessibility of the Open Food Facts logo on the homepage" @@ -2971,5 +2972,49 @@ "menu_button_list_actions": "Select an action", "@menu_button_list_actions": { "description": "Button to select an action in a list (eg: Share, Delete, …)" + }, + "error_loading_photo": "Error loading photo", + "@error_loading_photo": { + "description": "Error message when loading a photo fails to load" + }, + "photo_viewer_details_button": "Details", + "@photo_viewer_details_button": { + "description": "Button to show details of the photo" + }, + "photo_viewer_details_button_accessibility_label": "Details of this photo", + "@photo_viewer_details_button_accessibility_label": { + "description": "Accessibility label for the Details button on a photo" + }, + "photo_viewer_details_title": "Details of the photo", + "@photo_viewer_details_title": { + "description": "Title of the photo details dialog" + }, + "photo_viewer_details_contributor_title": "Contributor", + "@photo_viewer_details_contributor_title": { + "description": "Label for the author of a photo" + }, + "photo_viewer_details_size_title": "Size", + "@photo_viewer_details_size_title": { + "description": "Label for the size of a photo" + }, + "photo_viewer_details_size_value": "{width} x {height} pixels", + "@photo_viewer_details_size_value": { + "description": "Value for the size of a photo", + "placeholders": { + "width": { + "type": "int" + }, + "height": { + "type": "int" + } + } + }, + "photo_viewer_details_date_title": "Date", + "@photo_viewer_details_date_title": { + "description": "Label for the uploaded date of a photo" + }, + "photo_viewer_details_url_title": "URL", + "@photo_viewer_details_url_title": { + "description": "Label for the link of a photo" } } \ No newline at end of file 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 3936ac36b1a..1a25b281bef 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 @@ -120,6 +120,8 @@ class _RawGridGallery extends StatelessWidget { // order by descending ids index = rawImages.length - 1 - index; final ProductImage productImage = rawImages[index]; + final String? heroTag = productImage.imgid; + return Padding( padding: EdgeInsetsDirectional.only( start: VERY_SMALL_SPACE, @@ -130,10 +132,14 @@ class _RawGridGallery extends StatelessWidget { onTap: () async => Navigator.push( context, MaterialPageRoute( - builder: (BuildContext context) => ProductImageOtherPage( - product, - int.parse(productImage.imgid!), - ), + builder: (BuildContext context) { + return ProductImageOtherPage( + product: product, + images: rawImages.reversed.toList(growable: false), + currentImage: productImage, + heroTag: heroTag, + ); + }, ), ), child: ProductImageWidget( @@ -141,6 +147,7 @@ class _RawGridGallery extends StatelessWidget { barcode: product.barcode!, squareSize: squareSize, imageSize: imageSize, + heroTag: heroTag, ), ), ); 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 d8722384468..72babd739d7 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 @@ -1,40 +1,363 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:intl/intl.dart'; import 'package:openfoodfacts/openfoodfacts.dart'; +import 'package:provider/provider.dart'; +import 'package:smooth_app/generic_lib/bottom_sheets/smooth_bottom_sheet.dart'; +import 'package:smooth_app/generic_lib/design_constants.dart'; +import 'package:smooth_app/helpers/launch_url_helper.dart'; import 'package:smooth_app/helpers/product_cards_helper.dart'; +import 'package:smooth_app/pages/image/product_image_helper.dart'; import 'package:smooth_app/query/product_query.dart'; +import 'package:smooth_app/resources/app_icons.dart' as icons; +import 'package:smooth_app/themes/smooth_theme_colors.dart'; import 'package:smooth_app/widgets/smooth_scaffold.dart'; /// Full page display of a raw product image. -class ProductImageOtherPage extends StatelessWidget { - const ProductImageOtherPage( - this.product, - this.imageId, - ); +class ProductImageOtherPage extends StatefulWidget { + const ProductImageOtherPage({ + required this.product, + required this.images, + required this.currentImage, + this.heroTag, + }); final Product product; - final int imageId; + final List images; + final ProductImage currentImage; + final String? heroTag; + + @override + State createState() => _ProductImageOtherPageState(); +} + +class _ProductImageOtherPageState extends State { + late PageController _pageController; + + @override + void initState() { + super.initState(); + _pageController = PageController( + initialPage: widget.images.indexOf(widget.currentImage), + ); + } + + @override + Widget build(BuildContext context) { + final AppLocalizations appLocalizations = AppLocalizations.of(context); + return ChangeNotifierProvider.value( + value: _pageController, + child: SmoothScaffold( + appBar: buildEditProductAppBar( + context: context, + title: appLocalizations.edit_product_form_item_photos_title, + product: widget.product, + ), + body: Stack( + alignment: Alignment.bottomCenter, + children: [ + Positioned.fill( + child: PageView( + controller: _pageController, + children: widget.images.map( + (final ProductImage image) { + return _ProductImageViewer( + image: image, + barcode: widget.product.barcode!, + heroTag: + widget.currentImage == image ? widget.heroTag : null, + ); + }, + ).toList(growable: false), + ), + ), + Positioned( + top: SMALL_SPACE, + child: _ProductImagePageIndicator( + items: widget.images.length, + ), + ), + ], + ), + ), + ); + } +} + +class _ProductImageViewer extends StatelessWidget { + const _ProductImageViewer({ + required this.image, + required this.barcode, + this.heroTag, + }); + + final ProductImage image; + final String barcode; + final String? heroTag; + + @override + Widget build(BuildContext context) { + final SmoothColorsThemeExtension colors = + Theme.of(context).extension()!; + + return Stack( + children: [ + Positioned.fill( + child: HeroMode( + enabled: heroTag?.isNotEmpty == true, + child: Hero( + tag: heroTag ?? '', + child: Image( + image: NetworkImage( + image.getUrl( + barcode, + uriHelper: ProductQuery.uriProductHelper, + ), + ), + fit: BoxFit.cover, + loadingBuilder: ( + _, + final Widget child, + final ImageChunkEvent? loadingProgress, + ) { + if (loadingProgress != null) { + return const Center( + child: CircularProgressIndicator.adaptive(), + ); + } else { + return child; + } + }, + errorBuilder: (_, __, ___) => Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const icons.Warning( + size: 48.0, + color: Colors.red, + ), + const SizedBox(height: SMALL_SPACE), + Text(AppLocalizations.of(context).error_loading_photo), + ], + ), + ), + ), + ), + ), + Positioned( + bottom: SMALL_SPACE + MediaQuery.viewPaddingOf(context).bottom, + left: SMALL_SPACE, + right: SMALL_SPACE, + child: IntrinsicHeight( + child: Row( + children: [ + _ProductImageDetailsButton( + image: image, + barcode: barcode, + ), + const Spacer(), + if (image.expired) _ProductImageOutdatedLabel(colors: colors), + ], + ), + ), + ), + ], + ); + } +} + +class _ProductImageOutdatedLabel extends StatelessWidget { + const _ProductImageOutdatedLabel({ + required this.colors, + }); + + final SmoothColorsThemeExtension colors; + + @override + Widget build(BuildContext context) { + return Semantics( + child: SizedBox( + height: double.infinity, + child: DecoratedBox( + decoration: BoxDecoration( + color: colors.red.withOpacity(0.9), + borderRadius: CIRCULAR_BORDER_RADIUS, + ), + child: Padding( + padding: const EdgeInsets.all(SMALL_SPACE), + child: Row( + children: [ + const icons.Outdated( + size: 18.0, + color: Colors.white, + ), + const SizedBox(width: SMALL_SPACE), + Text( + AppLocalizations.of(context).product_image_outdated, + style: const TextStyle( + fontSize: 13.0, + color: Colors.white, + ), + ), + ], + ), + ), + ), + ), + ); + } +} + +class _ProductImageDetailsButton extends StatelessWidget { + const _ProductImageDetailsButton({ + required this.image, + required this.barcode, + }); + + final ProductImage image; + final String barcode; @override Widget build(BuildContext context) { final AppLocalizations appLocalizations = AppLocalizations.of(context); - return SmoothScaffold( - appBar: buildEditProductAppBar( - context: context, - title: appLocalizations.edit_product_form_item_photos_title, - product: product, + final String url = image.url ?? + image.getUrl( + barcode, + uriHelper: ProductQuery.uriProductHelper, + ); + + return DecoratedBox( + decoration: const BoxDecoration( + color: Colors.black45, + borderRadius: CIRCULAR_BORDER_RADIUS, ), - body: Image( - image: NetworkImage( - ProductImage.raw( - imgid: imageId.toString(), - size: ImageSize.ORIGINAL, - ).getUrl( - product.barcode!, - uriHelper: ProductQuery.uriProductHelper, + child: Material( + type: MaterialType.transparency, + child: InkWell( + borderRadius: CIRCULAR_BORDER_RADIUS, + onTap: () { + showSmoothModalSheet( + context: context, + builder: (BuildContext context) { + return SmoothModalSheet( + title: appLocalizations.photo_viewer_details_title, + body: Column( + children: [ + ListTile( + title: Text(appLocalizations + .photo_viewer_details_contributor_title), + // TODO(g123k): add contributor + subtitle: const Text('TODO'), + ), + ListTile( + title: Text( + appLocalizations.photo_viewer_details_date_title), + subtitle: Text(image.uploaded != null + ? DateFormat.yMMMMEEEEd().format(image.uploaded!) + : '-'), + ), + ListTile( + title: Text( + appLocalizations.photo_viewer_details_size_title), + subtitle: Text( + image.width != null && image.height != null + ? appLocalizations + .photo_viewer_details_size_value( + image.width!, + image.height!, + ) + : '-', + ), + ), + if (url.isNotEmpty) + ListTile( + title: Text(appLocalizations + .photo_viewer_details_url_title), + subtitle: Text(url), + trailing: const Icon(Icons.open_in_new_rounded), + onTap: () { + LaunchUrlHelper.launchURL(url); + }, + ), + SizedBox( + height: MediaQuery.viewPaddingOf(context).bottom), + ], + ), + ); + }); + }, + child: Padding( + padding: const EdgeInsetsDirectional.only( + start: SMALL_SPACE, + top: SMALL_SPACE, + bottom: SMALL_SPACE, + end: MEDIUM_SPACE, + ), + child: Semantics( + label: appLocalizations + .photo_viewer_details_button_accessibility_label, + button: true, + excludeSemantics: true, + child: Row( + children: [ + const icons.Info( + size: 15.0, + color: Colors.white, + ), + const SizedBox(width: SMALL_SPACE), + Text( + appLocalizations.photo_viewer_details_button, + style: const TextStyle( + color: Colors.white, + ), + ), + ], + ), + ), ), ), - fit: BoxFit.cover, + ), + ); + } +} + +class _ProductImagePageIndicator extends StatelessWidget { + const _ProductImagePageIndicator({required this.items}); + + final int items; + + @override + Widget build(BuildContext context) { + return DecoratedBox( + decoration: BoxDecoration( + color: Colors.black.withOpacity(0.5), + borderRadius: CIRCULAR_BORDER_RADIUS, + ), + child: Padding( + padding: const EdgeInsets.all(SMALL_SPACE), + child: Selector( + selector: (_, PageController value) { + if (!value.position.hasPixels) { + return 0; + } + + final int page = + (value.offset / value.position.viewportDimension).round(); + if (page < 0) { + return 0; + } else if (page > items - 1) { + return items - 1; + } else { + return page; + } + }, + shouldRebuild: (int previous, int next) => previous != next, + builder: (BuildContext context, int progress, _) { + return Text( + '${progress + 1} / $items', + style: const TextStyle(color: Colors.white), + ); + }, + ), ), ); } diff --git a/packages/smooth_app/lib/pages/image/product_image_widget.dart b/packages/smooth_app/lib/pages/image/product_image_widget.dart index 7393a6bd841..030bef83cd2 100644 --- a/packages/smooth_app/lib/pages/image/product_image_widget.dart +++ b/packages/smooth_app/lib/pages/image/product_image_widget.dart @@ -18,11 +18,13 @@ class ProductImageWidget extends StatelessWidget { required this.barcode, required this.squareSize, this.imageSize, + this.heroTag, }); final ProductImage productImage; final String barcode; final double squareSize; + final String? heroTag; /// Allows to fetch the optimized version of the image final ImageSize? imageSize; @@ -47,6 +49,7 @@ class ProductImageWidget extends StatelessWidget { imageSize: imageSize, ), ), + heroTag: heroTag, rounded: false, ); final DateTime? uploaded = productImage.uploaded; diff --git a/packages/smooth_app/macos/Podfile.lock b/packages/smooth_app/macos/Podfile.lock deleted file mode 100644 index c802b6a34ca..00000000000 --- a/packages/smooth_app/macos/Podfile.lock +++ /dev/null @@ -1,131 +0,0 @@ -PODS: - - audioplayers_darwin (0.0.1): - - FlutterMacOS - - connectivity_plus (0.0.1): - - FlutterMacOS - - ReachabilitySwift - - device_info_plus (0.0.1): - - FlutterMacOS - - file_selector_macos (0.0.1): - - FlutterMacOS - - flutter_image_compress_macos (1.0.0): - - FlutterMacOS - - flutter_secure_storage_macos (6.1.1): - - FlutterMacOS - - FlutterMacOS (1.0.0) - - in_app_review (0.2.0): - - FlutterMacOS - - mobile_scanner (3.5.6): - - FlutterMacOS - - package_info_plus (0.0.1): - - FlutterMacOS - - path_provider_foundation (0.0.1): - - Flutter - - FlutterMacOS - - ReachabilitySwift (5.2.2) - - rive_common (0.0.1): - - FlutterMacOS - - Sentry/HybridSDK (8.21.0): - - SentryPrivate (= 8.21.0) - - sentry_flutter (0.0.1): - - Flutter - - FlutterMacOS - - Sentry/HybridSDK (= 8.21.0) - - SentryPrivate (8.21.0) - - share_plus (0.0.1): - - FlutterMacOS - - shared_preferences_foundation (0.0.1): - - Flutter - - FlutterMacOS - - sqflite (0.0.3): - - Flutter - - FlutterMacOS - - url_launcher_macos (0.0.1): - - FlutterMacOS - -DEPENDENCIES: - - audioplayers_darwin (from `Flutter/ephemeral/.symlinks/plugins/audioplayers_darwin/macos`) - - connectivity_plus (from `Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos`) - - device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`) - - file_selector_macos (from `Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos`) - - flutter_image_compress_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_image_compress_macos/macos`) - - flutter_secure_storage_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos`) - - FlutterMacOS (from `Flutter/ephemeral`) - - in_app_review (from `Flutter/ephemeral/.symlinks/plugins/in_app_review/macos`) - - mobile_scanner (from `Flutter/ephemeral/.symlinks/plugins/mobile_scanner/macos`) - - package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`) - - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) - - rive_common (from `Flutter/ephemeral/.symlinks/plugins/rive_common/macos`) - - sentry_flutter (from `Flutter/ephemeral/.symlinks/plugins/sentry_flutter/macos`) - - share_plus (from `Flutter/ephemeral/.symlinks/plugins/share_plus/macos`) - - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) - - sqflite (from `Flutter/ephemeral/.symlinks/plugins/sqflite/darwin`) - - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) - -SPEC REPOS: - trunk: - - ReachabilitySwift - - Sentry - - SentryPrivate - -EXTERNAL SOURCES: - audioplayers_darwin: - :path: Flutter/ephemeral/.symlinks/plugins/audioplayers_darwin/macos - connectivity_plus: - :path: Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos - device_info_plus: - :path: Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos - file_selector_macos: - :path: Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos - flutter_image_compress_macos: - :path: Flutter/ephemeral/.symlinks/plugins/flutter_image_compress_macos/macos - flutter_secure_storage_macos: - :path: Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos - FlutterMacOS: - :path: Flutter/ephemeral - in_app_review: - :path: Flutter/ephemeral/.symlinks/plugins/in_app_review/macos - mobile_scanner: - :path: Flutter/ephemeral/.symlinks/plugins/mobile_scanner/macos - package_info_plus: - :path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos - path_provider_foundation: - :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin - rive_common: - :path: Flutter/ephemeral/.symlinks/plugins/rive_common/macos - sentry_flutter: - :path: Flutter/ephemeral/.symlinks/plugins/sentry_flutter/macos - share_plus: - :path: Flutter/ephemeral/.symlinks/plugins/share_plus/macos - shared_preferences_foundation: - :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin - sqflite: - :path: Flutter/ephemeral/.symlinks/plugins/sqflite/darwin - url_launcher_macos: - :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos - -SPEC CHECKSUMS: - audioplayers_darwin: dcad41de4fbd0099cb3749f7ab3b0cb8f70b810c - connectivity_plus: 18d3c32514c886e046de60e9c13895109866c747 - device_info_plus: 5401765fde0b8d062a2f8eb65510fb17e77cf07f - file_selector_macos: 54fdab7caa3ac3fc43c9fac4d7d8d231277f8cf2 - flutter_image_compress_macos: c26c3c13ea0f28ae6dea4e139b3292e7729f99f1 - flutter_secure_storage_macos: 59459653abe1adb92abbc8ea747d79f8d19866c9 - FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 - in_app_review: a850789fad746e89bce03d4aeee8078b45a53fd0 - mobile_scanner: 54ceceae0c8da2457e26a362a6be5c61154b1829 - package_info_plus: fa739dd842b393193c5ca93c26798dff6e3d0e0c - path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 - ReachabilitySwift: 2128f3a8c9107e1ad33574c6e58e8285d460b149 - rive_common: cf5ab646aa576b2d742d0e2d528126fbf032c856 - Sentry: ebc12276bd17613a114ab359074096b6b3725203 - sentry_flutter: dff1df05dc39c83d04f9330b36360fc374574c5e - SentryPrivate: d651efb234cf385ec9a1cdd3eff94b5e78a0e0fe - share_plus: 76dd39142738f7a68dd57b05093b5e8193f220f7 - shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 - sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec - url_launcher_macos: 5f437abeda8c85500ceb03f5c1938a8c5a705399 - -PODFILE CHECKSUM: 0d3963a09fc94f580682bd88480486da345dc3f0 - -COCOAPODS: 1.15.2 From 7b3cfab9d5dd08f2b108ce6aabc02887046a0b5d Mon Sep 17 00:00:00 2001 From: Edouard Marquez Date: Mon, 5 Aug 2024 10:03:32 +0200 Subject: [PATCH 15/24] feat: User lists: change the way to switch between lists (#5521) * User lists: change the way the switch between lists * Improve a11n --- .../product/common/product_list_page.dart | 152 +++++++++++++----- .../smooth_app/lib/resources/app_icons.dart | 26 +-- 2 files changed, 127 insertions(+), 51 deletions(-) diff --git a/packages/smooth_app/lib/pages/product/common/product_list_page.dart b/packages/smooth_app/lib/pages/product/common/product_list_page.dart index 2336258b8a8..5a183073e83 100644 --- a/packages/smooth_app/lib/pages/product/common/product_list_page.dart +++ b/packages/smooth_app/lib/pages/product/common/product_list_page.dart @@ -30,6 +30,8 @@ import 'package:smooth_app/pages/product/common/product_refresher.dart'; import 'package:smooth_app/pages/product_list_user_dialog_helper.dart'; import 'package:smooth_app/pages/scan/carousel/scan_carousel_manager.dart'; import 'package:smooth_app/query/product_query.dart'; +import 'package:smooth_app/resources/app_icons.dart' as icons; +import 'package:smooth_app/themes/theme_provider.dart'; import 'package:smooth_app/widgets/smooth_app_bar.dart'; import 'package:smooth_app/widgets/smooth_menu_button.dart'; import 'package:smooth_app/widgets/smooth_scaffold.dart'; @@ -146,42 +148,6 @@ class _ProductListPageState extends State appBar: SmoothAppBar( centerTitle: false, actions: [ - if (widget.allowToSwitchBetweenLists) - IconButton( - icon: const Icon(CupertinoIcons.square_list), - tooltip: appLocalizations.action_change_list, - onPressed: () async { - final ProductList? selected = - await showSmoothDraggableModalSheet( - context: context, - header: SmoothModalSheetHeader( - title: appLocalizations.product_list_select, - suffix: SmoothModalSheetHeaderButton( - label: appLocalizations.product_list_create, - prefix: const Icon(Icons.add_circle_outline_sharp), - tooltip: appLocalizations.product_list_create_tooltip, - onTap: () async => - ProductListUserDialogHelper(daoProductList) - .showCreateUserListDialog(context), - ), - ), - bodyBuilder: (BuildContext context) => AllProductListModal( - currentList: productList, - ), - initHeight: _computeModalInitHeight(context), - ); - - if (selected == null) { - return; - } - if (context.mounted) { - await daoProductList.get(selected); - if (context.mounted) { - setState(() => productList = selected); - } - } - }, - ), SmoothPopupMenuButton( onSelected: (final ProductListPopupItem action) async { final ProductList? differentProductList = @@ -202,13 +168,12 @@ class _ProductListPageState extends State ], ), ], - title: AutoSizeText( - ProductQueryPageHelper.getProductListLabel( - productList, - appLocalizations, - ), - maxLines: 2, + title: _ProductListAppBarTitle( + productList: productList, + onTap: () => _onChangeList(appLocalizations, daoProductList), + enabled: widget.allowToSwitchBetweenLists, ), + titleSpacing: 0.0, actionMode: _selectionMode, onLeaveActionMode: () { setState(() => _selectionMode = false); @@ -502,4 +467,107 @@ class _ProductListPageState extends State } return false; } + + Future _onChangeList( + AppLocalizations appLocalizations, + DaoProductList daoProductList, + ) async { + final ProductList? selected = + await showSmoothDraggableModalSheet( + context: context, + header: SmoothModalSheetHeader( + title: appLocalizations.product_list_select, + suffix: SmoothModalSheetHeaderButton( + label: appLocalizations.product_list_create, + prefix: const Icon(Icons.add_circle_outline_sharp), + tooltip: appLocalizations.product_list_create_tooltip, + onTap: () async => ProductListUserDialogHelper(daoProductList) + .showCreateUserListDialog(context), + ), + ), + bodyBuilder: (BuildContext context) => AllProductListModal( + currentList: productList, + ), + initHeight: _computeModalInitHeight(context), + ); + + if (selected == null) { + return; + } + if (context.mounted) { + await daoProductList.get(selected); + if (context.mounted) { + setState(() => productList = selected); + } + } + } +} + +class _ProductListAppBarTitle extends StatelessWidget { + const _ProductListAppBarTitle({ + required this.productList, + required this.onTap, + required this.enabled, + }); + + final ProductList productList; + final VoidCallback onTap; + final bool enabled; + + @override + Widget build(BuildContext context) { + final AppLocalizations appLocalizations = AppLocalizations.of(context); + final String title = ProductQueryPageHelper.getProductListLabel( + productList, + appLocalizations, + ); + + return Semantics( + label: enabled ? appLocalizations.action_change_list : null, + value: title, + button: enabled, + excludeSemantics: true, + child: SizedBox( + height: kToolbarHeight, + child: InkWell( + borderRadius: context.read().isAmoledTheme + ? ANGULAR_BORDER_RADIUS + : null, + onTap: enabled ? onTap : null, + child: Padding( + padding: const EdgeInsetsDirectional.symmetric( + horizontal: NavigationToolbar.kMiddleSpacing, + ), + child: LayoutBuilder( + builder: (_, BoxConstraints constraints) { + return Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + ConstrainedBox( + constraints: BoxConstraints( + maxWidth: constraints.maxWidth * 0.9 - + (enabled ? (MEDIUM_SPACE - 15.0) : 0), + ), + child: AutoSizeText( + title, + maxLines: 2, + ), + ), + if (enabled) ...[ + const SizedBox(width: MEDIUM_SPACE), + icons.AppIconTheme( + semanticLabel: appLocalizations.action_change_list, + size: 15.0, + child: const icons.Chevron.down(), + ) + ] + ], + ); + }, + ), + ), + ), + ), + ); + } } diff --git a/packages/smooth_app/lib/resources/app_icons.dart b/packages/smooth_app/lib/resources/app_icons.dart index 2d6dc46fdaa..0f9306227df 100644 --- a/packages/smooth_app/lib/resources/app_icons.dart +++ b/packages/smooth_app/lib/resources/app_icons.dart @@ -695,6 +695,7 @@ abstract class AppIcon extends StatelessWidget { this.color, this.shadow, this.size, + this.semanticLabel, super.key, }) : assert(size == null || size >= 0); @@ -702,6 +703,7 @@ abstract class AppIcon extends StatelessWidget { final Color? color; final double? size; final Shadow? shadow; + final String? semanticLabel; @override @mustCallSuper @@ -719,14 +721,17 @@ abstract class AppIcon extends StatelessWidget { Theme.of(context).iconTheme.color, }; - return Icon(icon, - color: color, - size: size ?? iconTheme?.size, - shadows: shadow != null - ? [shadow!] - : iconTheme?.shadow != null - ? [iconTheme!.shadow!] - : null); + return Icon( + icon, + color: color, + size: size ?? iconTheme?.size, + semanticLabel: iconTheme?.semanticLabel ?? semanticLabel, + shadows: shadow != null + ? [shadow!] + : iconTheme?.shadow != null + ? [iconTheme!.shadow!] + : null, + ); } } @@ -739,11 +744,13 @@ class AppIconTheme extends InheritedWidget { this.color, this.size, this.shadow, + this.semanticLabel, }); final Color? color; final double? size; final Shadow? shadow; + final String? semanticLabel; static AppIconTheme of(BuildContext context) { final AppIconTheme? result = maybeOf(context); @@ -758,7 +765,8 @@ class AppIconTheme extends InheritedWidget { @override bool updateShouldNotify(AppIconTheme oldWidget) { return color != oldWidget.color || - size != oldWidget.size || + semanticLabel != oldWidget.semanticLabel || + shadow != oldWidget.shadow || shadow != oldWidget.shadow; } } From 27b2c961499a3e6dd6614f0572188a34495e51b6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 Aug 2024 12:06:16 +0200 Subject: [PATCH 16/24] chore(deps): bump actions/setup-java from 4.2.1 to 4.2.2 (#5523) Bumps [actions/setup-java](https://github.com/actions/setup-java) from 4.2.1 to 4.2.2. - [Release notes](https://github.com/actions/setup-java/releases) - [Commits](https://github.com/actions/setup-java/compare/v4.2.1...v4.2.2) --- updated-dependencies: - dependency-name: actions/setup-java dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../workflows/android-release-to-org-openfoodfacts-scanner.yml | 2 +- .github/workflows/ios-release-to-org-openfoodfacts-scanner.yml | 2 +- .github/workflows/postsubmit.yml | 2 +- .github/workflows/waldo_sessions.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/android-release-to-org-openfoodfacts-scanner.yml b/.github/workflows/android-release-to-org-openfoodfacts-scanner.yml index 403e377ccbe..c8c5cb04c5c 100644 --- a/.github/workflows/android-release-to-org-openfoodfacts-scanner.yml +++ b/.github/workflows/android-release-to-org-openfoodfacts-scanner.yml @@ -63,7 +63,7 @@ jobs: - run: echo Release type ${{ inputs.RELEASE_TYPE }} + Build type ${{ inputs.BUILD_TYPE }} + Tag name null if not github release ${{ inputs.TAG_NAME }} - name: Setup Java JDK - uses: actions/setup-java@v4.2.1 + uses: actions/setup-java@v4.2.2 with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} diff --git a/.github/workflows/ios-release-to-org-openfoodfacts-scanner.yml b/.github/workflows/ios-release-to-org-openfoodfacts-scanner.yml index ca38e958008..d105f552ecc 100644 --- a/.github/workflows/ios-release-to-org-openfoodfacts-scanner.yml +++ b/.github/workflows/ios-release-to-org-openfoodfacts-scanner.yml @@ -61,7 +61,7 @@ jobs: run: bundle install working-directory: ./packages/smooth_app/android/ - name: Setup Java JDK - uses: actions/setup-java@v4.2.1 + uses: actions/setup-java@v4.2.2 with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} diff --git a/.github/workflows/postsubmit.yml b/.github/workflows/postsubmit.yml index 3ba797c1cda..3fc85dbe166 100644 --- a/.github/workflows/postsubmit.yml +++ b/.github/workflows/postsubmit.yml @@ -16,7 +16,7 @@ jobs: uses: actions/checkout@v4 - name: Setup Java JDK - uses: actions/setup-java@v4.2.1 + uses: actions/setup-java@v4.2.2 with: distribution: 'zulu' java-version: 17 diff --git a/.github/workflows/waldo_sessions.yml b/.github/workflows/waldo_sessions.yml index d6765be39df..d61bcb53d2e 100644 --- a/.github/workflows/waldo_sessions.yml +++ b/.github/workflows/waldo_sessions.yml @@ -27,7 +27,7 @@ jobs: fetch-depth: 0 - name: Setup Java JDK - uses: actions/setup-java@v4.2.1 + uses: actions/setup-java@v4.2.2 with: distribution: 'zulu' java-version: 17 From 30ca6b64b2e3a4fd9834d150a43a9ce95858c0ad Mon Sep 17 00:00:00 2001 From: Edouard Marquez Date: Wed, 7 Aug 2024 17:33:51 +0200 Subject: [PATCH 17/24] feat: Improvements for the search experience (#5519) * Improvements * Fix typo * One more typo --- packages/smooth_app/lib/l10n/app_en.arb | 4 + .../locations/search_location_helper.dart | 4 +- .../lib/pages/navigator/app_navigator.dart | 13 +- .../preferences/user_preferences_account.dart | 2 +- .../user_preferences_contribute.dart | 2 +- .../user_preferences_dev_mode.dart | 4 +- .../lib/pages/prices/price_location_card.dart | 4 +- .../product/common/product_query_page.dart | 100 +++--- .../common/product_query_page_helper.dart | 43 ++- .../product/common/search_empty_screen.dart | 22 +- .../pages/product/common/search_helper.dart | 16 +- .../product/common/search_loading_screen.dart | 1 + .../lib/pages/product/summary_card.dart | 2 +- .../carousel/main_card/scan_main_card.dart | 89 +++--- .../lib/pages/scan/search_page.dart | 267 ---------------- .../lib/pages/search/search_field.dart | 287 ++++++++++++++++++ .../{scan => search}/search_history_view.dart | 9 +- .../lib/pages/search/search_page.dart | 164 ++++++++++ .../search_product_helper.dart | 29 +- .../smooth_app/lib/widgets/smooth_hero.dart | 87 ++++++ 20 files changed, 744 insertions(+), 405 deletions(-) delete mode 100644 packages/smooth_app/lib/pages/scan/search_page.dart create mode 100644 packages/smooth_app/lib/pages/search/search_field.dart rename packages/smooth_app/lib/pages/{scan => search}/search_history_view.dart (96%) create mode 100644 packages/smooth_app/lib/pages/search/search_page.dart rename packages/smooth_app/lib/pages/{scan => search}/search_product_helper.dart (87%) create mode 100644 packages/smooth_app/lib/widgets/smooth_hero.dart diff --git a/packages/smooth_app/lib/l10n/app_en.arb b/packages/smooth_app/lib/l10n/app_en.arb index bfad1e2f3de..72cf11612ef 100644 --- a/packages/smooth_app/lib/l10n/app_en.arb +++ b/packages/smooth_app/lib/l10n/app_en.arb @@ -497,6 +497,10 @@ "@search": { "description": "Hint text of a search text input field" }, + "search_store": "Search for a store", + "@search_store": { + "description": "Hint text of a search store text input field" + }, "tap_for_more": "Tap to see more info…", "@Product": {}, "product": "Product", diff --git a/packages/smooth_app/lib/pages/locations/search_location_helper.dart b/packages/smooth_app/lib/pages/locations/search_location_helper.dart index c371bb098ef..2c086f223d3 100644 --- a/packages/smooth_app/lib/pages/locations/search_location_helper.dart +++ b/packages/smooth_app/lib/pages/locations/search_location_helper.dart @@ -8,14 +8,14 @@ import 'package:smooth_app/pages/product/common/search_helper.dart'; /// Search helper dedicated to location search. class SearchLocationHelper extends SearchHelper { - const SearchLocationHelper(); + SearchLocationHelper(); @override String get historyKey => DaoStringList.keySearchLocationHistory; @override String getHintText(final AppLocalizations appLocalizations) => - 'Rechercher un magasin'; + appLocalizations.search_store; @override void search( diff --git a/packages/smooth_app/lib/pages/navigator/app_navigator.dart b/packages/smooth_app/lib/pages/navigator/app_navigator.dart index 68f33560b2b..44c9086a5f7 100644 --- a/packages/smooth_app/lib/pages/navigator/app_navigator.dart +++ b/packages/smooth_app/lib/pages/navigator/app_navigator.dart @@ -18,8 +18,8 @@ import 'package:smooth_app/pages/product/edit_product_page.dart'; import 'package:smooth_app/pages/product/new_product_page.dart'; import 'package:smooth_app/pages/product/product_loader_page.dart'; import 'package:smooth_app/pages/scan/carousel/scan_carousel_manager.dart'; -import 'package:smooth_app/pages/scan/search_page.dart'; -import 'package:smooth_app/pages/scan/search_product_helper.dart'; +import 'package:smooth_app/pages/search/search_page.dart'; +import 'package:smooth_app/pages/search/search_product_helper.dart'; import 'package:smooth_app/pages/user_management/sign_up_page.dart'; import 'package:smooth_app/query/product_query.dart'; @@ -204,7 +204,13 @@ class _SmoothGoRouter { ), GoRoute( path: _InternalAppRoutes.SEARCH_PAGE, - builder: (_, __) => const SearchPage(SearchProductHelper()), + builder: (_, GoRouterState state) { + if (state.extra != null) { + return SearchPage.fromExtra(state.extra! as SearchPageExtra); + } else { + return SearchPage(SearchProductHelper()); + } + }, ), GoRoute( path: _InternalAppRoutes._GUIDES, @@ -452,6 +458,7 @@ class AppRoutes { '/${_InternalAppRoutes._GUIDES}/${_InternalAppRoutes.GUIDE_NUTRISCORE_V2_PAGE}'; static String get SIGNUP => '/${_InternalAppRoutes.SIGNUP_PAGE}'; + // Open an external link (where path is relative to the OFF website) static String EXTERNAL(String path) => '/${_InternalAppRoutes.EXTERNAL_PAGE}/?path=$path'; diff --git a/packages/smooth_app/lib/pages/preferences/user_preferences_account.dart b/packages/smooth_app/lib/pages/preferences/user_preferences_account.dart index 3121ddff96c..73974491aeb 100644 --- a/packages/smooth_app/lib/pages/preferences/user_preferences_account.dart +++ b/packages/smooth_app/lib/pages/preferences/user_preferences_account.dart @@ -443,7 +443,7 @@ class UserPreferencesAccount extends AbstractUserPreferences { }) => _getListTile( title, - () async => ProductQueryPageHelper().openBestChoice( + () async => ProductQueryPageHelper.openBestChoice( name: title, localDatabase: localDatabase, productQuery: productQuery, diff --git a/packages/smooth_app/lib/pages/preferences/user_preferences_contribute.dart b/packages/smooth_app/lib/pages/preferences/user_preferences_contribute.dart index 530c2e94062..12ca3580a73 100644 --- a/packages/smooth_app/lib/pages/preferences/user_preferences_contribute.dart +++ b/packages/smooth_app/lib/pages/preferences/user_preferences_contribute.dart @@ -172,7 +172,7 @@ class UserPreferencesContribute extends AbstractUserPreferences { final LocalDatabase localDatabase = context.read(); Navigator.of(context).pop(); - ProductQueryPageHelper().openBestChoice( + ProductQueryPageHelper.openBestChoice( name: appLocalizations.all_search_to_be_completed_title, localDatabase: localDatabase, productQuery: PagedToBeCompletedProductQuery(), diff --git a/packages/smooth_app/lib/pages/preferences/user_preferences_dev_mode.dart b/packages/smooth_app/lib/pages/preferences/user_preferences_dev_mode.dart index f14ae46d4f6..fc0bfdbb1ec 100644 --- a/packages/smooth_app/lib/pages/preferences/user_preferences_dev_mode.dart +++ b/packages/smooth_app/lib/pages/preferences/user_preferences_dev_mode.dart @@ -27,7 +27,7 @@ import 'package:smooth_app/pages/preferences/user_preferences_item.dart'; import 'package:smooth_app/pages/preferences/user_preferences_page.dart'; import 'package:smooth_app/pages/preferences/user_preferences_search_page.dart'; import 'package:smooth_app/pages/preferences/user_preferences_widgets.dart'; -import 'package:smooth_app/pages/scan/search_page.dart'; +import 'package:smooth_app/pages/search/search_page.dart'; import 'package:smooth_app/query/product_query.dart'; /// Full page display of "dev mode" for the preferences page. @@ -421,7 +421,7 @@ class UserPreferencesDevMode extends AbstractUserPreferences { context, MaterialPageRoute( builder: (BuildContext context) => SearchPage( - const SearchLocationHelper(), + SearchLocationHelper(), preloadedList: preloadedList, autofocus: false, ), diff --git a/packages/smooth_app/lib/pages/prices/price_location_card.dart b/packages/smooth_app/lib/pages/prices/price_location_card.dart index bd3d9f14998..ad34b1457d6 100644 --- a/packages/smooth_app/lib/pages/prices/price_location_card.dart +++ b/packages/smooth_app/lib/pages/prices/price_location_card.dart @@ -10,7 +10,7 @@ import 'package:smooth_app/pages/locations/osm_location.dart'; import 'package:smooth_app/pages/locations/search_location_helper.dart'; import 'package:smooth_app/pages/locations/search_location_preloaded_item.dart'; import 'package:smooth_app/pages/prices/price_model.dart'; -import 'package:smooth_app/pages/scan/search_page.dart'; +import 'package:smooth_app/pages/search/search_page.dart'; /// Card that displays the location for price adding. class PriceLocationCard extends StatelessWidget { @@ -52,7 +52,7 @@ class PriceLocationCard extends StatelessWidget { context, MaterialPageRoute( builder: (BuildContext context) => SearchPage( - const SearchLocationHelper(), + SearchLocationHelper(), preloadedList: preloadedList, autofocus: false, ), diff --git a/packages/smooth_app/lib/pages/product/common/product_query_page.dart b/packages/smooth_app/lib/pages/product/common/product_query_page.dart index 05e8a9ad268..ef14c35be99 100644 --- a/packages/smooth_app/lib/pages/product/common/product_query_page.dart +++ b/packages/smooth_app/lib/pages/product/common/product_query_page.dart @@ -32,17 +32,19 @@ import 'package:smooth_app/widgets/ranking_floating_action_button.dart'; import 'package:smooth_app/widgets/smooth_app_bar.dart'; import 'package:smooth_app/widgets/smooth_scaffold.dart'; +/// A page that can be used like a screen, if [includeAppBar] is true. +/// Otherwise, it can be embedded in another screen. class ProductQueryPage extends StatefulWidget { const ProductQueryPage({ required this.productListSupplier, required this.name, - required this.editableAppBarTitle, + this.includeAppBar = true, this.searchResult = true, }); final ProductListSupplier productListSupplier; final String name; - final bool editableAppBarTitle; + final bool includeAppBar; final bool searchResult; @override @@ -57,7 +59,7 @@ class _ProductQueryPageState extends State late ScrollController _scrollController; late ProductQueryModel _model; - late final OpenFoodFactsCountry? _country; + late OpenFoodFactsCountry? _country; @override String get actionName => 'Opened search_page'; @@ -88,9 +90,13 @@ class _ProductQueryPageState extends State } @override - void dispose() { - _scrollController.dispose(); - super.dispose(); + void didUpdateWidget(ProductQueryPage oldWidget) { + super.didUpdateWidget(oldWidget); + + if (oldWidget.productListSupplier != widget.productListSupplier) { + _model = _getModel(widget.productListSupplier); + _country = widget.productListSupplier.productQuery.country; + } } @override @@ -124,11 +130,11 @@ class _ProductQueryPageState extends State // TODO(monsieurtanuki): should be tracked as well, shouldn't it? return SearchEmptyScreen( name: widget.name, + includeAppBar: widget.includeAppBar, emptiness: _getEmptyText( themeData, appLocalizations.no_product_found, ), - actions: _getAppBarButtons(), ); } AnalyticsHelper.trackSearch( @@ -149,6 +155,12 @@ class _ProductQueryPageState extends State ); } + @override + void dispose() { + _scrollController.dispose(); + super.dispose(); + } + // TODO(monsieurtanuki): put that in a specific Widget class Widget _getNotEmptyScreen( final Size screenSize, @@ -162,8 +174,8 @@ class _ProductQueryPageState extends State children: [ Expanded( child: RankingFloatingActionButton( - onPressed: () => Navigator.push( - context, + onPressed: () => + Navigator.of(context, rootNavigator: true).push( MaterialPageRoute( builder: (BuildContext context) => PersonalizedRankingPage( @@ -212,26 +224,27 @@ class _ProductQueryPageState extends State ), ], ), - appBar: SmoothAppBar( - backgroundColor: themeData.scaffoldBackgroundColor, - elevation: 2, - automaticallyImplyLeading: false, - leading: const SmoothBackButton(), - title: SearchAppBarTitle( - title: widget.searchResult - ? widget.name - : appLocalizations.product_search_same_category, - editableAppBarTitle: - widget.searchResult && widget.editableAppBarTitle, - multiLines: !widget.searchResult, - ), - subTitle: !widget.searchResult ? Text(widget.name) : null, - actions: _getAppBarButtons(), - ), + appBar: widget.includeAppBar + ? SmoothAppBar( + backgroundColor: themeData.scaffoldBackgroundColor, + elevation: 2, + automaticallyImplyLeading: false, + leading: const SmoothBackButton(), + title: SearchAppBarTitle( + title: widget.searchResult + ? widget.name + : appLocalizations.product_search_same_category, + editableAppBarTitle: widget.searchResult, + multiLines: !widget.searchResult, + ), + subTitle: !widget.searchResult ? Text(widget.name) : null, + ) + : null, body: RefreshIndicator( onRefresh: () async => _refreshList(), child: ListView.builder( controller: _scrollController, + padding: widget.includeAppBar ? null : EdgeInsets.zero, // To allow refresh even when not the whole page is filled physics: const AlwaysScrollableScrollPhysics(), itemBuilder: (BuildContext context, int index) { @@ -298,6 +311,7 @@ class _ProductQueryPageState extends State ) { return SearchEmptyScreen( name: widget.name, + includeAppBar: false, emptiness: Padding( padding: const EdgeInsets.all(SMALL_SPACE), child: SmoothErrorCard( @@ -331,25 +345,21 @@ class _ProductQueryPageState extends State ), if (worldQuery != null) _getLargeButtonWithIcon( - _getWorldAction(appLocalizations, worldQuery), + _getWorldAction( + appLocalizations, + worldQuery, + widget.includeAppBar, + ), ), ], ), ); } - List _getAppBarButtons() { - final AppLocalizations appLocalizations = AppLocalizations.of(context); + Widget _getTopMessagesCard() { final PagedProductQuery pagedProductQuery = _model.supplier.productQuery; final PagedProductQuery? worldQuery = pagedProductQuery.getWorldQuery(); - return [ - if (worldQuery != null) - _getIconButton(_getWorldAction(appLocalizations, worldQuery)), - ]; - } - Widget _getTopMessagesCard() { - final PagedProductQuery pagedProductQuery = _model.supplier.productQuery; return FutureBuilder( future: _getTranslatedCountry(), builder: ( @@ -383,7 +393,19 @@ class _ProductQueryPageState extends State child: SmoothCard( child: Padding( padding: const EdgeInsets.all(SMALL_SPACE), - child: Text(messages.join('\n')), + child: Row( + children: [ + Expanded(child: Text(messages.join('\n'))), + if (pagedProductQuery.getWorldQuery() != null) + _getIconButton( + _getWorldAction( + appLocalizations, + worldQuery!, + widget.includeAppBar, + ), + ), + ], + ), ), ), ); @@ -399,7 +421,7 @@ class _ProductQueryPageState extends State final List localizedCountries = await IsoCountries.isoCountriesForLocale(locale); for (final Country country in localizedCountries) { - if (country.countryCode.toLowerCase() == _country.offTag.toLowerCase()) { + if (country.countryCode.toLowerCase() == _country?.offTag.toLowerCase()) { return country.name; } } @@ -422,15 +444,17 @@ class _ProductQueryPageState extends State _Action _getWorldAction( final AppLocalizations appLocalizations, final PagedProductQuery worldQuery, + final bool editableAppBarTitle, ) => _Action( text: appLocalizations.world_results_action, iconData: Icons.public, - onPressed: () async => ProductQueryPageHelper().openBestChoice( + onPressed: () async => ProductQueryPageHelper.openBestChoice( productQuery: worldQuery, localDatabase: context.read(), name: widget.name, context: context, + editableAppBarTitle: editableAppBarTitle, ), ); diff --git a/packages/smooth_app/lib/pages/product/common/product_query_page_helper.dart b/packages/smooth_app/lib/pages/product/common/product_query_page_helper.dart index fd4cb0e10ec..80201057e86 100644 --- a/packages/smooth_app/lib/pages/product/common/product_query_page_helper.dart +++ b/packages/smooth_app/lib/pages/product/common/product_query_page_helper.dart @@ -8,32 +8,55 @@ import 'package:smooth_app/pages/product/common/search_helper.dart'; import 'package:smooth_app/query/paged_product_query.dart'; class ProductQueryPageHelper { - Future openBestChoice({ + const ProductQueryPageHelper._(); + + static Future getBestChoiceWidget({ required final PagedProductQuery productQuery, required final LocalDatabase localDatabase, required final String name, required final BuildContext context, bool editableAppBarTitle = true, bool searchResult = true, - SearchQueryCallback? editQueryCallback, }) async { final ProductListSupplier supplier = await ProductListSupplier.getBestSupplier( productQuery, localDatabase, ); + + return ProductQueryPage( + productListSupplier: supplier, + name: name, + includeAppBar: editableAppBarTitle, + searchResult: searchResult, + ); + } + + static Future openBestChoice({ + required final PagedProductQuery productQuery, + required final LocalDatabase localDatabase, + required final String name, + required final BuildContext context, + bool editableAppBarTitle = true, + bool searchResult = true, + SearchQueryCallback? editQueryCallback, + }) async { + final Widget widget = await getBestChoiceWidget( + productQuery: productQuery, + localDatabase: localDatabase, + name: name, + context: context, + editableAppBarTitle: editableAppBarTitle, + searchResult: searchResult, + ); + if (!context.mounted) { return; } - final bool? result = await Navigator.push( - context, + + final bool? result = await Navigator.of(context).push( MaterialPageRoute( - builder: (BuildContext context) => ProductQueryPage( - productListSupplier: supplier, - name: name, - editableAppBarTitle: editableAppBarTitle, - searchResult: searchResult, - ), + builder: (BuildContext context) => widget, ), ); diff --git a/packages/smooth_app/lib/pages/product/common/search_empty_screen.dart b/packages/smooth_app/lib/pages/product/common/search_empty_screen.dart index 2ab31bed112..98dbf68f7ad 100644 --- a/packages/smooth_app/lib/pages/product/common/search_empty_screen.dart +++ b/packages/smooth_app/lib/pages/product/common/search_empty_screen.dart @@ -8,25 +8,29 @@ class SearchEmptyScreen extends StatelessWidget { required this.name, required this.emptiness, this.actions, + this.includeAppBar = true, Key? key, }) : super(key: key); final String name; final Widget emptiness; final List? actions; + final bool includeAppBar; @override Widget build(BuildContext context) { return SmoothScaffold( - appBar: AppBar( - backgroundColor: Theme.of(context).scaffoldBackgroundColor, - leading: const SmoothBackButton(), - title: SearchAppBarTitle( - title: name, - editableAppBarTitle: false, - ), - actions: actions, - ), + appBar: includeAppBar + ? AppBar( + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + leading: const SmoothBackButton(), + title: SearchAppBarTitle( + title: name, + editableAppBarTitle: false, + ), + actions: actions, + ) + : null, body: Center(child: emptiness), ); } diff --git a/packages/smooth_app/lib/pages/product/common/search_helper.dart b/packages/smooth_app/lib/pages/product/common/search_helper.dart index e3313f562c4..fb171d7779a 100644 --- a/packages/smooth_app/lib/pages/product/common/search_helper.dart +++ b/packages/smooth_app/lib/pages/product/common/search_helper.dart @@ -6,8 +6,10 @@ import 'package:smooth_app/database/local_database.dart'; typedef SearchQueryCallback = void Function(String query); /// Common "text-field + history" search helper. -abstract class SearchHelper { - const SearchHelper(); +/// Will emit a [SearchQuery] when a search is performed. +/// By default (with the [null] value), the history will be displayed. +abstract class SearchHelper extends ValueNotifier { + SearchHelper() : super(null); /// Action to perform for a search. @protected @@ -58,3 +60,13 @@ abstract class SearchHelper { }, ); } + +class SearchQuery { + const SearchQuery({ + required this.search, + required this.widget, + }) : assert(search.length > 0); + + final String search; + final Widget widget; +} diff --git a/packages/smooth_app/lib/pages/product/common/search_loading_screen.dart b/packages/smooth_app/lib/pages/product/common/search_loading_screen.dart index d04fd382412..6c60417a585 100644 --- a/packages/smooth_app/lib/pages/product/common/search_loading_screen.dart +++ b/packages/smooth_app/lib/pages/product/common/search_loading_screen.dart @@ -19,6 +19,7 @@ class SearchLoadingScreen extends StatelessWidget { return SearchEmptyScreen( name: title, + includeAppBar: false, emptiness: FractionallySizedBox( widthFactor: 0.75, child: Column( diff --git a/packages/smooth_app/lib/pages/product/summary_card.dart b/packages/smooth_app/lib/pages/product/summary_card.dart index 6245291f22e..df54b727673 100644 --- a/packages/smooth_app/lib/pages/product/summary_card.dart +++ b/packages/smooth_app/lib/pages/product/summary_card.dart @@ -298,7 +298,7 @@ class _SummaryCardState extends State with UpToDateMixin { addPanelButton( localizations.product_search_same_category, iconData: Icons.leaderboard, - onPressed: () async => ProductQueryPageHelper().openBestChoice( + onPressed: () async => ProductQueryPageHelper.openBestChoice( name: categoryLabel!, localDatabase: context.read(), productQuery: CategoryProductQuery(categoryTag!), diff --git a/packages/smooth_app/lib/pages/scan/carousel/main_card/scan_main_card.dart b/packages/smooth_app/lib/pages/scan/carousel/main_card/scan_main_card.dart index 389cc3aa0e6..044350ca9ec 100644 --- a/packages/smooth_app/lib/pages/scan/carousel/main_card/scan_main_card.dart +++ b/packages/smooth_app/lib/pages/scan/carousel/main_card/scan_main_card.dart @@ -9,8 +9,9 @@ import 'package:smooth_app/helpers/provider_helper.dart'; import 'package:smooth_app/helpers/strings_helper.dart'; import 'package:smooth_app/pages/navigator/app_navigator.dart'; import 'package:smooth_app/pages/scan/carousel/main_card/scan_tagline.dart'; -import 'package:smooth_app/resources/app_icons.dart'; -import 'package:smooth_app/themes/smooth_theme_colors.dart'; +import 'package:smooth_app/pages/search/search_field.dart'; +import 'package:smooth_app/pages/search/search_page.dart'; +import 'package:smooth_app/pages/search/search_product_helper.dart'; import 'package:smooth_app/themes/theme_provider.dart'; class ScanMainCard extends StatelessWidget { @@ -121,65 +122,51 @@ class _SearchCard extends StatelessWidget { class _SearchBar extends StatelessWidget { const _SearchBar(); - static const double SEARCH_BAR_HEIGHT = 47.0; + static const String HERO_TAG = 'search_field'; @override Widget build(BuildContext context) { final AppLocalizations localizations = AppLocalizations.of(context); - final SmoothColorsThemeExtension theme = - Theme.of(context).extension()!; - final bool lightTheme = !context.watch().isDarkMode(context); return Semantics( button: true, - child: SizedBox( - height: SEARCH_BAR_HEIGHT, - child: InkWell( - onTap: () => AppNavigator.of(context).push(AppRoutes.SEARCH), - borderRadius: BorderRadius.circular(30.0), - child: Ink( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(30.0), - color: lightTheme ? Colors.white : theme.greyDark, - border: Border.all(color: theme.primaryBlack), - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - child: Padding( - padding: const EdgeInsetsDirectional.only( - start: 20.0, - end: BALANCED_SPACE, - bottom: 3.0, - ), - child: Text( - localizations.homepage_main_card_search_field_hint, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: TextStyle( - color: lightTheme ? Colors.black : Colors.white, - ), - ), - ), + child: Hero( + tag: HERO_TAG, + child: Material( + // ↑ Needed by the Hero Widget + type: MaterialType.transparency, + child: SizedBox( + height: SearchFieldUIHelper.SEARCH_BAR_HEIGHT, + child: InkWell( + onTap: () => AppNavigator.of(context).push( + AppRoutes.SEARCH, + extra: SearchPageExtra( + searchHelper: SearchProductHelper(), + autofocus: true, + heroTag: HERO_TAG, ), - AspectRatio( - aspectRatio: 1.0, - child: DecoratedBox( - decoration: BoxDecoration( - color: theme.primaryDark, - shape: BoxShape.circle, - ), - child: const Padding( - padding: EdgeInsets.all(BALANCED_SPACE), - child: Search( - size: 20.0, - color: Colors.white, + ), + borderRadius: SearchFieldUIHelper.SEARCH_BAR_BORDER_RADIUS, + child: Ink( + decoration: SearchFieldUIHelper.decoration(context), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: Padding( + padding: SearchFieldUIHelper.SEARCH_BAR_PADDING, + child: Text( + localizations.homepage_main_card_search_field_hint, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: SearchFieldUIHelper.textStyle(context), + ), ), ), - ), - ) - ], + const SearchBarIcon(), + ], + ), + ), ), ), ), diff --git a/packages/smooth_app/lib/pages/scan/search_page.dart b/packages/smooth_app/lib/pages/scan/search_page.dart deleted file mode 100644 index 68d11d70918..00000000000 --- a/packages/smooth_app/lib/pages/scan/search_page.dart +++ /dev/null @@ -1,267 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -import 'package:provider/provider.dart'; -import 'package:smooth_app/generic_lib/design_constants.dart'; -import 'package:smooth_app/generic_lib/duration_constants.dart'; -import 'package:smooth_app/pages/product/common/search_helper.dart'; -import 'package:smooth_app/pages/product/common/search_preloaded_item.dart'; -import 'package:smooth_app/pages/scan/search_history_view.dart'; -import 'package:smooth_app/widgets/smooth_app_bar.dart'; -import 'package:smooth_app/widgets/smooth_scaffold.dart'; - -class SearchPage extends StatefulWidget { - const SearchPage( - this.searchHelper, { - this.preloadedList, - this.autofocus = true, - }); - - final SearchHelper searchHelper; - final List? preloadedList; - final bool autofocus; - - @override - State createState() => _SearchPageState(); -} - -class _SearchPageState extends State { - // https://github.com/openfoodfacts/smooth-app/pull/2219 - final TextEditingController _searchTextController = TextEditingController(); - final FocusNode _searchFocusNode = FocusNode(); - - @override - Widget build(BuildContext context) { - return SmoothScaffold( - appBar: SmoothAppBar(toolbarHeight: 0.0), - body: ChangeNotifierProvider( - create: (_) => _searchTextController, - child: Column( - children: [ - Padding( - padding: const EdgeInsets.all(BALANCED_SPACE), - child: SearchField( - autofocus: widget.autofocus, - focusNode: _searchFocusNode, - searchHelper: widget.searchHelper, - ), - ), - Expanded( - child: SearchHistoryView( - focusNode: _searchFocusNode, - onTap: (String query) => - widget.searchHelper.searchWithController( - context, - query, - _searchTextController, - _searchFocusNode, - ), - searchHelper: widget.searchHelper, - preloadedList: widget.preloadedList ?? [], - ), - ), - ], - ), - ), - ); - } -} - -class SearchField extends StatefulWidget { - const SearchField({ - required this.searchHelper, - this.autofocus = false, - this.showClearButton = true, - this.readOnly = false, - this.onFocus, - this.backgroundColor, - this.foregroundColor, - this.focusNode, - }); - - final SearchHelper searchHelper; - final bool autofocus; - final bool showClearButton; - - /// If true, the Widget will only display the UI - final bool readOnly; - final void Function()? onFocus; - final Color? backgroundColor; - final Color? foregroundColor; - - final FocusNode? focusNode; - - @override - State createState() => _SearchFieldState(); -} - -class _SearchFieldState extends State { - late FocusNode _focusNode; - late TextEditingController _controller; - - bool _isEmpty = true; - - @override - void initState() { - super.initState(); - - _focusNode = widget.focusNode ?? FocusNode(); - _focusNode.addListener(_handleFocusChange); - - if (widget.autofocus) { - _focusNode.requestFocus(); - } - } - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - - try { - _controller = Provider.of(context); - } catch (err) { - _controller = TextEditingController(); - } - - _controller.removeListener(_handleTextChange); - _controller.addListener(_handleTextChange); - } - - @override - void dispose() { - _focusNode.removeListener(_handleFocusChange); - _focusNode.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - final AppLocalizations localizations = AppLocalizations.of(context); - - try { - _controller = Provider.of(context); - } catch (err) { - _controller = TextEditingController(); - } - - final InputDecoration inputDecoration = InputDecoration( - fillColor: widget.backgroundColor, - labelStyle: Theme.of(context).textTheme.bodyMedium?.copyWith( - color: widget.foregroundColor, - ), - filled: true, - border: const OutlineInputBorder( - borderRadius: CIRCULAR_BORDER_RADIUS, - borderSide: BorderSide.none, - ), - contentPadding: const EdgeInsets.symmetric( - horizontal: 25.0, - vertical: 17.0, - ), - hintText: widget.searchHelper.getHintText(localizations), - suffixIcon: - widget.showClearButton ? _buildClearButton(localizations) : null, - ); - - const TextStyle textStyle = TextStyle(fontSize: 18.0); - - if (widget.readOnly) { - return InkWell( - borderRadius: CIRCULAR_BORDER_RADIUS, - splashColor: Theme.of(context).primaryColor, - onTap: () { - widget.onFocus?.call(); - }, - child: Ink( - decoration: BoxDecoration( - borderRadius: CIRCULAR_BORDER_RADIUS, - color: Theme.of(context).brightness == Brightness.light - ? Colors.white - : null, - ), - child: InputDecorator( - decoration: inputDecoration, - child: Text( - inputDecoration.hintText!, - style: Theme.of(context) - .textTheme - .titleMedium! - .copyWith(color: Theme.of(context).hintColor) - .merge(textStyle), - ), - ), - ), - ); - } else { - return TextField( - textInputAction: TextInputAction.search, - controller: _controller, - focusNode: _focusNode, - onSubmitted: (String query) => widget.searchHelper.searchWithController( - context, - query, - _controller, - _focusNode, - ), - decoration: inputDecoration, - style: textStyle, - ); - } - } - - Widget _buildClearButton(AppLocalizations localizations) { - return Padding( - padding: const EdgeInsetsDirectional.only(end: MEDIUM_SPACE), - child: ClipOval( - child: Material( - type: MaterialType.transparency, - child: IconButton( - tooltip: localizations.clear_search, - onPressed: _handleClear, - icon: AnimatedCrossFade( - duration: SmoothAnimationsDuration.short, - crossFadeState: _isEmpty - ? CrossFadeState.showFirst - : CrossFadeState.showSecond, - // Closes the page. - firstChild: Icon( - Icons.close, - semanticLabel: localizations.clear_search, - ), - // Clears the text. - secondChild: Icon( - Icons.cancel, - semanticLabel: localizations.clear_search, - ), - ), - ), - ), - ), - ); - } - - void _handleTextChange() { - //Only rebuild the widget if the text length is 0 or 1 as we only check if - //the text length is empty or not - if (_controller.text.isEmpty || _controller.text.length == 1) { - setState(() { - _isEmpty = _controller.text.isEmpty; - }); - } - } - - void _handleFocusChange() { - if (_focusNode.hasFocus && widget.onFocus != null) { - _focusNode.unfocus(); - widget.onFocus?.call(); - } - } - - // FIXME(monsieurtanuki): when we paste from the clipboard and then clear, _isEmpty is not changed and therefore we pop instead of clearing. - void _handleClear() { - if (_isEmpty) { - Navigator.pop(context); - } else { - _controller.clear(); - } - } -} diff --git a/packages/smooth_app/lib/pages/search/search_field.dart b/packages/smooth_app/lib/pages/search/search_field.dart new file mode 100644 index 00000000000..baefe1ab293 --- /dev/null +++ b/packages/smooth_app/lib/pages/search/search_field.dart @@ -0,0 +1,287 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:provider/provider.dart'; +import 'package:smooth_app/generic_lib/design_constants.dart'; +import 'package:smooth_app/pages/product/common/search_helper.dart'; +import 'package:smooth_app/resources/app_icons.dart' as icons; +import 'package:smooth_app/themes/constant_icons.dart'; +import 'package:smooth_app/themes/smooth_theme_colors.dart'; +import 'package:smooth_app/themes/theme_provider.dart'; +import 'package:smooth_app/widgets/smooth_hero.dart'; + +class SearchField extends StatefulWidget { + const SearchField({ + required this.searchHelper, + this.autofocus = false, + this.showClearButton = true, + this.heroTag, + this.onFocus, + this.backgroundColor, + this.foregroundColor, + this.focusNode, + this.enableSuggestions = false, + this.autocorrect = false, + }); + + final SearchHelper searchHelper; + final bool autofocus; + final bool showClearButton; + final bool enableSuggestions; + final bool autocorrect; + + final String? heroTag; + final void Function()? onFocus; + final Color? backgroundColor; + final Color? foregroundColor; + + final FocusNode? focusNode; + + @override + State createState() => _SearchFieldState(); +} + +class _SearchFieldState extends State { + late FocusNode _focusNode; + TextEditingController? _controller; + + @override + void initState() { + super.initState(); + _focusNode = widget.focusNode ?? FocusNode(); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + + try { + _controller = Provider.of(context); + } catch (err) { + _controller = TextEditingController(); + } + } + + @override + Widget build(BuildContext context) { + final AppLocalizations localizations = AppLocalizations.of(context); + + try { + _controller ??= Provider.of(context); + } catch (err) { + _controller = TextEditingController(); + } + + final TextStyle textStyle = SearchFieldUIHelper.textStyle(context); + + return ChangeNotifierProvider.value( + value: _controller!, + child: SmoothHero( + tag: widget.heroTag, + enabled: widget.heroTag != null, + onAnimationEnded: widget.autofocus + ? (HeroFlightDirection direction) { + /// The autofocus should only be requested once the Animation is over + if (direction == HeroFlightDirection.push) { + WidgetsBinding.instance.addPostFrameCallback((_) { + _focusNode.requestFocus(); + }); + } + } + : null, + child: Material( + // ↑ Needed by the Hero Widget + child: TextField( + controller: _controller, + focusNode: _focusNode, + onSubmitted: (String query) => _performSearch(context, query), + textInputAction: TextInputAction.search, + enableSuggestions: widget.enableSuggestions, + autocorrect: widget.autocorrect, + style: textStyle, + decoration: _getInputDecoration( + context, + localizations, + ), + cursorColor: textStyle.color, + ), + ), + ), + ); + } + + InputDecoration _getInputDecoration( + BuildContext context, + AppLocalizations localizations, + ) { + final BoxDecoration decoration = SearchFieldUIHelper.decoration(context); + final OutlineInputBorder border = OutlineInputBorder( + borderRadius: decoration.borderRadius! as BorderRadius, + borderSide: decoration.border!.top.copyWith(width: 2.0), + ); + + return InputDecoration( + fillColor: decoration.color, + filled: true, + constraints: const BoxConstraints.tightFor( + height: SearchFieldUIHelper.SEARCH_BAR_HEIGHT, + ), + border: border, + enabledBorder: border, + focusedBorder: border, + contentPadding: SearchFieldUIHelper.SEARCH_BAR_PADDING, + hintText: widget.searchHelper.getHintText(localizations), + prefixIcon: const Align( + alignment: AlignmentDirectional.centerStart, + child: _BackIcon(), + ), + prefixIconConstraints: BoxConstraints.tightFor( + width: SearchFieldUIHelper.SEARCH_BAR_HEIGHT + + (SearchFieldUIHelper.SEARCH_BAR_PADDING.horizontal) / 2, + ), + suffixIcon: widget.showClearButton + ? _SearchIcon( + onTap: () => _performSearch(context, _controller!.text), + ) + : null, + ); + } + + void _performSearch(BuildContext context, String query) => + widget.searchHelper.searchWithController( + context, + query, + _controller!, + _focusNode, + ); + + @override + void dispose() { + /// The [FocusNode] provided to this Widget is disposed elsewhere + if (_focusNode != widget.focusNode) { + _focusNode.dispose(); + } + + super.dispose(); + } +} + +class _BackIcon extends StatelessWidget { + const _BackIcon(); + + @override + Widget build(BuildContext context) { + return SearchBarIcon( + icon: Icon(ConstantIcons.instance.getBackIcon()), + label: MaterialLocalizations.of(context).closeButtonTooltip, + onTap: () => Navigator.of(context).pop(), + ); + } +} + +class _SearchIcon extends StatelessWidget { + const _SearchIcon({required this.onTap}); + + final VoidCallback onTap; + + @override + Widget build(BuildContext context) { + final AppLocalizations localizations = AppLocalizations.of(context); + + return SearchBarIcon( + icon: const icons.Search(), + label: localizations.search, + onTap: onTap, + ); + } +} + +class SearchBarIcon extends StatelessWidget { + const SearchBarIcon({ + this.icon, + this.onTap, + this.label, + super.key, + }) : assert(label == null || onTap != null); + + final VoidCallback? onTap; + final String? label; + final Widget? icon; + + @override + Widget build(BuildContext context) { + final SmoothColorsThemeExtension theme = + Theme.of(context).extension()!; + + final Widget widget = AspectRatio( + aspectRatio: 1.0, + child: DecoratedBox( + decoration: BoxDecoration( + color: theme.primaryDark, + shape: BoxShape.circle, + ), + child: Padding( + padding: const EdgeInsets.all(BALANCED_SPACE), + child: IconTheme( + data: const IconThemeData( + size: 20.0, + color: Colors.white, + ), + child: icon ?? const icons.Search(), + ), + ), + ), + ); + + if (onTap == null) { + return widget; + } else { + return Semantics( + label: label, + button: true, + excludeSemantics: true, + child: Tooltip( + message: label ?? '', + child: InkWell( + borderRadius: SearchFieldUIHelper.SEARCH_BAR_BORDER_RADIUS, + onTap: onTap, + child: widget, + ), + ), + ); + } + } +} + +/// Constants shared between [SearchField] and [_SearchBar] +class SearchFieldUIHelper { + const SearchFieldUIHelper._(); + + static const double SEARCH_BAR_HEIGHT = 47.0; + static const BorderRadius SEARCH_BAR_BORDER_RADIUS = BorderRadius.all( + Radius.circular(30.0), + ); + static const EdgeInsetsGeometry SEARCH_BAR_PADDING = + EdgeInsetsDirectional.only( + start: 20.0, + end: BALANCED_SPACE, + bottom: 3.0, + ); + + static TextStyle textStyle(BuildContext context) { + final bool lightTheme = !context.watch().isDarkMode(context); + return TextStyle(color: lightTheme ? Colors.black : Colors.white); + } + + static BoxDecoration decoration(BuildContext context) { + final SmoothColorsThemeExtension theme = + Theme.of(context).extension()!; + final bool lightTheme = !context.watch().isDarkMode(context); + + return BoxDecoration( + borderRadius: SearchFieldUIHelper.SEARCH_BAR_BORDER_RADIUS, + color: lightTheme ? Colors.white : theme.greyDark, + border: Border.all( + color: lightTheme ? theme.primaryBlack : theme.primarySemiDark), + ); + } +} diff --git a/packages/smooth_app/lib/pages/scan/search_history_view.dart b/packages/smooth_app/lib/pages/search/search_history_view.dart similarity index 96% rename from packages/smooth_app/lib/pages/scan/search_history_view.dart rename to packages/smooth_app/lib/pages/search/search_history_view.dart index a4b0a94507a..6f56e568d3e 100644 --- a/packages/smooth_app/lib/pages/scan/search_history_view.dart +++ b/packages/smooth_app/lib/pages/search/search_history_view.dart @@ -44,12 +44,13 @@ class _SearchHistoryViewState extends State { Widget build(BuildContext context) { return ListTileTheme( data: ListTileThemeData( - titleTextStyle: const TextStyle(fontSize: 20.0), - minLeadingWidth: 18.0, + titleTextStyle: const TextStyle(fontSize: 18.0), + minLeadingWidth: 10.0, iconColor: Theme.of(context).colorScheme.onSurface, textColor: Theme.of(context).colorScheme.onSurface, ), child: ListView.builder( + padding: EdgeInsets.zero, itemBuilder: (BuildContext context, int i) { if (i == 0) { return _SearchItemPasteFromClipboard( @@ -150,7 +151,7 @@ class _SearchHistoryTile extends StatelessWidget { child: InkWell( onTap: () => onTap(), child: Padding( - padding: const EdgeInsetsDirectional.only(start: 18.0, end: 13.0), + padding: const EdgeInsetsDirectional.only(start: 8.0), child: ListTile( leading: const Padding( padding: EdgeInsetsDirectional.only(top: VERY_SMALL_SPACE), @@ -204,7 +205,7 @@ class _SearchItemPasteFromClipboard extends StatelessWidget { } }, child: Padding( - padding: const EdgeInsetsDirectional.only(start: 18.0, end: 13.0), + padding: const EdgeInsetsDirectional.only(start: 8.0, end: 13.0), child: ListTile( title: Text(localizations.paste_from_clipboard), leading: const Icon(Icons.copy), diff --git a/packages/smooth_app/lib/pages/search/search_page.dart b/packages/smooth_app/lib/pages/search/search_page.dart new file mode 100644 index 00000000000..cda42435bbd --- /dev/null +++ b/packages/smooth_app/lib/pages/search/search_page.dart @@ -0,0 +1,164 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:smooth_app/generic_lib/design_constants.dart'; +import 'package:smooth_app/helpers/provider_helper.dart'; +import 'package:smooth_app/pages/product/common/search_helper.dart'; +import 'package:smooth_app/pages/product/common/search_preloaded_item.dart'; +import 'package:smooth_app/pages/search/search_field.dart'; +import 'package:smooth_app/pages/search/search_history_view.dart'; +import 'package:smooth_app/widgets/smooth_scaffold.dart'; + +/// The [SearchPage] screen. +/// It can opened directly with the [SearchPageExtra] constructor. +/// From GoRouter, the page is named [AppRoutes.SEARCH] and we need to pass a +/// [SearchPageExtra] object for extras. +class SearchPage extends StatefulWidget { + const SearchPage( + this.searchHelper, { + this.preloadedList, + this.autofocus = true, + this.heroTag, + }); + + SearchPage.fromExtra(SearchPageExtra extra) + : this( + extra.searchHelper, + preloadedList: extra.preloadedList, + autofocus: extra.autofocus ?? true, + heroTag: extra.heroTag, + ); + + final SearchHelper searchHelper; + final List? preloadedList; + final bool autofocus; + final String? heroTag; + + @override + State createState() => _SearchPageState(); +} + +class SearchPageExtra { + const SearchPageExtra({ + required this.searchHelper, + this.preloadedList, + this.autofocus, + this.heroTag, + }); + + final SearchHelper searchHelper; + final List? preloadedList; + + /// If not passed, will default to [false] + final bool? autofocus; + final String? heroTag; +} + +class _SearchPageState extends State { + // https://github.com/openfoodfacts/smooth-app/pull/2219 + final TextEditingController _searchTextController = TextEditingController(); + final FocusNode _searchFocusNode = FocusNode(); + final GlobalKey _navigatorKey = GlobalKey(); + + @override + Widget build(BuildContext context) { + return MultiProvider( + providers: >[ + ChangeNotifierProvider.value( + value: _searchTextController, + ), + ChangeNotifierProvider.value( + value: widget.searchHelper, + ), + ], + child: SmoothScaffold( + body: Column( + children: [ + ValueNotifierListener( + listener: _onSearchChanged, + child: SafeArea( + bottom: false, + child: Padding( + padding: const EdgeInsetsDirectional.symmetric( + vertical: SMALL_SPACE, + horizontal: BALANCED_SPACE, + ), + child: SearchField( + autofocus: widget.autofocus, + focusNode: _searchFocusNode, + searchHelper: widget.searchHelper, + heroTag: widget.heroTag, + ), + ), + ), + ), + Expanded( + child: Consumer( + builder: ( + BuildContext context, + SearchHelper searchHelper, + _, + ) { + /// Show the history when there is no search + if (searchHelper.value == null) { + return SearchHistoryView( + focusNode: _searchFocusNode, + onTap: (String query) => + widget.searchHelper.searchWithController( + context, + query, + _searchTextController, + _searchFocusNode, + ), + searchHelper: widget.searchHelper, + preloadedList: + widget.preloadedList ?? [], + ); + } else { + /// A custom [Navigator] is used to intercept the World + /// results to be embedded in this part of the screen and + /// not on a new one. + return Navigator( + key: _navigatorKey, + pages: >[ + MaterialPage( + child: searchHelper.value!.widget, + ), + ], + onPopPage: (Route route, dynamic result) { + if (!route.didPop(result)) { + return false; + } + return true; + }, + ); + } + }, + ), + ), + ], + ), + ), + ); + } + + void _onSearchChanged( + BuildContext context, + SearchQuery? oldValue, + SearchQuery? value, + ) { + if (value != null && _searchTextController.text != value.search) { + /// Update the search field when an history item is selected + WidgetsBinding.instance.addPostFrameCallback((_) { + _searchTextController.text = value.search; + }); + } else if (oldValue != null) { + /// If we were on the world results, ensure to go back to + /// the main list of results + WidgetsBinding.instance.addPostFrameCallback((_) { + _navigatorKey.currentState?.popUntil((Route route) { + return route.isFirst; + }); + }); + } + } +} diff --git a/packages/smooth_app/lib/pages/scan/search_product_helper.dart b/packages/smooth_app/lib/pages/search/search_product_helper.dart similarity index 87% rename from packages/smooth_app/lib/pages/scan/search_product_helper.dart rename to packages/smooth_app/lib/pages/search/search_product_helper.dart index 94fab981bbe..d2f6b3a71dd 100644 --- a/packages/smooth_app/lib/pages/scan/search_product_helper.dart +++ b/packages/smooth_app/lib/pages/search/search_product_helper.dart @@ -5,6 +5,7 @@ import 'package:smooth_app/data_models/fetched_product.dart'; import 'package:smooth_app/database/dao_string_list.dart'; import 'package:smooth_app/database/local_database.dart'; import 'package:smooth_app/helpers/analytics_helper.dart'; +import 'package:smooth_app/helpers/provider_helper.dart'; import 'package:smooth_app/helpers/string_extension.dart'; import 'package:smooth_app/pages/navigator/app_navigator.dart'; import 'package:smooth_app/pages/product/common/product_dialog_helper.dart'; @@ -14,7 +15,7 @@ import 'package:smooth_app/query/keywords_product_query.dart'; /// Search helper dedicated to product search. class SearchProductHelper extends SearchHelper { - const SearchProductHelper(); + SearchProductHelper(); @override String get historyKey => DaoStringList.keySearchProductHistory; @@ -52,7 +53,6 @@ class SearchProductHelper extends SearchHelper { query, context, localDatabase, - editProductQueryCallback: searchQueryCallback, ); } } @@ -99,14 +99,19 @@ class SearchProductHelper extends SearchHelper { Future _onSubmittedText( final String value, final BuildContext context, - final LocalDatabase localDatabase, { - SearchQueryCallback? editProductQueryCallback, - }) async => - ProductQueryPageHelper().openBestChoice( - name: value, - localDatabase: localDatabase, - productQuery: KeywordsProductQuery(value), - context: context, - editQueryCallback: editProductQueryCallback, - ); + final LocalDatabase localDatabase, + ) async { + emit( + SearchQuery( + search: value, + widget: await ProductQueryPageHelper.getBestChoiceWidget( + name: value, + localDatabase: localDatabase, + productQuery: KeywordsProductQuery(value), + context: context, + editableAppBarTitle: false, + ), + ), + ); + } } diff --git a/packages/smooth_app/lib/widgets/smooth_hero.dart b/packages/smooth_app/lib/widgets/smooth_hero.dart new file mode 100644 index 00000000000..aa0f33d3d1c --- /dev/null +++ b/packages/smooth_app/lib/widgets/smooth_hero.dart @@ -0,0 +1,87 @@ +import 'package:flutter/material.dart'; + +/// A custom [Hero] widget that allows to listen to the end of the animation. +/// This code is mainly a copy/paste from the Flutter widget, but some methods +/// are private. +/// +/// The goal here, is to be notified when the animation is finished and +/// thus trigger an autofocus event at the perfect timing. +class SmoothHero extends StatelessWidget { + const SmoothHero({ + required this.tag, + required this.enabled, + required this.child, + this.onAnimationEnded, + super.key, + }) : assert(!enabled || tag != null); + + final Object? tag; + final bool enabled; + final Widget child; + final Function(HeroFlightDirection direction)? onAnimationEnded; + + @override + Widget build(BuildContext context) { + return HeroMode( + enabled: enabled, + child: Hero( + tag: tag ?? '', + flightShuttleBuilder: + onAnimationEnded == null ? null : _flightShuttleBuilder, + child: child, + ), + ); + } + + Widget _flightShuttleBuilder( + BuildContext flightContext, + Animation animation, + HeroFlightDirection flightDirection, + BuildContext fromHeroContext, + BuildContext toHeroContext, + ) { + animation.addStatusListener((AnimationStatus status) { + _onAnimationStatusChanged(status, flightDirection); + }); + + /// Code from [heroes.dart] + final Hero toHero = toHeroContext.widget as Hero; + + final MediaQueryData? toMediaQueryData = MediaQuery.maybeOf(toHeroContext); + final MediaQueryData? fromMediaQueryData = + MediaQuery.maybeOf(fromHeroContext); + + if (toMediaQueryData == null || fromMediaQueryData == null) { + return toHero.child; + } + + final EdgeInsets fromHeroPadding = fromMediaQueryData.padding; + final EdgeInsets toHeroPadding = toMediaQueryData.padding; + + return AnimatedBuilder( + animation: animation, + builder: (BuildContext context, Widget? child) { + return MediaQuery( + data: toMediaQueryData.copyWith( + padding: (flightDirection == HeroFlightDirection.push) + ? EdgeInsetsTween( + begin: fromHeroPadding, + end: toHeroPadding, + ).evaluate(animation) + : EdgeInsetsTween( + begin: toHeroPadding, + end: fromHeroPadding, + ).evaluate(animation), + ), + child: toHero.child, + ); + }); + } + + void _onAnimationStatusChanged( + AnimationStatus status, HeroFlightDirection direction) { + if (status == AnimationStatus.completed) { + onAnimationEnded?.call(direction); + } + } +} From da8a2a02c0b189fccdba0a45bfba566b12322435 Mon Sep 17 00:00:00 2001 From: Edouard Marquez Date: Thu, 8 Aug 2024 12:25:28 +0200 Subject: [PATCH 18/24] Fix error if Podfile.lock doesn't exist (#5527) --- .github/workflows/ios-release-to-org-openfoodfacts-scanner.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ios-release-to-org-openfoodfacts-scanner.yml b/.github/workflows/ios-release-to-org-openfoodfacts-scanner.yml index d105f552ecc..8a9b54dc058 100644 --- a/.github/workflows/ios-release-to-org-openfoodfacts-scanner.yml +++ b/.github/workflows/ios-release-to-org-openfoodfacts-scanner.yml @@ -110,7 +110,7 @@ jobs: VERSION_CODE: ${{ inputs.VERSION_CODE }} - name: Build app - run: cd ./packages/smooth_app && cd ios && rm -rf Pods && rm Podfile.lock && flutter pub get && pod install && cd .. && flutter build ios --release --no-codesign -t lib/entrypoints/ios/main_ios.dart + run: cd ./packages/smooth_app && cd ios && rm -rf Pods && rm -f Podfile.lock && flutter pub get && pod install && cd .. && flutter build ios --release --no-codesign -t lib/entrypoints/ios/main_ios.dart env: GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }} SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} From a8bce8ac40238d1bf2610cc929681d4480079eb9 Mon Sep 17 00:00:00 2001 From: monsieurtanuki Date: Mon, 12 Aug 2024 13:40:25 +0200 Subject: [PATCH 19/24] feat: 5526 - new Prices prod/test url flag (#5528) Impacted files: * `background_task_add_prices.dart`: Prices API called using new Prices prod/test url * `get_prices_model.dart`: Prices API called using new Prices prod/test url * `price_user_button.dart`: Prices API called using new Prices prod/test url * `prices_proofs_page.dart`: Prices API called using new Prices prod/test url * `prices_users_page.dart`: Prices API called using new Prices prod/test url * `product_prices_list.dart`: Prices API called using new Prices prod/test url * `product_query.dart`: new Prices prod/test url * `user_preferences_account.dart`: Prices API called using new Prices prod/test url * `user_preferences_dev_mode.dart`: new prod/test flag for Prices url --- .../background/background_task_add_price.dart | 9 +++--- .../preferences/user_preferences_account.dart | 6 ++-- .../user_preferences_dev_mode.dart | 29 +++++++++++++++++++ .../lib/pages/prices/get_prices_model.dart | 2 +- .../lib/pages/prices/price_user_button.dart | 2 +- .../lib/pages/prices/prices_proofs_page.dart | 8 ++--- .../lib/pages/prices/prices_users_page.dart | 4 +-- .../lib/pages/prices/product_prices_list.dart | 2 +- .../smooth_app/lib/query/product_query.dart | 20 +++++++++---- 9 files changed, 60 insertions(+), 22 deletions(-) diff --git a/packages/smooth_app/lib/background/background_task_add_price.dart b/packages/smooth_app/lib/background/background_task_add_price.dart index a17b2ff50c2..cc99c2084b3 100644 --- a/packages/smooth_app/lib/background/background_task_add_price.dart +++ b/packages/smooth_app/lib/background/background_task_add_price.dart @@ -14,6 +14,7 @@ import 'package:smooth_app/database/local_database.dart'; import 'package:smooth_app/pages/crop_parameters.dart'; import 'package:smooth_app/pages/prices/eraser_model.dart'; import 'package:smooth_app/pages/prices/eraser_painter.dart'; +import 'package:smooth_app/query/product_query.dart'; // TODO(monsieurtanuki): use transient file, in order to have instant access to proof image? /// Background task about adding a product price. @@ -344,7 +345,7 @@ class BackgroundTaskAddPrice extends BackgroundTask { await OpenPricesAPIClient.getAuthenticationToken( username: user.userId, password: user.password, - uriHelper: uriProductHelper, + uriHelper: ProductQuery.uriPricesHelper, ); if (token.isError) { throw Exception('Could not get token: ${token.error}'); @@ -367,7 +368,7 @@ class BackgroundTaskAddPrice extends BackgroundTask { imageUri: initialImageUri, mediaType: initialMediaType, bearerToken: bearerToken, - uriHelper: uriProductHelper, + uriHelper: ProductQuery.uriPricesHelper, ); if (uploadProof.isError) { throw Exception('Could not upload proof: ${uploadProof.error}'); @@ -390,7 +391,7 @@ class BackgroundTaskAddPrice extends BackgroundTask { await OpenPricesAPIClient.createPrice( price: newPrice, bearerToken: bearerToken, - uriHelper: uriProductHelper, + uriHelper: ProductQuery.uriPricesHelper, ); if (addedPrice.isError) { throw Exception('Could not add price: ${addedPrice.error}'); @@ -400,7 +401,7 @@ class BackgroundTaskAddPrice extends BackgroundTask { // close session final MaybeError closedSession = await OpenPricesAPIClient.deleteUserSession( - uriHelper: uriProductHelper, + uriHelper: ProductQuery.uriPricesHelper, bearerToken: bearerToken, ); if (closedSession.isError) { diff --git a/packages/smooth_app/lib/pages/preferences/user_preferences_account.dart b/packages/smooth_app/lib/pages/preferences/user_preferences_account.dart index 73974491aeb..04b2e2762b8 100644 --- a/packages/smooth_app/lib/pages/preferences/user_preferences_account.dart +++ b/packages/smooth_app/lib/pages/preferences/user_preferences_account.dart @@ -276,7 +276,7 @@ class UserPreferencesAccount extends AbstractUserPreferences { displayProduct: true, uri: OpenPricesAPIClient.getUri( path: 'app/prices', - uriHelper: ProductQuery.uriProductHelper, + uriHelper: ProductQuery.uriPricesHelper, ), title: appLocalizations.all_search_prices_latest_title, ), @@ -363,7 +363,7 @@ class UserPreferencesAccount extends AbstractUserPreferences { () async => LaunchUrlHelper.launchURL( OpenPricesAPIClient.getUri( path: path, - uriHelper: ProductQuery.uriProductHelper, + uriHelper: ProductQuery.uriPricesHelper, ).toString(), ), Icons.open_in_new, @@ -425,7 +425,7 @@ class UserPreferencesAccount extends AbstractUserPreferences { GetPricesParameters() ..owner = owner ..pageSize = 1, - uriHelper: ProductQuery.uriProductHelper, + uriHelper: ProductQuery.uriPricesHelper, ); if (result.isError) { return null; diff --git a/packages/smooth_app/lib/pages/preferences/user_preferences_dev_mode.dart b/packages/smooth_app/lib/pages/preferences/user_preferences_dev_mode.dart index fc0bfdbb1ec..5e65b3ff776 100644 --- a/packages/smooth_app/lib/pages/preferences/user_preferences_dev_mode.dart +++ b/packages/smooth_app/lib/pages/preferences/user_preferences_dev_mode.dart @@ -48,6 +48,7 @@ class UserPreferencesDevMode extends AbstractUserPreferences { ); static const String userPreferencesFlagProd = '__devWorkingOnProd'; + static const String userPreferencesFlagPriceProd = '__devWorkingOnPricesProd'; static const String userPreferencesTestEnvDomain = '__testEnvHost'; static const String userPreferencesFlagEditIngredients = '__editIngredients'; static const String userPreferencesFlagBoostedComparison = @@ -269,6 +270,34 @@ class UserPreferencesDevMode extends AbstractUserPreferences { ), onTap: () async => _changeTestEnvDomain(), ), + const UserPreferencesItemSection( + label: 'Prices Server configuration', + ), + UserPreferencesItemTile( + title: 'Switch between prices.openfoodfacts.org (PROD) and test env', + trailing: DropdownButton( + value: + userPreferences.getFlag(userPreferencesFlagPriceProd) ?? true, + elevation: 16, + onChanged: (bool? newValue) async { + await userPreferences.setFlag( + userPreferencesFlagPriceProd, + newValue, + ); + ProductQuery.setQueryType(userPreferences); + }, + items: const >[ + DropdownMenuItem( + value: true, + child: Text('PROD'), + ), + DropdownMenuItem( + value: false, + child: Text('TEST'), + ), + ], + ), + ), UserPreferencesItemSection( label: appLocalizations.dev_mode_section_news, ), diff --git a/packages/smooth_app/lib/pages/prices/get_prices_model.dart b/packages/smooth_app/lib/pages/prices/get_prices_model.dart index 2087975356d..84b5333f4f7 100644 --- a/packages/smooth_app/lib/pages/prices/get_prices_model.dart +++ b/packages/smooth_app/lib/pages/prices/get_prices_model.dart @@ -57,7 +57,7 @@ class GetPricesModel { ) => OpenPricesAPIClient.getUri( path: 'app/products/$barcode', - uriHelper: ProductQuery.uriProductHelper, + uriHelper: ProductQuery.uriPricesHelper, ); /// Query parameters. diff --git a/packages/smooth_app/lib/pages/prices/price_user_button.dart b/packages/smooth_app/lib/pages/prices/price_user_button.dart index d7bcd09da52..c9521ab4fc2 100644 --- a/packages/smooth_app/lib/pages/prices/price_user_button.dart +++ b/packages/smooth_app/lib/pages/prices/price_user_button.dart @@ -42,7 +42,7 @@ class PriceUserButton extends StatelessWidget { displayProduct: true, uri: OpenPricesAPIClient.getUri( path: 'app/users/$user', - uriHelper: ProductQuery.uriProductHelper, + uriHelper: ProductQuery.uriPricesHelper, ), title: showUserTitle(user: user, context: context), subtitle: user, diff --git a/packages/smooth_app/lib/pages/prices/prices_proofs_page.dart b/packages/smooth_app/lib/pages/prices/prices_proofs_page.dart index fac691981f4..fd3189d8d81 100644 --- a/packages/smooth_app/lib/pages/prices/prices_proofs_page.dart +++ b/packages/smooth_app/lib/pages/prices/prices_proofs_page.dart @@ -47,7 +47,7 @@ class _PricesProofsPageState extends State onPressed: () async => LaunchUrlHelper.launchURL( OpenPricesAPIClient.getUri( path: 'app/dashboard/proofs', - uriHelper: ProductQuery.uriProductHelper, + uriHelper: ProductQuery.uriPricesHelper, ).toString(), ), ), @@ -152,7 +152,7 @@ class _PricesProofsPageState extends State await OpenPricesAPIClient.getAuthenticationToken( username: user.userId, password: user.password, - uriHelper: ProductQuery.uriProductHelper, + uriHelper: ProductQuery.uriPricesHelper, ); final String bearerToken = token.value; @@ -167,12 +167,12 @@ class _PricesProofsPageState extends State ] ..pageSize = _pageSize ..pageNumber = 1, - uriHelper: ProductQuery.uriProductHelper, + uriHelper: ProductQuery.uriPricesHelper, bearerToken: bearerToken, ); await OpenPricesAPIClient.deleteUserSession( - uriHelper: ProductQuery.uriProductHelper, + uriHelper: ProductQuery.uriPricesHelper, bearerToken: bearerToken, ); diff --git a/packages/smooth_app/lib/pages/prices/prices_users_page.dart b/packages/smooth_app/lib/pages/prices/prices_users_page.dart index 4ec9283aaec..6e0b801c37d 100644 --- a/packages/smooth_app/lib/pages/prices/prices_users_page.dart +++ b/packages/smooth_app/lib/pages/prices/prices_users_page.dart @@ -46,7 +46,7 @@ class _PricesUsersPageState extends State onPressed: () async => LaunchUrlHelper.launchURL( OpenPricesAPIClient.getUri( path: 'app/users', - uriHelper: ProductQuery.uriProductHelper, + uriHelper: ProductQuery.uriPricesHelper, ).toString(), ), ), @@ -140,6 +140,6 @@ class _PricesUsersPageState extends State ] ..pageSize = _pageSize ..pageNumber = 1, - uriHelper: ProductQuery.uriProductHelper, + uriHelper: ProductQuery.uriPricesHelper, ); } diff --git a/packages/smooth_app/lib/pages/prices/product_prices_list.dart b/packages/smooth_app/lib/pages/prices/product_prices_list.dart index 8f30271732d..4de382f88f9 100644 --- a/packages/smooth_app/lib/pages/prices/product_prices_list.dart +++ b/packages/smooth_app/lib/pages/prices/product_prices_list.dart @@ -126,6 +126,6 @@ class _ProductPricesListState extends State ) async => OpenPricesAPIClient.getPrices( parameters, - uriHelper: ProductQuery.uriProductHelper, + uriHelper: ProductQuery.uriPricesHelper, ); } diff --git a/packages/smooth_app/lib/query/product_query.dart b/packages/smooth_app/lib/query/product_query.dart index 4f636f519bd..ca81edf58d5 100644 --- a/packages/smooth_app/lib/query/product_query.dart +++ b/packages/smooth_app/lib/query/product_query.dart @@ -166,16 +166,24 @@ abstract class ProductQuery { static late UriProductHelper uriProductHelper; + /// Product helper only for prices. + static late UriProductHelper uriPricesHelper; + static bool isLoggedIn() => OpenFoodAPIConfiguration.globalUser != null; /// Sets the query type according to the current [UserPreferences] static void setQueryType(final UserPreferences userPreferences) { - final bool queryTypeProd = userPreferences - .getFlag(UserPreferencesDevMode.userPreferencesFlagProd) ?? - true; - uriProductHelper = queryTypeProd - ? uriHelperFoodProd - : getTestUriProductHelper(userPreferences); + UriProductHelper getProductHelper(final String flagProd) => + userPreferences.getFlag(flagProd) ?? true + ? uriHelperFoodProd + : getTestUriProductHelper(userPreferences); + + uriProductHelper = getProductHelper( + UserPreferencesDevMode.userPreferencesFlagProd, + ); + uriPricesHelper = getProductHelper( + UserPreferencesDevMode.userPreferencesFlagPriceProd, + ); } /// Returns the standard test env, or the custom test env if relevant. From 06e9fea0fb2a5c4b246e800780341dbf0e16e781 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Aug 2024 14:08:05 +0200 Subject: [PATCH 20/24] chore(deps): bump uuid and matomo_tracker in /packages/smooth_app (#5505) * chore(deps): bump uuid and matomo_tracker in /packages/smooth_app Bumps [uuid](https://github.com/Daegalus/dart-uuid) and [matomo_tracker](https://github.com/Floating-Dartists/matomo-tracker). These dependencies needed to be updated together. Updates `uuid` from 3.0.7 to 4.4.2 - [Release notes](https://github.com/Daegalus/dart-uuid/releases) - [Changelog](https://github.com/daegalus/dart-uuid/blob/main/CHANGELOG.md) - [Commits](https://github.com/Daegalus/dart-uuid/compare/3.0.7...4.4.2) Updates `matomo_tracker` from 4.1.1 to 5.0.0-dev.2 - [Release notes](https://github.com/Floating-Dartists/matomo-tracker/releases) - [Changelog](https://github.com/Floating-Dartists/matomo-tracker/blob/main/CHANGELOG.md) - [Commits](https://github.com/Floating-Dartists/matomo-tracker/compare/4.1.1...5.0.0-dev.2) --- updated-dependencies: - dependency-name: uuid dependency-type: direct:production update-type: version-update:semver-major - dependency-name: matomo_tracker dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * breaking change: int to string --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Cirrus CI --- .../smooth_app/lib/helpers/analytics_helper.dart | 2 +- packages/smooth_app/pubspec.lock | 16 ++++++++++++---- packages/smooth_app/pubspec.yaml | 4 ++-- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/packages/smooth_app/lib/helpers/analytics_helper.dart b/packages/smooth_app/lib/helpers/analytics_helper.dart index 5170bc65a53..56b885cecd5 100644 --- a/packages/smooth_app/lib/helpers/analytics_helper.dart +++ b/packages/smooth_app/lib/helpers/analytics_helper.dart @@ -286,7 +286,7 @@ class AnalyticsHelper { try { await MatomoTracker.instance.initialize( url: 'https://analytics.openfoodfacts.org/matomo.php', - siteId: 2, + siteId: '2', visitorId: _visitorId, ); } catch (err) { diff --git a/packages/smooth_app/pubspec.lock b/packages/smooth_app/pubspec.lock index 31d9c599402..eeb9139d8d8 100644 --- a/packages/smooth_app/pubspec.lock +++ b/packages/smooth_app/pubspec.lock @@ -1028,10 +1028,10 @@ packages: dependency: "direct main" description: name: matomo_tracker - sha256: de5c08e80b566f8d1f0edf47f5704fe855fbef52377acb2796d28c2a3e36ea41 + sha256: "9c4bfa031191655b09d757c35b9ffeabff2a267a982ebd385b8dff0556d9e50f" url: "https://pub.dev" source: hosted - version: "4.1.1" + version: "5.0.0-dev.2" meta: dependency: transitive description: @@ -1491,6 +1491,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.10.0" + sprintf: + dependency: transitive + description: + name: sprintf + sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" + url: "https://pub.dev" + source: hosted + version: "7.0.0" sqflite: dependency: "direct main" description: @@ -1679,10 +1687,10 @@ packages: dependency: "direct main" description: name: uuid - sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313" + sha256: "83d37c7ad7aaf9aa8e275490669535c8080377cfa7a7004c24dfac53afffaa90" url: "https://pub.dev" source: hosted - version: "3.0.7" + version: "4.4.2" vector_graphics: dependency: transitive description: diff --git a/packages/smooth_app/pubspec.yaml b/packages/smooth_app/pubspec.yaml index affe85f10e5..8d917756537 100644 --- a/packages/smooth_app/pubspec.yaml +++ b/packages/smooth_app/pubspec.yaml @@ -30,12 +30,12 @@ dependencies: image_picker: 1.1.2 iso_countries: 2.2.0 latlong2: 0.9.1 - matomo_tracker: 4.1.1 + matomo_tracker: 5.0.0-dev.2 package_info_plus: 5.0.1 device_info_plus: 9.1.2 permission_handler: 11.3.1 photo_view: 0.15.0 - uuid: 3.0.7 + uuid: 4.4.2 provider: 6.1.2 sentry_flutter: 8.4.0 sqflite: 2.3.3+1 From 79a6ff69004e71a1cc2068702229f77943f68b7d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Aug 2024 18:04:43 +0200 Subject: [PATCH 21/24] chore(deps): bump audioplayers, package_info_plus and http in /packages/smooth_app (#5530) * chore(deps): bump audioplayers, package_info_plus and http Bumps [audioplayers](https://github.com/bluefireteam/audioplayers/tree/master/packages), [package_info_plus](https://github.com/fluttercommunity/plus_plugins/tree/main/packages/package_info_plus) and [http](https://github.com/dart-lang/http/tree/master/pkgs). These dependencies needed to be updated together. Updates `audioplayers` from 5.2.1 to 6.0.0 - [Changelog](https://github.com/bluefireteam/audioplayers/blob/main/CHANGELOG.md) - [Commits](https://github.com/bluefireteam/audioplayers/commits/audioplayers-v6.0.0/packages) Updates `package_info_plus` from 5.0.1 to 7.0.0 - [Release notes](https://github.com/fluttercommunity/plus_plugins/releases) - [Commits](https://github.com/fluttercommunity/plus_plugins/commits/package_info_plus-v7.0.0/packages/package_info_plus) Updates `http` from 1.2.0 to 1.2.2 - [Release notes](https://github.com/dart-lang/http/releases) - [Commits](https://github.com/dart-lang/http/commits/http-v1.2.2/pkgs) --- updated-dependencies: - dependency-name: audioplayers dependency-type: direct:production update-type: version-update:semver-major - dependency-name: package_info_plus dependency-type: direct:production update-type: version-update:semver-major - dependency-name: http dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Minor fixes --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Cirrus CI --- .../smooth_app/lib/pages/scan/scan_page.dart | 8 +- packages/smooth_app/pubspec.lock | 84 +++++++++---------- packages/smooth_app/pubspec.yaml | 6 +- 3 files changed, 49 insertions(+), 49 deletions(-) diff --git a/packages/smooth_app/lib/pages/scan/scan_page.dart b/packages/smooth_app/lib/pages/scan/scan_page.dart index a5229d43e1a..01185002a79 100644 --- a/packages/smooth_app/lib/pages/scan/scan_page.dart +++ b/packages/smooth_app/lib/pages/scan/scan_page.dart @@ -109,8 +109,8 @@ class _ScanPageState extends State { await _musicPlayer!.play( AssetSource('audio/beep.wav'), volume: 0.5, - ctx: const AudioContext( - android: AudioContextAndroid( + ctx: AudioContext( + android: const AudioContextAndroid( isSpeakerphoneOn: false, stayAwake: false, contentType: AndroidContentType.sonification, @@ -120,9 +120,9 @@ class _ScanPageState extends State { ), iOS: AudioContextIOS( category: AVAudioSessionCategory.soloAmbient, - options: [ + options: const { AVAudioSessionOptions.mixWithOthers, - ], + }, ), ), ); diff --git a/packages/smooth_app/pubspec.lock b/packages/smooth_app/pubspec.lock index eeb9139d8d8..91208e3ac8d 100644 --- a/packages/smooth_app/pubspec.lock +++ b/packages/smooth_app/pubspec.lock @@ -89,58 +89,58 @@ packages: dependency: "direct main" description: name: audioplayers - sha256: c05c6147124cd63e725e861335a8b4d57300b80e6e92cea7c145c739223bbaef + sha256: "752039d6aa752597c98ec212e9759519061759e402e7da59a511f39d43aa07d2" url: "https://pub.dev" source: hosted - version: "5.2.1" + version: "6.0.0" audioplayers_android: dependency: transitive description: name: audioplayers_android - sha256: b00e1a0e11365d88576320ec2d8c192bc21f1afb6c0e5995d1c57ae63156acb5 + sha256: de576b890befe27175c2f511ba8b742bec83765fa97c3ce4282bba46212f58e4 url: "https://pub.dev" source: hosted - version: "4.0.3" + version: "5.0.0" audioplayers_darwin: dependency: transitive description: name: audioplayers_darwin - sha256: "3034e99a6df8d101da0f5082dcca0a2a99db62ab1d4ddb3277bed3f6f81afe08" + sha256: e507887f3ff18d8e5a10a668d7bedc28206b12e10b98347797257c6ae1019c3b url: "https://pub.dev" source: hosted - version: "5.0.2" + version: "6.0.0" audioplayers_linux: dependency: transitive description: name: audioplayers_linux - sha256: "60787e73fefc4d2e0b9c02c69885402177e818e4e27ef087074cf27c02246c9e" + sha256: "3d3d244c90436115417f170426ce768856d8fe4dfc5ed66a049d2890acfa82f9" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "4.0.0" audioplayers_platform_interface: dependency: transitive description: name: audioplayers_platform_interface - sha256: "365c547f1bb9e77d94dd1687903a668d8f7ac3409e48e6e6a3668a1ac2982adb" + sha256: "6834dd48dfb7bc6c2404998ebdd161f79cd3774a7e6779e1348d54a3bfdcfaa5" url: "https://pub.dev" source: hosted - version: "6.1.0" + version: "7.0.0" audioplayers_web: dependency: transitive description: name: audioplayers_web - sha256: "22cd0173e54d92bd9b2c80b1204eb1eb159ece87475ab58c9788a70ec43c2a62" + sha256: db8fc420dadf80da18e2286c18e746fb4c3b2c5adbf0c963299dde046828886d url: "https://pub.dev" source: hosted - version: "4.1.0" + version: "5.0.0" audioplayers_windows: dependency: transitive description: name: audioplayers_windows - sha256: "9536812c9103563644ada2ef45ae523806b0745f7a78e89d1b5fb1951de90e1a" + sha256: "8605762dddba992138d476f6a0c3afd9df30ac5b96039929063eceed416795c2" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "4.0.0" auto_size_text: dependency: "direct main" description: @@ -329,10 +329,10 @@ packages: dependency: transitive description: name: cross_file - sha256: fedaadfa3a6996f75211d835aaeb8fede285dae94262485698afd832371b9a5e + sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670" url: "https://pub.dev" source: hosted - version: "0.3.3+8" + version: "0.3.4+2" crypto: dependency: transitive description: @@ -807,10 +807,10 @@ packages: dependency: "direct main" description: name: http - sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba + sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.2.2" http_parser: dependency: "direct main" description: @@ -956,18 +956,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" url: "https://pub.dev" source: hosted - version: "10.0.4" + version: "10.0.5" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.5" leak_tracker_testing: dependency: transitive description: @@ -1020,10 +1020,10 @@ packages: dependency: transitive description: name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.11.1" matomo_tracker: dependency: "direct main" description: @@ -1036,10 +1036,10 @@ packages: dependency: transitive description: name: meta - sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.12.0" + version: "1.15.0" mgrs_dart: dependency: transitive description: @@ -1117,18 +1117,18 @@ packages: dependency: "direct main" description: name: package_info_plus - sha256: "88bc797f44a94814f2213db1c9bd5badebafdfb8290ca9f78d4b9ee2a3db4d79" + sha256: "2c582551839386fa7ddbc7770658be7c0f87f388a4bff72066478f597c34d17f" url: "https://pub.dev" source: hosted - version: "5.0.1" + version: "7.0.0" package_info_plus_platform_interface: dependency: transitive description: name: package_info_plus_platform_interface - sha256: "9bc8ba46813a4cc42c66ab781470711781940780fd8beddd0c3da62506d3a6c6" + sha256: ac1f4a4847f1ade8e6a87d1f39f5d7c67490738642e2542f559ec38c37489a66 url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.1" path: dependency: "direct main" description: @@ -1261,10 +1261,10 @@ packages: dependency: transitive description: name: platform - sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" + sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" url: "https://pub.dev" source: hosted - version: "3.1.4" + version: "3.1.5" plugin_platform_interface: dependency: "direct dev" description: @@ -1442,10 +1442,10 @@ packages: dependency: transitive description: name: shared_preferences_web - sha256: "7b15ffb9387ea3e237bb7a66b8a23d2147663d391cafc5c8f37b2e7b4bde5d21" + sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "2.4.2" shared_preferences_windows: dependency: transitive description: @@ -1591,10 +1591,10 @@ packages: dependency: transitive description: name: test_api - sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" url: "https://pub.dev" source: hosted - version: "0.7.0" + version: "0.7.2" typed_data: dependency: transitive description: @@ -1671,10 +1671,10 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: fff0932192afeedf63cdd50ecbb1bc825d31aed259f02bb8dba0f3b729a5e88b + sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e" url: "https://pub.dev" source: hosted - version: "2.2.3" + version: "2.3.3" url_launcher_windows: dependency: transitive description: @@ -1735,10 +1735,10 @@ packages: dependency: transitive description: name: vm_service - sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" + sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc url: "https://pub.dev" source: hosted - version: "14.2.1" + version: "14.2.4" watcher: dependency: transitive description: @@ -1751,10 +1751,10 @@ packages: dependency: transitive description: name: web - sha256: "4188706108906f002b3a293509234588823c8c979dc83304e229ff400c996b05" + sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" url: "https://pub.dev" source: hosted - version: "0.4.2" + version: "0.5.1" webdriver: dependency: transitive description: diff --git a/packages/smooth_app/pubspec.yaml b/packages/smooth_app/pubspec.yaml index 8d917756537..48d87da9cd2 100644 --- a/packages/smooth_app/pubspec.yaml +++ b/packages/smooth_app/pubspec.yaml @@ -25,13 +25,13 @@ dependencies: flutter_secure_storage: 9.2.2 hive: 2.2.3 hive_flutter: 1.1.0 - http: 1.2.0 + http: 1.2.2 http_parser: 4.0.2 image_picker: 1.1.2 iso_countries: 2.2.0 latlong2: 0.9.1 matomo_tracker: 5.0.0-dev.2 - package_info_plus: 5.0.1 + package_info_plus: 7.0.0 device_info_plus: 9.1.2 permission_handler: 11.3.1 photo_view: 0.15.0 @@ -46,7 +46,7 @@ dependencies: diacritic: 0.1.5 app_store_shared: path: ../app_store/shared - audioplayers: 5.2.1 + audioplayers: 6.0.0 flutter_email_sender: 6.0.3 flutter_native_splash: 2.4.1 image: 4.2.0 From dfe5238535679ac26bc8a95cbd9b8251b4d48568 Mon Sep 17 00:00:00 2001 From: Edouard Marquez Date: Mon, 12 Aug 2024 18:14:45 +0200 Subject: [PATCH 22/24] Move the fastlane directory for Fdroid (#5532) --- .../metadata/android}/en-US/54.txt | 0 .../metadata/android}/en-US/full_description.txt | 0 .../android}/en-US/images/featureGraphic.png | Bin .../metadata/android}/en-US/images/icon.png | Bin .../android}/en-US/images/phoneScreenshots/1.png | Bin .../android}/en-US/images/phoneScreenshots/2.png | Bin .../android}/en-US/images/phoneScreenshots/3.png | Bin .../android}/en-US/images/phoneScreenshots/4.png | Bin .../android}/en-US/images/phoneScreenshots/5.png | Bin .../android}/en-US/images/phoneScreenshots/6.png | Bin .../android}/en-US/images/phoneScreenshots/7.png | Bin .../android}/en-US/images/phoneScreenshots/8.png | Bin .../android}/en-US/images/phoneScreenshots/9.png | Bin .../metadata/android}/en-US/short_description.txt | 0 .../metadata/android}/en-US/title.txt | 0 15 files changed, 0 insertions(+), 0 deletions(-) rename {packages/smooth_app/fastlane/metadata => fastlane/metadata/android}/en-US/54.txt (100%) rename {packages/smooth_app/fastlane/metadata => fastlane/metadata/android}/en-US/full_description.txt (100%) rename {packages/smooth_app/fastlane/metadata => fastlane/metadata/android}/en-US/images/featureGraphic.png (100%) rename {packages/smooth_app/fastlane/metadata => fastlane/metadata/android}/en-US/images/icon.png (100%) rename {packages/smooth_app/fastlane/metadata => fastlane/metadata/android}/en-US/images/phoneScreenshots/1.png (100%) rename {packages/smooth_app/fastlane/metadata => fastlane/metadata/android}/en-US/images/phoneScreenshots/2.png (100%) rename {packages/smooth_app/fastlane/metadata => fastlane/metadata/android}/en-US/images/phoneScreenshots/3.png (100%) rename {packages/smooth_app/fastlane/metadata => fastlane/metadata/android}/en-US/images/phoneScreenshots/4.png (100%) rename {packages/smooth_app/fastlane/metadata => fastlane/metadata/android}/en-US/images/phoneScreenshots/5.png (100%) rename {packages/smooth_app/fastlane/metadata => fastlane/metadata/android}/en-US/images/phoneScreenshots/6.png (100%) rename {packages/smooth_app/fastlane/metadata => fastlane/metadata/android}/en-US/images/phoneScreenshots/7.png (100%) rename {packages/smooth_app/fastlane/metadata => fastlane/metadata/android}/en-US/images/phoneScreenshots/8.png (100%) rename {packages/smooth_app/fastlane/metadata => fastlane/metadata/android}/en-US/images/phoneScreenshots/9.png (100%) rename {packages/smooth_app/fastlane/metadata => fastlane/metadata/android}/en-US/short_description.txt (100%) rename {packages/smooth_app/fastlane/metadata => fastlane/metadata/android}/en-US/title.txt (100%) diff --git a/packages/smooth_app/fastlane/metadata/en-US/54.txt b/fastlane/metadata/android/en-US/54.txt similarity index 100% rename from packages/smooth_app/fastlane/metadata/en-US/54.txt rename to fastlane/metadata/android/en-US/54.txt diff --git a/packages/smooth_app/fastlane/metadata/en-US/full_description.txt b/fastlane/metadata/android/en-US/full_description.txt similarity index 100% rename from packages/smooth_app/fastlane/metadata/en-US/full_description.txt rename to fastlane/metadata/android/en-US/full_description.txt diff --git a/packages/smooth_app/fastlane/metadata/en-US/images/featureGraphic.png b/fastlane/metadata/android/en-US/images/featureGraphic.png similarity index 100% rename from packages/smooth_app/fastlane/metadata/en-US/images/featureGraphic.png rename to fastlane/metadata/android/en-US/images/featureGraphic.png diff --git a/packages/smooth_app/fastlane/metadata/en-US/images/icon.png b/fastlane/metadata/android/en-US/images/icon.png similarity index 100% rename from packages/smooth_app/fastlane/metadata/en-US/images/icon.png rename to fastlane/metadata/android/en-US/images/icon.png diff --git a/packages/smooth_app/fastlane/metadata/en-US/images/phoneScreenshots/1.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png similarity index 100% rename from packages/smooth_app/fastlane/metadata/en-US/images/phoneScreenshots/1.png rename to fastlane/metadata/android/en-US/images/phoneScreenshots/1.png diff --git a/packages/smooth_app/fastlane/metadata/en-US/images/phoneScreenshots/2.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png similarity index 100% rename from packages/smooth_app/fastlane/metadata/en-US/images/phoneScreenshots/2.png rename to fastlane/metadata/android/en-US/images/phoneScreenshots/2.png diff --git a/packages/smooth_app/fastlane/metadata/en-US/images/phoneScreenshots/3.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png similarity index 100% rename from packages/smooth_app/fastlane/metadata/en-US/images/phoneScreenshots/3.png rename to fastlane/metadata/android/en-US/images/phoneScreenshots/3.png diff --git a/packages/smooth_app/fastlane/metadata/en-US/images/phoneScreenshots/4.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/4.png similarity index 100% rename from packages/smooth_app/fastlane/metadata/en-US/images/phoneScreenshots/4.png rename to fastlane/metadata/android/en-US/images/phoneScreenshots/4.png diff --git a/packages/smooth_app/fastlane/metadata/en-US/images/phoneScreenshots/5.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/5.png similarity index 100% rename from packages/smooth_app/fastlane/metadata/en-US/images/phoneScreenshots/5.png rename to fastlane/metadata/android/en-US/images/phoneScreenshots/5.png diff --git a/packages/smooth_app/fastlane/metadata/en-US/images/phoneScreenshots/6.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/6.png similarity index 100% rename from packages/smooth_app/fastlane/metadata/en-US/images/phoneScreenshots/6.png rename to fastlane/metadata/android/en-US/images/phoneScreenshots/6.png diff --git a/packages/smooth_app/fastlane/metadata/en-US/images/phoneScreenshots/7.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/7.png similarity index 100% rename from packages/smooth_app/fastlane/metadata/en-US/images/phoneScreenshots/7.png rename to fastlane/metadata/android/en-US/images/phoneScreenshots/7.png diff --git a/packages/smooth_app/fastlane/metadata/en-US/images/phoneScreenshots/8.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/8.png similarity index 100% rename from packages/smooth_app/fastlane/metadata/en-US/images/phoneScreenshots/8.png rename to fastlane/metadata/android/en-US/images/phoneScreenshots/8.png diff --git a/packages/smooth_app/fastlane/metadata/en-US/images/phoneScreenshots/9.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/9.png similarity index 100% rename from packages/smooth_app/fastlane/metadata/en-US/images/phoneScreenshots/9.png rename to fastlane/metadata/android/en-US/images/phoneScreenshots/9.png diff --git a/packages/smooth_app/fastlane/metadata/en-US/short_description.txt b/fastlane/metadata/android/en-US/short_description.txt similarity index 100% rename from packages/smooth_app/fastlane/metadata/en-US/short_description.txt rename to fastlane/metadata/android/en-US/short_description.txt diff --git a/packages/smooth_app/fastlane/metadata/en-US/title.txt b/fastlane/metadata/android/en-US/title.txt similarity index 100% rename from packages/smooth_app/fastlane/metadata/en-US/title.txt rename to fastlane/metadata/android/en-US/title.txt From 3e2bc4b1e11e6823240f70e2014791c0ee6ae7b5 Mon Sep 17 00:00:00 2001 From: monsieurtanuki Date: Mon, 12 Aug 2024 18:43:16 +0200 Subject: [PATCH 23/24] fix: 5437 - fine-tuning about price result display (#5531) Impacted files: * `price_product_widget.dart`: fixed to "if no brand, don't display an empty brand widget" * `product_prices_list.dart`: fixed to "if no price result, print 'no result'" --- .../lib/pages/prices/price_product_widget.dart | 3 ++- .../lib/pages/prices/product_prices_list.dart | 17 +++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/packages/smooth_app/lib/pages/prices/price_product_widget.dart b/packages/smooth_app/lib/pages/prices/price_product_widget.dart index 9e142a37a2b..776b9445cc0 100644 --- a/packages/smooth_app/lib/pages/prices/price_product_widget.dart +++ b/packages/smooth_app/lib/pages/prices/price_product_widget.dart @@ -27,7 +27,8 @@ class PriceProductWidget extends StatelessWidget { final bool unknown = priceProduct.name == null; final String? imageURL = priceProduct.imageURL; final int priceCount = priceProduct.priceCount; - final List? brands = priceProduct.brands?.split(','); + final List? brands = + priceProduct.brands == '' ? null : priceProduct.brands?.split(','); final String? quantity = priceProduct.quantity == null ? null : '${priceProduct.quantity} ${priceProduct.quantityUnit ?? 'g'}'; diff --git a/packages/smooth_app/lib/pages/prices/product_prices_list.dart b/packages/smooth_app/lib/pages/prices/product_prices_list.dart index 4de382f88f9..257b80dcdda 100644 --- a/packages/smooth_app/lib/pages/prices/product_prices_list.dart +++ b/packages/smooth_app/lib/pages/prices/product_prices_list.dart @@ -99,14 +99,15 @@ class _ProductPricesListState extends State } final AppLocalizations appLocalizations = AppLocalizations.of(context); - final String title = result.numberOfPages == 1 - ? appLocalizations.prices_list_length_one_page( - result.items!.length, - ) - : appLocalizations.prices_list_length_many_pages( - widget.model.parameters.pageSize!, - result.total!, - ); + final String title = + result.numberOfPages != null && result.numberOfPages! <= 1 + ? appLocalizations.prices_list_length_one_page( + result.items!.length, + ) + : appLocalizations.prices_list_length_many_pages( + widget.model.parameters.pageSize!, + result.total!, + ); children.insert( 0, SmoothCard(child: ListTile(title: Text(title))), From 65a49891868c6ef32a258a8cc361351325f2ca17 Mon Sep 17 00:00:00 2001 From: Pierre Slamich Date: Mon, 12 Aug 2024 19:06:14 +0200 Subject: [PATCH 24/24] ci: Create on-demand.yml (#5525) * ci: Create on-demand.yml * Update on-demand.yml --- .github/workflows/on-demand.yml | 102 ++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 .github/workflows/on-demand.yml diff --git a/.github/workflows/on-demand.yml b/.github/workflows/on-demand.yml new file mode 100644 index 00000000000..2161cd4b2cd --- /dev/null +++ b/.github/workflows/on-demand.yml @@ -0,0 +1,102 @@ +# This file contains actions that can be performed on PRs by issuing a comment +name: 🕹️ On demand PR action + +on: + issue_comment: + types: [created, edited] + +jobs: + # Action to update test results by issuing /lint + run_lint: + name: "On demand linting" + if: | + github.event.issue.pull_request && + (github.event.comment.body == '/lint') && + contains(fromJSON('["COLLABORATOR", "CONTRIBUTOR", "MEMBER", "OWNER"]'), github.event.comment.author_association) + runs-on: ubuntu-latest + steps: + - name: Get branch name + # see https://github.com/actions/checkout/issues/331 + id: get-branch + run: echo ::set-output name=branch::$(gh pr view $PR_NO --repo $REPO --json headRefName --jq '.headRefName') + env: + REPO: ${{ github.repository }} + PR_NO: ${{ github.event.issue.number }} + GITHUB_TOKEN: ${{ secrets.RELEASE_PLEASE_TOKEN }} + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1 + # grab the PR branch + ref: ${{ steps.get-branch.outputs.branch }} + # We can't use GITHUB_TOKEN here because, github actions can't trigger actions + # see: https://docs.github.com/en/actions/security-guides/automatic-token-authentication#using-the-github_token-in-a-workflow + # So this is a personal access token + token: ${{ secrets.RELEASE_PLEASE_TOKEN }} + # we need origin/main to have comparison linting work ! + - name: Fetch origin/develop + run: | + git remote set-branches --add origin develop + git fetch origin + - name: Run linting + run: XXXXXXXX + - name: Push changes if needed + uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: "chore: Linting changes" + branch: ${{ github.event.pull_request.head.ref }} + commit_user_name: Open Food Facts Bot + commit_user_email: contact@openfoodfacts.org + commit_author: Open Food Facts Bot + push_options: "" + status_options: '--untracked-files=no' + skip_dirty_check: false + create_branch: no + + delete_3_letter_translation_files: + name: "On demand deletion of 3-letter translation files" + if: | + github.event.issue.pull_request && + (github.event.comment.body == '/lint') && + contains(fromJSON('["COLLABORATOR", "CONTRIBUTOR", "MEMBER", "OWNER"]'), github.event.comment.author_association) + runs-on: ubuntu-latest + steps: + - name: Get branch name + # see https://github.com/actions/checkout/issues/331 + id: get-branch + run: echo ::set-output name=branch::$(gh pr view $PR_NO --repo $REPO --json headRefName --jq '.headRefName') + env: + REPO: ${{ github.repository }} + PR_NO: ${{ github.event.issue.number }} + GITHUB_TOKEN: ${{ secrets.RELEASE_PLEASE_TOKEN }} + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1 + # grab the PR branch + ref: ${{ steps.get-branch.outputs.branch }} + # We can't use GITHUB_TOKEN here because, github actions can't trigger actions + # see: https://docs.github.com/en/actions/security-guides/automatic-token-authentication#using-the-github_token-in-a-workflow + # So this is a personal access token + token: ${{ secrets.RELEASE_PLEASE_TOKEN }} + # we need origin/main to have comparison linting work ! + - name: Fetch origin/develop + run: | + git remote set-branches --add origin develop + git fetch origin + - name: Deletion of 3-letter translation files (1/2) + run: packages/smooth_app/ios/Runner/remove.sh + - name: Deletion of 3-letter translation files (2/2) + run: packages/smooth_app/lib/l10n/remove_3_letter_locales.sh + - name: Push changes if needed + uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: "chore: Deletion of 3-letter translation files" + branch: ${{ github.event.pull_request.head.ref }} + commit_user_name: Open Food Facts Bot + commit_user_email: contact@openfoodfacts.org + commit_author: Open Food Facts Bot + push_options: "" + status_options: '--untracked-files=no' + skip_dirty_check: false + create_branch: no