diff --git a/android/app/build.gradle b/android/app/build.gradle index fc7e5e7..62c3e2a 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -39,7 +39,8 @@ apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"*/ android { - compileSdkVersion 34 + namespace = "be.unov.myinfomate.mdlf" + compileSdkVersion 35 compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index cfe88f6..89e56bd 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-all.zip diff --git a/android/settings.gradle b/android/settings.gradle index 5ea421c..02c755b 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -31,7 +31,7 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "7.2.0" apply false + id "com.android.application" version "8.1.0" apply false id "org.jetbrains.kotlin.android" version "1.9.0" apply false } diff --git a/lib/Components/ScannerDialog.dart b/lib/Components/ScannerDialog.dart index 4e4fc21..94fe0ab 100644 --- a/lib/Components/ScannerDialog.dart +++ b/lib/Components/ScannerDialog.dart @@ -9,8 +9,7 @@ import 'package:mymuseum_visitapp/Screens/Quizz/quizz_page.dart'; import 'package:mymuseum_visitapp/app_context.dart'; import 'package:mymuseum_visitapp/constants.dart'; import 'package:permission_handler/permission_handler.dart'; -import 'package:qr_code_scanner/qr_code_scanner.dart'; - +import 'package:mobile_scanner/mobile_scanner.dart'; class ScannerDialog extends StatefulWidget { const ScannerDialog({Key? key, required this.appContext}) : super(key: key); @@ -22,19 +21,16 @@ class ScannerDialog extends StatefulWidget { } class _ScannerDialogState extends State { - Barcode? result; - QRViewController? controller; - final GlobalKey qrKey = GlobalKey(debugLabel: 'QR'); + final MobileScannerController controller = MobileScannerController(); + bool isProcessing = false; - // In order to get hot reload to work we need to pause the camera if the platform - // is android, or resume the camera if the platform is iOS. @override void reassemble() { super.reassemble(); if (Platform.isAndroid) { - controller!.pauseCamera(); + controller.stop(); } - controller!.resumeCamera(); + controller.start(); } @override @@ -42,208 +38,150 @@ class _ScannerDialogState extends State { Size size = MediaQuery.of(context).size; return Container( - height: size.height *0.5, - width: size.width *0.9, + height: size.height * 0.5, + width: size.width * 0.9, child: Stack( children: [ Center( child: ClipRRect( borderRadius: BorderRadius.circular(10.0), - child: _buildQrView(context), - ) - ), - Positioned( - top: 0, - right: 0, - child: Container( - width: 45, - height: 45, - decoration: BoxDecoration( - shape: BoxShape.rectangle, - color: kMainColor1, - borderRadius: BorderRadius.circular(20.0), + child: MobileScanner( + controller: controller, + //allowDuplicates: false, + onDetect: (barcodes) => _onDetect(barcodes), ), - margin: const EdgeInsets.all(8), - child: InkWell( - onTap: () async { - await controller?.toggleFlash(); - setState(() {}); - }, - child: FutureBuilder( - future: controller?.getFlashStatus(), - builder: (context, snapshot) { - return const Icon(Icons.flash_on, color: Colors.white); - }, - )), ), ), - Positioned( - bottom: 0, - right: 0, - child: Container( - width: 45, - height: 45, - decoration: BoxDecoration( - shape: BoxShape.rectangle, - color: kMainColor1, - borderRadius: BorderRadius.circular(20.0), - ), - margin: const EdgeInsets.all(8), - child: InkWell( - onTap: () async { - await controller?.flipCamera(); - setState(() {}); - }, - child: FutureBuilder( - future: controller?.getCameraInfo(), - builder: (context, snapshot) { - return const Icon(Icons.flip_camera_android, color: Colors.white); - }, - )), - ), + _buildControlButton( + icon: Icons.flash_on, + onTap: () => controller.toggleTorch(), + alignment: Alignment.topRight, + ), + _buildControlButton( + icon: Icons.flip_camera_android, + onTap: () => controller.switchCamera(), + alignment: Alignment.bottomRight, ), ], ), ); } - Widget _buildQrView(BuildContext context) { - // For this example we check how width or tall the device is and change the scanArea and overlay accordingly. - var scanArea = (MediaQuery.of(context).size.width < 400 || - MediaQuery.of(context).size.height < 400) - ? 225.0 - : 300.0; - - // To ensure the Scanner view is properly sizes after rotation - // we need to listen for Flutter SizeChanged notification and update controller - return QRView( - key: qrKey, - onQRViewCreated: _onQRViewCreated, - overlay: QrScannerOverlayShape( - borderColor: kMainColor1, - borderRadius: 10, - borderLength: 25, - borderWidth: 5, - overlayColor: Colors.black.withValues(alpha: 0.55), - cutOutSize: 225.0), - onPermissionSet: (ctrl, p) => _onPermissionSet(context, ctrl, p), + Widget _buildControlButton({ + required IconData icon, + required VoidCallback onTap, + required Alignment alignment, + }) { + return Align( + alignment: alignment, + child: Container( + width: 45, + height: 45, + margin: const EdgeInsets.all(8), + decoration: BoxDecoration( + shape: BoxShape.rectangle, + color: kMainColor1, + borderRadius: BorderRadius.circular(20.0), + ), + child: InkWell( + onTap: onTap, + child: Icon(icon, color: Colors.white), + ), + ), ); } - _onQRViewCreated(QRViewController controller) { - setState(() { - this.controller = controller; - }); - if (Platform.isAndroid) { - controller.pauseCamera(); - } - controller.resumeCamera(); - controller.scannedDataStream.listen((scanData) { - setState(() { - result = scanData; + void _onDetect(BarcodeCapture capture) { + if (isProcessing) return; - var code = result == null ? "" : result!.code.toString(); - if(result!.format == BarcodeFormat.qrcode) { - controller.pauseCamera(); + final barcode = capture.barcodes.first; + final code = barcode.rawValue ?? ""; - RegExp regExp = RegExp(r'^(?:https:\/\/web\.myinfomate\.be\/([^\/]+)\/([^\/]+)\/([^\/]+)|([^\/]+))$'); - var match = regExp.firstMatch(code); - String? instanceId; - String? configurationId; - String? sectionId; + if (barcode.format == BarcodeFormat.qrCode && code.isNotEmpty) { + isProcessing = true; - if (match != null) { - instanceId = match.group(1); - configurationId = match.group(2); - sectionId = match.group(3) ?? match.group(4); + // also support simple code (Fort saint heribert!) - print('InstanceId: $instanceId'); - print('ConfigurationId: $configurationId'); - print('SectionId: $sectionId'); - } else { - print('L\'URL ne correspond pas au format attendu.'); - } + RegExp regExp = RegExp(r'^(?:https:\/\/web\.myinfomate\.be\/([^\/]+)\/([^\/]+)\/([^\/]+)|([^\/]+))$'); // myinfomate + RegExp regExp2 = RegExp(r'^(?:https:\/\/web\.mymuseum\.be\/([^\/]+)\/([^\/]+)\/([^\/]+)|([^\/]+))$'); // myinfomate + var match = regExp.firstMatch(code); + var match2 = regExp2.firstMatch(code); + String? instanceId; + String? configurationId; + String? sectionId; + if(match == null) { + instanceId = match2?.group(1); + configurationId = match2?.group(2); + sectionId = match2?.group(3) ?? match2?.group(4); + } else { + instanceId = match.group(1); + configurationId = match.group(2); + sectionId = match.group(3) ?? match.group(4); + } - //print("QR CODE FOUND"); - /*ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('QR CODE FOUND - ${code.toString()}')), - );*/ - - VisitAppContext visitAppContext = widget.appContext!.getContext(); - - if(!visitAppContext.sectionIds!.contains(sectionId) || sectionId == null) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(TranslationHelper.getFromLocale('invalidQRCode', widget.appContext!.getContext())), backgroundColor: kMainColor2), - ); - Navigator.of(context).pop(); - - } else { - SectionDTO section = visitAppContext.currentSections!.firstWhere((cs) => cs!.id == sectionId)!; - switch(section.type) { - case SectionType.Article: - Navigator.pushReplacement( - context, - MaterialPageRoute( - builder: (context) { - return ArticlePage(visitAppContextIn: visitAppContext, articleId: section.id!); - }, - ), - ); - break; - case SectionType.Quizz: - Navigator.pushReplacement( - context, - MaterialPageRoute( - builder: (context) { - return QuizzPage(visitAppContextIn: visitAppContext, sectionId: section.id!); - }, - ), - ); - break; - } - } - } - }); - }); - } - - Future _onPermissionSet(BuildContext context, QRViewController ctrl, bool p) async { - //log('${DateTime.now().toIso8601String()}_onPermissionSet $p'); - if (!p) { - var status = await Permission.camera.status; - if(!status.isGranted) { + if ((match == null && match2 == null) || sectionId == null) { ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('no Permission')), + SnackBar(content: Text("L'URL ne correspond pas au format attendu."), backgroundColor: kMainColor2), ); + Navigator.of(context).pop(); + return; + } - // You can request multiple permissions at once. - Map statuses = await [ - Permission.camera, - ].request(); - print(statuses[Permission.camera]); - print(status); + VisitAppContext visitAppContext = widget.appContext!.getContext(); + + if (visitAppContext.sectionIds == null || !visitAppContext.sectionIds!.contains(sectionId)) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(TranslationHelper.getFromLocale('invalidQRCode', visitAppContext)), backgroundColor: kMainColor2), + ); + Navigator.of(context).pop(); + } else { + SectionDTO section = visitAppContext.currentSections!.firstWhere(( + cs) => cs!.id == sectionId)!; + switch (section.type) { + case SectionType.Article: + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) { + return ArticlePage(visitAppContextIn: visitAppContext, + articleId: section.id!); + }, + ), + ); + break; + case SectionType.Quizz: + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) { + return QuizzPage(visitAppContextIn: visitAppContext, + sectionId: section.id!); + }, + ), + ); + break; + } } } } @override void dispose() { - controller?.dispose(); + controller.dispose(); super.dispose(); } } -showScannerDialog (BuildContext context, AppContext appContext) { +showScannerDialog(BuildContext context, AppContext appContext) { showDialog( - builder: (BuildContext context) => AlertDialog( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(10.0)) - ), - content: ScannerDialog(appContext: appContext), - contentPadding: EdgeInsets.zero, - ), context: context + context: context, + builder: (BuildContext context) => AlertDialog( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(10.0)), + ), + content: ScannerDialog(appContext: appContext), + contentPadding: EdgeInsets.zero, + ), ); -} - - +} \ No newline at end of file diff --git a/lib/Screens/Scanner/scanner_old.dart b/lib/Screens/Scanner/scanner_old.dart deleted file mode 100644 index 82cdd9b..0000000 --- a/lib/Screens/Scanner/scanner_old.dart +++ /dev/null @@ -1,206 +0,0 @@ - -import 'dart:io'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:mymuseum_visitapp/Components/CustomAppBar.dart'; -import 'package:mymuseum_visitapp/Models/visitContext.dart'; -import 'package:mymuseum_visitapp/Screens/Article/article_page.dart'; -import 'package:mymuseum_visitapp/app_context.dart'; -import 'package:qr_code_scanner/qr_code_scanner.dart'; - -// NOT USED ANYMORE -class ScannerPage extends StatefulWidget { - const ScannerPage({Key? key}) : super(key: key); - - @override - State createState() => _ScannerPageState(); -} - -class _ScannerPageState extends State { - Barcode? result; - QRViewController? controller; - final GlobalKey qrKey = GlobalKey(debugLabel: 'QR'); - - // In order to get hot reload to work we need to pause the camera if the platform - // is android, or resume the camera if the platform is iOS. - @override - void reassemble() { - print("reassemble "); - super.reassemble(); - if (Platform.isAndroid) { - controller!.pauseCamera(); - } - controller!.resumeCamera(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: CustomAppBar( - title: "QR Code scan", - isHomeButton: false, - ), - body: Column( - children: [ - Expanded(flex: 4, child: _buildQrView(context)), - Expanded( - flex: 1, - child: FittedBox( - fit: BoxFit.contain, - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - if (result != null) - Text( - 'Barcode Type: ${describeEnum(result!.format)} Data: ${result!.code}') - else - const Text('Scan a code'), - Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Container( - margin: const EdgeInsets.all(8), - child: ElevatedButton( - onPressed: () async { - await controller?.toggleFlash(); - setState(() {}); - }, - child: FutureBuilder( - future: controller?.getFlashStatus(), - builder: (context, snapshot) { - return Icon(Icons.flash_on); - }, - )), - ), - Container( - margin: const EdgeInsets.all(8), - child: ElevatedButton( - onPressed: () async { - await controller?.flipCamera(); - setState(() {}); - }, - child: FutureBuilder( - future: controller?.getCameraInfo(), - builder: (context, snapshot) { - if (snapshot.data != null) { - return Text( - 'Camera facing ${describeEnum(snapshot.data!)}'); - } else { - return const Text('loading'); - } - }, - )), - ) - ], - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Container( - margin: const EdgeInsets.all(8), - child: ElevatedButton( - onPressed: () async { - await controller?.pauseCamera(); - }, - child: const Text('pause', - style: TextStyle(fontSize: 20)), - ), - ), - Container( - margin: const EdgeInsets.all(8), - child: ElevatedButton( - onPressed: () async { - //print(controller); - await controller?.resumeCamera(); - }, - child: const Text('resume', - style: TextStyle(fontSize: 20)), - ), - ) - ], - ), - ], - ), - ), - ) - ], - ), - ); - } - - Widget _buildQrView(BuildContext context) { - // For this example we check how width or tall the device is and change the scanArea and overlay accordingly. - var scanArea = (MediaQuery.of(context).size.width < 400 || - MediaQuery.of(context).size.height < 400) - ? 225.0 - : 300.0; - // To ensure the Scanner view is properly sizes after rotation - // we need to listen for Flutter SizeChanged notification and update controller - return QRView( - key: qrKey, - onQRViewCreated: _onQRViewCreated, - overlay: QrScannerOverlayShape( - borderColor: Colors.blueAccent, - borderRadius: 10, - borderLength: 25, - borderWidth: 5, - cutOutSize: 225.0), - onPermissionSet: (ctrl, p) => _onPermissionSet(context, ctrl, p), - ); - } - - void _onQRViewCreated(QRViewController controller) { - setState(() { - this.controller = controller; - }); - if (Platform.isAndroid) { - controller!.pauseCamera(); - } - controller!.resumeCamera(); - controller.scannedDataStream.listen((scanData) { - setState(() { - result = scanData; - print(result); - print(result!.code.toString()); - var code = result == null ? "" : result!.code.toString(); - if(result!.format == BarcodeFormat.qrcode) { - controller.pauseCamera(); - print("QR CODE FOUND"); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('QR CODE FOUND - ${code.toString()}')), - ); - - // TODO search in local if data == Id of Article - - // If so, navigate to article view - Navigator.pushReplacement( - context, - MaterialPageRoute( - builder: (context) { - return ArticlePage(articleId: code, visitAppContextIn: VisitAppContext()); // will not work.. - }, - ), - ); - } - }); - }); - } - - void _onPermissionSet(BuildContext context, QRViewController ctrl, bool p) { - //log('${DateTime.now().toIso8601String()}_onPermissionSet $p'); - if (!p) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('no Permission')), - ); - } - } - - @override - void dispose() { - controller?.dispose(); - super.dispose(); - } -} \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index 7f40a68..38a7903 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -612,6 +612,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.5" + mobile_scanner: + dependency: "direct main" + description: + name: mobile_scanner + sha256: "827765afbd4792ff3fd105ad593821ac0f6d8a7d352689013b07ee85be336312" + url: "https://pub.dev" + source: hosted + version: "4.0.1" nested: dependency: transitive description: @@ -852,14 +860,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.0" - qr_code_scanner: - dependency: "direct main" - description: - name: qr_code_scanner - sha256: f23b68d893505a424f0bd2e324ebea71ed88465d572d26bb8d2e78a4749591fd - url: "https://pub.dev" - source: hosted - version: "1.0.1" rxdart: dependency: transitive description: @@ -1210,7 +1210,7 @@ packages: source: hosted version: "14.3.0" wakelock_plus: - dependency: transitive + dependency: "direct main" description: name: wakelock_plus sha256: "14758533319a462ffb5aa3b7ddb198e59b29ac3b02da14173a1715d65d4e6e68" diff --git a/pubspec.yaml b/pubspec.yaml index d12aa27..8a823fe 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -31,7 +31,8 @@ dependencies: sdk: flutter flutter_localizations: sdk: flutter - qr_code_scanner: ^1.0.1 + #qr_code_scanner: ^1.0.1 + mobile_scanner: ^4.0.0 # that replace qr_code_scanner.. auto_size_text: ^3.0.0 openapi_generator_cli: ^5.0.2 openapi_generator: ^5.0.2 @@ -52,6 +53,8 @@ dependencies: diacritic: ^0.1.3 flutter_widget_from_html: ^0.15.2 + wakelock_plus: ^1.1.1 + manager_api: path: manager_api # The following adds the Cupertino Icons font to your application.