diff --git a/AuthKey_67L2G322GR.p8 b/AuthKey_67L2G322GR.p8 new file mode 100644 index 0000000..eddd4c6 --- /dev/null +++ b/AuthKey_67L2G322GR.p8 @@ -0,0 +1,6 @@ +-----BEGIN PRIVATE KEY----- +MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQg+oBl9YdOiMRXfQZe +nIe6tR1tojoOvvcohNJmJtH+SsagCgYIKoZIzj0DAQehRANCAATDY9E82MAgMI/g +bKF1t4zLHJ1Yt9uoOnedNYsfyZLhh3l3ZyXRj02uDXz04AsNbNFjkLJXPc4xY9ad ++A4rY70x +-----END PRIVATE KEY----- \ No newline at end of file diff --git a/lib/api/my_requests_api_client.dart b/lib/api/my_requests_api_client.dart index c9507b9..96eafa5 100644 --- a/lib/api/my_requests_api_client.dart +++ b/lib/api/my_requests_api_client.dart @@ -60,7 +60,7 @@ class MyRequestsApiClient { }, url, postParams); } - Future getSubmitNewRequest(List> list) async + Future getSubmitNewRequest(List> list) async { String url = "${ApiConsts.erpRest}SUBMIT_CCP_TRANSACTION"; Map postParams = { @@ -73,7 +73,7 @@ class MyRequestsApiClient { postParams["EITTransactionTBL"] = list; return await ApiClient().postJsonForObject((json) { GenericResponseModel? responseData = GenericResponseModel.fromJson(json); - return responseData.submitCcpTransactionList; + return responseData; }, url, postParams); } diff --git a/lib/classes/notifications.dart b/lib/classes/notifications.dart index eb6a837..9c198b3 100644 --- a/lib/classes/notifications.dart +++ b/lib/classes/notifications.dart @@ -1,15 +1,20 @@ import 'dart:io'; + import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; +// import 'package:huawei_hmsavailability/huawei_hmsavailability.dart'; import 'package:huawei_push/huawei_push.dart' as huawei_push; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/chat_call_kit.dart'; +import 'package:mohem_flutter_app/classes/date_uitl.dart'; import 'package:mohem_flutter_app/classes/utils.dart'; -import 'package:mohem_flutter_app/main.dart'; +import 'package:mohem_flutter_app/models/get_notifications_response_model.dart'; +import 'package:mohem_flutter_app/ui/notifications/notification_details_page.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:uuid/uuid.dart'; @@ -26,6 +31,8 @@ class AppNotifications { String _huaweiToken = ''; + late BuildContext context; + Future requestPermissions() async { if (Platform.isIOS) { await flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation()?.requestPermissions(alert: true, badge: true, sound: true); @@ -42,10 +49,13 @@ class AppNotifications { } } - void init(String? firebaseToken) async { + void init(String? firebaseToken, BuildContext context) async { // if (Platform.isAndroid) { // hmsApiAvailability = HmsApiAvailability(); // } + + this.context = context; + print("Firebase init"); await requestPermissions(); AppState().setDeviceToken = firebaseToken; @@ -63,7 +73,7 @@ class AppNotifications { if (initialMessage != null) _handleMessage(initialMessage); FirebaseMessaging.onMessage.listen((RemoteMessage message) { - if (message != null) _handleMessage(message); + if (message.notification != null) _handleMessage(message); }); FirebaseMessaging.onMessageOpenedApp.listen(_handleOpenApp); @@ -119,6 +129,25 @@ class AppNotifications { void _handleMessage(RemoteMessage message) { Utils.saveStringFromPrefs("isAppOpendByChat", "false"); + GetNotificationsResponseModel notification = GetNotificationsResponseModel(); + + notification.createdOn = DateUtil.getMonthDayYearDateFormatted(DateTime.now()); + notification.messageTypeData = message.data['picture']; + notification.message = message.data['message']; + notification.notificationType = message.data["NotificationType"].toString(); + if (message.data["NotificationType"] == "2") { + notification.videoURL = message.data["VideoUrl"]; + } + + Future.delayed(Duration(seconds: 5), () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (BuildContext context) => NotificationsDetailsPage( + notification: notification, + ), + ), + ); + }); if (message.data.isNotEmpty && message.data["messageType"] == 'chat') { Utils.saveStringFromPrefs("isAppOpendByChat", "true"); Utils.saveStringFromPrefs("notificationData", message.data["user_chat_history_response"].toString()); @@ -133,6 +162,26 @@ class AppNotifications { if (message.data.isNotEmpty && message.data["type"] == 'chat') { Utils.saveStringFromPrefs("isAppOpendByChat", "true"); Utils.saveStringFromPrefs("notificationData", message.data["user_chat_history_response"].toString()); + } else { + GetNotificationsResponseModel notification = GetNotificationsResponseModel(); + + notification.createdOn = DateUtil.getMonthDayYearDateFormatted(DateTime.now()); + notification.messageTypeData = message.data['picture']; + notification.message = message.data['message']; + notification.notificationType = message.data["NotificationType"].toString(); + if (message.data["NotificationType"] == "2") { + notification.videoURL = message.data["VideoUrl"]; + } + + Future.delayed(Duration(seconds: 5), () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (BuildContext context) => NotificationsDetailsPage( + notification: notification, + ), + ), + ); + }); } } diff --git a/lib/classes/utils.dart b/lib/classes/utils.dart index 34831c2..1838cb8 100644 --- a/lib/classes/utils.dart +++ b/lib/classes/utils.dart @@ -401,4 +401,15 @@ class Utils { } return false; } + + static bool isDate(String input, String format) { + try { + DateTime d = DateFormat(format).parseStrict(input); + //print(d); + return true; + } catch (e) { + //print(e); + return false; + } + } } diff --git a/lib/models/get_notifications_response_model.dart b/lib/models/get_notifications_response_model.dart new file mode 100644 index 0000000..adf08ee --- /dev/null +++ b/lib/models/get_notifications_response_model.dart @@ -0,0 +1,96 @@ +class GetNotificationsResponseModel { + int? id; + int? recordId; + int? patientID; + bool? projectOutSA; + String? deviceType; + String? deviceToken; + String? message; + String? messageType; + String? messageTypeData; + dynamic videoURL; + bool? isQueue; + String? isQueueOn; + String? createdOn; + String? createdBy; + String? notificationType; + bool? isSent; + String? isSentOn; + bool? isRead; + String? isReadOn; + int? channelID; + int? projectID; + + GetNotificationsResponseModel( + {this.id, + this.recordId, + this.patientID, + this.projectOutSA, + this.deviceType, + this.deviceToken, + this.message, + this.messageType, + this.messageTypeData, + this.videoURL, + this.isQueue, + this.isQueueOn, + this.createdOn, + this.createdBy, + this.notificationType, + this.isSent, + this.isSentOn, + this.isRead, + this.isReadOn, + this.channelID, + this.projectID}); + + GetNotificationsResponseModel.fromJson(Map json) { + id = json['Id']; + recordId = json['RecordId']; + patientID = json['PatientID']; + projectOutSA = json['ProjectOutSA']; + deviceType = json['DeviceType']; + deviceToken = json['DeviceToken']; + message = json['Message']; + messageType = json['MessageType']; + messageTypeData = json['MessageTypeData']; + videoURL = json['VideoURL']; + isQueue = json['IsQueue']; + isQueueOn = json['IsQueueOn']; + createdOn = json['CreatedOn']; + createdBy = json['CreatedBy']; + notificationType = json['NotificationType']; + isSent = json['IsSent']; + isSentOn = json['IsSentOn']; + isRead = json['IsRead']; + isReadOn = json['IsReadOn']; + channelID = json['ChannelID']; + projectID = json['ProjectID']; + } + + Map toJson() { + Map data = new Map(); + data['Id'] = this.id; + data['RecordId'] = this.recordId; + data['PatientID'] = this.patientID; + data['ProjectOutSA'] = this.projectOutSA; + data['DeviceType'] = this.deviceType; + data['DeviceToken'] = this.deviceToken; + data['Message'] = this.message; + data['MessageType'] = this.messageType; + data['MessageTypeData'] = this.messageTypeData; + data['VideoURL'] = this.videoURL; + data['IsQueue'] = this.isQueue; + data['IsQueueOn'] = this.isQueueOn; + data['CreatedOn'] = this.createdOn; + data['CreatedBy'] = this.createdBy; + data['NotificationType'] = this.notificationType; + data['IsSent'] = this.isSent; + data['IsSentOn'] = this.isSentOn; + data['IsRead'] = this.isRead; + data['IsReadOn'] = this.isReadOn; + data['ChannelID'] = this.channelID; + data['ProjectID'] = this.projectID; + return data; + } +} diff --git a/lib/models/itg/advertisement.dart b/lib/models/itg/advertisement.dart index 598a248..96f4037 100644 --- a/lib/models/itg/advertisement.dart +++ b/lib/models/itg/advertisement.dart @@ -10,6 +10,9 @@ class Advertisement { this.pageSize, this.pageNo, this.languageId, + this.isOptional, + this.skipButtonTextEn, + this.skipButtonTextAr, }); final int? advertisementId; @@ -22,6 +25,9 @@ class Advertisement { final dynamic pageSize; final dynamic pageNo; final dynamic languageId; + final bool? isOptional; + final String? skipButtonTextEn; + final String? skipButtonTextAr; factory Advertisement.fromJson(Map json) => Advertisement( advertisementId: json["advertisementId"] == null ? null : json["advertisementId"], @@ -34,6 +40,9 @@ class Advertisement { pageSize: json["pageSize"], pageNo: json["pageNo"], languageId: json["languageId"], + isOptional: json["isOptional"] == null ? null : json["isOptional"], + skipButtonTextEn: json["skipBtnTextEn"] == null ? null : json["skipBtnTextEn"], + skipButtonTextAr: json["skipBtnTextAr"] == null ? null : json["skipBtnTextAr"], ); Map toJson() => { diff --git a/lib/theme/app_theme.dart b/lib/theme/app_theme.dart index 586c3aa..8a78e46 100644 --- a/lib/theme/app_theme.dart +++ b/lib/theme/app_theme.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; import 'package:mohem_flutter_app/theme/colors.dart'; @@ -26,7 +27,7 @@ class AppTheme { splashColor: Colors.transparent, primaryColor: primaryColor, primaryColorDark: primaryColor, - buttonColor: Colors.black, + cardColor: Colors.black, toggleableActiveColor: secondaryColor, indicatorColor: secondaryColor, bottomSheetTheme: const BottomSheetThemeData( @@ -44,7 +45,11 @@ class AppTheme { floatingActionButtonTheme: const FloatingActionButtonThemeData(highlightElevation: 2, disabledElevation: 0, elevation: 2), appBarTheme: AppBarTheme( color: const Color(0xff515A5D), - brightness: Brightness.light, + systemOverlayStyle: const SystemUiOverlayStyle( + statusBarBrightness: Brightness.light, + statusBarIconBrightness: Brightness.light, + systemNavigationBarIconBrightness: Brightness.light, + ), elevation: 0.0, actionsIconTheme: IconThemeData( color: Colors.grey[800], diff --git a/lib/ui/attendance/monthly_attendance_screen.dart b/lib/ui/attendance/monthly_attendance_screen.dart index 1753c29..875c8ca 100644 --- a/lib/ui/attendance/monthly_attendance_screen.dart +++ b/lib/ui/attendance/monthly_attendance_screen.dart @@ -16,7 +16,7 @@ import 'package:mohem_flutter_app/models/get_schedule_shifts_details_list_model. import 'package:mohem_flutter_app/models/get_time_card_summary_list_model.dart'; import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; import 'package:mohem_flutter_app/widgets/circular_step_progress_bar.dart'; -import 'package:month_picker_dialog_2/month_picker_dialog_2.dart'; +import 'package:month_picker_dialog/month_picker_dialog.dart'; import 'package:pie_chart/pie_chart.dart'; import 'package:syncfusion_flutter_calendar/calendar.dart'; @@ -117,8 +117,10 @@ class _MonthlyAttendanceScreenState extends State { initialDate: formattedDate, firstDate: DateTime(searchYear - 2), lastDate: DateTime.now(), - confirmText: Text(LocaleKeys.confirm.tr()), - cancelText: Text(LocaleKeys.cancel.tr()), + confirmWidget: Text(LocaleKeys.confirm.tr()), + cancelWidget: Text(LocaleKeys.cancel.tr()), + // confirmText: Text(LocaleKeys.confirm.tr()), + // cancelText: Text(LocaleKeys.cancel.tr()), ).then((selectedDate) { if (selectedDate != null) { searchMonth = getMonth(selectedDate.month); diff --git a/lib/ui/landing/itg/its_add_screen_video_image.dart b/lib/ui/landing/itg/its_add_screen_video_image.dart index 61b2766..1e280d8 100644 --- a/lib/ui/landing/itg/its_add_screen_video_image.dart +++ b/lib/ui/landing/itg/its_add_screen_video_image.dart @@ -7,6 +7,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_countdown_timer/index.dart'; import 'package:lottie/lottie.dart'; import 'package:mohem_flutter_app/api/dashboard_api_client.dart'; +import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; import 'package:mohem_flutter_app/classes/lottie_consts.dart'; import 'package:mohem_flutter_app/classes/utils.dart'; @@ -15,6 +16,7 @@ import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; import 'package:mohem_flutter_app/main.dart'; import 'package:mohem_flutter_app/models/itg/advertisement.dart' as ads; +import 'package:mohem_flutter_app/widgets/button/default_button.dart'; import 'package:path_provider/path_provider.dart'; import 'package:video_player/video_player.dart'; @@ -39,6 +41,12 @@ class _ITGAdsScreenState extends State { String? masterID; int videoDuration = 0; + bool hasTimerEndedBool = false; + + final ValueNotifier hasTimerEnded = ValueNotifier(false); + + late CountdownTimerController timerController; + void checkFileType() async { String? rFile = advertisementData!.viewAttachFileColl!.first.base64String; String? rFileExt = advertisementData!.viewAttachFileColl!.first.fileName; @@ -56,6 +64,17 @@ class _ITGAdsScreenState extends State { setState(() {}); } + void changeTimer(bool isTimerEnd) { + hasTimerEndedBool = isTimerEnd; + hasTimerEnded.value = !hasTimerEnded.value; + } + + void onTimerEnd() { + changeTimer(true); + timerController.disposeTimer(); + timerController.dispose(); + } + Future processImage(String encodedBytes) async { try { Uint8List decodedBytes = base64Decode(encodedBytes.split("base64,").last); @@ -69,18 +88,15 @@ class _ITGAdsScreenState extends State { Future createVideoPlayer(String encodedBytes) async { try { - Uint8List decodedBytes = base64Decode(encodedBytes.split("base64,").last); - Directory appDocumentsDirectory = await getApplicationDocumentsDirectory(); // 1 - File file = Io.File("${appDocumentsDirectory.path}/myAdsVideo.mp4"); - file.writeAsBytesSync(decodedBytes); - VideoPlayerController controller = VideoPlayerController.file(file); + VideoPlayerController controller = VideoPlayerController.network(advertisementData!.viewAttachFileColl!.first.base64String!); await controller.initialize(); await controller.play(); await controller.setVolume(1.0); await controller.setLooping(false); return controller; } catch (e) { - return VideoPlayerController.asset("dataSource"); + print(e); + return VideoPlayerController.network("https://apimohemmweb.cloudsolutions.com.sa/ErmAttachment/compressedvideo.mp4"); } } @@ -94,8 +110,6 @@ class _ITGAdsScreenState extends State { @override void dispose() { if (_controller != null) _controller.dispose(); - // player.stop(); - // player.dispose(); super.dispose(); } @@ -107,6 +121,7 @@ class _ITGAdsScreenState extends State { if (advertisementData != null) { checkFileType(); videoDuration = advertisementData?.durationInSeconds ?? 0; + timerController = CountdownTimerController(endTime: DateTime.now().millisecondsSinceEpoch + 1000 * videoDuration, onEnd: onTimerEnd); } return Scaffold( backgroundColor: Colors.black, @@ -131,38 +146,61 @@ class _ITGAdsScreenState extends State { ), 30.height, CountdownTimer( + controller: timerController, endTime: DateTime.now().millisecondsSinceEpoch + 1000 * videoDuration, - onEnd: null, - endWidget: "00:00:00".toText14(color: Colors.white, isBold: true), + endWidget: "00:00:00".toText16(color: Colors.white, isBold: true), textStyle: const TextStyle(color: Colors.white, fontSize: 16, letterSpacing: -0.48, fontWeight: FontWeight.bold), ), 50.height, - Container(padding: const EdgeInsets.all(16), decoration: Utils.containerRadius(MyColors.white, 10), child: const Icon(Icons.thumb_up, color: MyColors.gradiantEndColor)) - .onPress(() { - try { - DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!).then((value) { + ValueListenableBuilder( + valueListenable: hasTimerEnded, + builder: (context, val, child) { + if (hasTimerEndedBool) { + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + padding: const EdgeInsets.all(16), decoration: Utils.containerRadius(MyColors.white, 10), child: const Icon(Icons.thumb_up, color: MyColors.gradiantEndColor)) + .onPress(() { + try { + Navigator.pop(context); + DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, "Like").then((value) { + logger.d(value); + }); + } catch (ex) { + logger.wtf(ex); + Utils.handleException(ex, context, null); + } + }), + 20.width, + Container( + padding: const EdgeInsets.all(16), decoration: Utils.containerRadius(MyColors.white, 10), child: const Icon(Icons.thumb_down, color: MyColors.gradiantEndColor)) + .onPress(() { + try { + Navigator.pop(context); + DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, "Dislike").then((value) { + logger.d(value); + }); + } catch (ex) { + logger.wtf(ex); + Utils.handleException(ex, context, null); + } + }), + ], + ); + } else { + return Container(); + } + }, + ), + 20.height, + if (advertisementData?.isOptional ?? false) + DefaultButton(AppState().isArabic(context) ? advertisementData?.skipButtonTextAr ?? "Skip" : advertisementData?.skipButtonTextEn ?? "Skip", () async { + Navigator.pop(context); + DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, "Skip").then((value) { logger.d(value); - Navigator.pop(context); }); - } catch (ex) { - logger.wtf(ex); - Utils.handleException(ex, context, null); - } - }), - // DefaultButton(LocaleKeys.home.tr(), () async { - // DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!).then((value) { - // logger.d(value); - // }); - // }).paddingOnly(left: 50, right: 50) - - // ElevatedButton( - // onPressed: () async { - // // DashboardApiClient().setAdvertisementViewed(widget.addMasterId, widget.advertisement!.advertisementId!).then((value) { - // // logger.d(value); - // // }); - // }, - // child: const Text("Go To Dashboard"), - // ) + }).paddingOnly(left: 100, right: 100) ], ); } else { @@ -182,9 +220,9 @@ class _ITGAdsScreenState extends State { Container(padding: const EdgeInsets.all(16), decoration: Utils.containerRadius(MyColors.white, 10), child: const Icon(Icons.thumb_up, color: MyColors.gradiantEndColor)).onPress( () { try { - DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!).then((value) { + Navigator.pop(context); + DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, "Like").then((value) { logger.d(value); - Navigator.pop(context); }); } catch (ex) { logger.wtf(ex); diff --git a/lib/ui/login/login_screen.dart b/lib/ui/login/login_screen.dart index 39878f0..cd3547f 100644 --- a/lib/ui/login/login_screen.dart +++ b/lib/ui/login/login_screen.dart @@ -277,6 +277,7 @@ class _LoginScreenState extends State with WidgetsBindingObserver { Future checkFirebaseToken() async { try { + await checkPrefs(); Utils.showLoading(context); if (Platform.isAndroid) { try { @@ -289,7 +290,8 @@ class _LoginScreenState extends State with WidgetsBindingObserver { await Firebase.initializeApp(); _firebaseMessaging = FirebaseMessaging.instance; firebaseToken = await _firebaseMessaging.getToken(); - AppNotifications().init(firebaseToken); + print(firebaseToken); + AppNotifications().init(firebaseToken, context); checkLoginInfo(); await FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(true); } @@ -299,7 +301,10 @@ class _LoginScreenState extends State with WidgetsBindingObserver { await Firebase.initializeApp(); _firebaseMessaging = FirebaseMessaging.instance; firebaseToken = await _firebaseMessaging.getToken(); - AppNotifications().init(firebaseToken); + String? firebaseAPNSToken = await _firebaseMessaging.getAPNSToken(); + print("Firebase Token: $firebaseToken"); + print("Firebase APNS Token: $firebaseAPNSToken"); + AppNotifications().init(firebaseToken, context); checkLoginInfo(); await FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(true); } @@ -311,17 +316,21 @@ class _LoginScreenState extends State with WidgetsBindingObserver { } void checkLoginInfo() async { - loginInfo = await LoginApiClient().getMobileLoginInfoNEW(AppState().getIsHuawei ? AppState().getHuaweiPushToken : firebaseToken ?? "", Platform.isAndroid ? "android" : "ios"); - if (loginInfo == null) { - await checkPrefs(); - _autoLogin = false; - Utils.hideLoading(context); - return; - } else { - loginInfo!.deviceToken = firebaseToken; - await checkPrefs(); + try { + loginInfo = await LoginApiClient().getMobileLoginInfoNEW(AppState().getIsHuawei ? AppState().getHuaweiPushToken : firebaseToken ?? "", Platform.isAndroid ? "android" : "ios"); + if (loginInfo == null) { + await checkPrefs(); + _autoLogin = false; + Utils.hideLoading(context); + return; + } else { + loginInfo!.deviceToken = firebaseToken; + await checkPrefs(); + Utils.hideLoading(context); + performLogin(); + } + } catch (ex) { Utils.hideLoading(context); - performLogin(); } } diff --git a/lib/ui/login/verify_last_login_screen.dart b/lib/ui/login/verify_last_login_screen.dart index 3ac6cde..9b8dbd0 100644 --- a/lib/ui/login/verify_last_login_screen.dart +++ b/lib/ui/login/verify_last_login_screen.dart @@ -6,7 +6,6 @@ import 'package:flutter/services.dart'; import 'package:flutter_callkit_incoming/entities/call_event.dart'; import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart'; import 'package:flutter_svg/svg.dart'; -import 'package:local_auth/auth_strings.dart'; import 'package:local_auth/local_auth.dart'; import 'package:mohem_flutter_app/api/login_api_client.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; @@ -27,6 +26,7 @@ import 'package:mohem_flutter_app/ui/dialogs/id/business_card_dialog.dart'; import 'package:mohem_flutter_app/ui/dialogs/id/employee_digital_id_dialog.dart'; import 'package:mohem_flutter_app/widgets/button/default_button.dart'; import 'package:mohem_flutter_app/widgets/dialogs/dialogs.dart'; +import 'package:local_auth_ios/local_auth_ios.dart'; // WhatsApp 4 // SMS 1 @@ -61,19 +61,18 @@ class _VerifyLastLoginScreenState extends State { super.initState(); } - Future callListeners() async { try { FlutterCallkitIncoming.onEvent.listen((CallEvent? event) async { switch (event!.event) { case Event.actionCallIncoming: - // await ChatVoipCall().declineCall(payload: jsonEncode(event.body)); + // await ChatVoipCall().declineCall(payload: jsonEncode(event.body)); break; case Event.actionCallStart: break; case Event.actionCallAccept: if (mounted) { - // isIncomingCall = true; + // isIncomingCall = true; moveToCallScreen(); } break; @@ -95,8 +94,7 @@ class _VerifyLastLoginScreenState extends State { break; } }); - } on Exception { - } + } on Exception {} } Future moveToCallScreen() async { @@ -108,7 +106,7 @@ class _VerifyLastLoginScreenState extends State { } var pageRoute = MaterialPageRoute(builder: (context) => StartCallPage()); Navigator.push(context, pageRoute).whenComplete(() { - // checkFirebaseToken(); + // checkFirebaseToken(); }); } else { FlutterCallkitIncoming.endAllCalls(); @@ -117,8 +115,6 @@ class _VerifyLastLoginScreenState extends State { } } - - @override Widget build(BuildContext context) { mobileLoginInfoListModel ??= ModalRoute.of(context)!.settings.arguments as GetMobileLoginInfoListModel; @@ -283,10 +279,18 @@ class _VerifyLastLoginScreenState extends State { Future loginWithFaceIDAndBiometrics() async { IOSAuthMessages iosStrings = - const IOSAuthMessages(cancelButton: 'cancel', goToSettingsButton: 'settings', goToSettingsDescription: 'Please set up your Touch ID.', lockOut: 'Please reenable your Touch ID'); + const IOSAuthMessages(cancelButton: 'cancel', goToSettingsButton: 'settings', goToSettingsDescription: 'Please set up your Touch ID.', lockOut: 'Please re enable your Touch ID'); bool authenticated = false; try { - authenticated = await auth.authenticate(localizedReason: 'Scan your fingerprint to authenticate', useErrorDialogs: true, stickyAuth: true, biometricOnly: true, iOSAuthStrings: iosStrings); + authenticated = await auth.authenticate( + localizedReason: 'Scan your fingerprint to authenticate', + authMessages: [iosStrings], + options: const AuthenticationOptions( + useErrorDialogs: true, + stickyAuth: true, + biometricOnly: true, + ), + ); } on PlatformException catch (e) { print(e); Utils.hideLoading(context); diff --git a/lib/ui/login/verify_login_screen.dart b/lib/ui/login/verify_login_screen.dart index 0147472..628adc9 100644 --- a/lib/ui/login/verify_login_screen.dart +++ b/lib/ui/login/verify_login_screen.dart @@ -4,7 +4,6 @@ import 'package:easy_localization/src/public_ext.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_svg/svg.dart'; -import 'package:local_auth/auth_strings.dart'; import 'package:local_auth/local_auth.dart'; import 'package:mohem_flutter_app/api/login_api_client.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; @@ -13,13 +12,13 @@ import 'package:mohem_flutter_app/classes/consts.dart'; import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/config/routes.dart'; import 'package:mohem_flutter_app/dialogs/otp_dialog.dart'; -import 'package:mohem_flutter_app/extensions/int_extensions.dart'; import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; import 'package:mohem_flutter_app/models/basic_member_information_model.dart'; import 'package:mohem_flutter_app/models/generic_response_model.dart'; import 'package:mohem_flutter_app/models/member_information_list_model.dart'; import 'package:mohem_flutter_app/models/privilege_list_model.dart'; +import 'package:local_auth_ios/local_auth_ios.dart'; // WhatsApp 2 // SMS 1 @@ -516,7 +515,16 @@ class _VerifyLoginScreenState extends State { const IOSAuthMessages(cancelButton: 'cancel', goToSettingsButton: 'settings', goToSettingsDescription: 'Please set up your Touch ID.', lockOut: 'Please reenable your Touch ID'); bool authenticated = false; try { - authenticated = await auth.authenticate(localizedReason: 'Scan your fingerprint to authenticate', useErrorDialogs: true, stickyAuth: true, biometricOnly: true, iOSAuthStrings: iosStrings); + // authenticated = await auth.authenticate(localizedReason: 'Scan your fingerprint to authenticate', useErrorDialogs: true, stickyAuth: true, biometricOnly: true, iOSAuthStrings: iosStrings); + authenticated = await auth.authenticate( + localizedReason: 'Scan your fingerprint to authenticate', + authMessages: [iosStrings], + options: const AuthenticationOptions( + useErrorDialogs: true, + stickyAuth: true, + biometricOnly: true, + ) + ); } on PlatformException catch (e) { print(e); Utils.hideLoading(context); @@ -572,7 +580,7 @@ class _VerifyLoginScreenState extends State { width: 38, color: isDisable ? MyColors.darkTextColor.withOpacity(0.7) : null, ), - _title.toText16(height: 20/16) + _title.toText16(height: 20 / 16) ], ), ), @@ -679,5 +687,4 @@ class _VerifyLoginScreenState extends State { // // isLoading = isTrue; // }); // } - } diff --git a/lib/ui/my_team/view_attendance.dart b/lib/ui/my_team/view_attendance.dart index a45f35c..7cb9dde 100644 --- a/lib/ui/my_team/view_attendance.dart +++ b/lib/ui/my_team/view_attendance.dart @@ -15,7 +15,7 @@ import 'package:mohem_flutter_app/models/get_time_card_summary_list_model.dart'; import 'package:mohem_flutter_app/models/my_team/get_employee_subordinates_list.dart'; import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; import 'package:mohem_flutter_app/widgets/circular_step_progress_bar.dart'; -import 'package:month_picker_dialog_2/month_picker_dialog_2.dart'; +import 'package:month_picker_dialog/month_picker_dialog.dart'; import 'package:pie_chart/pie_chart.dart'; import 'package:syncfusion_flutter_calendar/calendar.dart'; @@ -169,8 +169,10 @@ class _ViewAttendanceState extends State { initialDate: formattedDate, firstDate: DateTime(searchYear - 2), lastDate: DateTime.now(), - confirmText: Text(LocaleKeys.confirm.tr()), - cancelText: Text(LocaleKeys.cancel.tr()), + confirmWidget: Text(LocaleKeys.confirm.tr()), + cancelWidget: Text(LocaleKeys.cancel.tr()), + // confirmText: Text(LocaleKeys.confirm.tr()), + // cancelText: Text(LocaleKeys.cancel.tr()), ).then( (selectedDate) { if (selectedDate != null) { diff --git a/lib/ui/notifications/notification_details_page.dart b/lib/ui/notifications/notification_details_page.dart new file mode 100644 index 0000000..67573dc --- /dev/null +++ b/lib/ui/notifications/notification_details_page.dart @@ -0,0 +1,74 @@ +import 'package:flutter/material.dart'; +import 'package:lottie/lottie.dart'; +import 'package:mohem_flutter_app/models/get_notifications_response_model.dart'; +import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; + +class NotificationsDetailsPage extends StatefulWidget { + final GetNotificationsResponseModel notification; + + NotificationsDetailsPage({required this.notification}); + + @override + State createState() => _NotificationsDetailsPageState(); +} + +class _NotificationsDetailsPageState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBarWidget( + context, + title: "Notification Details", + ), + body: ListView( + physics: BouncingScrollPhysics(), + padding: EdgeInsets.all(21), + children: [ + Text( + widget.notification.createdOn!, + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + color: Color(0xff2E303A), + letterSpacing: -0.64, + ), + ), + if (widget.notification.messageTypeData != null) + if (widget.notification.messageTypeData!.isNotEmpty && widget.notification.notificationType != "2") + Padding( + padding: const EdgeInsets.only(top: 18), + child: Image.network(widget.notification.messageTypeData!, loadingBuilder: (BuildContext context, Widget child, ImageChunkEvent? loadingProgress) { + if (loadingProgress == null) return child; + return Center( + child: SizedBox( + width: 40.0, + height: 40.0, + child: showLoadingAnimation(), + ), + ); + }, fit: BoxFit.fill), + ), + SizedBox(height: 18), + Text( + widget.notification.message!.trim(), + style: const TextStyle( + fontSize: 12, + fontWeight: FontWeight.w600, + color: Color(0xff575757), + letterSpacing: -0.48, + ), + ), + ], + ), + ); + } + + Widget showLoadingAnimation() { + return Lottie.asset( + 'assets/lottie/loading.json', + repeat: true, + reverse: false, + ); + } +} diff --git a/lib/ui/screens/my_requests/my_requests.dart b/lib/ui/screens/my_requests/my_requests.dart index dd6147f..4d16219 100644 --- a/lib/ui/screens/my_requests/my_requests.dart +++ b/lib/ui/screens/my_requests/my_requests.dart @@ -76,70 +76,72 @@ class _MyRequestsState extends State { }), ), 12.height, - getCCPTransactionsList.isNotEmpty ? Expanded( - child: ListView.separated( - physics: const BouncingScrollPhysics(), - shrinkWrap: true, - itemBuilder: (BuildContext context, int index) { - return Container( - width: double.infinity, - padding: const EdgeInsets.only(left: 12, right: 12, top: 10, bottom: 12), - margin: const EdgeInsets.only(left: 12, right: 12, top: 10, bottom: 0), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(10), - boxShadow: [ - BoxShadow( - color: const Color(0xff000000).withOpacity(.05), - blurRadius: 26, - offset: const Offset(0, -3), - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - ("Request ID: " + getCCPTransactionsList[index].rEQUESTID.toString()).toText12(color: MyColors.grey57Color), - DateUtil.formatDateToDate(DateUtil.convertStringToDate(getCCPTransactionsList[index].rEQUESTDATE!), false).toText12(color: MyColors.grey70Color), - ], - ), - Container( - padding: const EdgeInsets.only(top: 10.0), - child: ("Phase: " + getCCPTransactionsList[index].cCPPHASE!).toText12(color: MyColors.grey57Color, isBold: true), - ), - Container( - padding: const EdgeInsets.only(top: 10.0), - child: "Program Name: ".toText12(color: MyColors.grey57Color, isBold: true), - ), - getCCPTransactionsList[index].cONCURRENTPROGRAMNAME!.toText12(color: MyColors.gradiantEndColor), - Container( - padding: const EdgeInsets.only(top: 10.0), - child: InkWell( - onTap: () { - getCCPOutput(getCCPTransactionsList[index].rEQUESTID.toString()); - }, - child: Row( - children: [ - "Output: ".toText12(color: MyColors.grey57Color), - 8.width, - "Open PDF".toText12(color: MyColors.grey57Color), - 6.width, - const Icon(Icons.launch, size: 16.0), - ], - ), + getCCPTransactionsList.isNotEmpty + ? Expanded( + child: ListView.separated( + physics: const BouncingScrollPhysics(), + shrinkWrap: true, + itemBuilder: (BuildContext context, int index) { + return Container( + width: double.infinity, + padding: const EdgeInsets.only(left: 12, right: 12, top: 10, bottom: 12), + margin: const EdgeInsets.only(left: 12, right: 12, top: 10, bottom: 0), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: const Color(0xff000000).withOpacity(.05), + blurRadius: 26, + offset: const Offset(0, -3), + ), + ], ), - ), - ], - ), - ); - }, - separatorBuilder: (BuildContext context, int index) => 12.height, - itemCount: getCCPTransactionsList.length), - ) : Container(), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + ("Request ID: " + getCCPTransactionsList[index].rEQUESTID.toString()).toText12(color: MyColors.grey57Color), + DateUtil.formatDateToDate(DateUtil.convertStringToDate(getCCPTransactionsList[index].rEQUESTDATE!), false).toText12(color: MyColors.grey70Color), + ], + ), + Container( + padding: const EdgeInsets.only(top: 10.0), + child: ("Phase: " + getCCPTransactionsList[index].cCPPHASE!).toText12(color: MyColors.grey57Color, isBold: true), + ), + Container( + padding: const EdgeInsets.only(top: 10.0), + child: "Program Name: ".toText12(color: MyColors.grey57Color, isBold: true), + ), + getCCPTransactionsList[index].cONCURRENTPROGRAMNAME!.toText12(color: MyColors.gradiantEndColor), + Container( + padding: const EdgeInsets.only(top: 10.0), + child: InkWell( + onTap: () { + getCCPOutput(getCCPTransactionsList[index].rEQUESTID.toString()); + }, + child: Row( + children: [ + "Output: ".toText12(color: MyColors.grey57Color), + 8.width, + "Open PDF".toText12(color: MyColors.grey57Color), + 6.width, + const Icon(Icons.launch, size: 16.0), + ], + ), + ), + ), + ], + ), + ); + }, + separatorBuilder: (BuildContext context, int index) => 12.height, + itemCount: getCCPTransactionsList.length), + ) + : Container(), ], ).expanded, 1.divider, @@ -153,7 +155,9 @@ class _MyRequestsState extends State { void openNewRequest() async { await Navigator.pushNamed(context, AppRoutes.newRequest).then((value) { - // getOpenTickets(); + if (value != null && value == "refresh") { + getCCPTransactions(selectedConcurrentProgramList?.cONCURRENTPROGRAMNAME); + } }); } diff --git a/lib/ui/screens/my_requests/new_request.dart b/lib/ui/screens/my_requests/new_request.dart index 670b18d..04d7cb4 100644 --- a/lib/ui/screens/my_requests/new_request.dart +++ b/lib/ui/screens/my_requests/new_request.dart @@ -5,12 +5,12 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:mohem_flutter_app/api/my_requests_api_client.dart'; import 'package:mohem_flutter_app/classes/utils.dart'; -import 'package:mohem_flutter_app/config/routes.dart'; import 'package:mohem_flutter_app/extensions/int_extensions.dart'; import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; import 'package:mohem_flutter_app/models/dyanmic_forms/validate_eit_transaction_model.dart'; +import 'package:mohem_flutter_app/models/generic_response_model.dart'; import 'package:mohem_flutter_app/models/get_eit_dff_structure_list_model.dart'; import 'package:mohem_flutter_app/models/my_requests/get_ccp_transactions_model.dart'; import 'package:mohem_flutter_app/models/my_requests/get_ccp_transations_list_model.dart'; @@ -118,14 +118,14 @@ class _NewRequestState extends State { return ValidateEitTransactionModel(dATEVALUE: dateVal, nAME: e.aPPLICATIONCOLUMNNAME, nUMBERVALUE: numberVal, tRANSACTIONNUMBER: 1, vARCHAR2VALUE: vatcherVal.toString()).toJson(); }).toList(); Utils.showLoading(context); - submitCcpTransactionList = await MyRequestsApiClient().getSubmitNewRequest(values); - getCCPTransactionsList = await MyRequestsApiClient().getCcpTransactions(values); + GenericResponseModel responseModel = await MyRequestsApiClient().getSubmitNewRequest(values); Utils.hideLoading(context); - Navigator.pushNamed( - context, - AppRoutes.myRequests, - ); - setState(() {}); + + if (responseModel.messageStatus == 1) { + Navigator.pop(context, "refresh"); + } else { + Utils.showToast(responseModel.errorEndUserMessage ?? ""); + } } catch (ex) { Utils.hideLoading(context); Utils.handleException(ex, context, null); @@ -214,13 +214,15 @@ class _NewRequestState extends State { pIDCOLUMNNAME: DateFormat('yyyy/MM/dd HH:MM:SS', "en_US").format(date1), pRETURNMSG: "null", pRETURNSTATUS: getCCPDFFStructureModelList![index].dEFAULTVALUE, - pVALUECOLUMNNAME: getCCPDFFStructureModelList![index].isDefaultTypeIsCDPS ? DateFormat('yyyy/MM/dd HH:MM:SS', "en_US").format(date) : DateFormat('yyyy-MM-ddThh:mm:ss.s').format(date)); + pVALUECOLUMNNAME: + getCCPDFFStructureModelList![index].isDefaultTypeIsCDPS ? DateFormat('yyyy/MM/dd HH:MM:SS', "en_US").format(date) : DateFormat('yyyy-MM-ddThh:mm:ss.s').format(date)); } else { eservicesdv = ESERVICESDV( pIDCOLUMNNAME: DateFormat('yyyy-MM-dd', "en_US").format(date1), pRETURNMSG: "null", pRETURNSTATUS: getCCPDFFStructureModelList![index].dEFAULTVALUE, - pVALUECOLUMNNAME: getCCPDFFStructureModelList![index].isDefaultTypeIsCDPS ? DateFormat('yyyy-MM-dd hh:mm:ss', "en_US").format(date) : DateFormat('yyyy-MM-ddThh:mm:ss.s').format(date)); + pVALUECOLUMNNAME: + getCCPDFFStructureModelList![index].isDefaultTypeIsCDPS ? DateFormat('yyyy-MM-dd hh:mm:ss', "en_US").format(date) : DateFormat('yyyy-MM-ddThh:mm:ss.s').format(date)); } getCCPDFFStructureModelList![index].eSERVICESDV = eservicesdv; setState(() {}); diff --git a/lib/ui/work_list/item_history_screen.dart b/lib/ui/work_list/item_history_screen.dart index 88abf06..e88dcba 100644 --- a/lib/ui/work_list/item_history_screen.dart +++ b/lib/ui/work_list/item_history_screen.dart @@ -58,6 +58,7 @@ class _ItemHistoryScreenState extends State { List actionHistoryList = []; List getAttachmentList = []; int tabIndex = 0; + PageController controller = PageController(); @override void initState() { @@ -136,7 +137,7 @@ class _ItemHistoryScreenState extends State { backgroundColor: Colors.white, body: ListView( padding: _screenParams!.isPRInfo ? const EdgeInsets.all(0) : const EdgeInsets.all(21), - physics: const BouncingScrollPhysics(), + physics: const NeverScrollableScrollPhysics(), children: [ if (_screenParams!.isPRInfo) prLinesDataView(), if (moItemHistoryList.isNotEmpty) loadMoItemHistoryData(), @@ -150,6 +151,7 @@ class _ItemHistoryScreenState extends State { Widget prLinesDataView() { return Column( + mainAxisSize: MainAxisSize.min, children: [ Container( padding: const EdgeInsets.only(left: 21, right: 21, top: 16, bottom: 16), @@ -177,36 +179,54 @@ class _ItemHistoryScreenState extends State { ), ), if (tabIndex == 0) _screenParams!.getPRInformationList!.pRHeader![0].dESCRIPTION!.toText14().paddingOnly(top: 20, right: 21, left: 21), - if (tabIndex == 0) - ListView.separated( - padding: const EdgeInsets.all(21), - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemBuilder: (cxt, index) => Column( - children: [ - ItemDetailGrid( - ItemDetailViewCol("Cost Center", _screenParams!.getPRInformationList!.pRLines![index].cOSTCENTER ?? ""), - ItemDetailViewCol("Code", _screenParams!.getPRInformationList!.pRLines![index].iTEMCODE ?? ""), - ), - ItemDetailGrid( - ItemDetailViewCol("Unit", _screenParams!.getPRInformationList!.pRLines![index].uOM ?? ""), - ItemDetailViewCol("Price (SAR)", _screenParams!.getPRInformationList!.pRLines![index].uNITPRICE.toString() ?? ""), - ), - ItemDetailGrid( - ItemDetailViewCol("Amount (SAR)", _screenParams!.getPRInformationList!.pRLines![index].lINEAMOUNT.toString() ?? ""), - ItemDetailViewCol("Quantity", _screenParams!.getPRInformationList!.pRLines![index].qUANTITY.toString() ?? ""), - ), - ItemDetailGrid( - ItemDetailViewCol("AMU (Last 3 months)", _screenParams!.getPRInformationList!.pRLines![index].iTEMAMU.toString() ?? ""), - ItemDetailViewCol("PR Number", _screenParams!.getPRInformationList!.pRHeader![0].pRNUMBER!.toString() ?? ""), - isItLast: true, - ), - ], - ).objectContainerView(), - separatorBuilder: (cxt, index) => 12.height, - itemCount: _screenParams!.getPRInformationList!.pRLines!.length), - if (tabIndex == 1) getPRActionsHistory(), //"ACTIONS".toText14().paddingOnly(top: 20, right: 21, left: 21), - if (tabIndex == 2) getPRAttachments(), + SizedBox( + height: MediaQuery.of(context).size.height, + child: PageView( + controller: controller, + onPageChanged: (pageIndex) { + setState(() { + tabIndex = pageIndex; + if (pageIndex == 1) { + getActionsDataFromApi(); + } + if (pageIndex == 2) { + getAttachmentsDataFromApi(); + } + }); + }, + children: [ + ListView.separated( + padding: const EdgeInsets.all(21), + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (cxt, index) => Column( + children: [ + ItemDetailGrid( + ItemDetailViewCol("Cost Center", _screenParams!.getPRInformationList!.pRLines![index].cOSTCENTER ?? ""), + ItemDetailViewCol("Code", _screenParams!.getPRInformationList!.pRLines![index].iTEMCODE ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol("Unit", _screenParams!.getPRInformationList!.pRLines![index].uOM ?? ""), + ItemDetailViewCol("Price (SAR)", _screenParams!.getPRInformationList!.pRLines![index].uNITPRICE.toString() ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol("Amount (SAR)", _screenParams!.getPRInformationList!.pRLines![index].lINEAMOUNT.toString() ?? ""), + ItemDetailViewCol("Quantity", _screenParams!.getPRInformationList!.pRLines![index].qUANTITY.toString() ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol("AMU (Last 3 months)", _screenParams!.getPRInformationList!.pRLines![index].iTEMAMU.toString() ?? ""), + ItemDetailViewCol("PR Number", _screenParams!.getPRInformationList!.pRHeader![0].pRNUMBER!.toString() ?? ""), + isItLast: true, + ), + ], + ).objectContainerView(), + separatorBuilder: (cxt, index) => 12.height, + itemCount: _screenParams!.getPRInformationList!.pRLines!.length), + getPRActionsHistory(), //"ACTIONS".toText14().paddingOnly(top: 20, right: 21, left: 21), + getPRAttachments(), + ], + ), + ), ], ); } @@ -550,7 +570,8 @@ class _ItemHistoryScreenState extends State { if (index == 2) { getAttachmentsDataFromApi(); } - tabIndex = index; + // tabIndex = index; + controller.jumpToPage(index); }); }).expanded; } diff --git a/lib/widgets/location/Location.dart b/lib/widgets/location/Location.dart index 62bd016..e324618 100644 --- a/lib/widgets/location/Location.dart +++ b/lib/widgets/location/Location.dart @@ -8,7 +8,7 @@ import 'package:mohem_flutter_app/classes/utils.dart'; class Location { static void havePermission(Function(bool) callback) { Geolocator.checkPermission().then((value) async { - if (value == LocationPermission.denied) { + if (value == LocationPermission.denied || value == LocationPermission.deniedForever) { value = await Geolocator.requestPermission(); callback(![LocationPermission.denied, LocationPermission.deniedForever].contains(value)); } else { diff --git a/lib/widgets/mark_attendance_widget.dart b/lib/widgets/mark_attendance_widget.dart index f11fafe..dfb4357 100644 --- a/lib/widgets/mark_attendance_widget.dart +++ b/lib/widgets/mark_attendance_widget.dart @@ -54,8 +54,6 @@ class _MarkAttendanceWidgetState extends State { } void checkAttendanceAvailability() async { - String? deviceID = await PlatformDeviceId.getDeviceId; - print("Platform Device ID: $deviceID"); bool isAvailable = await NfcManager.instance.isAvailable(); setState(() { AppState().privilegeListModel!.forEach((PrivilegeListModel element) { @@ -124,7 +122,7 @@ class _MarkAttendanceWidgetState extends State { mainAxisSize: MainAxisSize.min, children: [ LocaleKeys.markAttendance.tr().toSectionHeading(), - LocaleKeys.selectMethodOfAttendance.tr().tr().toText11(color: const Color(0xff535353)), + LocaleKeys.selectMethodOfAttendance.tr().toText11(color: const Color(0xff535353)), GridView( physics: const NeverScrollableScrollPhysics(), shrinkWrap: true, @@ -132,60 +130,145 @@ class _MarkAttendanceWidgetState extends State { gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: (MediaQuery.of(context).size.width < 550) ? 3 : 5, childAspectRatio: 1 / 1, crossAxisSpacing: 8, mainAxisSpacing: 8), children: [ - // if (isNfcEnabled) attendanceMethod("NFC", "assets/images/nfc.svg", isNfcEnabled, () { - // if (isNfcLocationEnabled) { + if (AppState().getIsHuawei) { + checkHuaweiLocationPermission("NFC"); + } else { + Location.isEnabled((bool isEnabled) { + if (isEnabled) { + Location.havePermission((bool permission) { + if (permission) { + Location.getCurrentLocation( + (Position position, bool isMocked) { + if (isMocked) { + markFakeAttendance("NFC", position.latitude.toString() ?? "", position.longitude.toString() ?? ""); + } else { + performNfcAttendance(widget.model, lat: position.latitude.toString() ?? "", lng: position.longitude.toString() ?? ""); + } + }, + context, + ); + } else { + showDialog( + context: context, + builder: (BuildContext cxt) => ConfirmDialog( + message: "You need to give location permission to mark attendance", + onTap: () async { + Navigator.pop(context); + await Geolocator.openAppSettings(); + }, + ), + ); + } + }); + } 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 (isWifiEnabled) + attendanceMethod("Wifi", "assets/images/wufu.svg", isWifiEnabled, () { if (AppState().getIsHuawei) { - checkHuaweiLocationPermission("NFC"); + checkHuaweiLocationPermission("WIFI"); } else { - Location.getCurrentLocation((Position position, bool isMocked) { - if (isMocked) { - markFakeAttendance("NFC", position.latitude.toString() ?? "", position.longitude.toString() ?? ""); + Location.isEnabled((bool isEnabled) { + if (isEnabled) { + Location.havePermission((bool permission) { + if (permission) { + Location.getCurrentLocation( + (Position position, bool isMocked) { + if (isMocked) { + markFakeAttendance("WIFI", position.latitude.toString() ?? "", position.longitude.toString() ?? ""); + } else { + performWifiAttendance(widget.model, lat: position.latitude.toString() ?? "", lng: position.longitude.toString() ?? ""); + } + }, + context, + ); + } else { + showDialog( + context: context, + builder: (BuildContext cxt) => ConfirmDialog( + message: "You need to give location permission to mark attendance", + onTap: () async { + Navigator.pop(context); + await Geolocator.openAppSettings(); + }, + ), + ); + } + }); } else { - performNfcAttendance(widget.model, lat: position.latitude.toString() ?? "", lng: position.longitude.toString() ?? ""); + 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(); + }, + ), + ); } - }, context); + }); } - // } else { - // performNfcAttendance(widget.model); - // } - }), - if (isWifiEnabled) - attendanceMethod("Wifi", "assets/images/wufu.svg", isWifiEnabled, () { - // if (isWifiLocationEnabled) { - if (AppState().getIsHuawei) { - checkHuaweiLocationPermission("WIFI"); - } else { - Location.getCurrentLocation((Position position, bool isMocked) { - if (isMocked) { - markFakeAttendance("WIFI", position.latitude.toString() ?? "", position.longitude.toString() ?? ""); - } else { - performWifiAttendance(widget.model, lat: position.latitude.toString() ?? "", lng: position.longitude.toString() ?? ""); - } - }, context); - } - // } else { - // performWifiAttendance(widget.model); - // } }), if (isQrEnabled) attendanceMethod("QR", "assets/images/ic_qr.svg", isQrEnabled, () async { - // if (isQrLocationEnabled) { - if (AppState().getIsHuawei) { - checkHuaweiLocationPermission("QR"); - } else { - Location.getCurrentLocation((Position position, bool isMocked) { - if (isMocked) { - markFakeAttendance("QR", position.latitude.toString() ?? "", position.longitude.toString() ?? ""); - } else { - performQrCodeAttendance(widget.model, lat: position.latitude.toString() ?? "", lng: position.longitude.toString() ?? ""); - } - }, context); - } - // } else { - // performQrCodeAttendance(widget.model); - // } - // performQrCodeAttendance(model); + if (AppState().getIsHuawei) { + checkHuaweiLocationPermission("QR"); + } else { + Location.isEnabled((bool isEnabled) { + if (isEnabled) { + Location.havePermission((bool permission) { + if (permission) { + Location.getCurrentLocation( + (Position position, bool isMocked) { + if (isMocked) { + markFakeAttendance("QR", position.latitude.toString() ?? "", position.longitude.toString() ?? ""); + } else { + performQrCodeAttendance(widget.model, lat: position.latitude.toString() ?? "", lng: position.longitude.toString() ?? ""); + } + }, + context, + ); + } else { + showDialog( + context: context, + builder: (BuildContext cxt) => ConfirmDialog( + message: "You need to give location permission to mark attendance", + onTap: () async { + Navigator.pop(context); + await Geolocator.openAppSettings(); + }, + ), + ); + } + }); + } 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(); + }, + ), + ); + } + }); + } }), ], ) diff --git a/pubspec.yaml b/pubspec.yaml index 442f752..785bf4d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -43,7 +43,7 @@ dependencies: permission_handler: ^10.2.0 flutter_svg: any sizer: ^2.0.15 - local_auth: ^1.1.9 + local_auth: ^2.1.6 fluttertoast: ^8.0.8 syncfusion_flutter_calendar: ^19.4.48 # flutter_calendar_carousel: ^2.1.0 @@ -61,8 +61,8 @@ dependencies: image_picker: ^0.8.5+3 file_picker: ^4.6.1 geolocator: ^9.0.2 - month_year_picker: ^0.2.0+1 - month_picker_dialog_2: 0.5.5 + month_year_picker: any + month_picker_dialog: ^2.0.2 open_file: ^3.2.1 wifi_iot: ^0.3.18 flutter_html: ^3.0.0-alpha.6 @@ -126,8 +126,6 @@ dependency_overrides: dev_dependencies: - flutter_test: - sdk: flutter # The "flutter_lints" package below contains a set of recommended lints to # encourage good coding practices. The lint set provided by the package is