mirror of
https://github.com/openfoodfacts/smooth-app.git
synced 2025-08-26 21:50:18 +08:00
fix: Camera fix (#946)
Co-authored-by: monsieurtanuki <fabrice_fontaine@hotmail.com>
This commit is contained in:
@ -1,7 +1,6 @@
|
|||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
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:flutter_widget_from_html_core/flutter_widget_from_html_core.dart';
|
||||||
import 'package:openfoodfacts/model/KnowledgePanel.dart';
|
import 'package:openfoodfacts/model/KnowledgePanel.dart';
|
||||||
import 'package:openfoodfacts/model/KnowledgePanelElement.dart';
|
import 'package:openfoodfacts/model/KnowledgePanelElement.dart';
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
import 'package:openfoodfacts/model/Product.dart';
|
import 'package:openfoodfacts/model/Product.dart';
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
import 'package:openfoodfacts/model/Product.dart';
|
import 'package:openfoodfacts/model/Product.dart';
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
import 'package:openfoodfacts/model/Product.dart';
|
|
||||||
import 'package:openfoodfacts/openfoodfacts.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_image_carousel.dart';
|
||||||
import 'package:smooth_app/cards/product_cards/product_title_card.dart';
|
import 'package:smooth_app/cards/product_cards/product_title_card.dart';
|
||||||
|
@ -24,6 +24,7 @@ class UserPreferences extends ChangeNotifier {
|
|||||||
'lastVisitedOnboardingPage';
|
'lastVisitedOnboardingPage';
|
||||||
static const String _TAG_PREFIX_FLAG = 'FLAG_PREFIX_';
|
static const String _TAG_PREFIX_FLAG = 'FLAG_PREFIX_';
|
||||||
static const String _TAG_DEV_MODE = 'devMode';
|
static const String _TAG_DEV_MODE = 'devMode';
|
||||||
|
static const String _TAG_CAMERA_DECLINE = 'declined_camera_use_once';
|
||||||
|
|
||||||
Future<void> init(final ProductPreferences productPreferences) async {
|
Future<void> init(final ProductPreferences productPreferences) async {
|
||||||
if (_sharedPreferences.getBool(_TAG_INIT) != null) {
|
if (_sharedPreferences.getBool(_TAG_INIT) != null) {
|
||||||
@ -80,6 +81,13 @@ class UserPreferences extends ChangeNotifier {
|
|||||||
: OnboardingPage.values[pageIndex];
|
: OnboardingPage.values[pageIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> 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;
|
String _getFlagTag(final String key) => _TAG_PREFIX_FLAG + key;
|
||||||
|
|
||||||
Future<void> setFlag(
|
Future<void> setFlag(
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:openfoodfacts/model/OrderedNutrients.dart';
|
import 'package:openfoodfacts/model/OrderedNutrients.dart';
|
||||||
import 'package:openfoodfacts/model/Product.dart';
|
|
||||||
import 'package:openfoodfacts/openfoodfacts.dart';
|
import 'package:openfoodfacts/openfoodfacts.dart';
|
||||||
import 'package:openfoodfacts/utils/CountryHelper.dart';
|
import 'package:openfoodfacts/utils/CountryHelper.dart';
|
||||||
import 'package:smooth_app/database/product_query.dart';
|
import 'package:smooth_app/database/product_query.dart';
|
||||||
|
@ -6,7 +6,6 @@ import 'package:openfoodfacts/interface/JsonObject.dart';
|
|||||||
import 'package:openfoodfacts/model/Nutriments.dart';
|
import 'package:openfoodfacts/model/Nutriments.dart';
|
||||||
import 'package:openfoodfacts/model/OrderedNutrient.dart';
|
import 'package:openfoodfacts/model/OrderedNutrient.dart';
|
||||||
import 'package:openfoodfacts/model/OrderedNutrients.dart';
|
import 'package:openfoodfacts/model/OrderedNutrients.dart';
|
||||||
import 'package:openfoodfacts/model/Product.dart';
|
|
||||||
import 'package:openfoodfacts/openfoodfacts.dart';
|
import 'package:openfoodfacts/openfoodfacts.dart';
|
||||||
import 'package:openfoodfacts/utils/UnitHelper.dart';
|
import 'package:openfoodfacts/utils/UnitHelper.dart';
|
||||||
import 'package:smooth_app/database/product_query.dart';
|
import 'package:smooth_app/database/product_query.dart';
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
import 'package:openfoodfacts/model/Attribute.dart';
|
import 'package:openfoodfacts/model/Attribute.dart';
|
||||||
import 'package:openfoodfacts/model/AttributeGroup.dart';
|
import 'package:openfoodfacts/model/AttributeGroup.dart';
|
||||||
import 'package:openfoodfacts/model/Product.dart';
|
|
||||||
import 'package:openfoodfacts/openfoodfacts.dart';
|
import 'package:openfoodfacts/openfoodfacts.dart';
|
||||||
import 'package:openfoodfacts/personalized_search/preference_importance.dart';
|
import 'package:openfoodfacts/personalized_search/preference_importance.dart';
|
||||||
import 'package:smooth_app/cards/data_cards/score_card.dart';
|
import 'package:smooth_app/cards/data_cards/score_card.dart';
|
||||||
|
@ -35,10 +35,16 @@ class _ContinuousScanPageState extends State<ContinuousScanPage> {
|
|||||||
final double carouselHeight = constraints.maxHeight /
|
final double carouselHeight = constraints.maxHeight /
|
||||||
1.81; // roughly 55% of the available height
|
1.81; // roughly 55% of the available height
|
||||||
final double viewFinderBottomOffset = carouselHeight / 2.0;
|
final double viewFinderBottomOffset = carouselHeight / 2.0;
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(toolbarHeight: 0.0),
|
final List<Widget> children = getScannerWidgets(
|
||||||
body: Stack(
|
context,
|
||||||
children: <Widget>[
|
constraints,
|
||||||
|
_model,
|
||||||
|
);
|
||||||
|
|
||||||
|
//Insert scanner at the right position
|
||||||
|
children.insert(
|
||||||
|
1,
|
||||||
SmoothRevealAnimation(
|
SmoothRevealAnimation(
|
||||||
delay: 400,
|
delay: 400,
|
||||||
startOffset: Offset.zero,
|
startOffset: Offset.zero,
|
||||||
@ -54,12 +60,12 @@ class _ContinuousScanPageState extends State<ContinuousScanPage> {
|
|||||||
onQRViewCreated: setupScanner,
|
onQRViewCreated: setupScanner,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
...getScannerWidgets(
|
);
|
||||||
context,
|
|
||||||
constraints,
|
return Scaffold(
|
||||||
_model,
|
appBar: AppBar(toolbarHeight: 0.0),
|
||||||
),
|
body: Stack(
|
||||||
],
|
children: children,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -102,9 +102,15 @@ class MLKitScannerPageState extends State<MLKitScannerPage> {
|
|||||||
|
|
||||||
return LayoutBuilder(
|
return LayoutBuilder(
|
||||||
builder: (BuildContext context, BoxConstraints constraints) {
|
builder: (BuildContext context, BoxConstraints constraints) {
|
||||||
return Stack(
|
final List<Widget> children = getScannerWidgets(
|
||||||
fit: StackFit.expand,
|
context,
|
||||||
children: <Widget>[
|
constraints,
|
||||||
|
_model,
|
||||||
|
);
|
||||||
|
|
||||||
|
//Inserting the scanner at the right position
|
||||||
|
children.insert(
|
||||||
|
1,
|
||||||
SmoothRevealAnimation(
|
SmoothRevealAnimation(
|
||||||
delay: 400,
|
delay: 400,
|
||||||
startOffset: Offset.zero,
|
startOffset: Offset.zero,
|
||||||
@ -118,12 +124,11 @@ class MLKitScannerPageState extends State<MLKitScannerPage> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
...getScannerWidgets(
|
);
|
||||||
context,
|
|
||||||
constraints,
|
return Stack(
|
||||||
_model,
|
fit: StackFit.expand,
|
||||||
),
|
children: children,
|
||||||
],
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:smooth_app/data_models/continuous_scan_model.dart';
|
import 'package:smooth_app/data_models/continuous_scan_model.dart';
|
||||||
import 'package:smooth_app/data_models/user_preferences.dart';
|
import 'package:smooth_app/data_models/user_preferences.dart';
|
||||||
@ -33,6 +34,24 @@ class _ScanPageState extends State<ScanPage> {
|
|||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<PermissionStatus> _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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final UserPreferences userPreferences = context.read<UserPreferences>();
|
final UserPreferences userPreferences = context.read<UserPreferences>();
|
||||||
@ -40,6 +59,27 @@ class _ScanPageState extends State<ScanPage> {
|
|||||||
return const Center(child: CircularProgressIndicator());
|
return const Center(child: CircularProgressIndicator());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return FutureBuilder<PermissionStatus>(
|
||||||
|
future: _permissionCheck(userPreferences),
|
||||||
|
builder: (
|
||||||
|
BuildContext context,
|
||||||
|
AsyncSnapshot<PermissionStatus> snapshot,
|
||||||
|
) {
|
||||||
|
if (!snapshot.hasData) {
|
||||||
|
return const Center(child: CircularProgressIndicator());
|
||||||
|
} else if (snapshot.hasError) {
|
||||||
|
return const Center(child: Text('Error'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
final Widget child;
|
||||||
|
|
||||||
if (userPreferences.getFlag(
|
if (userPreferences.getFlag(
|
||||||
@ -55,5 +95,7 @@ class _ScanPageState extends State<ScanPage> {
|
|||||||
create: (BuildContext context) => _model!,
|
create: (BuildContext context) => _model!,
|
||||||
child: child,
|
child: child,
|
||||||
);
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,8 +96,8 @@ List<Widget> getScannerWidgets(
|
|||||||
padding: qrScannerPadding,
|
padding: qrScannerPadding,
|
||||||
child: SvgPicture.asset(
|
child: SvgPicture.asset(
|
||||||
'assets/actions/scanner_alt_2.svg',
|
'assets/actions/scanner_alt_2.svg',
|
||||||
width: 60.0,
|
width: scannerSize.width,
|
||||||
height: 6,
|
height: scannerSize.height,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -29,10 +29,10 @@ dependencies:
|
|||||||
matomo: ^1.1.0
|
matomo: ^1.1.0
|
||||||
modal_bottom_sheet: ^2.0.0
|
modal_bottom_sheet: ^2.0.0
|
||||||
openfoodfacts: ^1.10.0
|
openfoodfacts: ^1.10.0
|
||||||
# Uncomment those lines if you want to use a local version of the openfoodfacts package
|
|
||||||
# openfoodfacts:
|
# openfoodfacts:
|
||||||
# path: ../../../openfoodfacts-dart
|
# path: ../../../openfoodfacts-dart
|
||||||
package_info_plus: ^1.3.0
|
package_info_plus: ^1.3.0
|
||||||
|
permission_handler: ^8.3.0
|
||||||
photo_view: ^0.13.0
|
photo_view: ^0.13.0
|
||||||
provider: ^6.0.2
|
provider: ^6.0.2
|
||||||
qr_code_scanner: ^0.6.1
|
qr_code_scanner: ^0.6.1
|
||||||
|
Reference in New Issue
Block a user