From 887217646a3688a6a682498305552bd3a097ad1c Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 <50428976+WaseemAbbasi22@users.noreply.github.com> Date: Thu, 2 Apr 2026 16:01:26 +0300 Subject: [PATCH] QR scanning fixes for Huawei --- .../utils/swipe_general_utils.dart | 237 ++++++++++++------ lib/views/widgets/qr/scan_qr.dart | 173 +++++++++---- pubspec.lock | 8 + pubspec.yaml | 1 + 4 files changed, 307 insertions(+), 112 deletions(-) diff --git a/lib/new_views/swipe_module/utils/swipe_general_utils.dart b/lib/new_views/swipe_module/utils/swipe_general_utils.dart index fb66a0b7..4eb96010 100644 --- a/lib/new_views/swipe_module/utils/swipe_general_utils.dart +++ b/lib/new_views/swipe_module/utils/swipe_general_utils.dart @@ -152,35 +152,86 @@ class SwipeGeneralUtils { } //huawei permission part.... - void getHuaweiCurrentLocation({SwipeTypeEnum? attendanceType, required BuildContext context}) async { + Future getHuaweiCurrentLocation({ + SwipeTypeEnum? attendanceType, + required BuildContext context, + }) async { try { showLoading(context); - FusedLocationProviderClient locationService = FusedLocationProviderClient()..initFusedLocationService(); - LocationRequest locationRequest = LocationRequest(); - locationRequest.priority = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY; - locationRequest.interval = 500; - List locationRequestList = [locationRequest]; - LocationSettingsRequest locationSettingsRequest = LocationSettingsRequest(requests: locationRequestList); - - late StreamSubscription _streamSubscription; - int requestCode = (await (locationService.requestLocationUpdates(locationRequest)))!; - _streamSubscription = locationService.onLocationData!.listen( - (Location location) async { + + final locationService = FusedLocationProviderClient()..initFusedLocationService(); + final locationRequest = LocationRequest() + ..priority = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY + ..interval = 500; + + final requestCode = await locationService.requestLocationUpdates(locationRequest) ?? 0; + + final streamSubscription = locationService.onLocationData?.listen( + (location) async { + if (location == null) { + hideLoading(context); + debugPrint("Location data is null"); + return; + } + hideLoading(context); await locationService.removeLocationUpdates(requestCode); - handleSwipeOperation(swipeType: attendanceType!, context: context, lat: location.latitude ?? 0, long: location.longitude ?? 0); - requestCode = 0; - _streamSubscription.cancel(); + handleSwipeOperation( + swipeType: attendanceType!, + context: context, + lat: location.latitude ?? 0, + long: location.longitude ?? 0, + ); }, ); + streamSubscription?.onDone(() { + streamSubscription.cancel(); + }); } catch (error) { - log("HUAWEI LOCATION ERROR!!!!!"); - log('$error'); + debugPrint("HUAWEI LOCATION ERROR!!!!!"); + debugPrint('$error'); hideLoading(context); - // handleException(error, context, null); + showDialog( + context: context, + builder: (BuildContext cxt) => ConfirmDialog( + message: "Unable to fetch location. Please try again.", + onTap: () { + Navigator.pop(context); + }, + ), + ); } } + // void getHuaweiCurrentLocation({SwipeTypeEnum? attendanceType, required BuildContext context}) async { + // try { + // showLoading(context); + // FusedLocationProviderClient locationService = FusedLocationProviderClient()..initFusedLocationService(); + // LocationRequest locationRequest = LocationRequest(); + // locationRequest.priority = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY; + // locationRequest.interval = 500; + // List locationRequestList = [locationRequest]; + // LocationSettingsRequest locationSettingsRequest = LocationSettingsRequest(requests: locationRequestList); + // + // late StreamSubscription _streamSubscription; + // int requestCode = (await (locationService.requestLocationUpdates(locationRequest)))!; + // _streamSubscription = locationService.onLocationData!.listen( + // (Location location) async { + // hideLoading(context); + // await locationService.removeLocationUpdates(requestCode); + // handleSwipeOperation(swipeType: attendanceType!, context: context, lat: location.latitude ?? 0, long: location.longitude ?? 0); + // requestCode = 0; + // _streamSubscription.cancel(); + // }, + // ); + // } catch (error) { + // log("HUAWEI LOCATION ERROR!!!!!"); + // log('$error'); + // hideLoading(context); + // // handleException(error, context, null); + // } + // } + Future requestPermissions() async { var result = await [ Permission.location, @@ -188,31 +239,71 @@ class SwipeGeneralUtils { return (result[Permission.location] == PermissionStatus.granted || result[Permission.locationAlways] == PermissionStatus.granted); } - void checkHuaweiLocationPermission({required SwipeTypeEnum attendanceType, required BuildContext context}) async { - // Permission_Handler permissionHandler = PermissionHandler(); - LocationUtilities.isEnabled((bool isEnabled) async { - if (isEnabled) { - LocationUtilities.havePermission((bool permission) async { - if (permission) { - getHuaweiCurrentLocation(attendanceType: attendanceType, context: context); - } else { - bool has = await requestPermissions(); - if (has) { - getHuaweiCurrentLocation(attendanceType: attendanceType, context: context); - } else { - showDialog( - context: context, - builder: (BuildContext cxt) => ConfirmDialog( - message: "You need to give location permission to mark attendance", - onTap: () { - Navigator.pop(context); - }, - ), - ); - } - } - }); - } else { +//TODO delete older code after confirm the new one is working fine in huawei devices + // void checkHuaweiLocationPermission({required SwipeTypeEnum attendanceType, required BuildContext context}) async { + // // Permission_Handler permissionHandler = PermissionHandler(); + // LocationUtilities.isEnabled((bool isEnabled) async { + // if (isEnabled) { + // LocationUtilities.havePermission((bool permission) async { + // if (permission) { + // getHuaweiCurrentLocation(attendanceType: attendanceType, context: context); + // } else { + // bool has = await requestPermissions(); + // if (has) { + // getHuaweiCurrentLocation(attendanceType: attendanceType, context: context); + // } else { + // showDialog( + // context: context, + // builder: (BuildContext cxt) => ConfirmDialog( + // message: "You need to give location permission to mark attendance", + // onTap: () { + // Navigator.pop(context); + // }, + // ), + // ); + // } + // } + // }); + // } else { + // showDialog( + // context: context, + // builder: (BuildContext cxt) => ConfirmDialog( + // message: "You need to enable location services to mark attendance", + // onTap: () async { + // Navigator.pop(context); + // await Geolocator.openLocationSettings(); + // }, + // ), + // ); + // } + // }); + // + // // if (await permissionHandler.hasLocationPermission()) { + // // getHuaweiCurrentLocation(attendanceType); + // // } else { + // // bool has = await requestPermissions(); + // // if (has) { + // // getHuaweiCurrentLocation(attendanceType); + // // } else { + // // showDialog( + // // context: context, + // // builder: (BuildContext cxt) => ConfirmDialog( + // // message: "You need to give location permission to mark attendance", + // // onTap: () { + // // Navigator.pop(context); + // // }, + // // ), + // // ); + // // } + // // } + // } + Future checkHuaweiLocationPermission({ + required SwipeTypeEnum attendanceType, + required BuildContext context, + }) async { + try { + final isEnabled = await LocationUtilities.isEnabledAsync(); + if (!isEnabled) { showDialog( context: context, builder: (BuildContext cxt) => ConfirmDialog( @@ -223,27 +314,40 @@ class SwipeGeneralUtils { }, ), ); + return; } - }); - // if (await permissionHandler.hasLocationPermission()) { - // getHuaweiCurrentLocation(attendanceType); - // } else { - // bool has = await requestPermissions(); - // if (has) { - // getHuaweiCurrentLocation(attendanceType); - // } else { - // showDialog( - // context: context, - // builder: (BuildContext cxt) => ConfirmDialog( - // message: "You need to give location permission to mark attendance", - // onTap: () { - // Navigator.pop(context); - // }, - // ), - // ); - // } - // } + final hasPermission = await LocationUtilities.havePermissionAsync(); + if (!hasPermission) { + final granted = await requestPermissions(); + if (!granted) { + showDialog( + context: context, + builder: (BuildContext cxt) => ConfirmDialog( + message: "You need to give location permission to mark attendance", + onTap: () { + Navigator.pop(context); + }, + ), + ); + return; + } + } + + // Proceed to get location + await getHuaweiCurrentLocation(attendanceType: attendanceType, context: context); + } catch (error) { + debugPrint("Error in checkHuaweiLocationPermission: $error"); + showDialog( + context: context, + builder: (BuildContext cxt) => ConfirmDialog( + message: "An unexpected error occurred. Please try again.", + onTap: () { + Navigator.pop(context); + }, + ), + ); + } } void handleSwipeOperation({required SwipeTypeEnum swipeType, required double lat, required double long, required BuildContext context}) { @@ -362,7 +466,6 @@ class SwipeGeneralUtils { ); return; } - // Check if location is enabled final isEnabled = await LocationUtilities.isEnabledAsync(); if (!isEnabled) { showInfoDialog( @@ -371,8 +474,6 @@ class SwipeGeneralUtils { ); return; } - - // Check permission final hasPermission = await LocationUtilities.havePermissionAsync(); if (!hasPermission) { showInfoDialog( @@ -381,11 +482,7 @@ class SwipeGeneralUtils { ); return; } - - // Show loader showLoading(context); - - // Get location await LocationUtilities.getCurrentLocation( (Position position, bool isMocked) { hideLoading(context); @@ -426,7 +523,7 @@ class SwipeGeneralUtils { } } -//older code.. +//TODO delete older code.. // void handleSwipe({required SwipeTypeEnum swipeType, required bool isEnable, required BuildContext context}) async { // if (Platform.isAndroid && !(await isGoogleServicesAvailable())) { // checkHuaweiLocationPermission(attendanceType: swipeType, context: context); diff --git a/lib/views/widgets/qr/scan_qr.dart b/lib/views/widgets/qr/scan_qr.dart index bbef7f70..0edec5ae 100644 --- a/lib/views/widgets/qr/scan_qr.dart +++ b/lib/views/widgets/qr/scan_qr.dart @@ -1,87 +1,176 @@ import 'dart:io'; - import 'package:flutter/material.dart'; +import 'package:google_api_availability/google_api_availability.dart'; import 'package:mobile_scanner/mobile_scanner.dart'; import 'package:qr_code_scanner_plus/qr_code_scanner_plus.dart'; - +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; import '../buttons/app_icon_button.dart'; class ScanQr extends StatefulWidget { const ScanQr({Key? key}) : super(key: key); @override - _ScanQrState createState() => _ScanQrState(); + State createState() => _ScanQrState(); } class _ScanQrState extends State { - // Barcode result; - // QRViewController? _controller; - - MobileScannerController? controller; + MobileScannerController? mobileController; + QRViewController? qrController; - bool _scanDone = false; final GlobalKey qrKey = GlobalKey(debugLabel: 'QR_scanner'); - // 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. + bool _scanDone = false; + bool _isHuawei = false; + bool _isLoading = true; @override void initState() { - // TODO: implement initState super.initState(); - controller = MobileScannerController( - detectionSpeed: DetectionSpeed.noDuplicates, - formats: [], - returnImage: false, - torchEnabled: false, - invertImage: false, - autoZoom: true, - ); + _initScanner(); } - // - // @override - // void reassemble() { - // super.reassemble(); - // if (Platform.isAndroid) { - // controller?.pauseCamera(); - // } else if (Platform.isIOS) { - // _controller?.resumeCamera(); - // } - // } + Future _initScanner() async { + _isHuawei = Platform.isAndroid && !(await isGoogleServicesAvailable()); + + if (!_isHuawei) { + mobileController = MobileScannerController( + detectionSpeed: DetectionSpeed.noDuplicates, + formats: [], + returnImage: false, + torchEnabled: false, + invertImage: false, + autoZoom: true, + ); + } + + if (mounted) { + setState(() { + _isLoading = false; + }); + } + } + + Future isGoogleServicesAvailable() async { + GooglePlayServicesAvailability availability = await GoogleApiAvailability.instance.checkGooglePlayServicesAvailability(); + String status = availability.toString().split('.').last; + return status == "success"; + } + + void _onQrViewCreated(QRViewController controller) { + qrController = controller; + controller.scannedDataStream.listen((scanData) { + if (_scanDone) return; + if (scanData.code == null || scanData.code!.isEmpty) return; + + _scanDone = true; + Navigator.of(context).pop(scanData.code); + }); + } @override void dispose() { + mobileController?.dispose(); + qrController?.dispose(); super.dispose(); - // _controller?.dispose(); } @override Widget build(BuildContext context) { + if (_isLoading) { + return const Scaffold( + body: Center(child: CircularProgressIndicator()), + ); + } + return Scaffold( body: Stack( children: [ - MobileScanner( - tapToFocus: true, - controller: controller, - onDetect: (result) { - if (!_scanDone) { - _scanDone = true; - Navigator.of(context).pop(result.barcodes.first.rawValue); - } + _isHuawei + ? QRView( + key: qrKey, + onQRViewCreated: _onQrViewCreated, + overlay: QrScannerOverlayShape( + borderColor: Colors.white, + borderRadius: 12, + borderLength: 30, + borderWidth: 4, + cutOutSize: MediaQuery.of(context).size.width * 0.7, + ), + ) + : MobileScanner( + controller: mobileController, + onDetect: (capture) { + if (_scanDone) return; + final barcodes = capture.barcodes; + if (barcodes.isEmpty) return; + final value = barcodes.first.rawValue; + if (value == null || value.isEmpty) return; + + _scanDone = true; + Navigator.of(context).pop(value); + }, + ), + _ScannerOverlay( + // scanDone: _scanDone, + onBack: () { + if (!_scanDone) _scanDone = true; + Navigator.of(context).pop(); }, + showSvgOverlay: !_isHuawei, + ), + ], + ), + ); + } +} + +class _ScannerOverlay extends StatelessWidget { + final VoidCallback onBack; + final bool showSvgOverlay; + + const _ScannerOverlay({ + Key? key, + required this.onBack, + this.showSvgOverlay = true, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return SizedBox.expand( + child: Stack( + children: [ + if (showSvgOverlay) + Center( + child: 'scan'.toSvgAsset( + height: 283.toScreenHeight.toInt(), + width: 283.toScreenWidth.toInt(), + fit: BoxFit.fitHeight, + ), + ), + Positioned( + bottom: 80, // adjust if needed + left: 0, + right: 0, + child: Center( + child: Text( + "Point camera at a QR code to scan", + style: TextStyle( + color: Colors.white.withOpacity(0.8), + fontSize: 16, + ), + ), + ), ), SafeArea( child: Padding( padding: const EdgeInsets.all(12.0), child: AIconButton( iconData: Icons.arrow_back, - onPressed: () { - Navigator.of(context).pop(); - }, + onPressed: onBack, ), ), - ) + ), ], ), ); diff --git a/pubspec.lock b/pubspec.lock index 7d4d8c0e..590577cc 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -750,6 +750,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.14.0+300" + huawei_scan: + dependency: "direct main" + description: + name: huawei_scan + sha256: "71bc8ce2e90fa07c2d82829ce928ebe3e69b3326fb55d2e7a68f62d9efdef6dd" + url: "https://pub.dev" + source: hosted + version: "2.12.0+304" image: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index fc8eab61..eccb9416 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -106,6 +106,7 @@ dependencies: audio_waveforms: ^1.3.0 signalr_netcore: ^1.4.4 ellipsized_text: ^2.0.0 + huawei_scan: ^2.12.0+304 local_auth_darwin: ^1.4.0 dev_dependencies: