import 'dart:async'; import 'dart:convert'; import 'dart:developer'; import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:geolocator/geolocator.dart'; import 'package:google_api_availability/google_api_availability.dart'; import 'package:huawei_location/huawei_location.dart'; import 'package:intl/intl.dart'; import 'package:nfc_manager/nfc_manager.dart'; import 'package:nfc_manager/platform_tags.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:test_sa/controllers/providers/api/user_provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/main.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; import 'package:test_sa/new_views/swipe_module/dialoge/confirm_dialog.dart'; import 'package:test_sa/new_views/swipe_module/dialoge/nfc_reader_sheet.dart'; import 'package:test_sa/new_views/swipe_module/enums/swipe_type.dart'; import 'package:test_sa/new_views/swipe_module/models/swipe_model.dart'; import 'package:test_sa/new_views/swipe_module/swipe_success_view.dart'; import 'package:test_sa/new_views/swipe_module/utils/location_utils.dart'; import 'package:test_sa/views/widgets/qr/scan_qr.dart'; import 'package:wifi_iot/wifi_iot.dart'; class SwipeGeneralUtils { SwipeGeneralUtils._(); static SwipeGeneralUtils instance = SwipeGeneralUtils._(); static bool _isLoadingVisible = false; static bool get isLoading => _isLoadingVisible; void markFakeAttendance(dynamic sourceName, String lat, String long, @required BuildContext context) async { showLoading(context); try { hideLoading(navigatorKey.currentState!.overlay!.context); confirmDialog(navigatorKey.currentState!.overlay!.context, "Fake Location)"); } catch (ex) { log('$ex'); hideLoading(context); //handleException(ex, context, null); } } void showLoading(BuildContext context) { WidgetsBinding.instance.addPostFrameCallback((_) { _isLoadingVisible = true; showDialog( context: context, barrierColor: Colors.black.withOpacity(0.5), useRootNavigator: false, builder: (BuildContext context) => const AppLazyLoading(), ).then((value) { _isLoadingVisible = false; }); }); } void hideLoading(BuildContext context) { if (_isLoadingVisible) { _isLoadingVisible = false; Navigator.of(context).pop(); } _isLoadingVisible = false; } static Future getStringFromPrefs(String key) async { SharedPreferences prefs = await SharedPreferences.getInstance(); return prefs.getString(key) ?? ""; } void confirmDialog(cxt, String message, {VoidCallback? onTap}) { showDialog( context: cxt, builder: (BuildContext cxt) => ConfirmDialog(message: message, onTap: onTap), ); } void showErrorDialog({String ?message, required BuildContext context}) { showDialog( context: context, builder: (context) => ConfirmDialog(message: message, title: 'Error', onTap: () => Navigator.pop(context)), ); } void showMDialog(context, {Widget ?child, Color? backgroundColor, bool isDismissable = true, bool isBusniessCard = false}) async { return showDialog( context: context, barrierDismissible: isDismissable, builder: (context) { return Dialog( shape: isBusniessCard ? const RoundedRectangleBorder( borderRadius: BorderRadius.all( Radius.circular(15.0), ), ) : null, backgroundColor: backgroundColor, child: child, ); }, ); } Widget attendanceTypeCard(String title, String icon, bool isEnabled, VoidCallback onPress, BuildContext context) { return Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: isEnabled ? Colors.white : AppColor.white70, borderRadius: BorderRadius.circular(18), border: Border.all(color: AppColor.white70, width: 2), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ icon.toSvgAsset(color: isEnabled ? null : Colors.grey.withOpacity(0.5)), title.heading5(context).custom(color: isEnabled ? AppColor.neutral50 : Colors.grey.withOpacity(0.5)), ], ), ).onPress( () { if (!isEnabled) return; onPress(); }, ); } //huawei permission part.... 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); 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; //TODO cancel this stream when listening done.. // _streamSubscription.cancel(); }, ); } catch (error) { log("HUAWEI LOCATION ERROR!!!!!"); log('$error'); hideLoading(context); // handleException(error, context, null); } } Future requestPermissions() async { var result = await [ Permission.location, ].request(); 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 { 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); // }, // ), // ); // } // } } void handleSwipeOperation({required SwipeTypeEnum swipeType,required double lat,required double long,required BuildContext context}) { switch (swipeType) { case SwipeTypeEnum.NFC: handleNfcAttendance(latitude: lat, longitude: long, context: context); return; case SwipeTypeEnum.QR: performQrCodeAttendance(latitude: lat, longitude: long, context: context); return; case SwipeTypeEnum.Wifi: performWifiAttendance(latitude: lat, long: long, context: context); return; } } String formatTimeOnly(DateTime dateTime) { return DateFormat.Hms().format(dateTime); } Future performQrCodeAttendance({double ?latitude, double? longitude,required BuildContext context}) async { UserProvider userProvider = Provider.of(context, listen: false); String qrCodeValue = await Navigator.of(context).push( MaterialPageRoute(builder: (_) => ScanQr()), ) as String; if (qrCodeValue != null) { showLoading(context); try { final swipeModel = Swipe( swipeTypeValue: SwipeTypeEnum.QR.getIntFromSwipeTypeEnum(), value: qrCodeValue, latitude: latitude, longitude: longitude, ); await userProvider.makeSwipe(model: swipeModel).then((swipeResponse) { if (swipeResponse.isSuccess==true) { hideLoading(context); Navigator.pushNamed(context, SwipeSuccessView.routeName); } else { hideLoading(context); showDialog( barrierDismissible: true, context: context, builder: (cxt) => ConfirmDialog( message: swipeResponse.message ?? "", onTap: () { Navigator.pop(context); }, onCloseTap: () {}, ), ); } }); } catch (ex) { log('$ex'); hideLoading(context); //this need to confirm where it comes.. // handleException(ex, context, null); } } } Future handleNfcAttendance({double ?latitude = 0, double? longitude = 0,required BuildContext context}) async { // UserProvider _userProvider = Provider.of(context,listen:false); if (Platform.isIOS) { readNFc(onRead: (String nfcId) async { await _processNfcAttendance(nfcId, latitude, longitude, context); }); } else { showNfcReader(context, onNcfScan: (String nfcId) async { await _processNfcAttendance(nfcId ?? '', latitude, longitude, context); }); } } Future _processNfcAttendance( String nfcId, double ?latitude, double ?longitude, BuildContext context, ) async { showLoading(context); try { final swipeModel = Swipe(swipeTypeValue: SwipeTypeEnum.NFC.getIntFromSwipeTypeEnum(), value: nfcId, latitude: latitude, longitude: longitude); UserProvider userProvider = Provider.of(context, listen: false); final swipeResponse = await userProvider.makeSwipe(model: swipeModel); if (swipeResponse.isSuccess==true) { hideLoading(context); Navigator.pushNamed(context, SwipeSuccessView.routeName); } else { hideLoading(context); showErrorDialog(message: swipeResponse.message ?? "Unexpected error occurred", context: context); } } catch (errSwipeGeneralUtilsor) { hideLoading(context); } } void handleSwipe({required SwipeTypeEnum swipeType, required bool isEnable, required BuildContext context}) async { if (Platform.isAndroid && !(await isGoogleServicesAvailable())) { checkHuaweiLocationPermission(attendanceType: swipeType, context: context); } else { LocationUtilities.isEnabled((bool isEnabled) { if (isEnabled) { LocationUtilities.havePermission((bool permission) { if (permission) { showLoading(context); LocationUtilities.getCurrentLocation( (Position position, bool isMocked) { if (isMocked) { hideLoading(context); markFakeAttendance(swipeType.name, position.latitude.toString() ?? "", position.longitude.toString() ?? "", context); } else { hideLoading(context); handleSwipeOperation(swipeType: swipeType, lat: position.latitude, long: position.longitude, context: context); } }, () { hideLoading(context); confirmDialog(context, "Unable to determine your location, Please make sure that your location services are turned on & working."); }, context, ); } else { showInfoDialog( message: "You need to give location permission to mark attendance", onTap: () async { await Geolocator.openAppSettings(); }); } }); } else { showInfoDialog( message: "You need to enable location services to mark attendance", onTap: () async { await Geolocator.openLocationSettings(); }); } }); } } void showInfoDialog({required String message, VoidCallback? onTap}) { showDialog( context: navigatorKey.currentState!.overlay!.context, builder: (BuildContext cxt) => ConfirmDialog( message: message, onTap: () async { Navigator.pop(navigatorKey.currentState!.overlay!.context); onTap!(); }, ), ); } List availableAttendanceMethodList({required BuildContext context, required UserProvider userProvider, required bool isNfcSupported}) { List availableMethods = []; if (userProvider.user!.enableNFC!) { availableMethods.add(attendanceTypeCard(SwipeTypeEnum.NFC.name, 'nfc_icon', isNfcSupported, () { Navigator.pop(context); handleSwipe(swipeType: SwipeTypeEnum.NFC, isEnable: userProvider.user!.enableNFC!, context: navigatorKey.currentState!.overlay!.context); }, context)); } if (userProvider.user!.enableQR!) { availableMethods.add(attendanceTypeCard(SwipeTypeEnum.QR.name, 'qr', userProvider.user!.enableQR!, () { Navigator.pop(context); handleSwipe(swipeType: SwipeTypeEnum.QR, isEnable: userProvider.user!.enableQR!, context: navigatorKey.currentState!.overlay!.context); }, context)); } if (kDebugMode) { userProvider.user!.enableWifi!= true; } if (userProvider.user!.enableWifi!) { availableMethods.add(attendanceTypeCard(SwipeTypeEnum.Wifi.name, 'wifi_icon', userProvider.user!.enableWifi!, () { Navigator.pop(context); handleSwipe(swipeType: SwipeTypeEnum.Wifi, isEnable: userProvider.user!.enableWifi!, context: navigatorKey.currentState!.overlay!.context); }, context)); } return availableMethods; } void showSwipeTypeBottomSheetSheet({required bool isNfcSupported}) { BuildContext context = navigatorKey.currentState!.overlay!.context; UserProvider _userProvider = Provider.of(context, listen: false); showModalBottomSheet( context: context, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical( top: Radius.circular(20), ), ), clipBehavior: Clip.antiAliasWithSaveLayer, builder: (BuildContext context) => Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ context.translation.markAttendance.heading4(context).custom(color: AppColor.white936), 8.height, context.translation.selectMethodToMarkAttendance.bodyText2(context).custom(color: AppColor.neutral120), 12.height, GridView( padding: const EdgeInsets.all(0), shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, childAspectRatio: 1, crossAxisSpacing: 12, mainAxisSpacing: 12), children: availableAttendanceMethodList(context: context, userProvider: _userProvider, isNfcSupported: isNfcSupported)), ], ).paddingAll(16), ); } void readNFc({Function(String) ?onRead}) { NfcManager.instance.startSession(onDiscovered: (NfcTag tag) async { MifareUltralight f; if (Platform.isAndroid) { f = MifareUltralight(tag: tag, identifier: tag.data["nfca"]["identifier"], type: 2, maxTransceiveLength: 252, timeout: 22); } else { f = MifareUltralight(tag: tag, identifier: tag.data["mifare"]["identifier"], type: 2, maxTransceiveLength: 252, timeout: 22); } String identifier = f.identifier.map((e) => e.toRadixString(16).padLeft(2, '0')).join(''); NfcManager.instance.stopSession(); onRead!(identifier); }).catchError((err) { print(err); }); } //HUAWEI DECISION MAKING Future isGoogleServicesAvailable() async { GooglePlayServicesAvailability availability = await GoogleApiAvailability.instance.checkGooglePlayServicesAvailability(); String status = availability.toString().split('.').last; if (status == "success") { return true; } return false; } Future performWifiAttendance({required double latitude, required double long, required BuildContext context}) async { String ssId = String.fromCharCodes(base64Decode("SE1HLU1PSEVNTQ==")); String password = String.fromCharCodes(base64Decode("TTBoZW1tQDEyMTI=")); showLoading(context); bool isConnected = await WiFiForIoTPlugin.connect(ssId, password: password, joinOnce: Platform.isIOS ? false : true, security: NetworkSecurity.WPA, withInternet: false); if (Platform.isIOS) { if (await WiFiForIoTPlugin.getSSID() == ssId) { isConnected = true; } else { isConnected = false; } } UserProvider userProvider = Provider.of(context, listen: false); if (isConnected) { await WiFiForIoTPlugin.forceWifiUsage(true); await Future.delayed(const Duration(seconds: 6)); try { final swipeModel = Swipe(swipeTypeValue: SwipeTypeEnum.Wifi.getIntFromSwipeTypeEnum(), value: '', latitude: latitude, longitude: long); final swipeResponse = await userProvider.makeSwipe(model: swipeModel); await closeWifiRequest(); if (swipeResponse.isSuccess==true) { hideLoading(context); Navigator.pushNamed(context, SwipeSuccessView.routeName); } else { hideLoading(context); await Future.delayed(const Duration(milliseconds: 250)); showErrorDialog(message: swipeResponse.message ?? "Unexpected error occurred", context: context); } } catch (errSwipeGeneralUtilsor) { hideLoading(context); await closeWifiRequest(); } } else { // if (userProvider.) { hideLoading(context); confirmDialog(context, "Come Near HMG Wifi"); // } else { // await closeWifiRequest(); // } await closeWifiRequest(); } } Future closeWifiRequest() async { if (Platform.isAndroid) { await WiFiForIoTPlugin.forceWifiUsage(false); } return await WiFiForIoTPlugin.disconnect(); } }