From 16417788b582147e1618fd37ca6469f8e2e825a1 Mon Sep 17 00:00:00 2001 From: Andy Date: Tue, 2 Jul 2024 09:10:21 +0200 Subject: [PATCH 1/3] 1507: add concrete camera resolution for specific model to fix qr code scanning --- .../qr_code_scanner/qr_code_scanner.dart | 31 +++++++++++++++---- frontend/lib/main.dart | 2 +- ...id_certificate.dart => android_utils.dart} | 10 ++++++ 3 files changed, 36 insertions(+), 7 deletions(-) rename frontend/lib/util/{android_certificate.dart => android_utils.dart} (60%) diff --git a/frontend/lib/identification/qr_code_scanner/qr_code_scanner.dart b/frontend/lib/identification/qr_code_scanner/qr_code_scanner.dart index b2f08bd5b..9f938e259 100644 --- a/frontend/lib/identification/qr_code_scanner/qr_code_scanner.dart +++ b/frontend/lib/identification/qr_code_scanner/qr_code_scanner.dart @@ -8,6 +8,8 @@ import 'package:mobile_scanner/mobile_scanner.dart'; import 'package:ehrenamtskarte/l10n/translations.g.dart'; +import 'package:ehrenamtskarte/util/android_utils.dart'; + typedef OnCodeScannedCallback = Future Function(Uint8List code); class QrCodeScanner extends StatefulWidget { @@ -20,12 +22,29 @@ class QrCodeScanner extends StatefulWidget { } class _QRViewState extends State { + bool _hasCameraIssues = false; + + @override + void initState() { + super.initState(); + // Workaround for https://github.com/juliansteenbakker/mobile_scanner/issues/698 + // Check once the qr code scanner was initialized if the device has camera issues + // Depending on that set a controller with predefined camera solution to fix that qr code reading issues + WidgetsBinding.instance.addPostFrameCallback((_) async { + setState(() async { + _hasCameraIssues = await isDeviceWithCameraIssues(); + }); + }); + } + final MobileScannerController _controller = MobileScannerController( - torchEnabled: false, - detectionSpeed: DetectionSpeed.normal, - formats: [BarcodeFormat.qrCode], - returnImage: false, - ); + torchEnabled: false, detectionSpeed: DetectionSpeed.normal, formats: [BarcodeFormat.qrCode], returnImage: false); + final MobileScannerController _controllerPredefinedCameraResolution = MobileScannerController( + torchEnabled: false, + detectionSpeed: DetectionSpeed.normal, + formats: [BarcodeFormat.qrCode], + returnImage: false, + cameraResolution: const Size(640, 480)); final GlobalKey qrKey = GlobalKey(debugLabel: 'QR'); // Determines whether a code is currently processed by the onCodeScanned callback @@ -37,7 +56,7 @@ class _QRViewState extends State { @override Widget build(BuildContext context) { final t = context.t; - final controller = _controller; + final controller = _hasCameraIssues ? _controllerPredefinedCameraResolution : _controller; return Stack( children: [ Column( diff --git a/frontend/lib/main.dart b/frontend/lib/main.dart index fa97484e0..2474a2e44 100644 --- a/frontend/lib/main.dart +++ b/frontend/lib/main.dart @@ -5,7 +5,7 @@ import 'package:ehrenamtskarte/configuration/definitions.dart'; import 'package:ehrenamtskarte/l10n/translations.g.dart'; import 'package:ehrenamtskarte/sentry.dart'; import 'package:ehrenamtskarte/settings_provider.dart'; -import 'package:ehrenamtskarte/util/android_certificate.dart'; +import 'package:ehrenamtskarte/util/android_utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:slang/builder/model/enums.dart'; diff --git a/frontend/lib/util/android_certificate.dart b/frontend/lib/util/android_utils.dart similarity index 60% rename from frontend/lib/util/android_certificate.dart rename to frontend/lib/util/android_utils.dart index 0ebba8e09..ee419a020 100644 --- a/frontend/lib/util/android_certificate.dart +++ b/frontend/lib/util/android_utils.dart @@ -12,3 +12,13 @@ Future certificateIsRequired() async { AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo; return androidInfo.version.sdkInt < 25; } + +Future isDeviceWithCameraIssues() async { + if (!Platform.isAndroid) { + return false; + } + List devicesWithoutQRCodeDetection = ['SM-A236B']; + DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); + AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo; + return devicesWithoutQRCodeDetection.contains(androidInfo.model); +} From 9a07cc50c1a541424205a02de6dbad280e158c97 Mon Sep 17 00:00:00 2001 From: Andy Date: Tue, 2 Jul 2024 19:52:56 +0200 Subject: [PATCH 2/3] 1507: added all a23 models --- frontend/lib/util/android_utils.dart | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/frontend/lib/util/android_utils.dart b/frontend/lib/util/android_utils.dart index ee419a020..e41d0a34d 100644 --- a/frontend/lib/util/android_utils.dart +++ b/frontend/lib/util/android_utils.dart @@ -17,7 +17,22 @@ Future isDeviceWithCameraIssues() async { if (!Platform.isAndroid) { return false; } - List devicesWithoutQRCodeDetection = ['SM-A236B']; + // All models of Galaxy A23 + List devicesWithoutQRCodeDetection = [ + 'SM-A235F', + 'SM-A235M', + 'SM-A235N', + 'SM-A233C', + 'SM-A2360', + 'SM-A236B', + 'SM-A236E', + 'SM-A236M', + 'SM-A236U', + 'SM-A236U1', + 'SM-S236DL', + 'SM-S237VL', + 'SM-A236V' + ]; DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo; return devicesWithoutQRCodeDetection.contains(androidInfo.model); From 5e867b865d02aaabd591192cd4ea3367069b1ad1 Mon Sep 17 00:00:00 2001 From: Andy Date: Wed, 3 Jul 2024 13:49:25 +0200 Subject: [PATCH 3/3] 1507: add a future builder to handle async method in initState --- .../qr_code_scanner/qr_code_scanner.dart | 127 +++++++++--------- 1 file changed, 67 insertions(+), 60 deletions(-) diff --git a/frontend/lib/identification/qr_code_scanner/qr_code_scanner.dart b/frontend/lib/identification/qr_code_scanner/qr_code_scanner.dart index 9f938e259..ae692cb9d 100644 --- a/frontend/lib/identification/qr_code_scanner/qr_code_scanner.dart +++ b/frontend/lib/identification/qr_code_scanner/qr_code_scanner.dart @@ -3,6 +3,7 @@ import 'dart:typed_data'; import 'package:ehrenamtskarte/identification/qr_code_scanner/qr_code_scanner_controls.dart'; import 'package:ehrenamtskarte/identification/qr_code_scanner/qr_overlay_shape.dart'; +import 'package:ehrenamtskarte/widgets/error_message.dart'; import 'package:flutter/material.dart'; import 'package:mobile_scanner/mobile_scanner.dart'; @@ -22,7 +23,7 @@ class QrCodeScanner extends StatefulWidget { } class _QRViewState extends State { - bool _hasCameraIssues = false; + late Future _hasCameraIssues; @override void initState() { @@ -30,11 +31,7 @@ class _QRViewState extends State { // Workaround for https://github.com/juliansteenbakker/mobile_scanner/issues/698 // Check once the qr code scanner was initialized if the device has camera issues // Depending on that set a controller with predefined camera solution to fix that qr code reading issues - WidgetsBinding.instance.addPostFrameCallback((_) async { - setState(() async { - _hasCameraIssues = await isDeviceWithCameraIssues(); - }); - }); + _hasCameraIssues = isDeviceWithCameraIssues(); } final MobileScannerController _controller = MobileScannerController( @@ -55,66 +52,76 @@ class _QRViewState extends State { @override Widget build(BuildContext context) { - final t = context.t; - final controller = _hasCameraIssues ? _controllerPredefinedCameraResolution : _controller; - return Stack( - children: [ - Column( - children: [ - Expanded( - flex: 4, - child: Stack( - fit: StackFit.expand, - children: [ - MobileScanner( - key: qrKey, - placeholderBuilder: (context, _) => Align( - alignment: Alignment.center, - child: Icon(Icons.camera_alt_outlined, size: 128, color: Colors.grey), + return FutureBuilder( + future: _hasCameraIssues, + builder: (context, AsyncSnapshot snapshot) { + final hasCameraIssues = snapshot.data; + if (snapshot.hasError && snapshot.error != null) { + return ErrorMessage(snapshot.error.toString()); + } else if (hasCameraIssues == null) { + return const Center(); + } + final controller = hasCameraIssues ? _controllerPredefinedCameraResolution : _controller; + final t = context.t; + return Stack( + children: [ + Column( + children: [ + Expanded( + flex: 4, + child: Stack( + fit: StackFit.expand, + children: [ + MobileScanner( + key: qrKey, + placeholderBuilder: (context, _) => Align( + alignment: Alignment.center, + child: Icon(Icons.camera_alt_outlined, size: 128, color: Colors.grey), + ), + onDetect: (barcodes) => _onCodeScanned(barcodes), + controller: controller, + ), + DecoratedBox( + decoration: ShapeDecoration( + shape: QrScannerOverlayShape( + borderRadius: 10, + borderColor: Theme.of(context).colorScheme.secondary, + borderLength: 30, + borderWidth: 10, + cutOutSize: _calculateScanArea(context), + ), + ), + ), + ], ), - onDetect: (barcodes) => _onCodeScanned(barcodes), - controller: controller, ), - DecoratedBox( - decoration: ShapeDecoration( - shape: QrScannerOverlayShape( - borderRadius: 10, - borderColor: Theme.of(context).colorScheme.secondary, - borderLength: 30, - borderWidth: 10, - cutOutSize: _calculateScanArea(context), + Expanded( + flex: 1, + child: FittedBox( + fit: BoxFit.contain, + child: Column( + children: [ + Container( + margin: const EdgeInsets.all(8), + child: Text(t.identification.scanQRCode), + ), + QrCodeScannerControls(controller: controller) + ], ), ), - ), + ) ], ), - ), - Expanded( - flex: 1, - child: FittedBox( - fit: BoxFit.contain, - child: Column( - children: [ - Container( - margin: const EdgeInsets.all(8), - child: Text(t.identification.scanQRCode), - ), - QrCodeScannerControls(controller: controller) - ], - ), - ), - ) - ], - ), - if (showWaiting) - Center( - child: Card( - child: Padding( - padding: const EdgeInsets.all(32), - child: CircularProgressIndicator(), - ))), - ], - ); + if (showWaiting) + Center( + child: Card( + child: Padding( + padding: const EdgeInsets.all(32), + child: CircularProgressIndicator(), + ))), + ], + ); + }); } double _calculateScanArea(BuildContext context) {