diff --git a/packages/smooth_app/lib/generic_lib/dialogs/smooth_alert_dialog.dart b/packages/smooth_app/lib/generic_lib/dialogs/smooth_alert_dialog.dart index 5e3476ba7da..f267cc1dba6 100644 --- a/packages/smooth_app/lib/generic_lib/dialogs/smooth_alert_dialog.dart +++ b/packages/smooth_app/lib/generic_lib/dialogs/smooth_alert_dialog.dart @@ -26,6 +26,7 @@ import 'package:smooth_app/helpers/keyboard_helper.dart'; class SmoothAlertDialog extends StatelessWidget { const SmoothAlertDialog({ this.title, + this.leadingTitle, required this.body, this.positiveAction, this.negativeAction, @@ -41,6 +42,7 @@ class SmoothAlertDialog extends StatelessWidget { ); final String? title; + final Widget? leadingTitle; final bool close; final Widget body; final SmoothActionButton? positiveAction; @@ -143,7 +145,12 @@ class SmoothAlertDialog extends StatelessWidget { child: Column( mainAxisSize: MainAxisSize.min, children: [ - if (title != null) _SmoothDialogTitle(label: title!, close: close), + if (title != null) + _SmoothDialogTitle( + label: title!, + close: close, + leading: leadingTitle, + ), body, ], ), @@ -158,15 +165,20 @@ class _SmoothDialogTitle extends StatelessWidget { const _SmoothDialogTitle({ required this.label, required this.close, + this.leading, }); static const double _titleHeight = 32.0; final String label; final bool close; + final Widget? leading; @override Widget build(BuildContext context) { + final TextStyle textStyle = + Theme.of(context).textTheme.displayMedium ?? const TextStyle(); + return Column( mainAxisSize: MainAxisSize.min, children: [ @@ -176,12 +188,24 @@ class _SmoothDialogTitle extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.center, children: [ + if (leading != null) + Padding( + padding: EdgeInsetsDirectional.only( + top: leading is Icon ? 2.0 : 0.0, + end: SMALL_SPACE, + ), + child: IconTheme( + data: IconThemeData( + color: textStyle.color, + ), + child: leading!), + ), _buildCross(true), Expanded( child: FittedBox( child: Text( label, - style: Theme.of(context).textTheme.displayMedium, + style: textStyle, ), ), ), @@ -221,16 +245,21 @@ class _SmoothDialogCrossButton extends StatelessWidget { maintainAnimation: true, maintainState: true, visible: visible, - child: InkWell( - customBorder: const CircleBorder(), - child: const Padding( - padding: EdgeInsets.all(SMALL_SPACE), - child: Icon( - Icons.close, - size: _SmoothDialogTitle._titleHeight - (2 * SMALL_SPACE), + child: Semantics( + label: MaterialLocalizations.of(context).closeButtonLabel, + button: true, + excludeSemantics: true, + child: InkWell( + customBorder: const CircleBorder(), + child: const Padding( + padding: EdgeInsets.all(SMALL_SPACE), + child: Icon( + Icons.close, + size: _SmoothDialogTitle._titleHeight - (2 * SMALL_SPACE), + ), ), + onTap: () => Navigator.of(context, rootNavigator: true).pop(), ), - onTap: () => Navigator.of(context, rootNavigator: true).pop(), ), ); } else { diff --git a/packages/smooth_app/lib/l10n/app_en.arb b/packages/smooth_app/lib/l10n/app_en.arb index b083ea0a688..576149baf18 100644 --- a/packages/smooth_app/lib/l10n/app_en.arb +++ b/packages/smooth_app/lib/l10n/app_en.arb @@ -1491,6 +1491,14 @@ "@edit_ingredients_loading_photo_btn_text": { "description": "Ingredients edition - Loading photo from the server" }, + "edit_ingredients_loading_photo_help_dialog_title": "Why do I see this message?", + "@edit_ingredients_loading_photo_help_dialog_title": { + "description": "Ingredients edition - Dialog explaining why the photo is loading - Title" + }, + "edit_ingredients_loading_photo_help_dialog_body": "To use the \"Extract ingredients\" feature, the photo needs to be uploaded first.\n\nPlease wait a few seconds or enter them manually.", + "@edit_ingredients_loading_photo_help_dialog_body": { + "description": "Ingredients edition - Dialog explaining why the photo is loading - Content" + }, "edit_ingredients_refresh_photo_btn_text": "Refresh photo", "@edit_ingredients_refresh_photo_btn_text": { "description": "Ingredients edition - Refresh photo" @@ -1507,6 +1515,14 @@ "@edit_packaging_loading_photo_btn_text": { "description": "Packaging edition - Loading photo from the server" }, + "edit_packaging_loading_photo_help_dialog_title": "Why do I see this message?", + "@edit_packaging_loading_photo_help_dialog_title": { + "description": "Packaging edition - Dialog explaining why the photo is loading - Title" + }, + "edit_packaging_loading_photo_help_dialog_body": "To use the \"Extract packaging\" feature, the photo needs to be uploaded first.\n\nPlease wait a few seconds or enter them manually.", + "@edit_packaging_loading_photo_help_dialog_body": { + "description": "Packaging edition - Dialog explaining why the photo is loading - Content" + }, "edit_packaging_refresh_photo_btn_text": "Refresh photo", "@edit_packaging_refresh_photo_btn_text": { "description": "Packaging edition - Refresh photo" diff --git a/packages/smooth_app/lib/pages/product/edit_ocr/edit_ocr_main_action.dart b/packages/smooth_app/lib/pages/product/edit_ocr/edit_ocr_main_action.dart index 3cf5930fce8..6fa71cb85e7 100644 --- a/packages/smooth_app/lib/pages/product/edit_ocr/edit_ocr_main_action.dart +++ b/packages/smooth_app/lib/pages/product/edit_ocr/edit_ocr_main_action.dart @@ -113,14 +113,13 @@ class _EditOcrActionExtractingContent extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ - const CircularProgressIndicator.adaptive(), + const _ExtractMainActionProgressIndicator(), Expanded( child: Text( helper.getActionExtractingData(appLocalizations), textAlign: TextAlign.center, ), ), - const CircularProgressIndicator.adaptive(), ], ), ), @@ -184,21 +183,107 @@ class _EditOcrActionLoadingContent extends StatelessWidget { @override Widget build(BuildContext context) { return Padding( - padding: const EdgeInsets.symmetric(horizontal: MEDIUM_SPACE), + padding: const EdgeInsetsDirectional.only( + start: MEDIUM_SPACE, + end: VERY_SMALL_SPACE, + ), child: Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ + const _ExtractMainActionProgressIndicator(), Expanded( child: Text( helper.getActionLoadingPhoto(appLocalizations), ), ), - const CircularProgressIndicator.adaptive(), + AspectRatio( + aspectRatio: 1.0, + child: InkWell( + onTap: () => _openExplanation(context), + borderRadius: ANGULAR_BORDER_RADIUS, + child: Icon( + Icons.info_outline, + semanticLabel: helper.getActionLoadingPhotoDialogTitle( + appLocalizations, + ), + ), + ), + ) ], ), ); } + + void _openExplanation(BuildContext context) { + showDialog( + context: context, + builder: (BuildContext context) { + final AppLocalizations appLocalizations = AppLocalizations.of(context); + + return SmoothAlertDialog( + title: helper.getActionLoadingPhotoDialogTitle( + appLocalizations, + ), + leadingTitle: const Icon( + Icons.info_outline, + semanticLabel: '', + ), + close: true, + body: Text( + helper.getActionLoadingPhotoDialogBody( + appLocalizations, + ), + ), + positiveAction: SmoothActionButton( + text: appLocalizations.okay, + onPressed: () => Navigator.pop(context), + ), + ); + }, + ); + } +} + +/// We use a custom progress indicator, because Material and Cupertino Widgets +/// don't have the same size. +class _ExtractMainActionProgressIndicator extends StatelessWidget { + const _ExtractMainActionProgressIndicator(); + + @override + Widget build(BuildContext context) { + if (Platform.isIOS || Platform.isMacOS) { + return const Padding( + padding: EdgeInsetsDirectional.only( + start: SMALL_SPACE, + end: MEDIUM_SPACE, + top: SMALL_SPACE, + bottom: SMALL_SPACE, + ), + child: CupertinoActivityIndicator( + radius: 10.0, + color: Colors.white, + ), + ); + } + + return const Padding( + padding: EdgeInsetsDirectional.only( + start: SMALL_SPACE, + end: MEDIUM_SPACE, + top: MEDIUM_SPACE, + bottom: MEDIUM_SPACE, + ), + child: AspectRatio( + aspectRatio: 1.0, + child: CircularProgressIndicator( + strokeWidth: 2.5, + valueColor: AlwaysStoppedAnimation(Colors.white), + // backgroundColor: Colors.white, + ), + ), + ); + } } enum _OcrState { diff --git a/packages/smooth_app/lib/pages/product/edit_ocr/edit_ocr_page.dart b/packages/smooth_app/lib/pages/product/edit_ocr/edit_ocr_page.dart index 88479a33be6..1f737bc5744 100644 --- a/packages/smooth_app/lib/pages/product/edit_ocr/edit_ocr_page.dart +++ b/packages/smooth_app/lib/pages/product/edit_ocr/edit_ocr_page.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:openfoodfacts/openfoodfacts.dart'; diff --git a/packages/smooth_app/lib/pages/product/edit_ocr/ocr_helper.dart b/packages/smooth_app/lib/pages/product/edit_ocr/ocr_helper.dart index 2a232e05e04..f8cdc759b71 100644 --- a/packages/smooth_app/lib/pages/product/edit_ocr/ocr_helper.dart +++ b/packages/smooth_app/lib/pages/product/edit_ocr/ocr_helper.dart @@ -42,6 +42,14 @@ abstract class OcrHelper { /// Returns the "loading photo" button label String getActionLoadingPhoto(final AppLocalizations appLocalizations); + /// Returns the title of the dialog to explain the "loading photo" state + String getActionLoadingPhotoDialogTitle( + final AppLocalizations appLocalizations); + + /// Returns the content of the dialog to explain the "loading photo" state + String getActionLoadingPhotoDialogBody( + final AppLocalizations appLocalizations); + /// Returns the "Extracting data…" button label String getActionExtractingData(final AppLocalizations appLocalizations); diff --git a/packages/smooth_app/lib/pages/product/edit_ocr/ocr_ingredients_helper.dart b/packages/smooth_app/lib/pages/product/edit_ocr/ocr_ingredients_helper.dart index a721059e75a..d2720d98b57 100644 --- a/packages/smooth_app/lib/pages/product/edit_ocr/ocr_ingredients_helper.dart +++ b/packages/smooth_app/lib/pages/product/edit_ocr/ocr_ingredients_helper.dart @@ -53,6 +53,14 @@ class OcrIngredientsHelper extends OcrHelper { String getActionLoadingPhoto(AppLocalizations appLocalizations) => appLocalizations.edit_ingredients_loading_photo_btn_text; + @override + String getActionLoadingPhotoDialogTitle(AppLocalizations appLocalizations) => + appLocalizations.edit_ingredients_loading_photo_help_dialog_title; + + @override + String getActionLoadingPhotoDialogBody(AppLocalizations appLocalizations) => + appLocalizations.edit_ingredients_loading_photo_help_dialog_body; + @override String getActionRefreshPhoto(final AppLocalizations appLocalizations) => appLocalizations.edit_ingredients_refresh_photo_btn_text; diff --git a/packages/smooth_app/lib/pages/product/edit_ocr/ocr_packaging_helper.dart b/packages/smooth_app/lib/pages/product/edit_ocr/ocr_packaging_helper.dart index a22d6f94350..6590f15a993 100644 --- a/packages/smooth_app/lib/pages/product/edit_ocr/ocr_packaging_helper.dart +++ b/packages/smooth_app/lib/pages/product/edit_ocr/ocr_packaging_helper.dart @@ -56,6 +56,14 @@ class OcrPackagingHelper extends OcrHelper { String getActionLoadingPhoto(AppLocalizations appLocalizations) => appLocalizations.edit_packaging_loading_photo_btn_text; + @override + String getActionLoadingPhotoDialogTitle(AppLocalizations appLocalizations) => + appLocalizations.edit_packaging_loading_photo_help_dialog_title; + + @override + String getActionLoadingPhotoDialogBody(AppLocalizations appLocalizations) => + appLocalizations.edit_packaging_loading_photo_help_dialog_body; + @override String getActionRefreshPhoto(final AppLocalizations appLocalizations) => appLocalizations.edit_packaging_refresh_photo_btn_text;