diff --git a/packages/smooth_app/lib/cards/product_cards/knowledge_panels/knowledge_panel_table_card.dart b/packages/smooth_app/lib/cards/product_cards/knowledge_panels/knowledge_panel_table_card.dart index a6fb7a64cb7..c7d2458566a 100644 --- a/packages/smooth_app/lib/cards/product_cards/knowledge_panels/knowledge_panel_table_card.dart +++ b/packages/smooth_app/lib/cards/product_cards/knowledge_panels/knowledge_panel_table_card.dart @@ -1,7 +1,6 @@ import 'dart:math'; import 'package:flutter/material.dart'; -import 'package:flutter/painting.dart'; import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart'; import 'package:openfoodfacts/model/KnowledgePanel.dart'; import 'package:openfoodfacts/model/KnowledgePanelElement.dart'; diff --git a/packages/smooth_app/lib/cards/product_cards/product_image_carousel.dart b/packages/smooth_app/lib/cards/product_cards/product_image_carousel.dart index 02296286786..4dff57ffd92 100644 --- a/packages/smooth_app/lib/cards/product_cards/product_image_carousel.dart +++ b/packages/smooth_app/lib/cards/product_cards/product_image_carousel.dart @@ -1,4 +1,3 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:openfoodfacts/model/Product.dart'; diff --git a/packages/smooth_app/lib/cards/product_cards/product_title_card.dart b/packages/smooth_app/lib/cards/product_cards/product_title_card.dart index a8924553579..a4f400d08a4 100644 --- a/packages/smooth_app/lib/cards/product_cards/product_title_card.dart +++ b/packages/smooth_app/lib/cards/product_cards/product_title_card.dart @@ -1,4 +1,3 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:openfoodfacts/model/Product.dart'; diff --git a/packages/smooth_app/lib/cards/product_cards/question_card.dart b/packages/smooth_app/lib/cards/product_cards/question_card.dart index b611955dd6e..4a198c4d287 100644 --- a/packages/smooth_app/lib/cards/product_cards/question_card.dart +++ b/packages/smooth_app/lib/cards/product_cards/question_card.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -import 'package:openfoodfacts/model/Product.dart'; import 'package:openfoodfacts/openfoodfacts.dart'; import 'package:smooth_app/cards/product_cards/product_image_carousel.dart'; import 'package:smooth_app/cards/product_cards/product_title_card.dart'; diff --git a/packages/smooth_app/lib/data_models/user_preferences.dart b/packages/smooth_app/lib/data_models/user_preferences.dart index 57a0b8f3a4e..4a9a6630f10 100644 --- a/packages/smooth_app/lib/data_models/user_preferences.dart +++ b/packages/smooth_app/lib/data_models/user_preferences.dart @@ -24,6 +24,7 @@ class UserPreferences extends ChangeNotifier { 'lastVisitedOnboardingPage'; static const String _TAG_PREFIX_FLAG = 'FLAG_PREFIX_'; static const String _TAG_DEV_MODE = 'devMode'; + static const String _TAG_CAMERA_DECLINE = 'declined_camera_use_once'; Future init(final ProductPreferences productPreferences) async { if (_sharedPreferences.getBool(_TAG_INIT) != null) { @@ -80,6 +81,13 @@ class UserPreferences extends ChangeNotifier { : OnboardingPage.values[pageIndex]; } + Future setCameraDecline(final bool declined) async { + _sharedPreferences.setBool(_TAG_CAMERA_DECLINE, declined); + } + + bool get cameraDeclinedOnce => + _sharedPreferences.getBool(_TAG_CAMERA_DECLINE) ?? false; + String _getFlagTag(final String key) => _TAG_PREFIX_FLAG + key; Future setFlag( diff --git a/packages/smooth_app/lib/pages/product/nutrition_page.dart b/packages/smooth_app/lib/pages/product/nutrition_page.dart index 4eeae95d679..0928e97ac85 100644 --- a/packages/smooth_app/lib/pages/product/nutrition_page.dart +++ b/packages/smooth_app/lib/pages/product/nutrition_page.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:openfoodfacts/model/OrderedNutrients.dart'; -import 'package:openfoodfacts/model/Product.dart'; import 'package:openfoodfacts/openfoodfacts.dart'; import 'package:openfoodfacts/utils/CountryHelper.dart'; import 'package:smooth_app/database/product_query.dart'; diff --git a/packages/smooth_app/lib/pages/product/nutrition_page_loaded.dart b/packages/smooth_app/lib/pages/product/nutrition_page_loaded.dart index ee89fb1d75c..c4f855efb0a 100644 --- a/packages/smooth_app/lib/pages/product/nutrition_page_loaded.dart +++ b/packages/smooth_app/lib/pages/product/nutrition_page_loaded.dart @@ -6,7 +6,6 @@ import 'package:openfoodfacts/interface/JsonObject.dart'; import 'package:openfoodfacts/model/Nutriments.dart'; import 'package:openfoodfacts/model/OrderedNutrient.dart'; import 'package:openfoodfacts/model/OrderedNutrients.dart'; -import 'package:openfoodfacts/model/Product.dart'; import 'package:openfoodfacts/openfoodfacts.dart'; import 'package:openfoodfacts/utils/UnitHelper.dart'; import 'package:smooth_app/database/product_query.dart'; diff --git a/packages/smooth_app/lib/pages/product/summary_card.dart b/packages/smooth_app/lib/pages/product/summary_card.dart index 803149ae093..77e4ab73ea1 100644 --- a/packages/smooth_app/lib/pages/product/summary_card.dart +++ b/packages/smooth_app/lib/pages/product/summary_card.dart @@ -1,9 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:openfoodfacts/model/Attribute.dart'; import 'package:openfoodfacts/model/AttributeGroup.dart'; -import 'package:openfoodfacts/model/Product.dart'; import 'package:openfoodfacts/openfoodfacts.dart'; import 'package:openfoodfacts/personalized_search/preference_importance.dart'; import 'package:smooth_app/cards/data_cards/score_card.dart'; diff --git a/packages/smooth_app/lib/pages/scan/continuous_scan_page.dart b/packages/smooth_app/lib/pages/scan/continuous_scan_page.dart index a7b3cec0ebc..169052b873d 100644 --- a/packages/smooth_app/lib/pages/scan/continuous_scan_page.dart +++ b/packages/smooth_app/lib/pages/scan/continuous_scan_page.dart @@ -35,31 +35,37 @@ class _ContinuousScanPageState extends State { final double carouselHeight = constraints.maxHeight / 1.81; // roughly 55% of the available height final double viewFinderBottomOffset = carouselHeight / 2.0; + + final List children = getScannerWidgets( + context, + constraints, + _model, + ); + + //Insert scanner at the right position + children.insert( + 1, + SmoothRevealAnimation( + delay: 400, + startOffset: Offset.zero, + animationCurve: Curves.easeInOutBack, + child: QRView( + overlay: QrScannerOverlayShape( + // We use [SmoothViewFinder] instead of the overlay. + overlayColor: Colors.transparent, + // This offset adjusts the scanning area on iOS. + cutOutBottomOffset: viewFinderBottomOffset, + ), + key: _scannerViewKey, + onQRViewCreated: setupScanner, + ), + ), + ); + return Scaffold( appBar: AppBar(toolbarHeight: 0.0), body: Stack( - children: [ - SmoothRevealAnimation( - delay: 400, - startOffset: Offset.zero, - animationCurve: Curves.easeInOutBack, - child: QRView( - overlay: QrScannerOverlayShape( - // We use [SmoothViewFinder] instead of the overlay. - overlayColor: Colors.transparent, - // This offset adjusts the scanning area on iOS. - cutOutBottomOffset: viewFinderBottomOffset, - ), - key: _scannerViewKey, - onQRViewCreated: setupScanner, - ), - ), - ...getScannerWidgets( - context, - constraints, - _model, - ), - ], + children: children, ), ); }, diff --git a/packages/smooth_app/lib/pages/scan/ml_kit_scan_page.dart b/packages/smooth_app/lib/pages/scan/ml_kit_scan_page.dart index 6b8a05d1b28..66978865296 100644 --- a/packages/smooth_app/lib/pages/scan/ml_kit_scan_page.dart +++ b/packages/smooth_app/lib/pages/scan/ml_kit_scan_page.dart @@ -102,28 +102,33 @@ class MLKitScannerPageState extends State { return LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { - return Stack( - fit: StackFit.expand, - children: [ - SmoothRevealAnimation( - delay: 400, - startOffset: Offset.zero, - animationCurve: Curves.easeInOutBack, - child: Transform.scale( - scale: scale, - child: Center( - child: CameraPreview( - _controller!, - ), + final List children = getScannerWidgets( + context, + constraints, + _model, + ); + + //Inserting the scanner at the right position + children.insert( + 1, + SmoothRevealAnimation( + delay: 400, + startOffset: Offset.zero, + animationCurve: Curves.easeInOutBack, + child: Transform.scale( + scale: scale, + child: Center( + child: CameraPreview( + _controller!, ), ), ), - ...getScannerWidgets( - context, - constraints, - _model, - ), - ], + ), + ); + + return Stack( + fit: StackFit.expand, + children: children, ); }, ); diff --git a/packages/smooth_app/lib/pages/scan/scan_page.dart b/packages/smooth_app/lib/pages/scan/scan_page.dart index f87ae668e2b..2fad1bc8999 100644 --- a/packages/smooth_app/lib/pages/scan/scan_page.dart +++ b/packages/smooth_app/lib/pages/scan/scan_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:permission_handler/permission_handler.dart'; import 'package:provider/provider.dart'; import 'package:smooth_app/data_models/continuous_scan_model.dart'; import 'package:smooth_app/data_models/user_preferences.dart'; @@ -33,6 +34,24 @@ class _ScanPageState extends State { setState(() {}); } + Future _permissionCheck( + UserPreferences userPreferences) async { + final PermissionStatus status = await Permission.camera.status; + + //If is denied, is not restricted by for example parental control and is not already declined once + if (status.isDenied && + !status.isRestricted && + !userPreferences.cameraDeclinedOnce) { + final PermissionStatus newStatus = await Permission.camera.request(); + if (!newStatus.isGranted && !newStatus.isLimited) { + userPreferences.setCameraDecline(true); + } + return newStatus; + } else { + return status; + } + } + @override Widget build(BuildContext context) { final UserPreferences userPreferences = context.read(); @@ -40,20 +59,43 @@ class _ScanPageState extends State { return const Center(child: CircularProgressIndicator()); } - final Widget child; + return FutureBuilder( + future: _permissionCheck(userPreferences), + builder: ( + BuildContext context, + AsyncSnapshot snapshot, + ) { + if (!snapshot.hasData) { + return const Center(child: CircularProgressIndicator()); + } else if (snapshot.hasError) { + return const Center(child: Text('Error')); + } - if (userPreferences.getFlag( - UserPreferencesDevMode.userPreferencesFlagUseMLKit, - ) ?? - true) { - child = const MLKitScannerPage(); - } else { - child = const ContinuousScanPage(); - } + // TODO(M123): show no camera access screen + if (snapshot.data!.isDenied || + snapshot.data!.isPermanentlyDenied || + snapshot.data!.isRestricted) { + const Center( + child: Text('No camera access granted'), + ); + } + + final Widget child; + + if (userPreferences.getFlag( + UserPreferencesDevMode.userPreferencesFlagUseMLKit, + ) ?? + true) { + child = const MLKitScannerPage(); + } else { + child = const ContinuousScanPage(); + } - return ChangeNotifierProvider( - create: (BuildContext context) => _model!, - child: child, + return ChangeNotifierProvider( + create: (BuildContext context) => _model!, + child: child, + ); + }, ); } } diff --git a/packages/smooth_app/lib/pages/scan/scan_page_helper.dart b/packages/smooth_app/lib/pages/scan/scan_page_helper.dart index c730b288c6b..6d4ba383c53 100644 --- a/packages/smooth_app/lib/pages/scan/scan_page_helper.dart +++ b/packages/smooth_app/lib/pages/scan/scan_page_helper.dart @@ -96,8 +96,8 @@ List getScannerWidgets( padding: qrScannerPadding, child: SvgPicture.asset( 'assets/actions/scanner_alt_2.svg', - width: 60.0, - height: 6, + width: scannerSize.width, + height: scannerSize.height, color: Colors.white, ), ), diff --git a/packages/smooth_app/pubspec.yaml b/packages/smooth_app/pubspec.yaml index 9f9363578d8..58ba51867f4 100644 --- a/packages/smooth_app/pubspec.yaml +++ b/packages/smooth_app/pubspec.yaml @@ -29,10 +29,10 @@ dependencies: matomo: ^1.1.0 modal_bottom_sheet: ^2.0.0 openfoodfacts: ^1.10.0 - # Uncomment those lines if you want to use a local version of the openfoodfacts package # openfoodfacts: # path: ../../../openfoodfacts-dart package_info_plus: ^1.3.0 + permission_handler: ^8.3.0 photo_view: ^0.13.0 provider: ^6.0.2 qr_code_scanner: ^0.6.1