From d44bc376813a31cd9085a6b61cea0ccc7e342d69 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Mon, 18 Dec 2023 11:08:41 +0300 Subject: [PATCH 001/135] marathon tutorial added. --- assets/langs/ar-SA.json | 3 +- assets/langs/en-US.json | 1 + lib/api/marathon/marathon_api_client.dart | 19 ++ lib/classes/consts.dart | 5 +- lib/classes/file_process.dart | 25 +- lib/config/routes.dart | 3 + lib/generated/locale_keys.g.dart | 1 + lib/models/itg/advertisement.dart | 5 +- lib/models/itg/itg_response_model.dart | 32 ++- .../marathon/tutorial_notification_model.dart | 104 ++++++++ lib/ui/landing/dashboard_screen.dart | 55 +++- lib/ui/marathon/marathon_provider.dart | 12 + .../marathon_tutorial_viewer_screen.dart | 239 ++++++++++++++++++ .../offers_and_discounts_details.dart | 2 +- 14 files changed, 483 insertions(+), 23 deletions(-) create mode 100644 lib/models/marathon/tutorial_notification_model.dart create mode 100644 lib/ui/marathon/marathon_tutorial_viewer_screen.dart diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 8ff0ea3..7ac0e9f 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -542,5 +542,6 @@ "uploadedDocuments": "المستندات التي تم تحميلها", "addAtLeastOneAttachment": "الرجاء إضافة مرفق واحد على الأقل.", "pleaseClickButtonToJoinMarathon": "الرجاء الضغط على الزر أدناه للانضمام إلى الماراثون", - "youCannotJoinTheMarathon": "لا يمكنك الانضمام إلى الماراثون لأنك تجاوزت الحد الزمني" + "youCannotJoinTheMarathon": "لا يمكنك الانضمام إلى الماراثون لأنك تجاوزت الحد الزمني", + "open": "يفتح" } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 2449802..b679368 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -559,6 +559,7 @@ "userSearch": "User Search", "userName": "User Name", "userId": "UserID", + "open": "open", "addAtLeastOneAttachment": "Please add at least one attachment.", "pleaseClickButtonToJoinMarathon": "Press the button below to join the Marathon.", "youCannotJoinTheMarathon": "You cannot join the Marathon because you have exceeded the time limit." diff --git a/lib/api/marathon/marathon_api_client.dart b/lib/api/marathon/marathon_api_client.dart index 428e586..d9021c6 100644 --- a/lib/api/marathon/marathon_api_client.dart +++ b/lib/api/marathon/marathon_api_client.dart @@ -11,6 +11,7 @@ import 'package:mohem_flutter_app/config/routes.dart'; import 'package:mohem_flutter_app/models/marathon/marathon_generic_model.dart'; import 'package:mohem_flutter_app/models/marathon/marathon_model.dart'; import 'package:mohem_flutter_app/models/marathon/question_model.dart'; +import 'package:mohem_flutter_app/models/marathon/tutorial_notification_model.dart'; import 'package:mohem_flutter_app/models/marathon/winner_model.dart'; import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart'; import 'package:provider/provider.dart'; @@ -195,6 +196,24 @@ class MarathonApiClient { return null; } + Future getMarathonTutorial() async { + Response response = await ApiClient().getJsonForResponse( + // ApiConsts.marathonGetTutorial, + "https://marathoon.com/uatservice/api/tutorial/GetTutorialNotification", + token: AppState().getMarathonToken == null || AppState().getMarathonToken == "" ? await getMarathonToken() : AppState().getMarathonToken, + ); + try { + MarathonGenericModel marathonModel = MarathonGenericModel.fromJson(jsonDecode(response.body)); + if (marathonModel.data is List) { + return TutorialNotificationModel.fromJson(marathonModel.data[0]); + } + } catch (ex) { + print(ex); + } + + return null; + } + // late HubConnection hubConnection; // Future buildHubConnection(BuildContext context, String prizeId) async { // HttpConnectionOptions httpOptions = HttpConnectionOptions(skipNegotiation: false, logMessageContent: true); diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index d345415..4d64e9c 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -3,8 +3,8 @@ import 'package:mohem_flutter_app/ui/marathon/widgets/question_card.dart'; class ApiConsts { //static String baseUrl = "http://10.200.204.20:2801/"; // Local server // static String baseUrl = "https://erptstapp.srca.org.sa"; // SRCA server - // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver - static String baseUrl = "https://hmgwebservices.com"; // Live server + static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver + // static String baseUrl = "https://hmgwebservices.com"; // Live server static String baseUrlServices = baseUrl + "/Services/"; // server // static String baseUrlServices = "https://api.cssynapses.com/tangheem/"; // Live server static String utilitiesRest = baseUrlServices + "Utilities.svc/REST/"; @@ -51,6 +51,7 @@ class ApiConsts { static String marathonQualifiersUrl = marathonBaseUrl + "winner/getWinner/"; static String marathonSelectedWinner = marathonBaseUrl + "winner/getSelectedWinner/"; static String marathonGetMarathonersCount = marathonBaseUrl + "Participant/GetRemainingParticipants"; + static String marathonGetTutorial = marathonBaseUrl + "tutorial/GetTutorialNotification"; //DummyCards for the UI static CardContent dummyQuestion = const CardContent(); diff --git a/lib/classes/file_process.dart b/lib/classes/file_process.dart index 6974702..83ea15b 100644 --- a/lib/classes/file_process.dart +++ b/lib/classes/file_process.dart @@ -4,6 +4,7 @@ import 'dart:typed_data'; import 'package:open_file/open_file.dart'; import 'package:path_provider/path_provider.dart'; +import 'package:http/http.dart' as http; class FileProcess { static bool isFolderCreated = false; @@ -23,9 +24,9 @@ class FileProcess { } } - static void openFile(String fileName) { + static void openFile(String fileName, {bool isFullPath = false}) { String dir = directory!.path + "/$fileName.pdf"; - OpenFile.open(dir); + OpenFile.open(isFullPath ? fileName : dir); } static Future downloadFile(String base64Content, String fileName) async { @@ -37,4 +38,24 @@ class FileProcess { await file.writeAsBytes(bytes); return file; } + + static Future downloadFileFromUrl(String url,String fileName) async { + await checkDocumentFolder(); + String filePath = '${directory!.path}/$fileName'; + + if (await File(filePath).exists()) { + await Future.delayed(const Duration(seconds: 1)); + return filePath; + } else { + var response = await http.get(Uri.parse(url)); + if (response.statusCode == 200) { + var bytes = response.bodyBytes; + File file = File(filePath); + await file.writeAsBytes(bytes); + return filePath; + } else { + throw Exception('Failed to download file'); + } + } + } } diff --git a/lib/config/routes.dart b/lib/config/routes.dart index 07a927d..33559e2 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -27,6 +27,7 @@ import 'package:mohem_flutter_app/ui/login/verify_login_screen.dart'; import 'package:mohem_flutter_app/ui/marathon/marathon_intro_screen.dart'; import 'package:mohem_flutter_app/ui/marathon/marathon_screen.dart'; import 'package:mohem_flutter_app/ui/marathon/marathon_sponsor_video_screen.dart'; +import 'package:mohem_flutter_app/ui/marathon/marathon_tutorial_viewer_screen.dart'; import 'package:mohem_flutter_app/ui/marathon/marathon_waiting_screen.dart'; import 'package:mohem_flutter_app/ui/misc/request_submit_screen.dart'; import 'package:mohem_flutter_app/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart'; @@ -203,6 +204,7 @@ class AppRoutes { static const String marathonWinnerScreen = "/marathonWinnerScreen"; static const String marathonSponsorVideoScreen = "/marathonSponsorVideoScreen"; static const String marathonWaitingScreen = "/marathonWaitingScreen"; + static const String marathonTutorialScreen = "/marathonTutorialScreen"; static const String unsafeDeviceScreen = "/unsafeDeviceScreen"; static const String appUpdateScreen = "/appUpdateScreen"; @@ -319,6 +321,7 @@ class AppRoutes { marathonScreen: (BuildContext context) => MarathonScreen(), marathonSponsorVideoScreen: (BuildContext context) => const SponsorVideoScreen(), marathonWaitingScreen: (BuildContext context) => const MarathonWaitingScreen(), + marathonTutorialScreen: (BuildContext context) => const MarathonTutorialViewerScreen(), unsafeDeviceScreen: (BuildContext context) => const UnsafeDeviceScreen(), appUpdateScreen: (BuildContext context) => const AppUpdateScreen(), diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 7a3501f..a6fd43d 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -549,4 +549,5 @@ abstract class LocaleKeys { static const addAtLeastOneAttachment ='addAtLeastOneAttachment'; static const pleaseClickButtonToJoinMarathon ='pleaseClickButtonToJoinMarathon'; static const youCannotJoinTheMarathon ='youCannotJoinTheMarathon'; + static const open ='open'; } diff --git a/lib/models/itg/advertisement.dart b/lib/models/itg/advertisement.dart index ebcf704..fb172ad 100644 --- a/lib/models/itg/advertisement.dart +++ b/lib/models/itg/advertisement.dart @@ -94,8 +94,9 @@ class ViewAttachFileColl { dynamic referenceItemId; dynamic content; dynamic filePath; + dynamic languageId; - ViewAttachFileColl({this.attachmentId, this.fileName, this.contentType, this.attachFileStream, this.base64String, this.isActive, this.referenceItemId, this.content, this.filePath}); + ViewAttachFileColl({this.attachmentId, this.fileName, this.contentType, this.attachFileStream, this.base64String, this.isActive, this.referenceItemId, this.content, this.filePath, this.languageId}); ViewAttachFileColl.fromJson(Map json) { attachmentId = json['attachmentId']; @@ -107,6 +108,7 @@ class ViewAttachFileColl { referenceItemId = json['referenceItemId']; content = json['content']; filePath = json['filePath']; + languageId = json['languageId']; } Map toJson() { @@ -120,6 +122,7 @@ class ViewAttachFileColl { data['referenceItemId'] = this.referenceItemId; data['content'] = this.content; data['filePath'] = this.filePath; + data['languageId'] = this.languageId; return data; } } diff --git a/lib/models/itg/itg_response_model.dart b/lib/models/itg/itg_response_model.dart index dff7869..e8d8acf 100644 --- a/lib/models/itg/itg_response_model.dart +++ b/lib/models/itg/itg_response_model.dart @@ -46,19 +46,31 @@ class ItgResponseResult { this.errormsg, }); - final dynamic totalItemsCount; - final ItgResponseData? data; - final dynamic errormsg; - - factory ItgResponseResult.fromJson(Map json) => ItgResponseResult( - totalItemsCount: json["totalItemsCount"], - data: json["data"] == null ? null : ItgResponseData.fromJson(json["data"]), - errormsg: json["errormsg"], - ); + dynamic totalItemsCount; + List? data; + dynamic errormsg; + + ItgResponseResult.fromJson(Map json) { + totalItemsCount = json['totalItemsCount']; + if (json['data'] != null) { + data = []; + json['data'].forEach((v) { + data!.add(ItgResponseData.fromJson(v)); + }); + } + errormsg = json['errormsg']; + } + + // + // factory ItgResponseResult.fromJson(Map json) => ItgResponseResult( + // totalItemsCount: json["totalItemsCount"], + // data: json["data"] == null ? null : ItgResponseData.fromJson(json["data"]), + // errormsg: json["errormsg"], + // ); Map toJson() => { "totalItemsCount": totalItemsCount, - "data": data == null ? null : data!.toJson(), + "data": data == null ? null : data!.map((v) => v.toJson()).toList(), "errormsg": errormsg, }; } diff --git a/lib/models/marathon/tutorial_notification_model.dart b/lib/models/marathon/tutorial_notification_model.dart new file mode 100644 index 0000000..ca1dd52 --- /dev/null +++ b/lib/models/marathon/tutorial_notification_model.dart @@ -0,0 +1,104 @@ +// class TutorialNotificationModel { +// List? data; +// bool? isSuccessful; +// String? message; +// int? statusCode; +// +// TutorialNotificationModel({this.data, this.isSuccessful, this.message, this.statusCode}); +// +// TutorialNotificationModel.fromJson(Map json) { +// if (json['data'] != null) { +// data = []; +// json['data'].forEach((v) { +// data!.add(new Data.fromJson(v)); +// }); +// } +// isSuccessful = json['isSuccessful']; +// message = json['message']; +// statusCode = json['statusCode']; +// } +// +// Map toJson() { +// final Map data = new Map(); +// if (this.data != null) { +// data['data'] = this.data!.map((v) => v.toJson()).toList(); +// } +// data['isSuccessful'] = this.isSuccessful; +// data['message'] = this.message; +// data['statusCode'] = this.statusCode; +// +// return data; +// } +// } + +class TutorialNotificationModel { + String? tutorialNotificationId; + String? tutorialName; + String? tutorialDescription; + String? startDate; + String? endDate; + String? fileName; + String? contentType; + String? filePath; + int? orderNo; + bool? isActive; + int? isStatus; + String? created; + String? createdBy; + String? modified; + String? modifiedBy; + + TutorialNotificationModel({this.tutorialNotificationId, + this.tutorialName, + this.tutorialDescription, + this.startDate, + this.endDate, + this.fileName, + this.contentType, + this.filePath, + this.orderNo, + this.isActive, + this.isStatus, + this.created, + this.createdBy, + this.modified, + this.modifiedBy}); + + TutorialNotificationModel.fromJson(Map json) { + tutorialNotificationId = json['tutorialNotificationId']; + tutorialName = json['tutorialName']; + tutorialDescription = json['tutorialDescription']; + startDate = json['startDate']; + endDate = json['endDate']; + fileName = json['fileName']; + contentType = json['contentType']; + filePath = json['filePath']; + orderNo = json['orderNo']; + isActive = json['isActive']; + isStatus = json['isStatus']; + created = json['created']; + createdBy = json['createdBy']; + modified = json['modified']; + modifiedBy = json['modifiedBy']; + } + + Map toJson() { + Map data = new Map(); + data['tutorialNotificationId'] = this.tutorialNotificationId; + data['tutorialName'] = this.tutorialName; + data['tutorialDescription'] = this.tutorialDescription; + data['startDate'] = this.startDate; + data['endDate'] = this.endDate; + data['fileName'] = this.fileName; + data['contentType'] = this.contentType; + data['filePath'] = this.filePath; + data['orderNo'] = this.orderNo; + data['isActive'] = this.isActive; + data['isStatus'] = this.isStatus; + data['created'] = this.created; + data['createdBy'] = this.createdBy; + data['modified'] = this.modified; + data['modifiedBy'] = this.modifiedBy; + return data; + } +} diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index 4116594..ea3b2cb 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -150,6 +150,7 @@ class _DashboardScreenState extends State with WidgetsBindingOb data.fetchMenuEntries(); data.getCategoryOffersListAPI(context); marathonProvider.getMarathonDetailsFromApi(); + marathonProvider.getMarathonTutorial(); if (isFromInit) { checkERMChannel(); } @@ -161,8 +162,8 @@ class _DashboardScreenState extends State with WidgetsBindingOb data.getITGNotification().then((val) { if (val!.result!.data != null) { print("-------------------- Survey ----------------------------"); - if (val.result!.data!.notificationType == "Survey") { - DashboardApiClient().getAdvertisementDetail(val.result!.data!.notificationMasterId ?? "").then( + if (val.result!.data!.first.notificationType == "Survey") { + DashboardApiClient().getAdvertisementDetail(val.result!.data!.first.notificationMasterId ?? "").then( (value) { if (value!.mohemmItgResponseItem!.statusCode == 200) { if (value.mohemmItgResponseItem!.result!.data != null) { @@ -178,13 +179,13 @@ class _DashboardScreenState extends State with WidgetsBindingOb ); } else { print("------------------------------------------- Ads --------------------"); - DashboardApiClient().getAdvertisementDetail(val.result!.data!.notificationMasterId ?? "").then( + DashboardApiClient().getAdvertisementDetail(val.result!.data!.first.notificationMasterId ?? "").then( (value) { if (value!.mohemmItgResponseItem!.statusCode == 200) { if (value.mohemmItgResponseItem!.result!.data != null) { Navigator.pushNamed(context, AppRoutes.advertisement, arguments: { - "masterId": val.result!.data!.notificationMasterId, - "advertisement": value.mohemmItgResponseItem!.result!.data!.advertisement, + "masterId": val.result!.data!.first.notificationMasterId, + "advertisement": value.mohemmItgResponseItem!.result!.data!.first.advertisement, }); } } @@ -493,7 +494,49 @@ class _DashboardScreenState extends State with WidgetsBindingOb mainAxisSize: MainAxisSize.min, children: [ ServicesWidget(), - context.watch().isLoading ? const MarathonBannerShimmer().paddingAll(20) : const MarathonBanner().paddingOnly(left: 21, right: 21, bottom: 21, top: 8), + context.watch().isLoading ? const MarathonBannerShimmer().paddingAll(20) : const MarathonBanner().paddingOnly(left: 21, right: 21, bottom: 8, top: 8), + context.watch().isTutorialLoading + ? const MarathonBannerShimmer().paddingAll(20) + : Container( + padding: EdgeInsets.only(bottom: 12, top: 12), + margin: EdgeInsets.only(left: 21, right: 21, bottom: 21, top: 8), + width: double.infinity, + alignment: Alignment.center, + decoration: BoxDecoration( + color: MyColors.backgroundBlackColor, + borderRadius: BorderRadius.circular(20), + border: Border.all(color: MyColors.lightGreyEDColor, width: 1), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + "Tutorial:", + style: TextStyle( + fontSize: 11, + fontStyle: FontStyle.italic, + fontWeight: FontWeight.w600, + color: MyColors.white.withOpacity(0.83), + letterSpacing: -0.4, + ), + ), + Text( + context.read().tutorial?.tutorialName ?? "", + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontStyle: FontStyle.italic, + fontSize: 19, + fontWeight: FontWeight.bold, + color: MyColors.white, + height: 32 / 22, + ), + ), + ], + ), + ).onPress(() { + Navigator.pushNamed(context, AppRoutes.marathonTutorialScreen); + }), ], ), ), diff --git a/lib/ui/marathon/marathon_provider.dart b/lib/ui/marathon/marathon_provider.dart index 544aad3..ecffd96 100644 --- a/lib/ui/marathon/marathon_provider.dart +++ b/lib/ui/marathon/marathon_provider.dart @@ -13,6 +13,7 @@ import 'package:mohem_flutter_app/config/routes.dart'; import 'package:mohem_flutter_app/models/marathon/marathon_generic_model.dart'; import 'package:mohem_flutter_app/models/marathon/marathon_model.dart'; import 'package:mohem_flutter_app/models/marathon/question_model.dart'; +import 'package:mohem_flutter_app/models/marathon/tutorial_notification_model.dart'; import 'package:mohem_flutter_app/models/marathon/winner_model.dart'; import 'package:mohem_flutter_app/models/privilege_list_model.dart'; import 'package:mohem_flutter_app/ui/marathon/widgets/question_card.dart'; @@ -594,4 +595,15 @@ class MarathonProvider extends ChangeNotifier { AppState().setIsDemoMarathon = true; await callNextQuestionApi(); } + + bool isTutorialLoading = false; + TutorialNotificationModel? tutorial; + + Future getMarathonTutorial() async { + isTutorialLoading = true; + notifyListeners(); + tutorial = await MarathonApiClient().getMarathonTutorial(); + isTutorialLoading = false; + notifyListeners(); + } } diff --git a/lib/ui/marathon/marathon_tutorial_viewer_screen.dart b/lib/ui/marathon/marathon_tutorial_viewer_screen.dart new file mode 100644 index 0000000..2e40ecf --- /dev/null +++ b/lib/ui/marathon/marathon_tutorial_viewer_screen.dart @@ -0,0 +1,239 @@ +import 'dart:convert'; +import 'dart:io' as Io; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:easy_localization/easy_localization.dart'; +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/file_process.dart'; +import 'package:mohem_flutter_app/classes/lottie_consts.dart'; +import 'package:mohem_flutter_app/classes/utils.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/main.dart'; +import 'package:mohem_flutter_app/models/itg/advertisement.dart' as ads; +import 'package:mohem_flutter_app/models/marathon/tutorial_notification_model.dart'; +import 'package:mohem_flutter_app/ui/chat/common.dart'; +import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart'; +import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; +import 'package:mohem_flutter_app/widgets/button/default_button.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:provider/provider.dart'; +import 'package:video_player/video_player.dart'; + +class MarathonTutorialViewerScreen extends StatefulWidget { + const MarathonTutorialViewerScreen({Key? key}) : super(key: key); + + @override + _MarathonTutorialViewerScreenState createState() => _MarathonTutorialViewerScreenState(); +} + +class _MarathonTutorialViewerScreenState extends State { + late Future _futureController; + VideoPlayerController? _controller; + bool skip = false; + + bool isVideo = false; + bool isImage = false; + bool isAudio = false; + bool isPdf = false; + + String link = ""; + + String ext = ''; + late File imageFile; + ads.Advertisement? advertisementData; + dynamic data; + String? masterID; + int videoDuration = 0; + + ValueNotifier videoLength = ValueNotifier(0); + + void checkFileTypes(String link) { + ext = "." + link.split(".").last.toLowerCase(); + if (ext == ".png" || ext == ".jpg" || ext == ".jpeg" || ext == ".gif") { + isImage = true; + } else if (ext == ".pdf") { + isPdf = true; + } else { + if (ext == ".aac") { + isAudio = true; + } + isVideo = true; + _futureController = createVideoPlayer(link); + } + + setState(() {}); + } + + Future processImage(String encodedBytes) async { + try { + Uint8List decodedBytes = base64Decode(encodedBytes.split("base64,").last); + Directory appDocumentsDirectory = await getApplicationDocumentsDirectory(); // 1 + imageFile = Io.File("${appDocumentsDirectory.path}/addImage$ext"); + imageFile.writeAsBytesSync(decodedBytes); + } catch (e) { + logger.d(e); + } + } + + Future createVideoPlayer(String link) async { + try { + VideoPlayerController controller = VideoPlayerController.networkUrl(Uri.parse(link)); + await controller.initialize(); + await controller.play(); + await controller.setVolume(1.0); + await controller.setLooping(false); + controller.addListener(() { + controller.position.then((value) { + videoLength.value = value!.inMilliseconds; + // if(controller.value.isCompleted) { + // videoLength.value = 0; + // } + }); + }); + return controller; + } catch (e) { + print(e); + return VideoPlayerController.network("https://apimohemmweb.cloudsolutions.com.sa/ErmAttachment/compressedvideo.mp4"); + } + } + + bool showControls = false; + + void showVideoControls() { + showControls = !showControls; + setState(() {}); + } + + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + _controller?.dispose(); + super.dispose(); + } + + TutorialNotificationModel? tutorial; + + @override + Widget build(BuildContext context) { + if (tutorial == null) { + tutorial ??= context.read().tutorial; + link = tutorial!.filePath!; + checkFileTypes(link); + } + + return Scaffold( + backgroundColor: Colors.black, + appBar: AppBarWidget(context, title: tutorial!.fileName!, showHomeButton: false), + body: Stack( + children: [ + if (isVideo) + FutureBuilder( + future: _futureController, + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.connectionState == ConnectionState.done && snapshot.data != null) { + _controller = snapshot.data as VideoPlayerController; + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Center( + child: isAudio + ? Lottie.asset(MyLottieConsts.audioPlaybackLottie) + : AspectRatio( + aspectRatio: _controller!.value.aspectRatio, + child: Stack( + alignment: Alignment.bottomCenter, + children: [ + VideoPlayer(_controller!), + AnimatedContainer( + duration: const Duration(milliseconds: 250), + color: Colors.black.withOpacity(showControls ? .4 : .0), + child: AnimatedOpacity( + opacity: showControls ? 1 : 0, + duration: const Duration(milliseconds: 250), + child: Column( + children: [ + Icon(_controller!.value.isPlaying ? Icons.pause : Icons.play_arrow, color: Colors.white) + .onPress(() { + if (!showControls) { + showVideoControls(); + return; + } + + if (_controller!.value.isPlaying) { + _controller!.pause(); + } else if (_controller!.value.isCompleted) { + videoLength.value = 0; + _controller!.play(); + } else { + _controller!.play(); + } + setState(() {}); + }) + .center + .expanded, + ValueListenableBuilder( + valueListenable: videoLength, + builder: (context, val, child) { + return SeekBar( + duration: _controller!.value.duration, + position: Duration(milliseconds: val), + bufferedPosition: Duration(), + onChanged: (duration) { + _controller!.seekTo(duration); + }, + ); + }), + ], + ), + ), + ).onPress(() { + showVideoControls(); + }), + ], + ), + ), + ), + 30.height, + ], + ); + } else { + return const Center( + child: CircularProgressIndicator( + color: Colors.white, + ), + ); + } + }, + ), + if (isImage) Image.network(link).center, + if (isPdf) + DefaultButton(LocaleKeys.open.tr(), () async { + try { + Utils.showLoading(context); + await FileProcess.downloadFileFromUrl(link, tutorial!.fileName!).then((path) { + Utils.hideLoading(context); + FileProcess.openFile(path, isFullPath: true); + }); + } catch (ex) { + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + } + }).paddingAll(21).center + ], + ), + ); + } +} diff --git a/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart b/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart index b4cb242..30a9fa2 100644 --- a/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart +++ b/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart @@ -76,7 +76,7 @@ class _OffersAndDiscountsDetailsState extends State { : getOffersList[0].titleEn!.toText22(isBold: true, color: const Color(0xff2B353E)).center, Html( data: AppState().isArabic(context) ? getOffersList[0].descriptionAr! : getOffersList[0].descriptionEn ?? "", - onLinkTap: (String? url, RenderContext context, Map attributes, _) { + onLinkTap: (String? url, Map attributes, _) { launchUrl(Uri.parse(url!)); }, ), -- 2.30.2 From 610d4788c232148df0b3b2c7dfacd356707a1eb9 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Mon, 25 Dec 2023 10:02:31 +0300 Subject: [PATCH 002/135] parameter added in survey. --- assets/images/{xcellent.svg => excellent.svg} | 0 assets/images/{bad.svg => fair.svg} | 0 assets/images/{normal.svg => ok.svg} | 0 lib/app_state/app_state.dart | 2 +- lib/models/itg/itg_response_model.dart | 67 +++++++++++++------ lib/models/itg/survey_model.dart | 19 +++++- lib/ui/landing/dashboard_screen.dart | 2 +- lib/ui/landing/itg/survey_screen.dart | 30 +++++---- 8 files changed, 80 insertions(+), 40 deletions(-) rename assets/images/{xcellent.svg => excellent.svg} (100%) rename assets/images/{bad.svg => fair.svg} (100%) rename assets/images/{normal.svg => ok.svg} (100%) diff --git a/assets/images/xcellent.svg b/assets/images/excellent.svg similarity index 100% rename from assets/images/xcellent.svg rename to assets/images/excellent.svg diff --git a/assets/images/bad.svg b/assets/images/fair.svg similarity index 100% rename from assets/images/bad.svg rename to assets/images/fair.svg diff --git a/assets/images/normal.svg b/assets/images/ok.svg similarity index 100% rename from assets/images/normal.svg rename to assets/images/ok.svg diff --git a/lib/app_state/app_state.dart b/lib/app_state/app_state.dart index 2cfc751..24d8edf 100644 --- a/lib/app_state/app_state.dart +++ b/lib/app_state/app_state.dart @@ -90,7 +90,7 @@ class AppState { String get getHuaweiPushToken => _huaweiPushToken; - final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 5.3, mobileType: Platform.isAndroid ? "android" : "ios"); + final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 6.3, mobileType: Platform.isAndroid ? "android" : "ios"); void setPostParamsInitConfig() { isAuthenticated = false; diff --git a/lib/models/itg/itg_response_model.dart b/lib/models/itg/itg_response_model.dart index e8d8acf..6a85cb1 100644 --- a/lib/models/itg/itg_response_model.dart +++ b/lib/models/itg/itg_response_model.dart @@ -45,34 +45,57 @@ class ItgResponseResult { this.data, this.errormsg, }); - - dynamic totalItemsCount; - List? data; - dynamic errormsg; - - ItgResponseResult.fromJson(Map json) { - totalItemsCount = json['totalItemsCount']; - if (json['data'] != null) { - data = []; +// +// final dynamic totalItemsCount; +// final ItgResponseData? data; +// final dynamic errormsg; +// +// factory ItgResponseResult.fromJson(Map json) => ItgResponseResult( +// totalItemsCount: json["totalItemsCount"], +// data: json["data"] == null ? null : ItgResponseData.fromJson(json["data"]), +// errormsg: json["errormsg"], +// ); +// +// Map toJson() => { +// "totalItemsCount": totalItemsCount, +// "data": data == null ? null : data!.toJson(), +// "errormsg": errormsg, +// }; +// } + +// todo these lines, for ERM new change on UAT +dynamic totalItemsCount; +List? data; +dynamic errormsg; + +ItgResponseResult.fromJson(Map json) { + totalItemsCount = json['totalItemsCount']; + if (json['data'] != null) { + data = []; + if(json['data'] is List) { json['data'].forEach((v) { data!.add(ItgResponseData.fromJson(v)); }); + } else { + data!.add(ItgResponseData.fromJson(json['data'])); } - errormsg = json['errormsg']; - } - // - // factory ItgResponseResult.fromJson(Map json) => ItgResponseResult( - // totalItemsCount: json["totalItemsCount"], - // data: json["data"] == null ? null : ItgResponseData.fromJson(json["data"]), - // errormsg: json["errormsg"], - // ); + } + errormsg = json['errormsg']; +} - Map toJson() => { - "totalItemsCount": totalItemsCount, - "data": data == null ? null : data!.map((v) => v.toJson()).toList(), - "errormsg": errormsg, - }; +// +// factory ItgResponseResult.fromJson(Map json) => ItgResponseResult( +// totalItemsCount: json["totalItemsCount"], +// data: json["data"] == null ? null : ItgResponseData.fromJson(json["data"]), +// errormsg: json["errormsg"], +// ); + +Map toJson() => { + "totalItemsCount": totalItemsCount, + "data": data == null ? null : data!.map((v) => v.toJson()).toList(), + "errormsg": errormsg, + }; } class ItgResponseData { diff --git a/lib/models/itg/survey_model.dart b/lib/models/itg/survey_model.dart index f9ac415..501ce65 100644 --- a/lib/models/itg/survey_model.dart +++ b/lib/models/itg/survey_model.dart @@ -9,13 +9,18 @@ class SurveyModel { dynamic pageNo; dynamic languageId; - SurveyModel({this.surveyId, this.referenceNo, this.title, this.description, this.questions, this.isActive, this.pageSize, this.pageNo, this.languageId}); + String? descriptionAr; + String? titleAr; + + SurveyModel({this.surveyId, this.referenceNo, this.title,this.titleAr, this.description, this.descriptionAr, this.questions, this.isActive, this.pageSize, this.pageNo, this.languageId}); SurveyModel.fromJson(Map json) { surveyId = json['surveyId']; referenceNo = json['referenceNo']; title = json['title']; + titleAr = json['titleAr']; description = json['description']; + descriptionAr = json['descriptionAr']; if (json['questions'] != null) { questions = []; json['questions'].forEach((v) { @@ -33,7 +38,9 @@ class SurveyModel { data['surveyId'] = this.surveyId; data['referenceNo'] = this.referenceNo; data['title'] = this.title; + data['titleAr'] = this.titleAr; data['description'] = this.description; + data['descriptionAr'] = this.descriptionAr; if (this.questions != null) { data['questions'] = this.questions!.map((v) => v.toJson()).toList(); } @@ -48,6 +55,7 @@ class SurveyModel { class Questions { int? questionId; String? title; + String? titleAr; bool? isRequired; String? type; int? sequenceNo; @@ -59,11 +67,12 @@ class Questions { dynamic pageNo; dynamic languageId; - Questions({this.questionId, this.title, this.isRequired, this.type, this.sequenceNo, this.surveyId, this.options, this.rspPercentage, this.isActive, this.pageSize, this.pageNo, this.languageId}); + Questions({this.questionId, this.title, this.titleAr, this.isRequired, this.type, this.sequenceNo, this.surveyId, this.options, this.rspPercentage, this.isActive, this.pageSize, this.pageNo, this.languageId}); Questions.fromJson(Map json) { questionId = json['questionId']; title = json['title']; + titleAr = json['titleAr']; isRequired = json['isRequired']; type = json['type']; sequenceNo = json['sequenceNo']; @@ -85,6 +94,7 @@ class Questions { Map data = new Map(); data['questionId'] = this.questionId; data['title'] = this.title; + data['titleAr'] = this.titleAr; data['isRequired'] = this.isRequired; data['type'] = this.type; data['sequenceNo'] = this.sequenceNo; @@ -104,6 +114,7 @@ class Questions { class Options { int? optionId; String? title; + String? titleAr; bool? isCommentsRequired; int? sequenceNo; int? questionId; @@ -114,11 +125,12 @@ class Options { dynamic pageNo; dynamic languageId; - Options({this.optionId, this.title, this.isCommentsRequired, this.sequenceNo, this.questionId, this.rspPercentage, this.count, this.isActive, this.pageSize, this.pageNo, this.languageId}); + Options({this.optionId, this.title,this.titleAr, this.isCommentsRequired, this.sequenceNo, this.questionId, this.rspPercentage, this.count, this.isActive, this.pageSize, this.pageNo, this.languageId}); Options.fromJson(Map json) { optionId = json['optionId']; title = json['title']; + titleAr = json['titleAr']; isCommentsRequired = json['isCommentsRequired']; sequenceNo = json['sequenceNo']; questionId = json['questionId']; @@ -134,6 +146,7 @@ class Options { Map data = new Map(); data['optionId'] = this.optionId; data['title'] = this.title; + data['titleAr'] = this.titleAr; data['isCommentsRequired'] = this.isCommentsRequired; data['sequenceNo'] = this.sequenceNo; data['questionId'] = this.questionId; diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index ea3b2cb..8b03af9 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -168,7 +168,7 @@ class _DashboardScreenState extends State with WidgetsBindingOb if (value!.mohemmItgResponseItem!.statusCode == 200) { if (value.mohemmItgResponseItem!.result!.data != null) { // Navigator.pushNamed(context, AppRoutes.survey, arguments: val.result!.data); - Navigator.pushNamed(context, AppRoutes.survey, arguments: value.mohemmItgResponseItem!.result!.data); + Navigator.pushNamed(context, AppRoutes.survey, arguments: value.mohemmItgResponseItem!.result!.data!.first); // Navigator.pushNamed(context, AppRoutes.advertisement, arguments: { // "masterId": val.result!.data!.notificationMasterId, // "advertisement": value.mohemmItgResponseItem!.result!.data!.advertisement, diff --git a/lib/ui/landing/itg/survey_screen.dart b/lib/ui/landing/itg/survey_screen.dart index 59f3c14..600be6a 100644 --- a/lib/ui/landing/itg/survey_screen.dart +++ b/lib/ui/landing/itg/survey_screen.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_rating_bar/flutter_rating_bar.dart'; import 'package:flutter_svg/flutter_svg.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/utils.dart'; import 'package:mohem_flutter_app/extensions/int_extensions.dart'; @@ -53,9 +54,9 @@ class _SurveyScreenState extends State { child: Column( children: [ 32.height, - itgResponseData?.survey?.title?.toText24() ?? const Text(""), + (AppState().isArabic(context) ? itgResponseData?.survey?.titleAr : itgResponseData?.survey?.title)?.toText24() ?? const Text(""), 8.height, - itgResponseData?.survey?.description?.toText16() ?? const Text(""), + (AppState().isArabic(context) ? itgResponseData?.survey?.descriptionAr : itgResponseData?.survey?.description)?.toText16() ?? const Text(""), ListView.builder( padding: EdgeInsets.zero, shrinkWrap: true, @@ -105,7 +106,7 @@ class _SurveyScreenState extends State { answeredQuestions.clear(); itgResponseData?.survey?.questions?.forEach((element) { if (element.type != "Stars") { - if(element.type == "Faces") { + if (element.type == "Faces") { _selectedIndex = element.options![0].optionId!; } answeredQuestions.add(element.options![0].optionId.toString()); @@ -122,15 +123,16 @@ class _SurveyScreenState extends State { return Column( children: [ 24.height, - question?.title?.toText18() ?? const Text(""), + (AppState().isArabic(context) ? question?.titleAr : question?.title)?.toText18() ?? const Text(""), 16.height, GridView.builder( padding: EdgeInsets.zero, - itemCount: question?.options?.length, + itemCount: question?.options?.length ?? 0, shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemBuilder: (context, index) { - return radioOption(question?.options?[index].title ?? "", question?.options?[index].optionId.toString() ?? "", answeredQuestions[parentIndex], parentIndex); + return radioOption((AppState().isArabic(context) ? (question!.options![index].titleAr) : question!.options![index].title) ?? "", question?.options?[index].optionId.toString() ?? "", + answeredQuestions[parentIndex], parentIndex); }, gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, @@ -145,7 +147,7 @@ class _SurveyScreenState extends State { mainAxisSize: MainAxisSize.min, children: [ 24.height, - question?.title?.toText18() ?? Text(""), + (AppState().isArabic(context) ? question?.titleAr : question?.title)?.toText18() ?? Text(""), 16.height, RatingBar.builder( initialRating: 3, @@ -171,7 +173,7 @@ class _SurveyScreenState extends State { mainAxisSize: MainAxisSize.min, children: [ 24.height, - question?.title?.toText18() ?? Text("asdasdasdasd"), + (AppState().isArabic(context) ? question?.titleAr : question?.title)?.toText18() ?? Text(""), 16.height, GridView( gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 5, crossAxisSpacing: 7, mainAxisSpacing: 7), @@ -179,11 +181,13 @@ class _SurveyScreenState extends State { padding: const EdgeInsets.only(top: 0), shrinkWrap: true, children: [ - optionUI("poor.svg", question?.options?[0].optionId, parentIndex), - optionUI("bad.svg", question?.options?[1].optionId, parentIndex), - optionUI("normal.svg", question?.options?[2].optionId, parentIndex), - optionUI("good.svg", question?.options?[3].optionId, parentIndex), - optionUI("xcellent.svg", question?.options?[4].optionId, parentIndex), + for (int i = 0; i < (question?.options?.length ?? 0); i++) optionUI("${question?.options![i].title!.toLowerCase()}.svg", question?.options?[i].optionId, parentIndex), + + // optionUI("poor.svg", question?.options?[0].optionId, parentIndex), + // optionUI("fair.svg", question?.options?[1].optionId, parentIndex), + // optionUI("ok.svg", question?.options?[2].optionId, parentIndex), + // optionUI("good.svg", question?.options?[3].optionId, parentIndex), + // optionUI("excellent.svg", question?.options?[4].optionId, parentIndex), ], ), ], -- 2.30.2 From 449c93649a96b31bf16a5dfd27d62211f51560af Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Mon, 1 Jan 2024 14:29:41 +0300 Subject: [PATCH 003/135] multiple survey added. --- lib/ui/landing/dashboard_screen.dart | 100 ++++++++++++------ .../itg/its_add_screen_video_image.dart | 50 ++++----- lib/ui/landing/itg/survey_screen.dart | 51 +++++---- 3 files changed, 122 insertions(+), 79 deletions(-) diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index 8b03af9..5de9052 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -16,6 +16,8 @@ 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/itg/itg_main_response.dart'; +import 'package:mohem_flutter_app/models/itg/itg_response_model.dart'; import 'package:mohem_flutter_app/models/offers_and_discounts/get_offers_list.dart'; import 'package:mohem_flutter_app/models/privilege_list_model.dart'; import 'package:mohem_flutter_app/provider/chat_provider_model.dart'; @@ -158,39 +160,72 @@ class _DashboardScreenState extends State with WidgetsBindingOb _refreshController.refreshCompleted(); } + int ermIndex = 0; + + void handleErmChannel(List list) async { + try { + if (ermIndex == list.length) { + return; + } + Utils.showLoading(context); + ItgMainRes? response = await DashboardApiClient().getAdvertisementDetail(list[ermIndex].notificationMasterId ?? ""); + Utils.hideLoading(context); + if (response!.mohemmItgResponseItem!.result!.data != null) { + if (list[ermIndex].notificationType == "Survey") { + await Navigator.pushNamed(context, AppRoutes.survey, arguments: response.mohemmItgResponseItem!.result!.data!.first); + } else { + await Navigator.pushNamed(context, AppRoutes.advertisement, arguments: { + "masterId": list[ermIndex].notificationMasterId, + "advertisement": response.mohemmItgResponseItem!.result!.data!.first.advertisement, + }); + } + } + ermIndex++; + handleErmChannel(list); + } catch (ex) { + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + return; + } + } + void checkERMChannel() { - data.getITGNotification().then((val) { + data.getITGNotification().then((val) async { if (val!.result!.data != null) { - print("-------------------- Survey ----------------------------"); - if (val.result!.data!.first.notificationType == "Survey") { - DashboardApiClient().getAdvertisementDetail(val.result!.data!.first.notificationMasterId ?? "").then( - (value) { - if (value!.mohemmItgResponseItem!.statusCode == 200) { - if (value.mohemmItgResponseItem!.result!.data != null) { - // Navigator.pushNamed(context, AppRoutes.survey, arguments: val.result!.data); - Navigator.pushNamed(context, AppRoutes.survey, arguments: value.mohemmItgResponseItem!.result!.data!.first); - // Navigator.pushNamed(context, AppRoutes.advertisement, arguments: { - // "masterId": val.result!.data!.notificationMasterId, - // "advertisement": value.mohemmItgResponseItem!.result!.data!.advertisement, - // }); - } - } - }, - ); - } else { - print("------------------------------------------- Ads --------------------"); - DashboardApiClient().getAdvertisementDetail(val.result!.data!.first.notificationMasterId ?? "").then( - (value) { - if (value!.mohemmItgResponseItem!.statusCode == 200) { - if (value.mohemmItgResponseItem!.result!.data != null) { - Navigator.pushNamed(context, AppRoutes.advertisement, arguments: { - "masterId": val.result!.data!.first.notificationMasterId, - "advertisement": value.mohemmItgResponseItem!.result!.data!.first.advertisement, - }); - } - } - }, - ); + ermIndex = 0; + val.result?.data?.removeWhere((element) => element.notificationType == "Announcement"); + handleErmChannel(val.result?.data ?? []); + { + // if (ERMvalue.notificationType == "Survey") { + // await DashboardApiClient().getAdvertisementDetail(val.result!.data!.first.notificationMasterId ?? "").then( + // (value) async { + // if (value!.mohemmItgResponseItem!.statusCode == 200) { + // if (value.mohemmItgResponseItem!.result!.data != null) { + // // Navigator.pushNamed(context, AppRoutes.survey, arguments: val.result!.data); + // await Navigator.pushNamed(context, AppRoutes.survey, arguments: value.mohemmItgResponseItem!.result!.data!.first); + // // Navigator.pushNamed(context, AppRoutes.advertisement, arguments: { + // // "masterId": val.result!.data!.notificationMasterId, + // // "advertisement": value.mohemmItgResponseItem!.result!.data!.advertisement, + // // }); + // } + // } + // }, + // ); + // } else { + // print("------------------------------------------- Ads --------------------"); + // await DashboardApiClient().getAdvertisementDetail(ERMvalue.notificationMasterId ?? "").then( + // (value) async { + // if (value!.mohemmItgResponseItem!.statusCode == 200) { + // if (value.mohemmItgResponseItem!.result!.data != null) { + // await Navigator.pushNamed(context, AppRoutes.advertisement, arguments: { + // "masterId": val.result!.data!.first.notificationMasterId, + // "advertisement": value.mohemmItgResponseItem!.result!.data!.first.advertisement, + // }); + // } + // } + // }, + // ); + // } } } }); @@ -535,7 +570,8 @@ class _DashboardScreenState extends State with WidgetsBindingOb ], ), ).onPress(() { - Navigator.pushNamed(context, AppRoutes.marathonTutorialScreen); + checkERMChannel(); + // Navigator.pushNamed(context, AppRoutes.marathonTutorialScreen); }), ], ), 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 8ce89d0..60bd4ba 100644 --- a/lib/ui/landing/itg/its_add_screen_video_image.dart +++ b/lib/ui/landing/itg/its_add_screen_video_image.dart @@ -35,7 +35,9 @@ class _ITGAdsScreenState extends State { bool isImage = false; bool isAudio = false; String ext = ''; - late File imageFile; + + // late File imageFile; + late String imageUrl; ads.Advertisement? advertisementData; dynamic data; String? masterID; @@ -47,12 +49,13 @@ class _ITGAdsScreenState extends State { late CountdownTimerController timerController; - void checkFileType() async { + void checkFileType() { String? rFile = advertisementData!.viewAttachFileColl!.first.base64String; String? rFileExt = advertisementData!.viewAttachFileColl!.first.fileName; ext = "." + rFileExt!.split(".").last.toLowerCase(); if (ext == ".png" || ext == ".jpg" || ext == ".jpeg" || ext == ".gif") { - await processImage(rFile!); + // await processImage(); + imageUrl = rFile!; isImage = true; } else { if (ext == ".aac") { @@ -62,11 +65,11 @@ class _ITGAdsScreenState extends State { _futureController = createVideoPlayer(rFile!); } - advertisementData?.actionButtonsColl!.forEach((element) { + // advertisementData?.actionButtonsColl!.forEach((element) { advertisementData?.actionButtonsColl!.removeWhere((element1) => element1.actionButtonId == advertisementData?.skipButtonId); - }); + //}); - setState(() {}); + // setState(() {}); } void changeTimer(bool isTimerEnd) { @@ -80,16 +83,17 @@ class _ITGAdsScreenState extends State { timerController.dispose(); } - Future processImage(String encodedBytes) async { - try { - Uint8List decodedBytes = base64Decode(encodedBytes.split("base64,").last); - Directory appDocumentsDirectory = await getApplicationDocumentsDirectory(); // 1 - imageFile = Io.File("${appDocumentsDirectory.path}/addImage$ext"); - imageFile.writeAsBytesSync(decodedBytes); - } catch (e) { - logger.d(e); - } - } + // + // Future processImage(String encodedBytes) async { + // try { + // Uint8List decodedBytes = base64Decode(encodedBytes.split("base64,").last); + // Directory appDocumentsDirectory = await getApplicationDocumentsDirectory(); // 1 + // imageFile = Io.File("${appDocumentsDirectory.path}/addImage$ext"); + // imageFile.writeAsBytesSync(decodedBytes); + // } catch (e) { + // logger.d(e); + // } + // } Future createVideoPlayer(String encodedBytes) async { try { @@ -176,13 +180,11 @@ class _ITGAdsScreenState extends State { itemBuilder: (context, index) { String? btnText = AppState().isArabic(context) ? advertisementData?.actionButtonsColl![index].btnTextAr : advertisementData?.actionButtonsColl![index].btnTextEn; return DefaultButton(btnText!, () async { - Navigator.pop(context); - DashboardApiClient() - .setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, advertisementData?.actionButtonsColl![index].actionValue) - .then((value) { - logger.d(value); - }); - }).paddingOnly(left: 60.0, right: 60.0, top: 8, bottom: 8); + Navigator.pop(context); + DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, advertisementData?.actionButtonsColl![index].actionValue).then((value) { + logger.d(value); + }); + }).paddingOnly(left: 60.0, right: 60.0, top: 8, bottom: 8); }, gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 1, @@ -266,7 +268,7 @@ class _ITGAdsScreenState extends State { crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ - Image.file(imageFile), + Image.network(imageUrl), 50.height, Container(padding: const EdgeInsets.all(16), decoration: Utils.containerRadius(MyColors.white, 10), child: const Icon(Icons.thumb_up, color: MyColors.gradiantEndColor)).onPress( () { diff --git a/lib/ui/landing/itg/survey_screen.dart b/lib/ui/landing/itg/survey_screen.dart index 600be6a..3bbb27f 100644 --- a/lib/ui/landing/itg/survey_screen.dart +++ b/lib/ui/landing/itg/survey_screen.dart @@ -15,6 +15,8 @@ import 'package:mohem_flutter_app/models/itg/itg_response_model.dart'; import 'package:mohem_flutter_app/models/itg/survey_model.dart'; import 'package:mohem_flutter_app/widgets/button/default_button.dart'; +import 'package:flutter/widgets.dart' as fw; + class SurveyScreen extends StatefulWidget { const SurveyScreen({Key? key}) : super(key: key); @@ -47,29 +49,32 @@ class _SurveyScreenState extends State { body: Column( children: [ Expanded( - child: ListView( - children: [ - Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - children: [ - 32.height, - (AppState().isArabic(context) ? itgResponseData?.survey?.titleAr : itgResponseData?.survey?.title)?.toText24() ?? const Text(""), - 8.height, - (AppState().isArabic(context) ? itgResponseData?.survey?.descriptionAr : itgResponseData?.survey?.description)?.toText16() ?? const Text(""), - ListView.builder( - padding: EdgeInsets.zero, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: itgResponseData?.survey?.questions?.length, - itemBuilder: (cxt, index) { - return answeredQuestions.isNotEmpty ? getSurveyWidget(itgResponseData?.survey?.questions![index], index) : Container(); - }, - ), - ], - ).paddingOnly(left: 21, right: 21), - ), - ], + child: Directionality( + textDirection: AppState().isArabic(context) ? fw.TextDirection.rtl : fw.TextDirection.ltr, + child: ListView( + children: [ + Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + children: [ + 32.height, + (AppState().isArabic(context) ? itgResponseData?.survey?.titleAr : itgResponseData?.survey?.title)?.toText24() ?? const Text(""), + 8.height, + (AppState().isArabic(context) ? itgResponseData?.survey?.descriptionAr : itgResponseData?.survey?.description)?.toText16() ?? const Text(""), + ListView.builder( + padding: EdgeInsets.zero, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: itgResponseData?.survey?.questions?.length, + itemBuilder: (cxt, index) { + return answeredQuestions.isNotEmpty ? getSurveyWidget(itgResponseData?.survey?.questions![index], index) : Container(); + }, + ), + ], + ).paddingOnly(left: 21, right: 21), + ), + ], + ), )), DefaultButton( LocaleKeys.submitSurvey.tr(), -- 2.30.2 From a411b8e978aebd195001f211d9fd9e5b8a73139f Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Wed, 3 Jan 2024 14:37:52 +0300 Subject: [PATCH 004/135] File picker permission issue fixed --- lib/api/chat/chat_api_client.dart | 2 ++ lib/app_state/app_state.dart | 2 +- lib/widgets/image_picker.dart | 56 +++++++++++++++++++++---------- pubspec.yaml | 6 ++-- 4 files changed, 45 insertions(+), 21 deletions(-) diff --git a/lib/api/chat/chat_api_client.dart b/lib/api/chat/chat_api_client.dart index d077026..daafa92 100644 --- a/lib/api/chat/chat_api_client.dart +++ b/lib/api/chat/chat_api_client.dart @@ -29,6 +29,7 @@ class ChatApiClient { Future getUserLoginToken() async { user.UserAutoLoginModel userLoginResponse = user.UserAutoLoginModel(); + String? deviceToken = AppState().getIsHuawei ? AppState().getHuaweiPushToken : AppState().getDeviceToken; Response response = await ApiClient().postJsonForResponse( "${ApiConsts.chatLoginTokenUrl}externaluserlogin", { @@ -38,6 +39,7 @@ class ChatApiClient { "platform": Platform.isIOS ? "ios" : "android", "deviceToken": AppState().getIsHuawei ? AppState().getHuaweiPushToken : AppState().getDeviceToken, "isHuaweiDevice": AppState().getIsHuawei, + "voipToken": "", }, ); diff --git a/lib/app_state/app_state.dart b/lib/app_state/app_state.dart index 2cfc751..1039b20 100644 --- a/lib/app_state/app_state.dart +++ b/lib/app_state/app_state.dart @@ -90,7 +90,7 @@ class AppState { String get getHuaweiPushToken => _huaweiPushToken; - final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 5.3, mobileType: Platform.isAndroid ? "android" : "ios"); + final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 5.4, mobileType: Platform.isAndroid ? "android" : "ios"); void setPostParamsInitConfig() { isAuthenticated = false; diff --git a/lib/widgets/image_picker.dart b/lib/widgets/image_picker.dart index ef04f84..19b1e00 100644 --- a/lib/widgets/image_picker.dart +++ b/lib/widgets/image_picker.dart @@ -8,6 +8,8 @@ import 'package:mohem_flutter_app/classes/colors.dart'; import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/widgets/bottom_sheet.dart'; import 'package:mohem_flutter_app/widgets/bottom_sheets/attachment_options.dart'; +import 'package:mohem_flutter_app/widgets/dialogs/confirm_dialog.dart'; +import 'package:permission_handler/permission_handler.dart'; class ImageOptions { static void showImageOptionsNew(BuildContext context, bool showFilesOption, Function(String, File) image) { @@ -43,24 +45,42 @@ class ImageOptions { } }, onFilesTap: () async { - FilePickerResult? result = await FilePicker.platform.pickFiles( - type: FileType.custom, - allowedExtensions: [ - 'jpg', - 'jpeg ', - 'pdf', - 'txt', - 'docx', - 'doc', - 'pptx', - 'xlsx', - 'png', - 'rar', - 'zip', - ], - ); - List files = result!.paths.map((path) => File(path!)).toList(); - image(result.files.first.path.toString(), files.first); + Permission.storage.isGranted.then((isGranted) { + if (!isGranted) { + Permission.manageExternalStorage.request().then((granted) async { + if (granted == PermissionStatus.granted) { + FilePickerResult? result = await FilePicker.platform.pickFiles( + type: FileType.custom, + allowedExtensions: [ + 'jpg', + 'jpeg ', + 'pdf', + 'txt', + 'docx', + 'doc', + 'pptx', + 'xlsx', + 'png', + 'rar', + 'zip', + ], + ); + List files = result!.paths.map((path) => File(path!)).toList(); + image(result.files.first.path.toString(), files.first); + } else { + showDialog( + context: context, + builder: (BuildContext cxt) => ConfirmDialog( + message: "You need to give storage permission to upload files.", + onTap: () { + Navigator.pop(context); + }, + ), + ); + } + }); + } + }); }, ), ); diff --git a/pubspec.yaml b/pubspec.yaml index e3b15bd..82ae41b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html #version: 3.3.01+300040 -version: 3.7.7+1 +version: 3.3.6+300046 environment: sdk: ">=2.16.0 <3.0.0" @@ -60,7 +60,7 @@ dependencies: # android_id: ^0.1.3+1 platform_device_id: ^1.0.1 image_picker: ^0.8.5+3 - file_picker: ^4.6.1 + file_picker: 5.2.5 geolocator: ^9.0.2 month_year_picker: ^0.2.0+1 month_picker_dialog_2: 0.5.5 @@ -124,6 +124,8 @@ dependencies: #todo its for temporary purpose, later will remove this. dotted_border: ^2.0.0+3 +# saf: ^1.0.3+4 + dependency_overrides: firebase_core_platform_interface: 4.5.1 -- 2.30.2 From c104de86ba4c6b21bdf71bb949f58ddc8bd0ef6f Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Sun, 7 Jan 2024 16:17:57 +0300 Subject: [PATCH 005/135] Updates --- android/app/src/main/AndroidManifest.xml | 10 ++++++++++ ios/Runner.xcodeproj/project.pbxproj | 6 +++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 3f5e424..ea79d76 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -8,6 +8,16 @@ + + + + + + + + diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 073c15f..e734dc5 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -376,7 +376,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 3.7.2; + MARKETING_VERSION = 3.7.8; PRODUCT_BUNDLE_IDENTIFIER = com.cloudsolutions.mohemm; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -514,7 +514,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 3.7.2; + MARKETING_VERSION = 3.7.8; PRODUCT_BUNDLE_IDENTIFIER = com.cloudsolutions.mohemm; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -544,7 +544,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 3.7.2; + MARKETING_VERSION = 3.7.8; PRODUCT_BUNDLE_IDENTIFIER = com.cloudsolutions.mohemm; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; -- 2.30.2 From fc3c1c057aec46a5a213adf01eafe7a5b724611c Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Thu, 11 Jan 2024 16:41:10 +0300 Subject: [PATCH 006/135] Attachments handled in transactions list mowadhafi --- lib/api/mowadhafhi/mowadhafhi_api_client.dart | 15 ++++ lib/classes/consts.dart | 4 +- .../mowadhafhi/get_ticket_transactions.dart | 40 +++++++-- .../get_transaction_attachment_model.dart | 52 ++++++++++++ .../screens/mowadhafhi/request_details.dart | 83 +++++++++++++++++-- .../view_transaction_attachment.dart | 34 ++++++++ .../worklist_fragments/actions_fragment.dart | 12 ++- 7 files changed, 219 insertions(+), 21 deletions(-) create mode 100644 lib/models/mowadhafhi/get_transaction_attachment_model.dart create mode 100644 lib/ui/screens/mowadhafhi/view_transaction_attachment.dart diff --git a/lib/api/mowadhafhi/mowadhafhi_api_client.dart b/lib/api/mowadhafhi/mowadhafhi_api_client.dart index e5ecc4b..d724c67 100644 --- a/lib/api/mowadhafhi/mowadhafhi_api_client.dart +++ b/lib/api/mowadhafhi/mowadhafhi_api_client.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:mohem_flutter_app/api/api_client.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/consts.dart'; @@ -10,6 +12,7 @@ import 'package:mohem_flutter_app/models/mowadhafhi/get_ticket_details.dart'; import 'package:mohem_flutter_app/models/mowadhafhi/get_ticket_transactions.dart'; import 'package:mohem_flutter_app/models/mowadhafhi/get_ticket_types.dart'; import 'package:mohem_flutter_app/models/mowadhafhi/get_tickets_list.dart'; +import 'package:mohem_flutter_app/models/mowadhafhi/get_transaction_attachment_model.dart'; class MowadhafhiApiClient { static final MowadhafhiApiClient _instance = MowadhafhiApiClient._internal(); @@ -51,6 +54,18 @@ class MowadhafhiApiClient { }, url, postParams); } + Future getTransactionAttachments(int? attachmentID) async { + String url = "${ApiConsts.cocRest}Mohemm_ITG_GetTicketAttachment"; + Map postParams = {"EmployeeNumber": AppState().memberInformationList?.eMPLOYEENUMBER, "ItgAttachmentId": attachmentID}; + + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject((json) { + GenericResponseModel? responseData = GenericResponseModel.fromJson(json); + var jsonDecodedData = jsonDecode(responseData.mohemmITGResponseItem!); + return GetTransactionAttachmentModel.fromJson(jsonDecodedData); + }, url, postParams); + } + Future> getTicketTypes() async { String url = "${ApiConsts.cocRest}Mohemm_ITG_GetTicketTypes"; Map postParams = {"EmployeeNumber": AppState().memberInformationList?.eMPLOYEENUMBER}; diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 437839b..bffc7ad 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -3,8 +3,8 @@ import 'package:mohem_flutter_app/ui/marathon/widgets/question_card.dart'; class ApiConsts { //static String baseUrl = "http://10.200.204.20:2801/"; // Local server // static String baseUrl = "https://erptstapp.srca.org.sa"; // SRCA server - // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver - static String baseUrl = "https://hmgwebservices.com"; // Live server + static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver + // static String baseUrl = "https://hmgwebservices.com"; // Live server static String baseUrlServices = baseUrl + "/Services/"; // server // static String baseUrlServices = "https://api.cssynapses.com/tangheem/"; // Live server static String utilitiesRest = baseUrlServices + "Utilities.svc/REST/"; diff --git a/lib/models/mowadhafhi/get_ticket_transactions.dart b/lib/models/mowadhafhi/get_ticket_transactions.dart index be793ca..3cb0ce1 100644 --- a/lib/models/mowadhafhi/get_ticket_transactions.dart +++ b/lib/models/mowadhafhi/get_ticket_transactions.dart @@ -1,24 +1,24 @@ class GetTicketTransactions { String? actionBy; String? actionDate; + List? attachments; String? comments; String? statusDisplayText; String? statusName; String? ticketId; int? ticketTransactionId; - GetTicketTransactions( - {this.actionBy, - this.actionDate, - this.comments, - this.statusDisplayText, - this.statusName, - this.ticketId, - this.ticketTransactionId}); + GetTicketTransactions({this.actionBy, this.actionDate, this.attachments, this.comments, this.statusDisplayText, this.statusName, this.ticketId, this.ticketTransactionId}); GetTicketTransactions.fromJson(Map json) { actionBy = json['actionBy']; actionDate = json['actionDate']; + if (json['attachments'] != null) { + attachments = []; + json['attachments'].forEach((v) { + attachments!.add(new Attachments.fromJson(v)); + }); + } comments = json['comments']; statusDisplayText = json['statusDisplayText']; statusName = json['statusName']; @@ -27,9 +27,12 @@ class GetTicketTransactions { } Map toJson() { - Map data = new Map(); + Map data = Map(); data['actionBy'] = this.actionBy; data['actionDate'] = this.actionDate; + if (this.attachments != null) { + data['attachments'] = this.attachments!.map((v) => v.toJson()).toList(); + } data['comments'] = this.comments; data['statusDisplayText'] = this.statusDisplayText; data['statusName'] = this.statusName; @@ -38,3 +41,22 @@ class GetTicketTransactions { return data; } } + +class Attachments { + int? attachmentId; + String? fileName; + + Attachments({this.attachmentId, this.fileName}); + + Attachments.fromJson(Map json) { + attachmentId = json['attachmentId']; + fileName = json['fileName']; + } + + Map toJson() { + Map data = Map(); + data['attachmentId'] = this.attachmentId; + data['fileName'] = this.fileName; + return data; + } +} diff --git a/lib/models/mowadhafhi/get_transaction_attachment_model.dart b/lib/models/mowadhafhi/get_transaction_attachment_model.dart new file mode 100644 index 0000000..1234946 --- /dev/null +++ b/lib/models/mowadhafhi/get_transaction_attachment_model.dart @@ -0,0 +1,52 @@ +class GetTransactionAttachmentModel { + int? attachmentId; + String? fileName; + String? contentType; + dynamic attachFileStream; + String? base64String; + dynamic isActive; + dynamic referenceItemId; + dynamic content; + dynamic filePath; + int? languageId; + + GetTransactionAttachmentModel( + {this.attachmentId, + this.fileName, + this.contentType, + this.attachFileStream, + this.base64String, + this.isActive, + this.referenceItemId, + this.content, + this.filePath, + this.languageId}); + + GetTransactionAttachmentModel.fromJson(Map json) { + attachmentId = json['attachmentId']; + fileName = json['fileName']; + contentType = json['contentType']; + attachFileStream = json['attachFileStream']; + base64String = json['base64String']; + isActive = json['isActive']; + referenceItemId = json['referenceItemId']; + content = json['content']; + filePath = json['filePath']; + languageId = json['languageId']; + } + + Map toJson() { + Map data = Map(); + data['attachmentId'] = this.attachmentId; + data['fileName'] = this.fileName; + data['contentType'] = this.contentType; + data['attachFileStream'] = this.attachFileStream; + data['base64String'] = this.base64String; + data['isActive'] = this.isActive; + data['referenceItemId'] = this.referenceItemId; + data['content'] = this.content; + data['filePath'] = this.filePath; + data['languageId'] = this.languageId; + return data; + } +} diff --git a/lib/ui/screens/mowadhafhi/request_details.dart b/lib/ui/screens/mowadhafhi/request_details.dart index aa22bdd..0dcaa13 100644 --- a/lib/ui/screens/mowadhafhi/request_details.dart +++ b/lib/ui/screens/mowadhafhi/request_details.dart @@ -1,3 +1,8 @@ +import 'dart:convert'; +import 'dart:io'; +import 'dart:io' as Io; +import 'dart:typed_data'; + import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:mohem_flutter_app/api/mowadhafhi/mowadhafhi_api_client.dart'; @@ -6,9 +11,13 @@ import 'package:mohem_flutter_app/classes/utils.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/main.dart'; import 'package:mohem_flutter_app/models/mowadhafhi/get_ticket_details.dart'; import 'package:mohem_flutter_app/models/mowadhafhi/get_ticket_transactions.dart'; +import 'package:mohem_flutter_app/models/mowadhafhi/get_transaction_attachment_model.dart'; +import 'package:mohem_flutter_app/ui/screens/mowadhafhi/view_transaction_attachment.dart'; import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; +import 'package:path_provider/path_provider.dart'; class MowadhafhiRequestDetails extends StatefulWidget { const MowadhafhiRequestDetails({Key? key}) : super(key: key); @@ -21,6 +30,9 @@ class _RequestDetailsState extends State { String? itgTicketID; List getTicketsByEmployeeList = []; List getTicketTransactionsList = []; + GetTransactionAttachmentModel? getTransactionAttachmentModel; + + late File imageFile; @override void initState() { @@ -43,7 +55,7 @@ class _RequestDetailsState extends State { backgroundColor: Colors.white, appBar: AppBarWidget( context, - title: LocaleKeys.mowadhafhiRequest.tr(), + title: LocaleKeys.mowadhafhiRequest.tr(), ), body: SingleChildScrollView( child: getTicketsByEmployeeList.length != 0 @@ -76,16 +88,16 @@ class _RequestDetailsState extends State { ], ), 8.height, - LocaleKeys.ticketReference.tr().toText12(color: MyColors.grey98Color), + LocaleKeys.ticketReference.tr().toText12(color: MyColors.grey98Color), getTicketsByEmployeeList![0].ticketReferenceNo!.toText14(color: MyColors.grey57Color), 8.height, - LocaleKeys.section.tr().toText12(color: MyColors.grey98Color), + LocaleKeys.section.tr().toText12(color: MyColors.grey98Color), getTicketsByEmployeeList![0].sectionName!.toText14(color: MyColors.grey57Color), 8.height, - LocaleKeys.topic.tr().toText12(color: MyColors.grey98Color), + LocaleKeys.topic.tr().toText12(color: MyColors.grey98Color), getTicketsByEmployeeList![0].topicName!.toText14(color: MyColors.grey57Color), 8.height, - LocaleKeys.description.tr().toText12(color: MyColors.grey98Color), + LocaleKeys.description.tr().toText12(color: MyColors.grey98Color), getTicketsByEmployeeList![0].description!.toText14(color: MyColors.grey57Color), ], ), @@ -128,15 +140,31 @@ class _RequestDetailsState extends State { Row( children: [ LocaleKeys.actionBy.tr().toText14(color: MyColors.grey57Color), + ": ".toText14(), getTicketTransactionsList![index].actionBy!.toText14(color: MyColors.grey57Color), ], ), + Row( + children: [ + LocaleKeys.actions.tr().toText14(color: MyColors.grey57Color), + ": ".toText14(), + getTicketTransactionsList![index].statusDisplayText!.toText14(color: MyColors.grey57Color), + ], + ), getTicketTransactionsList![index].comments!.toText14(color: MyColors.grey98Color), 12.height, + if (getTicketTransactionsList[index].attachments != null) + InkWell( + onTap: () { + print(getTicketTransactionsList[index].attachments![0].attachmentId); + getTransactionAttachment(getTicketTransactionsList[index].attachments![0].attachmentId!); + }, + child: LocaleKeys.attachments.tr().toText14(color: MyColors.gradiantEndColor, isUnderLine: true), + ), Row( mainAxisAlignment: MainAxisAlignment.end, children: [ - getTicketTransactionsList![0].actionDate!.split(" ")[0].toText12(color: MyColors.grey70Color), + getTicketTransactionsList![index].actionDate!.split(" ")[0].toText12(color: MyColors.grey70Color), ], ), ], @@ -212,4 +240,47 @@ class _RequestDetailsState extends State { Utils.handleException(ex, context, null); } } + + void getTransactionAttachment(int attachmentID) async { + try { + Utils.showLoading(context); + getTransactionAttachmentModel = await MowadhafhiApiClient().getTransactionAttachments(attachmentID); + debugPrint(getTransactionAttachmentModel?.fileName); + Utils.hideLoading(context); + setState(() {}); + handleTransactionAttachment(); + } catch (ex) { + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + } + } + + void handleTransactionAttachment() async { + String ext = ''; + String? rFile = getTransactionAttachmentModel!.base64String; + String? rFileExt = getTransactionAttachmentModel!.fileName; + + ext = "." + rFileExt!.split(".").last.toLowerCase(); + + if (ext == ".png" || ext == ".jpg" || ext == ".jpeg" || ext == ".gif" || ext == ".tiff") { + try { + Uint8List decodedBytes = base64Decode(rFile!.split("base64,").last); + Directory appDocumentsDirectory = await getApplicationDocumentsDirectory(); // 1 + imageFile = Io.File("${appDocumentsDirectory.path}/addImage$ext"); + imageFile.writeAsBytesSync(decodedBytes); + Navigator.push( + context, + MaterialPageRoute( + builder: (BuildContext context) => ViewTransactionAttachment( + imageFile: imageFile, + ), + ), + ); + } catch (e) { + logger.d(e); + } + } else { + Utils.showErrorDialog(context: context, onOkTapped: () {}, message: "Unable to view attachment"); + } + } } diff --git a/lib/ui/screens/mowadhafhi/view_transaction_attachment.dart b/lib/ui/screens/mowadhafhi/view_transaction_attachment.dart new file mode 100644 index 0000000..e6ef8bc --- /dev/null +++ b/lib/ui/screens/mowadhafhi/view_transaction_attachment.dart @@ -0,0 +1,34 @@ +import 'dart:io'; + +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:mohem_flutter_app/extensions/int_extensions.dart'; +import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; +import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; + +class ViewTransactionAttachment extends StatelessWidget { + final File imageFile; + + const ViewTransactionAttachment({Key? key, required this.imageFile}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBarWidget( + context, + title: LocaleKeys.mowadhafhiRequest.tr(), + ), + body: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.file(imageFile), + 50.height, + ], + ), + ), + ); + } +} diff --git a/lib/ui/work_list/worklist_fragments/actions_fragment.dart b/lib/ui/work_list/worklist_fragments/actions_fragment.dart index 1d88129..10d027a 100644 --- a/lib/ui/work_list/worklist_fragments/actions_fragment.dart +++ b/lib/ui/work_list/worklist_fragments/actions_fragment.dart @@ -167,10 +167,14 @@ class ActionsFragment extends StatelessWidget { Duration duration = DateTime.now().difference(dateTimeFrom); return "Action duration: " + DateUtil.formatDuration(duration); } else { - DateTime dateTimeTo = DateUtil.convertSimpleStringDateToDate(actionHistoryList[index].nOTIFICATIONDATE!); - DateTime dateTimeFrom = DateUtil.convertSimpleStringDateToDate(actionHistoryList[index + 1].nOTIFICATIONDATE!); - Duration duration = dateTimeTo.difference(dateTimeFrom); - return "Action duration: " + DateUtil.formatDuration(duration); + if (actionHistoryList[index + 1].nOTIFICATIONDATE!.isEmpty) { + return ""; + } else { + DateTime dateTimeTo = DateUtil.convertSimpleStringDateToDate(actionHistoryList[index].nOTIFICATIONDATE!); + DateTime dateTimeFrom = DateUtil.convertSimpleStringDateToDate(actionHistoryList[index + 1].nOTIFICATIONDATE!); + Duration duration = dateTimeTo.difference(dateTimeFrom); + return "Action duration: " + DateUtil.formatDuration(duration); + } } } -- 2.30.2 From 0728cc3dd4fd12f5c10768a2ff8625f82b3ff7fe Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Sun, 14 Jan 2024 11:03:27 +0300 Subject: [PATCH 007/135] Updated Mowadhafi Attachment Handling --- android/app/src/main/AndroidManifest.xml | 12 ++++++ android/app/src/main/res/xml/filepaths.xml | 5 +++ .../screens/mowadhafhi/request_details.dart | 40 +++++++++---------- 3 files changed, 35 insertions(+), 22 deletions(-) create mode 100644 android/app/src/main/res/xml/filepaths.xml diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index ea79d76..15b0c54 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,4 +1,5 @@ @@ -34,6 +35,17 @@ android:extractNativeLibs="true" android:networkSecurityConfig="@xml/network_security_config" android:roundIcon="@mipmap/ic_launcher_round"> + + + + + + + \ No newline at end of file diff --git a/lib/ui/screens/mowadhafhi/request_details.dart b/lib/ui/screens/mowadhafhi/request_details.dart index 0dcaa13..b2371ab 100644 --- a/lib/ui/screens/mowadhafhi/request_details.dart +++ b/lib/ui/screens/mowadhafhi/request_details.dart @@ -17,6 +17,7 @@ import 'package:mohem_flutter_app/models/mowadhafhi/get_ticket_transactions.dart import 'package:mohem_flutter_app/models/mowadhafhi/get_transaction_attachment_model.dart'; import 'package:mohem_flutter_app/ui/screens/mowadhafhi/view_transaction_attachment.dart'; import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; +import 'package:open_file/open_file.dart'; import 'package:path_provider/path_provider.dart'; class MowadhafhiRequestDetails extends StatefulWidget { @@ -245,9 +246,7 @@ class _RequestDetailsState extends State { try { Utils.showLoading(context); getTransactionAttachmentModel = await MowadhafhiApiClient().getTransactionAttachments(attachmentID); - debugPrint(getTransactionAttachmentModel?.fileName); Utils.hideLoading(context); - setState(() {}); handleTransactionAttachment(); } catch (ex) { Utils.hideLoading(context); @@ -255,32 +254,29 @@ class _RequestDetailsState extends State { } } + Future _createFileFromString(String encodedStr, String ext) async { + Uint8List bytes = base64.decode(encodedStr); + String dir = (await getApplicationDocumentsDirectory()).path; + File file = File("$dir/" + DateTime.now().millisecondsSinceEpoch.toString() + "." + ext); + await file.writeAsBytes(bytes); + return file.path; + } + void handleTransactionAttachment() async { String ext = ''; String? rFile = getTransactionAttachmentModel!.base64String; String? rFileExt = getTransactionAttachmentModel!.fileName; - ext = "." + rFileExt!.split(".").last.toLowerCase(); + ext = rFileExt!.split(".").last.toLowerCase(); - if (ext == ".png" || ext == ".jpg" || ext == ".jpeg" || ext == ".gif" || ext == ".tiff") { - try { - Uint8List decodedBytes = base64Decode(rFile!.split("base64,").last); - Directory appDocumentsDirectory = await getApplicationDocumentsDirectory(); // 1 - imageFile = Io.File("${appDocumentsDirectory.path}/addImage$ext"); - imageFile.writeAsBytesSync(decodedBytes); - Navigator.push( - context, - MaterialPageRoute( - builder: (BuildContext context) => ViewTransactionAttachment( - imageFile: imageFile, - ), - ), - ); - } catch (e) { - logger.d(e); - } - } else { - Utils.showErrorDialog(context: context, onOkTapped: () {}, message: "Unable to view attachment"); + try { + String path = await _createFileFromString(rFile!.split("base64,").last ?? "", ext ?? ""); + debugPrint(path); + + print(" file here: ${File(path).existsSync()}"); + await OpenFile.open(path); + } catch (ex) { + Utils.showToast("Cannot open file."); } } } -- 2.30.2 From 29643489d601c54e102371a5376fc9d23158848c Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Mon, 22 Jan 2024 12:56:39 +0300 Subject: [PATCH 008/135] Added permissions for viewing files --- android/app/src/main/res/xml/filepaths.xml | 3 ++ .../screens/mowadhafhi/request_details.dart | 44 ++++++++++++++----- 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/android/app/src/main/res/xml/filepaths.xml b/android/app/src/main/res/xml/filepaths.xml index b05757c..6c5db6a 100644 --- a/android/app/src/main/res/xml/filepaths.xml +++ b/android/app/src/main/res/xml/filepaths.xml @@ -2,4 +2,7 @@ + + + \ No newline at end of file diff --git a/lib/ui/screens/mowadhafhi/request_details.dart b/lib/ui/screens/mowadhafhi/request_details.dart index b2371ab..4ea47b0 100644 --- a/lib/ui/screens/mowadhafhi/request_details.dart +++ b/lib/ui/screens/mowadhafhi/request_details.dart @@ -17,8 +17,10 @@ import 'package:mohem_flutter_app/models/mowadhafhi/get_ticket_transactions.dart import 'package:mohem_flutter_app/models/mowadhafhi/get_transaction_attachment_model.dart'; import 'package:mohem_flutter_app/ui/screens/mowadhafhi/view_transaction_attachment.dart'; import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; +import 'package:mohem_flutter_app/widgets/dialogs/confirm_dialog.dart'; import 'package:open_file/open_file.dart'; import 'package:path_provider/path_provider.dart'; +import 'package:permission_handler/permission_handler.dart'; class MowadhafhiRequestDetails extends StatefulWidget { const MowadhafhiRequestDetails({Key? key}) : super(key: key); @@ -263,20 +265,38 @@ class _RequestDetailsState extends State { } void handleTransactionAttachment() async { - String ext = ''; - String? rFile = getTransactionAttachmentModel!.base64String; - String? rFileExt = getTransactionAttachmentModel!.fileName; - ext = rFileExt!.split(".").last.toLowerCase(); + Permission.storage.isGranted.then((isGranted) { + if (!isGranted) { + Permission.manageExternalStorage.request().then((granted) async { + if (granted == PermissionStatus.granted) { + String ext = ''; + String? rFile = getTransactionAttachmentModel!.base64String; + String? rFileExt = getTransactionAttachmentModel!.fileName; - try { - String path = await _createFileFromString(rFile!.split("base64,").last ?? "", ext ?? ""); - debugPrint(path); + ext = rFileExt!.split(".").last.toLowerCase(); - print(" file here: ${File(path).existsSync()}"); - await OpenFile.open(path); - } catch (ex) { - Utils.showToast("Cannot open file."); - } + try { + String path = await _createFileFromString(rFile!.split("base64,").last ?? "", ext ?? ""); + await OpenFile.open(path).catchError((err) { + print(err); + }); + } catch (ex) { + Utils.showToast("Cannot open file."); + } + } else { + showDialog( + context: context, + builder: (BuildContext cxt) => ConfirmDialog( + message: "You need to give storage permission to view files.", + onTap: () { + Navigator.pop(context); + }, + ), + ); + } + }); + } + }); } } -- 2.30.2 From 4e7e5bc0e7d1cb57ca12af57c944ee57dc4a50ab Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Mon, 22 Jan 2024 13:41:41 +0300 Subject: [PATCH 009/135] document type name updated in My Documents --- lib/ui/screens/mowadhafhi/request_details.dart | 2 -- lib/ui/screens/my_documents/my_documents_fragment.dart | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/ui/screens/mowadhafhi/request_details.dart b/lib/ui/screens/mowadhafhi/request_details.dart index 4ea47b0..352e195 100644 --- a/lib/ui/screens/mowadhafhi/request_details.dart +++ b/lib/ui/screens/mowadhafhi/request_details.dart @@ -265,7 +265,6 @@ class _RequestDetailsState extends State { } void handleTransactionAttachment() async { - Permission.storage.isGranted.then((isGranted) { if (!isGranted) { Permission.manageExternalStorage.request().then((granted) async { @@ -275,7 +274,6 @@ class _RequestDetailsState extends State { String? rFileExt = getTransactionAttachmentModel!.fileName; ext = rFileExt!.split(".").last.toLowerCase(); - try { String path = await _createFileFromString(rFile!.split("base64,").last ?? "", ext ?? ""); await OpenFile.open(path).catchError((err) { diff --git a/lib/ui/screens/my_documents/my_documents_fragment.dart b/lib/ui/screens/my_documents/my_documents_fragment.dart index 6bc46f7..5a9c88d 100644 --- a/lib/ui/screens/my_documents/my_documents_fragment.dart +++ b/lib/ui/screens/my_documents/my_documents_fragment.dart @@ -79,7 +79,7 @@ class _MyDocumentsFragmentState extends State { Navigator.pushNamed( context, AppRoutes.addDynamicInput, - arguments: DynamicListViewParams(documentfilteredList[index].dOCUMENTTYPE!, documentfilteredList[index].fUNCTIONNAME!, + arguments: DynamicListViewParams(documentfilteredList[index].dOCUMENTTYPENAME!, documentfilteredList[index].fUNCTIONNAME!, selectedEmp: AppState().getUserName, isAttachmentMandatory: true), ); }); -- 2.30.2 From 771914326fe0da00c30b995b3fe1a2a4f4315c10 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Sun, 4 Feb 2024 09:55:07 +0300 Subject: [PATCH 010/135] Forgot password flow updated --- lib/ui/login/login_screen.dart | 57 +++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/lib/ui/login/login_screen.dart b/lib/ui/login/login_screen.dart index 94724fc..46f66ba 100644 --- a/lib/ui/login/login_screen.dart +++ b/lib/ui/login/login_screen.dart @@ -17,11 +17,14 @@ import 'package:mohem_flutter_app/classes/consts.dart'; import 'package:mohem_flutter_app/classes/notifications.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/extensions/widget_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/check_mobile_app_version_model.dart'; +import 'package:mohem_flutter_app/models/generic_response_model.dart'; import 'package:mohem_flutter_app/models/get_mobile_login_info_list_model.dart'; import 'package:mohem_flutter_app/models/member_information_list_model.dart'; import 'package:mohem_flutter_app/models/member_login_list_model.dart'; @@ -59,6 +62,9 @@ class _LoginScreenState extends State { bool isOnExternalStorage = false; bool isDevelopmentModeEnable = false; + BasicMemberInformationModel? _basicMemberInformation; + GenericResponseModel? genericResponseModel; + // late HmsApiAvailability hmsApiAvailability; @override @@ -199,7 +205,8 @@ class _LoginScreenState extends State { onTap: () async { if (msg.toLowerCase().contains("password has expired")) { Navigator.pop(context); - await Navigator.pushNamed(context, AppRoutes.newPassword, arguments: username.text); + // await Navigator.pushNamed(context, AppRoutes.newPassword, arguments: username.text); + performForgotPassword(); } else { Navigator.pop(context); } @@ -209,6 +216,53 @@ class _LoginScreenState extends State { } } + void performForgotPassword() async { + // if (username.text.isEmpty) { + // return; + // } + Utils.showLoading(context); + try { + _basicMemberInformation = await LoginApiClient().getBasicUserInformation("CS", username.text); + genericResponseModel = await LoginApiClient().sendPublicActivationCode(_basicMemberInformation?.pMOBILENUMBER, username.text); + Utils.hideLoading(context); + OtpDialog( + context, + 1, + int.tryParse(_basicMemberInformation?.pMOBILENUMBER ?? ""), + (value, TextEditingController _pinPutController) async { + Utils.showLoading(context); + try { + GenericResponseModel? genericResponseModel = await LoginApiClient().checkPublicActivationCode(value, username.text); + if (genericResponseModel?.errorMessage != null) { + Utils.showToast(genericResponseModel?.errorMessage ?? ""); + return; + } + Utils.hideLoading(context); + await Navigator.pushNamed(context, AppRoutes.newPassword, arguments: username.text); + Navigator.pop(context); + Navigator.pop(context); + } catch (ex) { + print(ex); + _pinPutController.clear(); + otpFieldClear.value = ""; + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + } + }, + () => { + Navigator.pop(context), + }, + onResendCode: () { + performForgotPassword(); + }, + ).displayDialog(context); + } catch (ex) { + print(ex); + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + } + } + @override Widget build(BuildContext context) { if (isAppOpenBySystem == null) { @@ -279,6 +333,7 @@ class _LoginScreenState extends State { alignment: Alignment.centerRight, child: LocaleKeys.forgotPassword.tr().toText12(isUnderLine: true, color: MyColors.textMixColor).onPress(() { Navigator.pushNamed(context, AppRoutes.forgotPassword); + // performForgotPassword(); }), ), 20.height, -- 2.30.2 From 43e1e4df6b1da199adc7a15a686d393a2652a386 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Sun, 4 Feb 2024 11:03:55 +0300 Subject: [PATCH 011/135] forgot password changes --- assets/langs/ar-SA.json | 2 +- assets/langs/en-US.json | 2 +- lib/generated/codegen_loader.g.dart | 4 ++-- lib/ui/login/login_screen.dart | 12 +++++++----- lib/ui/login/new_password_screen.dart | 18 +++++++++--------- 5 files changed, 20 insertions(+), 18 deletions(-) diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 8ff0ea3..66db3f3 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -88,7 +88,7 @@ "atLeastOneNumeric": "رقم واحد على الأقل", "minimum8Characters": "8 أحرف على الأقل", "doNotAddRepeatingLetters": "لا تقم بإضافة أحرف متكررة", - "itShouldContainSpecialCharacter": "يجب أن يحتوي على طابع خاص", + "itShouldContainSpecialCharacter": "يجب لا يحتوي على أحرف خاصة", "confirmPasswordMustMatch": "يجب أن يتطابق تأكيد كلمة المرور", "sms": "رسالة قصيرة", "fingerPrint": "بصمة", diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 2449802..95f9ff3 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -85,7 +85,7 @@ "atLeastOneNumeric": "At least one numeric", "minimum8Characters": "Minimum 8 characters", "doNotAddRepeatingLetters": "Do not add repeating letters", - "itShouldContainSpecialCharacter": "It should contain special character", + "itShouldContainSpecialCharacter": "It should not contain special characters", "confirmPasswordMustMatch": "Confirm password must match", "sms": "SMS", "fingerPrint": "Fingerprint", diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index a433421..af972f6 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -104,7 +104,7 @@ class CodegenLoader extends AssetLoader { "atLeastOneNumeric": "رقم واحد على الأقل", "minimum8Characters": "8 أحرف على الأقل", "doNotAddRepeatingLetters": "لا تقم بإضافة أحرف متكررة", - "itShouldContainSpecialCharacter": "يجب أن يحتوي على طابع خاص", + "itShouldContainSpecialCharacter": "يجب لا يحتوي على أحرف خاصة", "confirmPasswordMustMatch": "يجب أن يتطابق تأكيد كلمة المرور", "sms": "رسالة قصيرة", "fingerPrint": "بصمة", @@ -639,7 +639,7 @@ class CodegenLoader extends AssetLoader { "atLeastOneNumeric": "At least one numeric", "minimum8Characters": "Minimum 8 characters", "doNotAddRepeatingLetters": "Do not add repeating letters", - "itShouldContainSpecialCharacter": "It should contain special character", + "itShouldContainSpecialCharacter": "It should not contain special character", "confirmPasswordMustMatch": "Confirm password must match", "sms": "SMS", "fingerPrint": "Fingerprint", diff --git a/lib/ui/login/login_screen.dart b/lib/ui/login/login_screen.dart index 46f66ba..c85ecb7 100644 --- a/lib/ui/login/login_screen.dart +++ b/lib/ui/login/login_screen.dart @@ -240,7 +240,7 @@ class _LoginScreenState extends State { Utils.hideLoading(context); await Navigator.pushNamed(context, AppRoutes.newPassword, arguments: username.text); Navigator.pop(context); - Navigator.pop(context); + // Navigator.pop(context); } catch (ex) { print(ex); _pinPutController.clear(); @@ -331,10 +331,12 @@ class _LoginScreenState extends State { 9.height, Align( alignment: Alignment.centerRight, - child: LocaleKeys.forgotPassword.tr().toText12(isUnderLine: true, color: MyColors.textMixColor).onPress(() { - Navigator.pushNamed(context, AppRoutes.forgotPassword); - // performForgotPassword(); - }), + child: LocaleKeys.forgotPassword.tr().toText12(isUnderLine: true, color: MyColors.textMixColor).onPress( + () { + // Navigator.pushNamed(context, AppRoutes.forgotPassword); + performForgotPassword(); + }, + ), ), 20.height, // DefaultButton( diff --git a/lib/ui/login/new_password_screen.dart b/lib/ui/login/new_password_screen.dart index 9efee64..11ba74b 100644 --- a/lib/ui/login/new_password_screen.dart +++ b/lib/ui/login/new_password_screen.dart @@ -102,20 +102,20 @@ class _NewPasswordScreenState extends State { passwordConstraintsUI(LocaleKeys.minimum8Characters.tr(), password.text.length >= 8), 8.height, passwordConstraintsUI(LocaleKeys.doNotAddRepeatingLetters.tr(), checkRepeatedChars(password.text)), - // 8.height, - // passwordConstraintsUI(LocaleKeys.itShouldContainSpecialCharacter.tr(), checkRegEx(r'[!@#$%^&*(),.?":{}|<>]')), + 8.height, + passwordConstraintsUI(LocaleKeys.itShouldContainSpecialCharacter.tr(), checkRegEx(r'^[a-zA-Z0-9]+$')), 8.height, passwordConstraintsUI(LocaleKeys.confirmPasswordMustMatch.tr(), password.text.isNotEmpty && password.text == confirmPassword.text), ], ).expanded, DefaultButton( - LocaleKeys.update.tr(), - (!isPasswordCompliant(password.text, 8)) - ? null - : () async { - setNewPassword(); - }) - .insideContainer + LocaleKeys.update.tr(), + (!isPasswordCompliant(password.text, 8)) + ? null + : () async { + setNewPassword(); + }, + ).insideContainer ], ), ); -- 2.30.2 From c7ff754dd80ad353fe9210e84cfa044c45ceae5d Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Tue, 6 Feb 2024 10:48:46 +0300 Subject: [PATCH 012/135] Password expired fixes & ITG Attachments implementation --- lib/api/worklist/worklist_api_client.dart | 16 +++ lib/extensions/string_extensions.dart | 3 +- lib/models/dashboard/itg_forms_model.dart | 10 +- .../itg_forms_attachments_model.dart | 25 +++++ lib/ui/login/new_password_screen.dart | 4 +- lib/ui/work_list/itg_detail_screen.dart | 50 ++++++++- .../itg_fragments/attachments_fragment.dart | 100 ++++++++++++++++++ .../attachments_fragment.dart | 31 +++++- 8 files changed, 227 insertions(+), 12 deletions(-) create mode 100644 lib/models/itg_forms_models/itg_forms_attachments_model.dart create mode 100644 lib/ui/work_list/itg_fragments/attachments_fragment.dart diff --git a/lib/api/worklist/worklist_api_client.dart b/lib/api/worklist/worklist_api_client.dart index 611bcf4..d2389ab 100644 --- a/lib/api/worklist/worklist_api_client.dart +++ b/lib/api/worklist/worklist_api_client.dart @@ -21,6 +21,7 @@ import 'package:mohem_flutter_app/models/get_quotation_analysis_list_model.dart' import 'package:mohem_flutter_app/models/get_stamp_ms_notification_body_list_model.dart'; import 'package:mohem_flutter_app/models/get_stamp_ns_notification_body_list_model.dart'; import 'package:mohem_flutter_app/models/get_user_item_type_list.dart'; +import 'package:mohem_flutter_app/models/itg_forms_models/itg_forms_attachments_model.dart'; import 'package:mohem_flutter_app/models/itg_forms_models/itg_request_model.dart'; import 'package:mohem_flutter_app/models/member_information_list_model.dart'; import 'package:mohem_flutter_app/models/notification_get_respond_attributes_list_model.dart'; @@ -364,6 +365,21 @@ class WorkListApiClient { }, url, postParams); } + Future?> getITGFormAttachments(String requestType, taskId, itemId, String employeeNumber) async { + String url = "${ApiConsts.cocRest}ITGGetFormDetialsAttachment"; + Map postParams = { + "RequestType": requestType, + "TaskID": taskId, + "ItemIDStr": itemId, + "EmployeeNumber": employeeNumber, + }; + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject((json) { + ItgFormsModel responseData = ItgFormsModel.fromJson(json); + return responseData.itgFormAttachmentsList; + }, url, postParams); + } + Future rejectITGRequest(String requestType, taskId, itemId, String employeeNumber, String comments) async { String url = "${ApiConsts.cocRest}ITGRejectRequest"; Map postParams = { diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index 3af55f0..91ded82 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -68,8 +68,9 @@ extension EmailValidator on String { style: TextStyle(fontSize: 10, fontStyle: fontStyle ?? FontStyle.normal, fontWeight: isBold ? FontWeight.bold : FontWeight.w600, color: color ?? MyColors.darkTextColor, letterSpacing: -0.4), ); - Widget toText11({Color? color, FontWeight? weight, bool isUnderLine = false, bool isBold = false, int maxLine = 0}) => Text( + Widget toText11({Color? color, FontWeight? weight, bool isUnderLine = false, bool isBold = false, bool isCenter = false, int maxLine = 0}) => Text( this, + textAlign: isCenter ? TextAlign.center : null, maxLines: (maxLine > 0) ? maxLine : null, style: TextStyle( fontSize: 11, diff --git a/lib/models/dashboard/itg_forms_model.dart b/lib/models/dashboard/itg_forms_model.dart index ae67ef8..7109d4e 100644 --- a/lib/models/dashboard/itg_forms_model.dart +++ b/lib/models/dashboard/itg_forms_model.dart @@ -4,6 +4,7 @@ import 'dart:convert'; +import 'package:mohem_flutter_app/models/itg_forms_models/itg_forms_attachments_model.dart'; import 'package:mohem_flutter_app/models/itg_forms_models/itg_request_model.dart'; import 'package:mohem_flutter_app/models/itg_forms_models/request_type_model.dart'; @@ -84,7 +85,8 @@ class ItgFormsModel { dynamic successMsgN; dynamic vidaUpdatedResponse; ITGRequest? itgRequest; - dynamic itgFormAttachmentsList; + // dynamic itgFormAttachmentsList; + List? itgFormAttachmentsList; String? message; dynamic mohemmItgDepartmentSectionsList; dynamic mohemmItgProjectDepartmentsList; @@ -128,7 +130,11 @@ class ItgFormsModel { successMsgN: json["SuccessMsgN"], vidaUpdatedResponse: json["VidaUpdatedResponse"], itgRequest: json['ITGRequest'] != null ? ITGRequest.fromJson(json['ITGRequest']) : null, - itgFormAttachmentsList: json["Itg_FormAttachmentsList"], + itgFormAttachmentsList: + json["Itg_FormAttachmentsList"] == null ? [] : json["Itg_FormAttachmentsList"]!.map((v) => ITGFormsAttachmentsModel.fromJson(v)).toList(), + + // json["RequestType"] == null ? [] : json['RequestType']!.map((v) => RequestType.fromJson(v)).toList(), + message: json["Message"] == null ? null : json["Message"], mohemmItgDepartmentSectionsList: json["Mohemm_ITG_DepartmentSectionsList"], mohemmItgProjectDepartmentsList: json["Mohemm_ITG_ProjectDepartmentsList"], diff --git a/lib/models/itg_forms_models/itg_forms_attachments_model.dart b/lib/models/itg_forms_models/itg_forms_attachments_model.dart new file mode 100644 index 0000000..2f5d8b5 --- /dev/null +++ b/lib/models/itg_forms_models/itg_forms_attachments_model.dart @@ -0,0 +1,25 @@ +class ITGFormsAttachmentsModel { + String? fileBase64; + dynamic fileData; + String? fileName; + String? fileType; + + ITGFormsAttachmentsModel( + {this.fileBase64, this.fileData, this.fileName, this.fileType}); + + ITGFormsAttachmentsModel.fromJson(Map json) { + fileBase64 = json['fileBase64']; + fileData = json['fileData']; + fileName = json['fileName']; + fileType = json['fileType']; + } + + Map toJson() { + Map data = new Map(); + data['fileBase64'] = this.fileBase64; + data['fileData'] = this.fileData; + data['fileName'] = this.fileName; + data['fileType'] = this.fileType; + return data; + } +} diff --git a/lib/ui/login/new_password_screen.dart b/lib/ui/login/new_password_screen.dart index 11ba74b..70b7456 100644 --- a/lib/ui/login/new_password_screen.dart +++ b/lib/ui/login/new_password_screen.dart @@ -102,8 +102,8 @@ class _NewPasswordScreenState extends State { passwordConstraintsUI(LocaleKeys.minimum8Characters.tr(), password.text.length >= 8), 8.height, passwordConstraintsUI(LocaleKeys.doNotAddRepeatingLetters.tr(), checkRepeatedChars(password.text)), - 8.height, - passwordConstraintsUI(LocaleKeys.itShouldContainSpecialCharacter.tr(), checkRegEx(r'^[a-zA-Z0-9]+$')), + // 8.height, + // passwordConstraintsUI(LocaleKeys.itShouldContainSpecialCharacter.tr(), checkRegEx(r'^[a-zA-Z0-9]+$')), 8.height, passwordConstraintsUI(LocaleKeys.confirmPasswordMustMatch.tr(), password.text.isNotEmpty && password.text == confirmPassword.text), ], diff --git a/lib/ui/work_list/itg_detail_screen.dart b/lib/ui/work_list/itg_detail_screen.dart index 5d48c53..546d320 100644 --- a/lib/ui/work_list/itg_detail_screen.dart +++ b/lib/ui/work_list/itg_detail_screen.dart @@ -3,6 +3,7 @@ import 'dart:convert'; import 'package:easy_localization/src/public_ext.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:lottie/lottie.dart'; import 'package:mohem_flutter_app/api/worklist/worklist_api_client.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; @@ -12,10 +13,12 @@ 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/itg_forms_models/allowed_actions_model.dart'; +import 'package:mohem_flutter_app/models/itg_forms_models/itg_forms_attachments_model.dart'; import 'package:mohem_flutter_app/models/itg_forms_models/itg_request_model.dart'; import 'package:mohem_flutter_app/models/itg_forms_models/request_detail_model.dart'; import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; import 'package:mohem_flutter_app/ui/work_list/itg_fragments/approval_level_fragment.dart'; +import 'package:mohem_flutter_app/ui/work_list/itg_fragments/attachments_fragment.dart'; import 'package:mohem_flutter_app/ui/work_list/itg_fragments/request_detail_fragment.dart'; import 'package:mohem_flutter_app/ui/work_list/sheets/delegate_sheet.dart'; import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; @@ -44,9 +47,12 @@ class _ItgDetailScreenState extends State { bool isRejectAvailable = false; List allowedActionList = []; + List itgFormAttachmentsList = []; late DashboardProviderModel providerData; + bool isAttachmentLoaded = false; + @override void initState() { providerData = Provider.of(context, listen: false); @@ -87,6 +93,7 @@ class _ItgDetailScreenState extends State { requestDetails = AppState().requestAllList![AppState().itgWorkListIndex!]; // ModalRoute.of(context)!.settings.arguments as WorkListResponseModel; providerData.itgFormsModel!.totalCount = providerData.itgFormsModel!.totalCount! - 1; getItgData(); + getItgRequestAttachments(); } } @@ -140,6 +147,7 @@ class _ItgDetailScreenState extends State { myTab(LocaleKeys.requestDetails.tr(), 0), myTab(LocaleKeys.approvalLevel.tr(), 1), myTab(LocaleKeys.requesterDetails.tr(), 2), + myTab(LocaleKeys.attachments.tr(), 3), ], ), ), @@ -157,6 +165,11 @@ class _ItgDetailScreenState extends State { voidCallback: reloadITG, ), RequestDetailFragment(fields: itgRequest?.fieldGoups?[0].fields ?? []), + isAttachmentLoaded + ? itgFormAttachmentsList.isEmpty + ? Utils.getNoDataWidget(context) + : ITGAttachmentsFragment(itgFormAttachmentsList) + : showLoadingAnimation(), ], ).expanded, if (isApproveAvailable || isRejectAvailable || isCloseAvailable) @@ -405,7 +418,7 @@ class _ItgDetailScreenState extends State { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ - title.toText12(color: isSelected ? Colors.white : Colors.white.withOpacity(.74), isCenter: true), + title.toText11(color: isSelected ? Colors.white : Colors.white.withOpacity(.74), isCenter: true), 4.height, Container( height: 8, @@ -478,7 +491,7 @@ class _ItgDetailScreenState extends State { ); } - void performAnswerAction(String requestType, taskId, itemId, String employeeNumber, String comments) async { + void performAnswerAction(String requestType, taskId, itemId, String employeeNumber, String comments) async { try { Utils.showLoading(context); ITGRequest? itgRequest = await WorkListApiClient().answerITGRequest(requestType, taskId, itemId, employeeNumber, "", comments); @@ -502,7 +515,7 @@ class _ItgDetailScreenState extends State { } } - void performRejectAction(String requestType, taskId, itemId, String employeeNumber, String comments) async { + void performRejectAction(String requestType, taskId, itemId, String employeeNumber, String comments) async { try { Utils.showLoading(context); ITGRequest? itgRequest = await WorkListApiClient().rejectITGRequest(requestType, taskId, itemId, employeeNumber, comments); @@ -526,7 +539,7 @@ class _ItgDetailScreenState extends State { } } - void performApproveAction(String requestType, taskId, itemId, String employeeNumber, String comments) async { + void performApproveAction(String requestType, taskId, itemId, String employeeNumber, String comments) async { try { Utils.showLoading(context); ITGRequest? itgRequest = await WorkListApiClient().approveITGRequest(requestType, taskId, itemId, employeeNumber, comments); @@ -576,6 +589,35 @@ class _ItgDetailScreenState extends State { } } + Widget showLoadingAnimation() { + return Lottie.asset( + 'assets/lottie/loading.json', + repeat: true, + reverse: false, + ); + } + + void getItgRequestAttachments() async { + try { + // Utils.showLoading(context); + itgFormAttachmentsList = + (await WorkListApiClient().getITGFormAttachments(requestDetails!.requestType!, requestDetails!.iD, requestDetails!.itemID, AppState().memberInformationList?.eMPLOYEENUMBER ?? ""))!; + // allowedActionList = itgRequest?.allowedActions ?? []; + // if (allowedActionList.isNotEmpty) { + // isCloseAvailable = allowedActionList.any((element) => element.action == "CLOSE"); + // isApproveAvailable = itgRequest!.allowedActions!.any((element) => element.action == "Approve"); + // isRejectAvailable = itgRequest!.allowedActions!.any((element) => element.action == "Reject"); + // } + // Utils.hideLoading(context); + setState(() { + isAttachmentLoaded = true; + }); + } catch (ex) { + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + } + } + void reloadITG() { animationIndex = animationIndex + 1; AppState().requestAllList!.removeAt(AppState().itgWorkListIndex!); diff --git a/lib/ui/work_list/itg_fragments/attachments_fragment.dart b/lib/ui/work_list/itg_fragments/attachments_fragment.dart new file mode 100644 index 0000000..a4a8372 --- /dev/null +++ b/lib/ui/work_list/itg_fragments/attachments_fragment.dart @@ -0,0 +1,100 @@ +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:mohem_flutter_app/classes/utils.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/models/itg_forms_models/itg_forms_attachments_model.dart'; +import 'package:mohem_flutter_app/widgets/dialogs/confirm_dialog.dart'; +import 'package:open_file/open_file.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:permission_handler/permission_handler.dart'; + +class ITGAttachmentsFragment extends StatelessWidget { + List itgFormAttachmentsList; + + ITGAttachmentsFragment(this.itgFormAttachmentsList); + + @override + Widget build(BuildContext context) { + return ListView.separated( + itemCount: itgFormAttachmentsList.length, + itemBuilder: (context, index) { + return Row( + children: [ + SvgPicture.asset(determineFileIcon(itgFormAttachmentsList[index].fileType ?? "")), + 12.width, + (itgFormAttachmentsList[index].fileName ?? "").toText16().expanded, + ], + ).objectContainerView().onPress(() async { + try { + Permission.storage.isGranted.then( + (isGranted) { + if (!isGranted) { + Permission.manageExternalStorage.request().then( + (granted) async { + if (granted == PermissionStatus.granted) { + String path = await _createFileFromString(itgFormAttachmentsList[index].fileBase64 ?? "", itgFormAttachmentsList[index].fileType ?? ""); + OpenFile.open(path); + } else { + showDialog( + context: context, + builder: (BuildContext cxt) => ConfirmDialog( + message: "You need to give storage permission to view files.", + onTap: () { + Navigator.pop(context); + }, + ), + ); + } + }, + ); + } + }, + ); + } catch (ex) { + Utils.showToast("Cannot open file."); + } + }); + }, + separatorBuilder: (BuildContext context, int index) => 12.height, + ).paddingAll(21); + } + + String determineFileIcon(String fileContentType) { + String icon = ""; + switch (fileContentType) { + case "pdf": + icon = "assets/images/pdf.svg"; + break; + case "xls": + icon = "assets/images/xls.svg"; + break; + case "xlsx": + icon = "assets/images/xls.svg"; + break; + case "png": + icon = "assets/images/png.svg"; + break; + case "jpg": + icon = "assets/images/jpg.svg"; + break; + case "jpeg": + icon = "assets/images/jpg.svg"; + break; + } + return icon; + } + + Future _createFileFromString(String encodedStr, String ext) async { + Uint8List bytes = base64.decode(encodedStr); + String dir = (await getApplicationDocumentsDirectory()).path; + File file = File("$dir/" + DateTime.now().millisecondsSinceEpoch.toString() + "." + ext); + await file.writeAsBytes(bytes); + return file.path; + } +} diff --git a/lib/ui/work_list/worklist_fragments/attachments_fragment.dart b/lib/ui/work_list/worklist_fragments/attachments_fragment.dart index bc1bde6..01a075b 100644 --- a/lib/ui/work_list/worklist_fragments/attachments_fragment.dart +++ b/lib/ui/work_list/worklist_fragments/attachments_fragment.dart @@ -9,8 +9,10 @@ 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/models/get_attachement_list_model.dart'; +import 'package:mohem_flutter_app/widgets/dialogs/confirm_dialog.dart'; import 'package:open_file/open_file.dart'; import 'package:path_provider/path_provider.dart'; +import 'package:permission_handler/permission_handler.dart'; class AttachmentsFragment extends StatelessWidget { final List getAttachmentList; @@ -30,9 +32,32 @@ class AttachmentsFragment extends StatelessWidget { ], ).objectContainerView().onPress(() async { try { - String path = await _createFileFromString(getAttachmentList[index].fILEDATA ?? "", getAttachmentList[index].fILECONTENTTYPE ?? ""); - OpenFile.open(path); - } catch (ex) {Utils.showToast("Cannot open file."); + Permission.storage.isGranted.then( + (isGranted) { + if (!isGranted) { + Permission.manageExternalStorage.request().then( + (granted) async { + if (granted == PermissionStatus.granted) { + String path = await _createFileFromString(getAttachmentList[index].fILEDATA ?? "", getAttachmentList[index].fILECONTENTTYPE ?? ""); + OpenFile.open(path); + } else { + showDialog( + context: context, + builder: (BuildContext cxt) => ConfirmDialog( + message: "You need to give storage permission to view files.", + onTap: () { + Navigator.pop(context); + }, + ), + ); + } + }, + ); + } + }, + ); + } catch (ex) { + Utils.showToast("Cannot open file."); } }); }, -- 2.30.2 From 697d44635c21b96a2d10a1a22f2fc1924fd9d05b Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Tue, 6 Feb 2024 11:01:16 +0300 Subject: [PATCH 013/135] Storage permissions handled --- .../itg_fragments/attachments_fragment.dart | 5 ++++- .../attachments_fragment.dart | 5 ++++- lib/widgets/image_picker.dart | 21 ++++++++++++++++++- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/lib/ui/work_list/itg_fragments/attachments_fragment.dart b/lib/ui/work_list/itg_fragments/attachments_fragment.dart index a4a8372..ec109e7 100644 --- a/lib/ui/work_list/itg_fragments/attachments_fragment.dart +++ b/lib/ui/work_list/itg_fragments/attachments_fragment.dart @@ -33,7 +33,7 @@ class ITGAttachmentsFragment extends StatelessWidget { ).objectContainerView().onPress(() async { try { Permission.storage.isGranted.then( - (isGranted) { + (isGranted) async { if (!isGranted) { Permission.manageExternalStorage.request().then( (granted) async { @@ -53,6 +53,9 @@ class ITGAttachmentsFragment extends StatelessWidget { } }, ); + } else { + String path = await _createFileFromString(itgFormAttachmentsList[index].fileBase64 ?? "", itgFormAttachmentsList[index].fileType ?? ""); + OpenFile.open(path); } }, ); diff --git a/lib/ui/work_list/worklist_fragments/attachments_fragment.dart b/lib/ui/work_list/worklist_fragments/attachments_fragment.dart index 01a075b..93309f1 100644 --- a/lib/ui/work_list/worklist_fragments/attachments_fragment.dart +++ b/lib/ui/work_list/worklist_fragments/attachments_fragment.dart @@ -33,7 +33,7 @@ class AttachmentsFragment extends StatelessWidget { ).objectContainerView().onPress(() async { try { Permission.storage.isGranted.then( - (isGranted) { + (isGranted) async { if (!isGranted) { Permission.manageExternalStorage.request().then( (granted) async { @@ -53,6 +53,9 @@ class AttachmentsFragment extends StatelessWidget { } }, ); + } else { + String path = await _createFileFromString(getAttachmentList[index].fILEDATA ?? "", getAttachmentList[index].fILECONTENTTYPE ?? ""); + OpenFile.open(path); } }, ); diff --git a/lib/widgets/image_picker.dart b/lib/widgets/image_picker.dart index 19b1e00..b98d80d 100644 --- a/lib/widgets/image_picker.dart +++ b/lib/widgets/image_picker.dart @@ -45,7 +45,7 @@ class ImageOptions { } }, onFilesTap: () async { - Permission.storage.isGranted.then((isGranted) { + Permission.storage.isGranted.then((isGranted) async { if (!isGranted) { Permission.manageExternalStorage.request().then((granted) async { if (granted == PermissionStatus.granted) { @@ -79,6 +79,25 @@ class ImageOptions { ); } }); + } else { + FilePickerResult? result = await FilePicker.platform.pickFiles( + type: FileType.custom, + allowedExtensions: [ + 'jpg', + 'jpeg ', + 'pdf', + 'txt', + 'docx', + 'doc', + 'pptx', + 'xlsx', + 'png', + 'rar', + 'zip', + ], + ); + List files = result!.paths.map((path) => File(path!)).toList(); + image(result.files.first.path.toString(), files.first); } }); }, -- 2.30.2 From 5f3c4b034fbb2877f855292e23a9ff34975a564f Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Tue, 6 Feb 2024 11:15:23 +0300 Subject: [PATCH 014/135] Monthly attendance fixes --- lib/ui/attendance/monthly_attendance_screen.dart | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/ui/attendance/monthly_attendance_screen.dart b/lib/ui/attendance/monthly_attendance_screen.dart index 1753c29..65f101b 100644 --- a/lib/ui/attendance/monthly_attendance_screen.dart +++ b/lib/ui/attendance/monthly_attendance_screen.dart @@ -304,10 +304,17 @@ class _MonthlyAttendanceScreenState extends State { if (details.date.month == formattedDate.month && details.date.year == formattedDate.year) { int val = details.date.day; //check day is off - if (getDayHoursTypeDetailsList.isNotEmpty) { - bool isDayIsOff = getDayHoursTypeDetailsList[val - 1].aTTENDEDFLAG == 'N' && getDayHoursTypeDetailsList[val - 1].dAYTYPE == 'OFF'; - bool isDayIsPresent = getDayHoursTypeDetailsList[val - 1].aTTENDEDFLAG == 'Y'; - bool isDayIsAbsent = getDayHoursTypeDetailsList[val - 1].aTTENDEDFLAG == 'N' && getDayHoursTypeDetailsList[val - 1].aBSENTFLAG == 'Y'; + // if (getDayHoursTypeDetailsList.isNotEmpty) { + // bool isDayIsOff = getDayHoursTypeDetailsList[val - 1].aTTENDEDFLAG == 'N' && getDayHoursTypeDetailsList[val - 1].dAYTYPE == 'OFF'; + // bool isDayIsPresent = getDayHoursTypeDetailsList[val - 1].aTTENDEDFLAG == 'Y'; + // bool isDayIsAbsent = getDayHoursTypeDetailsList[val - 1].aTTENDEDFLAG == 'N' && getDayHoursTypeDetailsList[val - 1].aBSENTFLAG == 'Y'; + List getDayHours = + getDayHoursTypeDetailsList.where((GetDayHoursTypeDetailsList element) => DateFormat("MM/dd/yyyy", "en_US").parse(element.sCHEDULEDATE!).day == details.date.day).toList(); + + if (getDayHours.isNotEmpty) { + bool isDayIsOff = getDayHoursTypeDetailsList[0].aTTENDEDFLAG == 'N' && getDayHoursTypeDetailsList[0].dAYTYPE == 'OFF'; + bool isDayIsPresent = getDayHoursTypeDetailsList[0].aTTENDEDFLAG == 'Y'; + bool isDayIsAbsent = getDayHoursTypeDetailsList[0].aTTENDEDFLAG == 'N' && getDayHoursTypeDetailsList[0].aBSENTFLAG == 'Y'; if (isDayIsOff) { return Container( -- 2.30.2 From d3358d578cd3093a9b3c0d933baba2943d14fd9f Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Wed, 7 Feb 2024 15:50:04 +0300 Subject: [PATCH 015/135] Update to stores --- android/app/src/main/res/xml/filepaths.xml | 14 +-- lib/api/chat/chat_api_client.dart | 2 +- lib/app_state/app_state.dart | 2 +- lib/classes/consts.dart | 4 +- lib/classes/file_process.dart | 4 +- lib/provider/chat_provider_model.dart | 4 +- lib/ui/landing/dashboard_screen.dart | 86 +++++++++---------- .../marathon_tutorial_viewer_screen.dart | 10 ++- .../screens/mowadhafhi/request_details.dart | 4 +- .../offers_and_discounts_details.dart | 2 +- lib/ui/work_list/item_history_screen.dart | 4 +- .../itg_fragments/attachments_fragment.dart | 31 +------ .../attachments_fragment.dart | 31 +------ lib/widgets/image_picker.dart | 2 +- pubspec.yaml | 9 +- 15 files changed, 81 insertions(+), 128 deletions(-) diff --git a/android/app/src/main/res/xml/filepaths.xml b/android/app/src/main/res/xml/filepaths.xml index 6c5db6a..087acc2 100644 --- a/android/app/src/main/res/xml/filepaths.xml +++ b/android/app/src/main/res/xml/filepaths.xml @@ -1,8 +1,8 @@ - - + + + + + + - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/lib/api/chat/chat_api_client.dart b/lib/api/chat/chat_api_client.dart index daafa92..14b4e42 100644 --- a/lib/api/chat/chat_api_client.dart +++ b/lib/api/chat/chat_api_client.dart @@ -39,7 +39,7 @@ class ChatApiClient { "platform": Platform.isIOS ? "ios" : "android", "deviceToken": AppState().getIsHuawei ? AppState().getHuaweiPushToken : AppState().getDeviceToken, "isHuaweiDevice": AppState().getIsHuawei, - "voipToken": "", + "voipToken": "80a3b01fc1ef2453eb4f1daa4fc31d8142d9cb67baf848e91350b607971fe2ba", }, ); diff --git a/lib/app_state/app_state.dart b/lib/app_state/app_state.dart index 51469c2..202584b 100644 --- a/lib/app_state/app_state.dart +++ b/lib/app_state/app_state.dart @@ -90,7 +90,7 @@ class AppState { String get getHuaweiPushToken => _huaweiPushToken; - final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 5.7, mobileType: Platform.isAndroid ? "android" : "ios"); + final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 5.8, mobileType: Platform.isAndroid ? "android" : "ios"); void setPostParamsInitConfig() { isAuthenticated = false; diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 4b3f54e..a6eaad2 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -3,8 +3,8 @@ import 'package:mohem_flutter_app/ui/marathon/widgets/question_card.dart'; class ApiConsts { //static String baseUrl = "http://10.200.204.20:2801/"; // Local server // static String baseUrl = "https://erptstapp.srca.org.sa"; // SRCA server - static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver - // static String baseUrl = "https://hmgwebservices.com"; // Live server + // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver + static String baseUrl = "https://hmgwebservices.com"; // Live server static String baseUrlServices = baseUrl + "/Services/"; // server // static String baseUrlServices = "https://api.cssynapses.com/tangheem/"; // Live server static String utilitiesRest = baseUrlServices + "Utilities.svc/REST/"; diff --git a/lib/classes/file_process.dart b/lib/classes/file_process.dart index 83ea15b..0720c8d 100644 --- a/lib/classes/file_process.dart +++ b/lib/classes/file_process.dart @@ -2,7 +2,7 @@ import 'dart:convert'; import 'dart:io'; import 'dart:typed_data'; -import 'package:open_file/open_file.dart'; +import 'package:open_filex/open_filex.dart'; import 'package:path_provider/path_provider.dart'; import 'package:http/http.dart' as http; @@ -26,7 +26,7 @@ class FileProcess { static void openFile(String fileName, {bool isFullPath = false}) { String dir = directory!.path + "/$fileName.pdf"; - OpenFile.open(isFullPath ? fileName : dir); + OpenFilex.open(isFullPath ? fileName : dir); } static Future downloadFile(String base64Content, String fileName) async { diff --git a/lib/provider/chat_provider_model.dart b/lib/provider/chat_provider_model.dart index 00545b2..0a37f8e 100644 --- a/lib/provider/chat_provider_model.dart +++ b/lib/provider/chat_provider_model.dart @@ -37,7 +37,7 @@ import 'package:mohem_flutter_app/models/my_team/get_employee_subordinates_list. import 'package:mohem_flutter_app/ui/chat/chat_detailed_screen.dart'; import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart'; import 'package:mohem_flutter_app/widgets/image_picker.dart'; -import 'package:open_file/open_file.dart'; +import 'package:open_filex/open_filex.dart'; import 'package:path_provider/path_provider.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:signalr_netcore/hub_connection.dart'; @@ -1674,7 +1674,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { try { String path = await downChatMedia(encodedString, fileTypeName ?? ""); Utils.hideLoading(context); - OpenFile.open(path); + OpenFilex.open(path); } catch (e) { Utils.showToast("Cannot open file."); } diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index 5de9052..9a91fe3 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -530,49 +530,49 @@ class _DashboardScreenState extends State with WidgetsBindingOb children: [ ServicesWidget(), context.watch().isLoading ? const MarathonBannerShimmer().paddingAll(20) : const MarathonBanner().paddingOnly(left: 21, right: 21, bottom: 8, top: 8), - context.watch().isTutorialLoading - ? const MarathonBannerShimmer().paddingAll(20) - : Container( - padding: EdgeInsets.only(bottom: 12, top: 12), - margin: EdgeInsets.only(left: 21, right: 21, bottom: 21, top: 8), - width: double.infinity, - alignment: Alignment.center, - decoration: BoxDecoration( - color: MyColors.backgroundBlackColor, - borderRadius: BorderRadius.circular(20), - border: Border.all(color: MyColors.lightGreyEDColor, width: 1), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Text( - "Tutorial:", - style: TextStyle( - fontSize: 11, - fontStyle: FontStyle.italic, - fontWeight: FontWeight.w600, - color: MyColors.white.withOpacity(0.83), - letterSpacing: -0.4, - ), - ), - Text( - context.read().tutorial?.tutorialName ?? "", - overflow: TextOverflow.ellipsis, - style: TextStyle( - fontStyle: FontStyle.italic, - fontSize: 19, - fontWeight: FontWeight.bold, - color: MyColors.white, - height: 32 / 22, - ), - ), - ], - ), - ).onPress(() { - checkERMChannel(); - // Navigator.pushNamed(context, AppRoutes.marathonTutorialScreen); - }), + // context.watch().isTutorialLoading + // ? const MarathonBannerShimmer().paddingAll(20) + // : Container( + // padding: EdgeInsets.only(bottom: 12, top: 12), + // margin: EdgeInsets.only(left: 21, right: 21, bottom: 21, top: 8), + // width: double.infinity, + // alignment: Alignment.center, + // decoration: BoxDecoration( + // color: MyColors.backgroundBlackColor, + // borderRadius: BorderRadius.circular(20), + // border: Border.all(color: MyColors.lightGreyEDColor, width: 1), + // ), + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // mainAxisSize: MainAxisSize.min, + // children: [ + // Text( + // "Tutorial:", + // style: TextStyle( + // fontSize: 11, + // fontStyle: FontStyle.italic, + // fontWeight: FontWeight.w600, + // color: MyColors.white.withOpacity(0.83), + // letterSpacing: -0.4, + // ), + // ), + // Text( + // context.read().tutorial?.tutorialName ?? "", + // overflow: TextOverflow.ellipsis, + // style: TextStyle( + // fontStyle: FontStyle.italic, + // fontSize: 19, + // fontWeight: FontWeight.bold, + // color: MyColors.white, + // height: 32 / 22, + // ), + // ), + // ], + // ), + // ).onPress(() { + // checkERMChannel(); + // // Navigator.pushNamed(context, AppRoutes.marathonTutorialScreen); + // }), ], ), ), diff --git a/lib/ui/marathon/marathon_tutorial_viewer_screen.dart b/lib/ui/marathon/marathon_tutorial_viewer_screen.dart index 2e40ecf..0cdc8d8 100644 --- a/lib/ui/marathon/marathon_tutorial_viewer_screen.dart +++ b/lib/ui/marathon/marathon_tutorial_viewer_screen.dart @@ -174,10 +174,12 @@ class _MarathonTutorialViewerScreenState extends State { ext = rFileExt!.split(".").last.toLowerCase(); try { String path = await _createFileFromString(rFile!.split("base64,").last ?? "", ext ?? ""); - await OpenFile.open(path).catchError((err) { + await OpenFilex.open(path).catchError((err) { print(err); }); } catch (ex) { diff --git a/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart b/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart index 30a9fa2..b4cb242 100644 --- a/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart +++ b/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart @@ -76,7 +76,7 @@ class _OffersAndDiscountsDetailsState extends State { : getOffersList[0].titleEn!.toText22(isBold: true, color: const Color(0xff2B353E)).center, Html( data: AppState().isArabic(context) ? getOffersList[0].descriptionAr! : getOffersList[0].descriptionEn ?? "", - onLinkTap: (String? url, Map attributes, _) { + onLinkTap: (String? url, RenderContext context, Map attributes, _) { launchUrl(Uri.parse(url!)); }, ), diff --git a/lib/ui/work_list/item_history_screen.dart b/lib/ui/work_list/item_history_screen.dart index e88dcba..7490d38 100644 --- a/lib/ui/work_list/item_history_screen.dart +++ b/lib/ui/work_list/item_history_screen.dart @@ -22,7 +22,7 @@ import 'package:mohem_flutter_app/models/get_quotation_analysis_list_model.dart' import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; import 'package:mohem_flutter_app/widgets/circular_avatar.dart'; import 'package:mohem_flutter_app/widgets/item_detail_view_widget.dart'; -import 'package:open_file/open_file.dart'; +import 'package:open_filex/open_filex.dart'; import 'package:path_provider/path_provider.dart'; class ItemHistoryScreenParams { @@ -278,7 +278,7 @@ class _ItemHistoryScreenState extends State { ).objectContainerView().onPress(() async { try { String path = await _createFileFromString(getAttachmentList[index].fILEDATA ?? "", getAttachmentList[index].fILECONTENTTYPE ?? ""); - OpenFile.open(path); + OpenFilex.open(path); } catch (ex) { Utils.showToast("Cannot open file."); } diff --git a/lib/ui/work_list/itg_fragments/attachments_fragment.dart b/lib/ui/work_list/itg_fragments/attachments_fragment.dart index ec109e7..d31e897 100644 --- a/lib/ui/work_list/itg_fragments/attachments_fragment.dart +++ b/lib/ui/work_list/itg_fragments/attachments_fragment.dart @@ -10,7 +10,7 @@ import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; import 'package:mohem_flutter_app/models/itg_forms_models/itg_forms_attachments_model.dart'; import 'package:mohem_flutter_app/widgets/dialogs/confirm_dialog.dart'; -import 'package:open_file/open_file.dart'; +import 'package:open_filex/open_filex.dart'; import 'package:path_provider/path_provider.dart'; import 'package:permission_handler/permission_handler.dart'; @@ -32,33 +32,8 @@ class ITGAttachmentsFragment extends StatelessWidget { ], ).objectContainerView().onPress(() async { try { - Permission.storage.isGranted.then( - (isGranted) async { - if (!isGranted) { - Permission.manageExternalStorage.request().then( - (granted) async { - if (granted == PermissionStatus.granted) { - String path = await _createFileFromString(itgFormAttachmentsList[index].fileBase64 ?? "", itgFormAttachmentsList[index].fileType ?? ""); - OpenFile.open(path); - } else { - showDialog( - context: context, - builder: (BuildContext cxt) => ConfirmDialog( - message: "You need to give storage permission to view files.", - onTap: () { - Navigator.pop(context); - }, - ), - ); - } - }, - ); - } else { - String path = await _createFileFromString(itgFormAttachmentsList[index].fileBase64 ?? "", itgFormAttachmentsList[index].fileType ?? ""); - OpenFile.open(path); - } - }, - ); + String path = await _createFileFromString(itgFormAttachmentsList[index].fileBase64 ?? "", itgFormAttachmentsList[index].fileType ?? ""); + OpenFilex.open(path); } catch (ex) { Utils.showToast("Cannot open file."); } diff --git a/lib/ui/work_list/worklist_fragments/attachments_fragment.dart b/lib/ui/work_list/worklist_fragments/attachments_fragment.dart index 93309f1..e1381ac 100644 --- a/lib/ui/work_list/worklist_fragments/attachments_fragment.dart +++ b/lib/ui/work_list/worklist_fragments/attachments_fragment.dart @@ -10,7 +10,7 @@ import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; import 'package:mohem_flutter_app/models/get_attachement_list_model.dart'; import 'package:mohem_flutter_app/widgets/dialogs/confirm_dialog.dart'; -import 'package:open_file/open_file.dart'; +import 'package:open_filex/open_filex.dart'; import 'package:path_provider/path_provider.dart'; import 'package:permission_handler/permission_handler.dart'; @@ -32,33 +32,8 @@ class AttachmentsFragment extends StatelessWidget { ], ).objectContainerView().onPress(() async { try { - Permission.storage.isGranted.then( - (isGranted) async { - if (!isGranted) { - Permission.manageExternalStorage.request().then( - (granted) async { - if (granted == PermissionStatus.granted) { - String path = await _createFileFromString(getAttachmentList[index].fILEDATA ?? "", getAttachmentList[index].fILECONTENTTYPE ?? ""); - OpenFile.open(path); - } else { - showDialog( - context: context, - builder: (BuildContext cxt) => ConfirmDialog( - message: "You need to give storage permission to view files.", - onTap: () { - Navigator.pop(context); - }, - ), - ); - } - }, - ); - } else { - String path = await _createFileFromString(getAttachmentList[index].fILEDATA ?? "", getAttachmentList[index].fILECONTENTTYPE ?? ""); - OpenFile.open(path); - } - }, - ); + String path = await _createFileFromString(getAttachmentList[index].fILEDATA ?? "", getAttachmentList[index].fILECONTENTTYPE ?? ""); + OpenFilex.open(path); } catch (ex) { Utils.showToast("Cannot open file."); } diff --git a/lib/widgets/image_picker.dart b/lib/widgets/image_picker.dart index b98d80d..38fcdef 100644 --- a/lib/widgets/image_picker.dart +++ b/lib/widgets/image_picker.dart @@ -47,7 +47,7 @@ class ImageOptions { onFilesTap: () async { Permission.storage.isGranted.then((isGranted) async { if (!isGranted) { - Permission.manageExternalStorage.request().then((granted) async { + Permission.storage.request().then((granted) async { if (granted == PermissionStatus.granted) { FilePickerResult? result = await FilePicker.platform.pickFiles( type: FileType.custom, diff --git a/pubspec.yaml b/pubspec.yaml index 82ae41b..f7264a4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html #version: 3.3.01+300040 -version: 3.3.6+300046 +version: 3.3.5+300045 environment: sdk: ">=2.16.0 <3.0.0" @@ -63,8 +63,9 @@ dependencies: file_picker: 5.2.5 geolocator: ^9.0.2 month_year_picker: ^0.2.0+1 - month_picker_dialog_2: 0.5.5 - open_file: ^3.2.1 + month_picker_dialog_2: ^0.5.5 +# open_file: ^3.2.1 + open_filex: ^4.4.0 wifi_iot: ^0.3.18 flutter_html: ^3.0.0-alpha.6 # flutter_barcode_scanner: ^2.0.0 @@ -100,7 +101,7 @@ dependencies: #Encryption flutter_des: ^2.1.0 - video_player: ^2.5.1 + video_player: 2.7.0 just_audio: ^0.9.30 # safe_device: ^1.1.2 flutter_layout_grid: ^2.0.1 -- 2.30.2 From 55c096aa7e14fd9863fc9c3cd7b64398cc952ad7 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Wed, 7 Feb 2024 17:34:20 +0300 Subject: [PATCH 016/135] Chat video fixes --- android/app/src/main/AndroidManifest.xml | 3 +- ios/Runner.xcodeproj/project.pbxproj | 6 +- lib/api/chat/chat_api_client.dart | 10 +- lib/provider/chat_provider_model.dart | 506 ++++++++------------- lib/ui/chat/chat_bubble.dart | 115 +++-- lib/ui/chat/chat_detailed_screen.dart | 13 +- lib/ui/chat/group_chat_bubble.dart | 203 ++++++--- lib/ui/chat/group_chat_detaied_screen.dart | 476 ++++++++++--------- lib/ui/landing/dashboard_screen.dart | 2 +- lib/widgets/image_picker.dart | 91 ++-- 10 files changed, 685 insertions(+), 740 deletions(-) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 15b0c54..64edcac 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -4,7 +4,6 @@ - @@ -18,7 +17,7 @@ - + diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index e734dc5..00c3cac 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -376,7 +376,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 3.7.8; + MARKETING_VERSION = 3.7.9; PRODUCT_BUNDLE_IDENTIFIER = com.cloudsolutions.mohemm; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -514,7 +514,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 3.7.8; + MARKETING_VERSION = 3.7.9; PRODUCT_BUNDLE_IDENTIFIER = com.cloudsolutions.mohemm; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -544,7 +544,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 3.7.8; + MARKETING_VERSION = 3.7.9; PRODUCT_BUNDLE_IDENTIFIER = com.cloudsolutions.mohemm; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/lib/api/chat/chat_api_client.dart b/lib/api/chat/chat_api_client.dart index 14b4e42..510f6fa 100644 --- a/lib/api/chat/chat_api_client.dart +++ b/lib/api/chat/chat_api_client.dart @@ -39,7 +39,7 @@ class ChatApiClient { "platform": Platform.isIOS ? "ios" : "android", "deviceToken": AppState().getIsHuawei ? AppState().getHuaweiPushToken : AppState().getDeviceToken, "isHuaweiDevice": AppState().getIsHuawei, - "voipToken": "80a3b01fc1ef2453eb4f1daa4fc31d8142d9cb67baf848e91350b607971fe2ba", + "voipToken": Platform.isIOS ? "80a3b01fc1ef2453eb4f1daa4fc31d8142d9cb67baf848e91350b607971fe2ba" : "", }, ); @@ -145,14 +145,14 @@ class ChatApiClient { } // Upload Chat Media - Future uploadMedia(String userId, File file) async { + Future uploadMedia(String userId, File file, String fileSource) async { if (kDebugMode) { print("${ApiConsts.chatMediaImageUploadUrl}upload"); print(AppState().chatDetails!.response!.token); } dynamic request = MultipartRequest('POST', Uri.parse('${ApiConsts.chatMediaImageUploadUrl}upload')); - request.fields.addAll({'userId': userId, 'fileSource': '1'}); + request.fields.addAll({'userId': userId, 'fileSource': fileSource}); request.files.add(await MultipartFile.fromPath('files', file.path)); request.headers.addAll({'Authorization': 'Bearer ${AppState().chatDetails!.response!.token}'}); StreamedResponse response = await request.send(); @@ -164,10 +164,10 @@ class ChatApiClient { } // Download File For Chat - Future downloadURL({required String fileName, required String fileTypeDescription}) async { + Future downloadURL({required String fileName, required String fileTypeDescription, required int fileSource}) async { Response response = await ApiClient().postJsonForResponse( "${ApiConsts.chatMediaImageUploadUrl}download", - {"fileType": fileTypeDescription, "fileName": fileName, "fileSource": 1}, + {"fileType": fileTypeDescription, "fileName": fileName, "fileSource": fileSource}, token: AppState().chatDetails!.response!.token, ); Uint8List data = Uint8List.fromList(response.bodyBytes); diff --git a/lib/provider/chat_provider_model.dart b/lib/provider/chat_provider_model.dart index 0a37f8e..0c73a4b 100644 --- a/lib/provider/chat_provider_model.dart +++ b/lib/provider/chat_provider_model.dart @@ -19,19 +19,14 @@ import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/config/routes.dart'; import 'package:mohem_flutter_app/main.dart'; import 'package:mohem_flutter_app/models/chat/chat_user_image_model.dart'; -import 'package:mohem_flutter_app/models/chat/create_group_request.dart' - as createGroup; -import 'package:mohem_flutter_app/models/chat/get_group_chat_history.dart' - as groupchathistory; +import 'package:mohem_flutter_app/models/chat/create_group_request.dart' as createGroup; +import 'package:mohem_flutter_app/models/chat/get_group_chat_history.dart' as groupchathistory; import 'package:mohem_flutter_app/models/chat/get_search_user_chat_model.dart'; import 'package:mohem_flutter_app/models/chat/get_single_user_chat_list_model.dart'; -import 'package:mohem_flutter_app/models/chat/get_user_groups_by_id.dart' - as groups; +import 'package:mohem_flutter_app/models/chat/get_user_groups_by_id.dart' as groups; import 'package:mohem_flutter_app/models/chat/get_user_groups_by_id.dart'; -import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart' - as userLoginToken; -import 'package:mohem_flutter_app/models/chat/make_user_favotire_unfavorite_chat_model.dart' - as fav; +import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart' as userLoginToken; +import 'package:mohem_flutter_app/models/chat/make_user_favotire_unfavorite_chat_model.dart' as fav; import 'package:mohem_flutter_app/models/chat/target_users.dart'; import 'package:mohem_flutter_app/models/my_team/get_employee_subordinates_list.dart'; import 'package:mohem_flutter_app/ui/chat/chat_detailed_screen.dart'; @@ -64,10 +59,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { List favUsersList = []; int paginationVal = 0; int? cTypingUserId = 0; - bool isTextMsg = false, - isReplyMsg = false, - isAttachmentMsg = false, - isVoiceMsg = false; + bool isTextMsg = false, isReplyMsg = false, isAttachmentMsg = false, isVoiceMsg = false; // Audio Recoding Work Timer? _timer; @@ -100,8 +92,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { List? uGroups = [], searchGroups = []; Future getUserAutoLoginToken() async { - userLoginToken.UserAutoLoginModel userLoginResponse = - await ChatApiClient().getUserLoginToken(); + userLoginToken.UserAutoLoginModel userLoginResponse = await ChatApiClient().getUserLoginToken(); if (userLoginResponse.response != null) { AppState().setchatUserDetails = userLoginResponse; } else { @@ -130,15 +121,10 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { Future getHubConnection() async { HubConnection hub; - HttpConnectionOptions httpOp = - HttpConnectionOptions(skipNegotiation: false, logMessageContent: true); + HttpConnectionOptions httpOp = HttpConnectionOptions(skipNegotiation: false, logMessageContent: true); hub = HubConnectionBuilder() - .withUrl( - ApiConsts.chatHubConnectionUrl + - "?UserId=${AppState().chatDetails!.response!.id}&source=Desktop&access_token=${AppState().chatDetails!.response!.token}", - options: httpOp) - .withAutomaticReconnect( - retryDelays: [2000, 5000, 10000, 20000]).build(); + .withUrl(ApiConsts.chatHubConnectionUrl + "?UserId=${AppState().chatDetails!.response!.id}&source=Desktop&access_token=${AppState().chatDetails!.response!.token}", options: httpOp) + .withAutomaticReconnect(retryDelays: [2000, 5000, 10000, 20000]).build(); return hub; } @@ -150,12 +136,9 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { chatHubConnection.on("OnUserTypingAsync", onUserTyping); chatHubConnection.on("OnUserCountAsync", userCountAsync); // chatHubConnection.on("OnUpdateUserChatHistoryWindowsAsync", updateChatHistoryWindow); - chatHubConnection.on( - "OnGetUserChatHistoryNotDeliveredAsync", chatNotDelivered); - chatHubConnection.on( - "OnUpdateUserChatHistoryStatusAsync", updateUserChatStatus); - chatHubConnection.on( - "OnGetGroupUserStatusAsync", getGroupUserStatus); + chatHubConnection.on("OnGetUserChatHistoryNotDeliveredAsync", chatNotDelivered); + chatHubConnection.on("OnUpdateUserChatHistoryStatusAsync", updateUserChatStatus); + chatHubConnection.on("OnGetGroupUserStatusAsync", getGroupUserStatus); // // {"type":1,"target":"","arguments":[[{"id":217869,"userName":"Sultan.Khan","email":"Sultan.Khan@cloudsolutions.com.sa","phone":null,"title":"Sultan.Khan","userStatus":1,"image":null,"unreadMessageCount":0,"userAction":3,"isPin":false,"isFav":false,"isAdmin":false,"rKey":null,"totalCount":0,"isHuaweiDevice":false,"deviceToken":null},{"id":15153,"userName":"Tamer.Fanasheh","email":"Tamer.F@cloudsolutions.com.sa","phone":null,"title":"Tamer Fanasheh","userStatus":2,"image":null,"unreadMessageCount":0,"userAction":3,"isPin":false,"isFav":false,"isAdmin":true,"rKey":null,"totalCount":0,"isHuaweiDevice":false,"deviceToken":null}]]} @@ -171,8 +154,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { // userGroups = await ChatApiClient().getGroupsByUserId(); if (favUList.response != null && recentChat.response != null) { favUsersList = favUList.response!; - favUsersList.sort((ChatUser a, ChatUser b) => - a.userName!.toLowerCase().compareTo(b.userName!.toLowerCase())); + favUsersList.sort((ChatUser a, ChatUser b) => a.userName!.toLowerCase().compareTo(b.userName!.toLowerCase())); for (dynamic user in recentChat.response!) { for (dynamic favUser in favUList.response!) { if (user.id == favUser.id) { @@ -183,12 +165,10 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } pChatHistory = recentChat.response ?? []; uGroups = userGroups.groupresponse ?? []; - pChatHistory!.sort((ChatUser a, ChatUser b) => - a.userName!.toLowerCase().compareTo(b.userName!.toLowerCase())); + pChatHistory!.sort((ChatUser a, ChatUser b) => a.userName!.toLowerCase().compareTo(b.userName!.toLowerCase())); searchedChats = pChatHistory; isLoading = false; - await invokeUserChatHistoryNotDeliveredAsync( - userId: int.parse(AppState().chatDetails!.response!.id.toString())); + await invokeUserChatHistoryNotDeliveredAsync(userId: int.parse(AppState().chatDetails!.response!.id.toString())); sort(); notifyListeners(); if (searchedChats!.isNotEmpty || favUsersList.isNotEmpty) { @@ -197,38 +177,27 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } Future invokeUserChatHistoryNotDeliveredAsync({required int userId}) async { - await chatHubConnection - .invoke("GetUserChatHistoryNotDeliveredAsync", args: [userId]); + await chatHubConnection.invoke("GetUserChatHistoryNotDeliveredAsync", args: [userId]); return ""; } - void getSingleUserChatHistory( - {required int senderUID, - required int receiverUID, - required bool loadMore, - bool isNewChat = false}) async { + void getSingleUserChatHistory({required int senderUID, required int receiverUID, required bool loadMore, bool isNewChat = false}) async { isLoading = true; if (isNewChat) userChatHistory = []; if (!loadMore) paginationVal = 0; isChatScreenActive = true; receiverID = receiverUID; - Response response = await ChatApiClient().getSingleUserChatHistory( - senderUID: senderUID, - receiverUID: receiverUID, - loadMore: loadMore, - paginationVal: paginationVal); + Response response = await ChatApiClient().getSingleUserChatHistory(senderUID: senderUID, receiverUID: receiverUID, loadMore: loadMore, paginationVal: paginationVal); if (response.statusCode == 204) { if (isNewChat) { userChatHistory = []; } else if (loadMore) {} } else { if (loadMore) { - List temp = - getSingleUserChatModel(response.body).reversed.toList(); + List temp = getSingleUserChatModel(response.body).reversed.toList(); userChatHistory.addAll(temp); } else { - userChatHistory = - getSingleUserChatModel(response.body).reversed.toList(); + userChatHistory = getSingleUserChatModel(response.body).reversed.toList(); } } isLoading = false; @@ -255,9 +224,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { dynamic data = [ { "userChatHistoryId": element.userChatHistoryId, - "TargetUserId": element.currentUserId == receiverID - ? element.currentUserId - : element.targetUserId, + "TargetUserId": element.currentUserId == receiverID ? element.currentUserId : element.targetUserId, "isDelivered": true, "isSeen": true, } @@ -279,8 +246,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { void updateUserChatHistoryStatusAsync(List data) { try { - chatHubConnection - .invoke("UpdateUserChatHistoryStatusAsync", args: [data]); + chatHubConnection.invoke("UpdateUserChatHistoryStatusAsync", args: [data]); } catch (e) { throw e; } @@ -288,26 +254,21 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { void updateUserChatHistoryOnMsg(List data) { try { - chatHubConnection - .invoke("UpdateUserChatHistoryStatusAsync", args: [data]); + chatHubConnection.invoke("UpdateUserChatHistoryStatusAsync", args: [data]); } catch (e) { throw e; } } - List getSingleUserChatModel(String str) => - List.from( - json.decode(str).map((x) => SingleUserChatModel.fromJson(x))); + List getSingleUserChatModel(String str) => List.from(json.decode(str).map((x) => SingleUserChatModel.fromJson(x))); List getGroupChatHistoryAsync(String str) => - List.from( - json.decode(str).map((x) => groupchathistory.GetGroupChatHistoryAsync.fromJson(x))); - + List.from(json.decode(str).map((x) => groupchathistory.GetGroupChatHistoryAsync.fromJson(x))); - Future uploadAttachments(String userId, File file) async { + Future uploadAttachments(String userId, File file, String fileSource) async { dynamic result; try { - Object? response = await ChatApiClient().uploadMedia(userId, file); + Object? response = await ChatApiClient().uploadMedia(userId, file, fileSource); if (response != null) { result = response; } else { @@ -332,9 +293,9 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { notifyListeners(); } - void getGroupUserStatus(List? args){ - //note: need to implement this function... - print(args); + void getGroupUserStatus(List? args) { + //note: need to implement this function... + print(args); } void onChatSeen(List? args) { @@ -363,8 +324,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { void updateChatHistoryWindow(List? args) { dynamic items = args!.toList(); if (kDebugMode) { - logger.i( - "---------------------------------Update Chat History Windows Async -------------------------------------"); + logger.i("---------------------------------Update Chat History Windows Async -------------------------------------"); } logger.d(items); // for (var user in searchedChats!) { @@ -433,26 +393,14 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { data.first.currentUserName = temp.first.targetUserName; data.first.currentUserEmail = temp.first.targetUserEmail; - if (data.first.fileTypeId == 12 || - data.first.fileTypeId == 4 || - data.first.fileTypeId == 3) { - data.first.image = await ChatApiClient().downloadURL( - fileName: data.first.contant!, - fileTypeDescription: - data.first.fileTypeResponse!.fileTypeDescription ?? - "image/jpg"); + if (data.first.fileTypeId == 12 || data.first.fileTypeId == 4 || data.first.fileTypeId == 3) { + data.first.image = await ChatApiClient().downloadURL(fileName: data.first.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 1); } if (data.first.userChatReplyResponse != null) { if (data.first.fileTypeResponse != null) { - if (data.first.userChatReplyResponse!.fileTypeId == 12 || - data.first.userChatReplyResponse!.fileTypeId == 4 || - data.first.userChatReplyResponse!.fileTypeId == 3) { - data.first.userChatReplyResponse!.image = await ChatApiClient() - .downloadURL( - fileName: data.first.userChatReplyResponse!.contant!, - fileTypeDescription: - data.first.fileTypeResponse!.fileTypeDescription ?? - "image/jpg"); + if (data.first.userChatReplyResponse!.fileTypeId == 12 || data.first.userChatReplyResponse!.fileTypeId == 4 || data.first.userChatReplyResponse!.fileTypeId == 3) { + data.first.userChatReplyResponse!.image = + await ChatApiClient().downloadURL(fileName: data.first.userChatReplyResponse!.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 1); data.first.userChatReplyResponse!.isImageLoaded = true; } } @@ -460,14 +408,11 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } if (searchedChats != null) { - dynamic contain = searchedChats! - .where((ChatUser element) => element.id == data.first.currentUserId); + dynamic contain = searchedChats!.where((ChatUser element) => element.id == data.first.currentUserId); if (contain.isEmpty) { List emails = []; - emails.add(await EmailImageEncryption() - .encrypt(val: data.first.currentUserEmail!)); - List chatImages = - await ChatApiClient().getUsersImages(encryptedEmails: emails); + emails.add(await EmailImageEncryption().encrypt(val: data.first.currentUserEmail!)); + List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); searchedChats!.add( ChatUser( id: data.first.currentUserId, @@ -479,9 +424,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { isImageLoaded: true, userStatus: 1, isTyping: false, - userLocalDownlaodedImage: await downloadImageLocal( - chatImages.first.profilePicture, - data.first.currentUserId.toString()), + userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, data.first.currentUserId.toString()), ), ); } @@ -506,9 +449,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { "userChatHistoryId": data.first.userChatHistoryId, "TargetUserId": temp.first.targetUserId, "isDelivered": true, - "isSeen": isChatScreenActive && data.first.currentUserId == receiverID - ? true - : false + "isSeen": isChatScreenActive && data.first.currentUserId == receiverID ? true : false } ]; updateUserChatHistoryOnMsg(list); @@ -519,38 +460,24 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { Future onGroupMsgReceived(List? parameters) async { List data = [], temp = []; - for (dynamic msg in parameters!) { - // groupChatHistory.add(groupchathistory.GetGroupChatHistoryAsync.fromJson(msg)); + // groupChatHistory.add(groupchathistory.GetGroupChatHistoryAsync.fromJson(msg)); data.add(groupchathistory.GetGroupChatHistoryAsync.fromJson(msg)); - temp =data; + temp = data; // data.first.currentUserId = temp.first.currentUserId; // data.first.currentUserName = temp.first.currentUserName; // // data.first.currentUserId = temp.first.currentUserId; // data.first.currentUserName = temp.first.currentUserName; - - if (data.first.fileTypeId == 12 || - data.first.fileTypeId == 4 || - data.first.fileTypeId == 3) { - data.first.image = await ChatApiClient().downloadURL( - fileName: data.first.contant!, - fileTypeDescription: - data.first.fileTypeResponse!.fileTypeDescription ?? - "image/jpg"); + if (data.first.fileTypeId == 12 || data.first.fileTypeId == 4 || data.first.fileTypeId == 3) { + data.first.image = await ChatApiClient().downloadURL(fileName: data.first.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 2); } if (data.first.groupChatReplyResponse != null) { if (data.first.fileTypeResponse != null) { - if (data.first.groupChatReplyResponse!.fileTypeId == 12 || - data.first.groupChatReplyResponse!.fileTypeId == 4 || - data.first.groupChatReplyResponse!.fileTypeId == 3) { - data.first.groupChatReplyResponse!.image = await ChatApiClient() - .downloadURL( - fileName: data.first.groupChatReplyResponse!.contant!, - fileTypeDescription: - data.first.fileTypeResponse!.fileTypeDescription ?? - "image/jpg"); + if (data.first.groupChatReplyResponse!.fileTypeId == 12 || data.first.groupChatReplyResponse!.fileTypeId == 4 || data.first.groupChatReplyResponse!.fileTypeId == 3) { + data.first.groupChatReplyResponse!.image = + await ChatApiClient().downloadURL(fileName: data.first.groupChatReplyResponse!.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 2); data.first.groupChatReplyResponse!.isImageLoaded = true; } } @@ -583,10 +510,10 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { // ), // ); // } - // } + // } groupChatHistory.insert(0, data.first); setMsgTune(); - // if (isChatScreenActive && data.first.currentUserId == receiverID) { + // if (isChatScreenActive && data.first.currentUserId == receiverID) { // } else { // if (searchedChats != null) { @@ -596,8 +523,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { // user.unreadMessageCount = tempCount + 1; // } // } - sort(); - //} + sort(); + //} //} // // List list = [ @@ -610,13 +537,11 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { // : false // } // ]; - // updateUserChatHistoryOnMsg(list); - // invokeChatCounter(userId: AppState().chatDetails!.response!.id!); + // updateUserChatHistoryOnMsg(list); + // invokeChatCounter(userId: AppState().chatDetails!.response!.id!); notifyListeners(); } - - void OnSubmitChatAsync(List? parameters) { print(isChatScreenActive); print(receiverID); @@ -634,8 +559,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { data.first.currentUserEmail = temp.first.targetUserEmail; } if (isChatScreenActive && data.first.currentUserId == receiverID) { - int index = userChatHistory.indexWhere( - (SingleUserChatModel element) => element.userChatHistoryId == 0); + int index = userChatHistory.indexWhere((SingleUserChatModel element) => element.userChatHistoryId == 0); logger.d(index); userChatHistory[index] = data.first; } @@ -645,8 +569,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { void sort() { searchedChats!.sort( - (ChatUser a, ChatUser b) => - b.unreadMessageCount!.compareTo(a.unreadMessageCount!), + (ChatUser a, ChatUser b) => b.unreadMessageCount!.compareTo(a.unreadMessageCount!), ); } @@ -698,6 +621,15 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { return 13; case ".mp3": return 14; + case ".mp4": + return 16; + case ".mov": + return 16; + case ".avi": + return 16; + case ".flv": + return 16; + default: return 0; } @@ -735,6 +667,15 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { return "audio/aac"; case ".mp3": return "audio/mp3"; + case ".mp4": + return "video/mp4"; + case ".avi": + return "video/avi"; + case ".flv": + return "video/flv"; + case ".mov": + return "video/mov"; + default: return ""; } @@ -777,22 +718,14 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { targetUserName: targetUserName, isReplied: false, fileTypeId: fileTypeId, - userChatReplyResponse: isReply - ? UserChatReplyResponse.fromJson(repliedMsg.first.toJson()) - : null, + userChatReplyResponse: isReply ? UserChatReplyResponse.fromJson(repliedMsg.first.toJson()) : null, fileTypeResponse: isAttachment ? FileTypeResponse( fileTypeId: fileTypeId, - fileTypeName: isVoiceMsg - ? getFileExtension(voiceFile!.path).toString() - : getFileExtension(selectedFile.path).toString(), + fileTypeName: isVoiceMsg ? getFileExtension(voiceFile!.path).toString() : getFileExtension(selectedFile.path).toString(), fileKind: "file", fileName: isVoiceMsg ? msg : selectedFile.path.split("/").last, - fileTypeDescription: isVoiceMsg - ? getFileTypeDescription( - getFileExtension(voiceFile!.path).toString()) - : getFileTypeDescription( - getFileExtension(selectedFile.path).toString()), + fileTypeDescription: isVoiceMsg ? getFileTypeDescription(getFileExtension(voiceFile!.path).toString()) : getFileTypeDescription(getFileExtension(selectedFile.path).toString()), ) : null, image: image, @@ -814,8 +747,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { String chatData = '{"contant":"$msg","contantNo":"$contentNo","chatEventId":$chatEventId,"fileTypeId": $fileTypeId,"currentUserId":${AppState().chatDetails!.response!.id},"chatSource":1,"userChatHistoryLineRequestList":[{"isSeen":false,"isDelivered":false,"targetUserId":$targetUserId,"targetUserStatus":1}],"chatReplyId":$chatReplyId,"conversationId":"$chatCID"}'; - await chatHubConnection - .invoke("AddChatUserAsync", args: [json.decode(chatData)]); + await chatHubConnection.invoke("AddChatUserAsync", args: [json.decode(chatData)]); } //groupChatMessage @@ -834,8 +766,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { int? userStatus, File? voiceFile, required bool isVoiceAttached, - required List userList - }) async { + required List userList}) async { Uuid uuid = const Uuid(); String contentNo = uuid.v4(); String msg; @@ -845,36 +776,36 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { msg = message.text; logger.w(msg); } - groupchathistory.GetGroupChatHistoryAsync data = - groupchathistory.GetGroupChatHistoryAsync( - //userChatHistoryId: 0, - chatEventId: chatEventId, - chatSource: 1, - contant: msg, - contantNo: contentNo, - conversationId: chatCID, - createdDate: DateTime.now().toString(), - currentUserId: AppState().chatDetails!.response!.id, - currentUserName: AppState().chatDetails!.response!.userName, - groupId: targetGroupId, - groupName: targetUserName, - isReplied: false, - fileTypeId: fileTypeId, - fileTypeResponse: isAttachment - ? groupchathistory.FileTypeResponse( - fileTypeId: fileTypeId, - fileTypeName: isVoiceMsg ? getFileExtension(voiceFile!.path).toString() : getFileExtension(selectedFile.path).toString(), - fileKind: "file", - fileName: isVoiceMsg ? msg : selectedFile.path.split("/").last, - fileTypeDescription: isVoiceMsg ? getFileTypeDescription(getFileExtension(voiceFile!.path).toString()) : getFileTypeDescription(getFileExtension(selectedFile.path).toString())) : null, - image: image, - isImageLoaded: isImageLoaded, - voice: isVoiceMsg ? voiceFile! : null, - voiceController: isVoiceMsg ? AudioPlayer() : null); + groupchathistory.GetGroupChatHistoryAsync data = groupchathistory.GetGroupChatHistoryAsync( + //userChatHistoryId: 0, + chatEventId: chatEventId, + chatSource: 1, + contant: msg, + contantNo: contentNo, + conversationId: chatCID, + createdDate: DateTime.now().toString(), + currentUserId: AppState().chatDetails!.response!.id, + currentUserName: AppState().chatDetails!.response!.userName, + groupId: targetGroupId, + groupName: targetUserName, + isReplied: false, + fileTypeId: fileTypeId, + fileTypeResponse: isAttachment + ? groupchathistory.FileTypeResponse( + fileTypeId: fileTypeId, + fileTypeName: isVoiceMsg ? getFileExtension(voiceFile!.path).toString() : getFileExtension(selectedFile.path).toString(), + fileKind: "file", + fileName: isVoiceMsg ? msg : selectedFile.path.split("/").last, + fileTypeDescription: isVoiceMsg ? getFileTypeDescription(getFileExtension(voiceFile!.path).toString()) : getFileTypeDescription(getFileExtension(selectedFile.path).toString())) + : null, + image: image, + isImageLoaded: isImageLoaded, + voice: isVoiceMsg ? voiceFile! : null, + voiceController: isVoiceMsg ? AudioPlayer() : null); if (kDebugMode) { logger.i("model data: " + jsonEncode(data)); } - groupChatHistory.insert(0, data); + groupChatHistory.insert(0, data); isTextMsg = false; isReplyMsg = false; isAttachmentMsg = false; @@ -883,27 +814,26 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { message.clear(); notifyListeners(); - List targetUsers =[]; + List targetUsers = []; for (GroupUserList element in userList) { - targetUsers.add(TargetUsers(isDelivered: false,isSeen: false, targetUserId: element.id, userAction: element.userAction, userStatus: element.userStatus)); - + targetUsers.add(TargetUsers(isDelivered: false, isSeen: false, targetUserId: element.id, userAction: element.userAction, userStatus: element.userStatus)); } String chatData = '{"contant":"$msg","contantNo":"$contentNo","chatEventId":$chatEventId,"fileTypeId":$fileTypeId,"currentUserId":${AppState().chatDetails!.response!.id},"chatSource":1,"groupId":$targetGroupId,"groupChatHistoryLineRequestList":${json.encode(targetUsers)},"chatReplyId": $chatReplyId,"conversationId":"${uuid.v4()}"}'; - await chatHubConnection.invoke("AddGroupChatHistoryAsync", - args: [json.decode(chatData)]); + await chatHubConnection.invoke("AddGroupChatHistoryAsync", args: [json.decode(chatData)]); } - void sendGroupChatMessage(BuildContext context, - {required int targetUserId, - required int userStatus, - required String userEmail, - required String targetUserName, - required List userList, - }) async { + void sendGroupChatMessage( + BuildContext context, { + required int targetUserId, + required int userStatus, + required String userEmail, + required String targetUserName, + required List userList, + }) async { if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { logger.d("// Normal Text Message"); if (message.text.isEmpty) { @@ -922,8 +852,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { isVoiceAttached: false, userEmail: userEmail, userStatus: userStatus, - userList:userList - ); + userList: userList); } else if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && isReplyMsg) { logger.d("// Text Message as Reply"); if (message.text.isEmpty) { @@ -943,15 +872,13 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { voiceFile: null, userEmail: userEmail, userStatus: userStatus, - userList:userList - ); + userList: userList); } // Attachment else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { logger.d("// Normal Image Message"); Utils.showLoading(context); - dynamic value = await uploadAttachments( - AppState().chatDetails!.response!.id.toString(), selectedFile); + dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile, "2"); String? ext = getFileExtension(selectedFile.path); Utils.hideLoading(context); sendGroupChatToServer( @@ -967,19 +894,16 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { isVoiceAttached: false, userEmail: userEmail, userStatus: userStatus, - userList:userList - ); + userList: userList); } else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && isReplyMsg) { logger.d("// Image as Reply Msg"); Utils.showLoading(context); - dynamic value = await uploadAttachments( - AppState().chatDetails!.response!.id.toString(), selectedFile); + dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile, "2"); String? ext = getFileExtension(selectedFile.path); Utils.hideLoading(context); sendGroupChatToServer( chatEventId: 2, fileTypeId: getFileType(ext.toString()), - targetGroupId: targetUserId, targetUserName: targetUserName, isAttachment: true, @@ -990,8 +914,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { isVoiceAttached: false, userEmail: userEmail, userStatus: userStatus, - userList:userList - ); + userList: userList); } //Voice @@ -1011,9 +934,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { isPlaying = false; isRecoding = false; Utils.showLoading(context); - dynamic value = await uploadAttachments( - AppState().chatDetails!.response!.id.toString(), voiceFile); - String? ext = getFileExtension(voiceFile.path); + dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile, "2"); + String? ext = getFileExtension(voiceFile.path); Utils.hideLoading(context); sendGroupChatToServer( chatEventId: 2, @@ -1029,8 +951,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { isVoiceAttached: true, userEmail: userEmail, userStatus: userStatus, - userList:userList - ); + userList: userList); notifyListeners(); } else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && isReplyMsg) { logger.d("// Voice as Reply Msg"); @@ -1049,9 +970,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { isRecoding = false; Utils.showLoading(context); - dynamic value = await uploadAttachments( - AppState().chatDetails!.response!.id.toString(), voiceFile); - String? ext = getFileExtension(voiceFile.path); + dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile, "2"); + String? ext = getFileExtension(voiceFile.path); Utils.hideLoading(context); sendGroupChatToServer( chatEventId: 2, @@ -1066,18 +986,15 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { isVoiceAttached: true, userEmail: userEmail, userStatus: userStatus, - userList:userList - ); + userList: userList); notifyListeners(); } if (searchedChats != null) { - dynamic contain = searchedChats! - .where((ChatUser element) => element.id == targetUserId); + dynamic contain = searchedChats!.where((ChatUser element) => element.id == targetUserId); if (contain.isEmpty) { List emails = []; emails.add(await EmailImageEncryption().encrypt(val: userEmail)); - List chatImages = - await ChatApiClient().getUsersImages(encryptedEmails: emails); + List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); searchedChats!.add( ChatUser( id: targetUserId, @@ -1098,13 +1015,13 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } } - void sendChatMessage(BuildContext context, - {required int targetUserId, - required int userStatus, - required String userEmail, - required String targetUserName, - - }) async { + void sendChatMessage( + BuildContext context, { + required int targetUserId, + required int userStatus, + required String userEmail, + required String targetUserName, + }) async { if (kDebugMode) { print("====================== Values ============================"); print("Is Text " + isTextMsg.toString()); @@ -1155,8 +1072,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { logger.d("// Normal Image Message"); Utils.showLoading(context); - dynamic value = await uploadAttachments( - AppState().chatDetails!.response!.id.toString(), selectedFile); + dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile, "1"); String? ext = getFileExtension(selectedFile.path); Utils.hideLoading(context); sendChatToServer( @@ -1175,8 +1091,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && isReplyMsg) { logger.d("// Image as Reply Msg"); Utils.showLoading(context); - dynamic value = await uploadAttachments( - AppState().chatDetails!.response!.id.toString(), selectedFile); + dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile, "1"); String? ext = getFileExtension(selectedFile.path); Utils.hideLoading(context); sendChatToServer( @@ -1211,8 +1126,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { isPlaying = false; isRecoding = false; Utils.showLoading(context); - dynamic value = await uploadAttachments( - AppState().chatDetails!.response!.id.toString(), voiceFile); + dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile, "1"); String? ext = getFileExtension(voiceFile.path); Utils.hideLoading(context); sendChatToServer( @@ -1246,8 +1160,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { isRecoding = false; Utils.showLoading(context); - dynamic value = await uploadAttachments( - AppState().chatDetails!.response!.id.toString(), voiceFile); + dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile, "1"); String? ext = getFileExtension(voiceFile.path); Utils.hideLoading(context); sendChatToServer( @@ -1266,13 +1179,11 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { notifyListeners(); } if (searchedChats != null) { - dynamic contain = searchedChats! - .where((ChatUser element) => element.id == targetUserId); + dynamic contain = searchedChats!.where((ChatUser element) => element.id == targetUserId); if (contain.isEmpty) { List emails = []; emails.add(await EmailImageEncryption().encrypt(val: userEmail)); - List chatImages = - await ChatApiClient().getUsersImages(encryptedEmails: emails); + List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); searchedChats!.add( ChatUser( id: targetUserId, @@ -1285,8 +1196,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { isTyping: false, isFav: false, userStatus: userStatus, - userLocalDownlaodedImage: await downloadImageLocal( - chatImages.first.profilePicture, targetUserId.toString()), + userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, targetUserId.toString()), ), ); notifyListeners(); @@ -1316,8 +1226,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } void selectImageToUpload(BuildContext context) { - ImageOptions.showImageOptionsNew(context, true, - (String image, File file) async { + ImageOptions.showImageOptionsNew(context, true, (String image, File file) async { if (checkFileSize(file.path)) { selectedFile = file; isAttachmentMsg = true; @@ -1353,8 +1262,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { bool checkFileSize(String path) { int fileSizeLimit = 1024; File f = File(path); - double fileSizeInKB = f.lengthSync() / 1024; - double fileSizeInMB = fileSizeInKB / 1024; + double fileSizeInKB = f.lengthSync() / 5000; + double fileSizeInMB = fileSizeInKB / 5000; if (fileSizeInKB > fileSizeLimit) { return false; } else { @@ -1406,6 +1315,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { repliedMsg.add(data); notifyListeners(); } + void groupChatReply(groupchathistory.GetGroupChatHistoryAsync data) { groupChatReplyData = []; data.isReplied = true; @@ -1413,6 +1323,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { groupChatReplyData.add(data); notifyListeners(); } + void closeMe() { repliedMsg = []; isReplyMsg = false; @@ -1425,18 +1336,13 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { return f.format(data); } - Future favoriteUser( - {required int userID, - required int targetUserID, - required bool fromSearch}) async { - fav.FavoriteChatUser favoriteChatUser = await ChatApiClient() - .favUser(userID: userID, targetUserID: targetUserID); + Future favoriteUser({required int userID, required int targetUserID, required bool fromSearch}) async { + fav.FavoriteChatUser favoriteChatUser = await ChatApiClient().favUser(userID: userID, targetUserID: targetUserID); if (favoriteChatUser.response != null) { for (ChatUser user in searchedChats!) { if (user.id == favoriteChatUser.response!.targetUserId!) { user.isFav = favoriteChatUser.response!.isFav; - dynamic contain = favUsersList!.where((ChatUser element) => - element.id == favoriteChatUser.response!.targetUserId!); + dynamic contain = favUsersList!.where((ChatUser element) => element.id == favoriteChatUser.response!.targetUserId!); if (contain.isEmpty) { favUsersList.add(user); } @@ -1446,8 +1352,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { for (ChatUser user in chatUsersList!) { if (user.id == favoriteChatUser.response!.targetUserId!) { user.isFav = favoriteChatUser.response!.isFav; - dynamic contain = favUsersList!.where((ChatUser element) => - element.id == favoriteChatUser.response!.targetUserId!); + dynamic contain = favUsersList!.where((ChatUser element) => element.id == favoriteChatUser.response!.targetUserId!); if (contain.isEmpty) { favUsersList.add(user); } @@ -1466,10 +1371,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { notifyListeners(); } - Future unFavoriteUser( - {required int userID, required int targetUserID}) async { - fav.FavoriteChatUser favoriteChatUser = await ChatApiClient() - .unFavUser(userID: userID, targetUserID: targetUserID); + Future unFavoriteUser({required int userID, required int targetUserID}) async { + fav.FavoriteChatUser favoriteChatUser = await ChatApiClient().unFavUser(userID: userID, targetUserID: targetUserID); if (favoriteChatUser.response != null) { for (ChatUser user in searchedChats!) { @@ -1574,14 +1477,12 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { emails.add(await EmailImageEncryption().encrypt(val: element.email!)); } - List chatImages = - await ChatApiClient().getUsersImages(encryptedEmails: emails); + List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); for (ChatUser user in searchedChats!) { for (ChatUserImageModel uImage in chatImages) { if (user.email == uImage.email) { user.image = uImage.profilePicture ?? ""; - user.userLocalDownlaodedImage = await downloadImageLocal( - uImage.profilePicture, user.id.toString()); + user.userLocalDownlaodedImage = await downloadImageLocal(uImage.profilePicture, user.id.toString()); user.isImageLoading = false; user.isImageLoaded = true; } @@ -1591,8 +1492,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { for (ChatUserImageModel uImage in chatImages) { if (favUser.email == uImage.email) { favUser.image = uImage.profilePicture ?? ""; - favUser.userLocalDownlaodedImage = await downloadImageLocal( - uImage.profilePicture, favUser.id.toString()); + favUser.userLocalDownlaodedImage = await downloadImageLocal(uImage.profilePicture, favUser.id.toString()); favUser.isImageLoading = false; favUser.isImageLoaded = true; } @@ -1609,8 +1509,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } else { await deleteFile(userID); Uint8List decodedBytes = base64Decode(encodedBytes); - Directory appDocumentsDirectory = - await getApplicationDocumentsDirectory(); + Directory appDocumentsDirectory = await getApplicationDocumentsDirectory(); String dirPath = '${appDocumentsDirectory.path}/chat_images'; if (!await Directory(dirPath).exists()) { await Directory(dirPath).create(); @@ -1633,8 +1532,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { Future downChatMedia(Uint8List bytes, String ext) async { String dir = (await getApplicationDocumentsDirectory()).path; - File file = File( - "$dir/" + DateTime.now().millisecondsSinceEpoch.toString() + "." + ext); + File file = File("$dir/" + DateTime.now().millisecondsSinceEpoch.toString() + "." + ext); await file.writeAsBytes(bytes); return file.path; } @@ -1657,20 +1555,10 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } } - Future getChatMedia(BuildContext context, - {required String fileName, - required String fileTypeName, - required int fileTypeID}) async { + Future getChatMedia(BuildContext context, {required String fileName, required String fileTypeName, required int fileTypeID, required int fileSource}) async { Utils.showLoading(context); - if (fileTypeID == 1 || - fileTypeID == 5 || - fileTypeID == 7 || - fileTypeID == 6 || - fileTypeID == 8 || - fileTypeID == 2) { - Uint8List encodedString = await ChatApiClient().downloadURL( - fileName: fileName, - fileTypeDescription: getFileTypeDescription(fileTypeName)); + if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8 || fileTypeID == 2 || fileTypeID == 16) { + Uint8List encodedString = await ChatApiClient().downloadURL(fileName: fileName, fileTypeDescription: getFileTypeDescription(fileTypeName), fileSource: fileSource); try { String path = await downChatMedia(encodedString, fileTypeName ?? ""); Utils.hideLoading(context); @@ -1692,19 +1580,15 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { return ""; } - void userTypingInvoke( - {required int currentUser, required int reciptUser}) async { - await chatHubConnection - .invoke("UserTypingAsync", args: [reciptUser, currentUser]); + void userTypingInvoke({required int currentUser, required int reciptUser}) async { + await chatHubConnection.invoke("UserTypingAsync", args: [reciptUser, currentUser]); } - void groupTypingInvoke( - {required GroupResponse groupDetails, required int groupId}) async { + + void groupTypingInvoke({required GroupResponse groupDetails, required int groupId}) async { var data = json.decode(json.encode(groupDetails.groupUserList)); - await chatHubConnection - .invoke("GroupTypingAsync", args: ["${groupDetails.adminUser!.userName}",data, groupId ]); + await chatHubConnection.invoke("GroupTypingAsync", args: ["${groupDetails.adminUser!.userName}", data, groupId]); } - //////// Audio Recoding Work //////////////////// Future initAudio({required int receiverId}) async { @@ -1718,8 +1602,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { await Directory(dirPath).create(); await File('$dirPath/.nomedia').create(); } - path = - "$dirPath/${AppState().chatDetails!.response!.id}-$receiverID-${DateTime.now().microsecondsSinceEpoch}.aac"; + path = "$dirPath/${AppState().chatDetails!.response!.id}-$receiverID-${DateTime.now().microsecondsSinceEpoch}.aac"; recorderController = RecorderController() ..androidEncoder = AndroidEncoder.aac ..androidOutputFormat = AndroidOutputFormat.mpeg4 @@ -1849,19 +1732,15 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { return numberStr; } - Future downChatVoice( - Uint8List bytes, String ext, SingleUserChatModel data) async { + Future downChatVoice(Uint8List bytes, String ext, SingleUserChatModel data) async { File file; try { - String dirPath = - '${(await getApplicationDocumentsDirectory()).path}/chat_audios'; + String dirPath = '${(await getApplicationDocumentsDirectory()).path}/chat_audios'; if (!await Directory(dirPath).exists()) { await Directory(dirPath).create(); await File('$dirPath/.nomedia').create(); } - file = File( - "$dirPath/${data.currentUserId}-${data.targetUserId}-${DateTime.now().microsecondsSinceEpoch}" + - ext); + file = File("$dirPath/${data.currentUserId}-${data.targetUserId}-${DateTime.now().microsecondsSinceEpoch}" + ext); await file.writeAsBytes(bytes); } catch (e) { if (kDebugMode) { @@ -1873,14 +1752,10 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } void scrollToMsg(SingleUserChatModel data) { - if (data.userChatReplyResponse != null && - data.userChatReplyResponse!.userChatHistoryId != null) { - int index = userChatHistory.indexWhere((SingleUserChatModel element) => - element.userChatHistoryId == - data.userChatReplyResponse!.userChatHistoryId); + if (data.userChatReplyResponse != null && data.userChatReplyResponse!.userChatHistoryId != null) { + int index = userChatHistory.indexWhere((SingleUserChatModel element) => element.userChatHistoryId == data.userChatReplyResponse!.userChatHistoryId); if (index >= 1) { - double contentSize = scrollController.position.viewportDimension + - scrollController.position.maxScrollExtent; + double contentSize = scrollController.position.viewportDimension + scrollController.position.maxScrollExtent; double target = contentSize * index / userChatHistory.length; scrollController.position.animateTo( target, @@ -1912,18 +1787,14 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { isImageLoading: false, image: element.eMPLOYEEIMAGE ?? "", isImageLoaded: element.eMPLOYEEIMAGE == null ? false : true, - userLocalDownlaodedImage: element.eMPLOYEEIMAGE == null - ? null - : await downloadImageLocal( - element.eMPLOYEEIMAGE ?? "", element.eMPLOYEENUMBER!), + userLocalDownlaodedImage: element.eMPLOYEEIMAGE == null ? null : await downloadImageLocal(element.eMPLOYEEIMAGE ?? "", element.eMPLOYEENUMBER!), ), ); } } } } else { - getEmployeeSubordinatesList = - await MyTeamApiClient().getEmployeeSubordinates("", "", ""); + getEmployeeSubordinatesList = await MyTeamApiClient().getEmployeeSubordinates("", "", ""); AppState().setemployeeSubordinatesList = getEmployeeSubordinatesList; for (GetEmployeeSubordinatesList element in getEmployeeSubordinatesList) { if (element.eMPLOYEEEMAILADDRESS != null) { @@ -1941,10 +1812,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { isImageLoading: false, image: element.eMPLOYEEIMAGE ?? "", isImageLoaded: element.eMPLOYEEIMAGE == null ? false : true, - userLocalDownlaodedImage: element.eMPLOYEEIMAGE == null - ? null - : await downloadImageLocal( - element.eMPLOYEEIMAGE ?? "", element.eMPLOYEENUMBER!), + userLocalDownlaodedImage: element.eMPLOYEEIMAGE == null ? null : await downloadImageLocal(element.eMPLOYEEIMAGE ?? "", element.eMPLOYEENUMBER!), ), ); } @@ -2013,14 +1881,12 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { SingleUserChatModel nUser = SingleUserChatModel(); Utils.saveStringFromPrefs("isAppOpendByChat", "false"); if (await Utils.getStringFromPrefs("notificationData") != "null") { - nUser = SingleUserChatModel.fromJson( - jsonDecode(await Utils.getStringFromPrefs("notificationData"))); + nUser = SingleUserChatModel.fromJson(jsonDecode(await Utils.getStringFromPrefs("notificationData"))); Utils.saveStringFromPrefs("notificationData", "null"); Future.delayed(const Duration(seconds: 2)); for (ChatUser user in searchedChats!) { if (user.id == nUser.targetUserId) { - Navigator.pushNamed(context, AppRoutes.chatDetailed, - arguments: ChatDetailedScreenParams(user, false)); + Navigator.pushNamed(context, AppRoutes.chatDetailed, arguments: ChatDetailedScreenParams(user, false)); return; } } @@ -2057,9 +1923,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { Future getGroupChatHistory(groups.GroupResponse groupDetails) async { isLoading = true; - groupChatHistory = await ChatApiClient().getGroupChatHistory( - groupDetails.groupId, - groupDetails.groupUserList as List); + groupChatHistory = await ChatApiClient().getGroupChatHistory(groupDetails.groupId, groupDetails.groupUserList as List); isLoading = false; @@ -2076,12 +1940,12 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { Future addGroupAndUsers(createGroup.CreateGroupRequest request) async { isLoading = true; var groups = await ChatApiClient().addGroupAndUsers(request); - userGroups.groupresponse! - .add(GroupResponse.fromJson(json.decode(groups)['response'])); + userGroups.groupresponse!.add(GroupResponse.fromJson(json.decode(groups)['response'])); isLoading = false; notifyListeners(); } + Future updateGroupAndUsers(createGroup.CreateGroupRequest request) async { isLoading = true; await ChatApiClient().updateGroupAndUsers(request); diff --git a/lib/ui/chat/chat_bubble.dart b/lib/ui/chat/chat_bubble.dart index d6483dc..28103f8 100644 --- a/lib/ui/chat/chat_bubble.dart +++ b/lib/ui/chat/chat_bubble.dart @@ -1,5 +1,4 @@ import 'dart:io'; -import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -18,9 +17,9 @@ import 'package:mohem_flutter_app/models/chat/get_single_user_chat_list_model.da import 'package:mohem_flutter_app/provider/chat_provider_model.dart'; import 'package:mohem_flutter_app/ui/chat/chat_full_image_preview.dart'; import 'package:mohem_flutter_app/ui/chat/common.dart'; -import 'package:path_provider/path_provider.dart'; import 'package:provider/provider.dart'; import 'package:rxdart/rxdart.dart'; +import 'package:video_player/video_player.dart'; class ChatBubble extends StatelessWidget { ChatBubble({Key? key, required this.dateTime, required this.cItem}) : super(key: key); @@ -82,7 +81,8 @@ class ChatBubble extends StatelessWidget { } } else { Utils.showLoading(context); - Uint8List encodedString = await ChatApiClient().downloadURL(fileName: data.contant!, fileTypeDescription: provider.getFileTypeDescription(data.fileTypeResponse!.fileTypeName ?? "")); + Uint8List encodedString = + await ChatApiClient().downloadURL(fileName: data.contant!, fileTypeDescription: provider.getFileTypeDescription(data.fileTypeResponse!.fileTypeName ?? ""), fileSource: 1); // try { File sFile = await provider.downChatVoice(encodedString, data.fileTypeResponse!.fileTypeName ?? "", data); if (sFile.path.isEmpty) { @@ -195,20 +195,26 @@ class ChatBubble extends StatelessWidget { }), ), ).paddingOnly(bottom: 4), - if (fileTypeID == 13 && cItem.voiceController != null) - currentWaveBubble(context, cItem) + if (fileTypeID == 13 && cItem.voiceController != null) currentWaveBubble(context, cItem), + if (fileTypeID == 16) + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + showVideoThumb(context, cItem), + Row( + children: [ + Directionality(textDirection: provider.getTextDirection(cItem.contant ?? ""), child: (cItem.contant ?? "").toText12().expanded), + ], + ), + ], + ) else Row( children: [ - if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8 - // || fileTypeID == 2 - ) + if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8) SvgPicture.asset(provider.getType(fileTypeName ?? ""), height: 30, width: 22, alignment: Alignment.center, fit: BoxFit.cover).paddingOnly(left: 0, right: 10), Directionality(textDirection: provider.getTextDirection(cItem.contant ?? ""), child: (cItem.contant ?? "").toText12().expanded), - if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8 - //|| fileTypeID == 2 - ) - const Icon(Icons.remove_red_eye, size: 16) + if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8) const Icon(Icons.remove_red_eye, size: 16) ], ), Align( @@ -276,7 +282,12 @@ class ChatBubble extends StatelessWidget { child: showImage( isReplyPreview: true, fileName: cItem.userChatReplyResponse!.contant!, - fileTypeDescription: cItem.userChatReplyResponse!.fileTypeResponse!.fileTypeDescription ?? "image/jpg"), + fileTypeDescription: cItem.fileTypeResponse != null && cItem.fileTypeResponse!.fileTypeDescription != null + ? cItem.fileTypeResponse!.fileTypeDescription + : cItem.fileTypeResponse!.fileTypeName + // fileTypeDescription: cItem.userChatReplyResponse!.fileTypeResponse!.fileTypeDescription ?? "image/jpg" + + ), ), ).paddingOnly(left: 10, right: 10, bottom: 16, top: 16) ], @@ -300,20 +311,26 @@ class ChatBubble extends StatelessWidget { }), ), ).paddingOnly(bottom: 4), - if (fileTypeID == 13 && cItem.voiceController != null) - recipetWaveBubble(context, cItem) + if (fileTypeID == 13 && cItem.voiceController != null) recipetWaveBubble(context, cItem), + if (fileTypeID == 16) + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + showVideoThumb(context, cItem), + Row( + children: [ + Directionality(textDirection: provider.getTextDirection(cItem.contant ?? ""), child: (cItem.contant ?? "").toText12(color: Colors.white).expanded), + ], + ), + ], + ) else Row( children: [ - if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8 - // || fileTypeID == 2 - ) + if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8) SvgPicture.asset(provider.getType(fileTypeName ?? ""), height: 30, width: 22, alignment: Alignment.center, fit: BoxFit.cover).paddingOnly(left: 0, right: 10), Directionality(textDirection: provider.getTextDirection(cItem.contant ?? ""), child: (cItem.contant ?? "").toText12(color: Colors.white).expanded), - if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8 - //|| fileTypeID == 2 - ) - const Icon(Icons.remove_red_eye, color: Colors.white, size: 16) + if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8) const Icon(Icons.remove_red_eye, color: Colors.white, size: 16) ], ), Align( @@ -324,11 +341,7 @@ class ChatBubble extends StatelessWidget { ), ], ), - ).paddingOnly(right: MediaQuery.of(context).size.width * 0.3); - } - - Widget voiceMsg(BuildContext context) { - return Container(); + ).paddingOnly(right: MediaQuery.of(context).size.width * 0.33); } Widget showImage({required bool isReplyPreview, required String fileName, required String fileTypeDescription}) { @@ -342,7 +355,7 @@ class ChatBubble extends StatelessWidget { ); } else { return FutureBuilder( - future: ChatApiClient().downloadURL(fileName: fileName, fileTypeDescription: fileTypeDescription), + future: ChatApiClient().downloadURL(fileName: fileName, fileTypeDescription: fileTypeDescription, fileSource: 1), builder: (BuildContext context, AsyncSnapshot snapshot) { if (snapshot.connectionState != ConnectionState.waiting) { if (snapshot.data == null) { @@ -470,4 +483,50 @@ class ChatBubble extends StatelessWidget { }, ); } + + Widget showVideoThumb(BuildContext context, SingleUserChatModel data) { + return LoadVideo(data: data); + } +} + +class LoadVideo extends StatefulWidget { + final SingleUserChatModel data; + + const LoadVideo({Key? key, required this.data}) : super(key: key); + + @override + State createState() => _LoadVideoState(); +} + +class _LoadVideoState extends State { + late VideoPlayerController videoController; + + @override + void initState() { + videoController = VideoPlayerController.networkUrl(Uri.parse('https://apiderichat.hmg.com/attachments/${widget.data.fileTypeResponse?.fileName}'))..initialize().then((_) {}); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return ClipRRect( + borderRadius: BorderRadius.circular(5.0), + child: AspectRatio( + aspectRatio: videoController.value.aspectRatio, + child: Stack( + alignment: Alignment.bottomCenter, + children: [ + VideoPlayer(videoController), + Align( + alignment: Alignment.center, + child: Icon( + Icons.play_arrow, + color: Colors.white.withOpacity(.7), + size: 56, + ), + ) + ], + ), + )); + } } diff --git a/lib/ui/chat/chat_detailed_screen.dart b/lib/ui/chat/chat_detailed_screen.dart index a81219b..8cafdec 100644 --- a/lib/ui/chat/chat_detailed_screen.dart +++ b/lib/ui/chat/chat_detailed_screen.dart @@ -152,14 +152,13 @@ class _ChatDetailScreenState extends State { logger.w(m.userChatHistory[i].toJson()); if (m.userChatHistory[i].fileTypeResponse != null && m.userChatHistory[i].fileTypeId != null) { if (m.userChatHistory[i].fileTypeId! == 1 || - m.userChatHistory[i].fileTypeId! == 5 || - m.userChatHistory[i].fileTypeId! == 7 || - m.userChatHistory[i].fileTypeId! == 6 || - m.userChatHistory[i].fileTypeId! == 8 - // || m.userChatHistory[i].fileTypeId! == 2 - ) { + m.userChatHistory[i].fileTypeId! == 5 || + m.userChatHistory[i].fileTypeId! == 7 || + m.userChatHistory[i].fileTypeId! == 6 || + m.userChatHistory[i].fileTypeId! == 8 || + m.userChatHistory[i].fileTypeId! == 16) { m.getChatMedia(context, - fileTypeName: m.userChatHistory[i].fileTypeResponse!.fileTypeName ?? "", fileTypeID: m.userChatHistory[i].fileTypeId!, fileName: m.userChatHistory[i].contant!); + fileTypeName: m.userChatHistory[i].fileTypeResponse!.fileTypeName ?? "", fileTypeID: m.userChatHistory[i].fileTypeId!, fileName: m.userChatHistory[i].contant!, fileSource: 1); } } }); diff --git a/lib/ui/chat/group_chat_bubble.dart b/lib/ui/chat/group_chat_bubble.dart index 69a50df..9907ed9 100644 --- a/lib/ui/chat/group_chat_bubble.dart +++ b/lib/ui/chat/group_chat_bubble.dart @@ -22,6 +22,7 @@ import 'package:mohem_flutter_app/ui/chat/common.dart'; import 'package:path_provider/path_provider.dart'; import 'package:provider/provider.dart'; import 'package:rxdart/rxdart.dart'; +import 'package:video_player/video_player.dart'; class GroupChatBubble extends StatelessWidget { GroupChatBubble({Key? key, required this.dateTime, required this.cItem}) @@ -66,19 +67,19 @@ class GroupChatBubble extends StatelessWidget { ? cItem.fileTypeResponse!.fileTypeDescription : ""; isDelivered = cItem.currentUserId == AppState().chatDetails!.response!.id && - cItem.isDelivered == true + cItem.isDelivered == true ? true : false; userName = AppState().chatDetails!.response!.userName == - cItem.currentUserName.toString() + cItem.currentUserName.toString() ? "You" : cItem.currentUserName.toString(); } void playVoice( - BuildContext context, { - required SingleUserChatModel data, - }) async { + BuildContext context, { + required SingleUserChatModel data, + }) async { if (data.voice != null && data.voice!.existsSync()) { if (Platform.isIOS) { Duration? duration = await data.voiceController! @@ -100,7 +101,7 @@ class GroupChatBubble extends StatelessWidget { Uint8List encodedString = await ChatApiClient().downloadURL( fileName: data.contant!, fileTypeDescription: provider.getFileTypeDescription( - data.fileTypeResponse!.fileTypeName ?? "")); + data.fileTypeResponse!.fileTypeName ?? ""), fileSource: 2); // try { File sFile = await provider.downChatVoice( encodedString, data.fileTypeResponse!.fileTypeName ?? "", data); @@ -122,7 +123,7 @@ class GroupChatBubble extends StatelessWidget { data.voiceController!.play(); } else { Duration? duration = - await data.voiceController!.setFilePath(sFile.path); + await data.voiceController!.setFilePath(sFile.path); await data.voiceController!.setLoopMode(LoopMode.off); await data.voiceController!.seek(duration); Utils.hideLoading(context); @@ -148,7 +149,7 @@ class GroupChatBubble extends StatelessWidget { cItem.voiceController!.positionStream, cItem.voiceController!.bufferedPositionStream, cItem.voiceController!.durationStream, - (Duration position, Duration bufferedPosition, Duration? duration) => + (Duration position, Duration bufferedPosition, Duration? duration) => PositionData( position, bufferedPosition, duration ?? Duration.zero)); @@ -189,24 +190,24 @@ class GroupChatBubble extends StatelessWidget { children: [ (userName) .toText12( - color: MyColors.gradiantStartColor, isBold: false) + color: MyColors.gradiantStartColor, isBold: false) .paddingOnly(right: 5, top: 5, bottom: 0, left: 5), Directionality( textDirection: provider.getTextDirection( cItem.groupChatReplyResponse != null ? cItem.groupChatReplyResponse!.contant - .toString() + .toString() : ""), child: (cItem.groupChatReplyResponse != null - ? cItem.groupChatReplyResponse!.contant - .toString() - : "") + ? cItem.groupChatReplyResponse!.contant + .toString() + : "") .toText10( - color: isCurrentUser - ? MyColors.grey71Color - : MyColors.white.withOpacity(0.5), - isBold: false, - maxlines: 4) + color: isCurrentUser + ? MyColors.grey71Color + : MyColors.white.withOpacity(0.5), + isBold: false, + maxlines: 4) .paddingOnly(right: 5, top: 5, bottom: 8, left: 5), ), ], @@ -223,11 +224,11 @@ class GroupChatBubble extends StatelessWidget { child: showImage( isReplyPreview: false, fileName: - cItem.groupChatReplyResponse!.contant!, + cItem.groupChatReplyResponse!.contant!, fileTypeDescription: cItem - .groupChatReplyResponse! - .fileTypeResponse! - .fileTypeDescription ?? + .groupChatReplyResponse! + .fileTypeResponse! + .fileTypeDescription ?? "image/jpg")), ).paddingOnly(left: 10, right: 10, bottom: 16, top: 16), ], @@ -243,10 +244,13 @@ class GroupChatBubble extends StatelessWidget { height: 140, width: 227, child: showImage( - isReplyPreview: false, - fileName: cItem.contant!, - fileTypeDescription: - cItem.fileTypeResponse!.fileTypeDescription) + isReplyPreview: false, + fileName: cItem.contant!, + fileTypeDescription: cItem.fileTypeResponse != null && + cItem.fileTypeResponse!.fileTypeDescription != + null + ? cItem.fileTypeResponse!.fileTypeDescription + : cItem.fileTypeResponse!.fileTypeName) .onPress(() { showDialog( context: context, @@ -258,7 +262,9 @@ class GroupChatBubble extends StatelessWidget { ), ).paddingOnly(bottom: 4), if (fileTypeID == 13 && cItem.voiceController != null) - currentWaveBubble(context, cItem) + currentWaveBubble(context, cItem), + if (fileTypeID == 16) + showVideoThumb(context, cItem) else Row( children: [ @@ -270,10 +276,10 @@ class GroupChatBubble extends StatelessWidget { // || fileTypeID == 2 ) SvgPicture.asset(provider.getType(fileTypeName ?? ""), - height: 30, - width: 22, - alignment: Alignment.center, - fit: BoxFit.cover) + height: 30, + width: 22, + alignment: Alignment.center, + fit: BoxFit.cover) .paddingOnly(left: 0, right: 10), Directionality( textDirection: provider.getTextDirection(cItem.contant ?? ""), @@ -349,27 +355,27 @@ class GroupChatBubble extends StatelessWidget { children: [ (userName) .toText12( - color: MyColors.gradiantStartColor, - isBold: false) + color: MyColors.gradiantStartColor, + isBold: false) .paddingOnly(right: 5, top: 5, bottom: 0, left: 5), Directionality( textDirection: provider.getTextDirection( cItem.groupChatReplyResponse != null ? cItem.groupChatReplyResponse!.contant - .toString() + .toString() : ""), child: (cItem.groupChatReplyResponse != null - ? cItem.groupChatReplyResponse!.contant - .toString() - : "") + ? cItem.groupChatReplyResponse!.contant + .toString() + : "") .toText10( - color: isCurrentUser - ? MyColors.grey71Color - : MyColors.white.withOpacity(0.5), - isBold: false, - maxlines: 4) + color: isCurrentUser + ? MyColors.grey71Color + : MyColors.white.withOpacity(0.5), + isBold: false, + maxlines: 4) .paddingOnly( - right: 5, top: 5, bottom: 8, left: 5), + right: 5, top: 5, bottom: 8, left: 5), ), ], ).expanded, @@ -385,11 +391,11 @@ class GroupChatBubble extends StatelessWidget { child: showImage( isReplyPreview: true, fileName: - cItem.groupChatReplyResponse!.contant!, + cItem.groupChatReplyResponse!.contant!, fileTypeDescription: cItem - .groupChatReplyResponse! - .fileTypeResponse! - .fileTypeDescription ?? + .groupChatReplyResponse! + .fileTypeResponse! + .fileTypeDescription ?? "image/jpg"), ), ).paddingOnly(left: 10, right: 10, bottom: 16, top: 16) @@ -406,11 +412,11 @@ class GroupChatBubble extends StatelessWidget { height: 140, width: 227, child: showImage( - isReplyPreview: false, - fileName: cItem.contant ?? "", - fileTypeDescription: - cItem.fileTypeResponse!.fileTypeDescription ?? - "image/jpg") + isReplyPreview: false, + fileName: cItem.contant ?? "", + fileTypeDescription: + cItem.fileTypeResponse!.fileTypeDescription ?? + "image/jpg") .onPress(() { showDialog( context: context, @@ -422,14 +428,18 @@ class GroupChatBubble extends StatelessWidget { ), ).paddingOnly(bottom: 4), if (fileTypeID == 13 && cItem.voiceController != null) - recipetWaveBubble(context, cItem) + recipetWaveBubble(context, cItem), + if (fileTypeID == 16) + showVideoThumb(context, cItem) else Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - cItem.currentUserName!.toText10( + cItem.currentUserName! + .toText10( color: Colors.black, - ).paddingOnly(bottom: 5), + ) + .paddingOnly(bottom: 5), Row( children: [ if (fileTypeID == 1 || @@ -440,14 +450,14 @@ class GroupChatBubble extends StatelessWidget { // || fileTypeID == 2 ) SvgPicture.asset(provider.getType(fileTypeName ?? ""), - height: 30, - width: 22, - alignment: Alignment.center, - fit: BoxFit.cover) + height: 30, + width: 22, + alignment: Alignment.center, + fit: BoxFit.cover) .paddingOnly(left: 0, right: 10), Directionality( textDirection: - provider.getTextDirection(cItem.contant ?? ""), + provider.getTextDirection(cItem.contant ?? ""), child: (cItem.contant ?? "") .toText12(color: Colors.white) .expanded), @@ -464,9 +474,11 @@ class GroupChatBubble extends StatelessWidget { ), Align( alignment: Alignment.topRight, - child: dateTime.toText10( + child: dateTime + .toText10( color: Colors.white.withOpacity(.71), - ).paddingOnly(top:5), + ) + .paddingOnly(top: 5), ), ], ), @@ -479,8 +491,8 @@ class GroupChatBubble extends StatelessWidget { Widget showImage( {required bool isReplyPreview, - required String fileName, - required String fileTypeDescription}) { + required String fileName, + required String fileTypeDescription}) { if (cItem.isImageLoaded != null && cItem.image != null) { return Image.memory( cItem.image!, @@ -492,7 +504,7 @@ class GroupChatBubble extends StatelessWidget { } else { return FutureBuilder( future: ChatApiClient().downloadURL( - fileName: fileName, fileTypeDescription: fileTypeDescription), + fileName: fileName, fileTypeDescription: fileTypeDescription, fileSource:2), builder: (BuildContext context, AsyncSnapshot snapshot) { if (snapshot.connectionState != ConnectionState.waiting) { if (snapshot.data == null) { @@ -528,7 +540,7 @@ class GroupChatBubble extends StatelessWidget { left: BorderSide( width: 6, color: - isCurrentUser ? MyColors.gradiantStartColor : MyColors.white), + isCurrentUser ? MyColors.gradiantStartColor : MyColors.white), ), color: isCurrentUser ? MyColors.black.withOpacity(0.10) @@ -547,7 +559,7 @@ class GroupChatBubble extends StatelessWidget { duration: positionData?.duration ?? Duration.zero, position: positionData?.position ?? Duration.zero, bufferedPosition: - positionData?.bufferedPosition ?? Duration.zero, + positionData?.bufferedPosition ?? Duration.zero, onChangeEnd: data.voiceController!.seek, ).expanded; }, @@ -557,6 +569,11 @@ class GroupChatBubble extends StatelessWidget { ).circle(5); } + Widget showVideoThumb(BuildContext context, GetGroupChatHistoryAsync data) { + + return LoadVideo(data: data); + } + Widget recipetWaveBubble( BuildContext context, GetGroupChatHistoryAsync data) { return Container( @@ -566,7 +583,7 @@ class GroupChatBubble extends StatelessWidget { left: BorderSide( width: 6, color: - isCurrentUser ? MyColors.gradiantStartColor : MyColors.white), + isCurrentUser ? MyColors.gradiantStartColor : MyColors.white), ), color: isCurrentUser ? MyColors.black.withOpacity(0.10) @@ -586,7 +603,7 @@ class GroupChatBubble extends StatelessWidget { duration: positionData?.duration ?? Duration.zero, position: positionData?.position ?? Duration.zero, bufferedPosition: - positionData?.bufferedPosition ?? Duration.zero, + positionData?.bufferedPosition ?? Duration.zero, onChangeEnd: data.voiceController!.seek, ).expanded; }, @@ -641,3 +658,51 @@ class GroupChatBubble extends StatelessWidget { ); } } + +class LoadVideo extends StatefulWidget { + final GetGroupChatHistoryAsync data; + const LoadVideo({Key? key, required this.data}) : super(key: key); + + @override + State createState() => _LoadVideoState(); +} + +class _LoadVideoState extends State { + late VideoPlayerController videoController; + + @override + void initState() { + videoController = VideoPlayerController.networkUrl(Uri.parse( + 'https://apiderichat.hmg.com/groupattachments/${widget.data.fileTypeResponse?.fileName}')) + ..initialize().then((_) { + + }); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Container( + margin: const EdgeInsets.all(10), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + ), + child: AspectRatio( + aspectRatio: videoController.value.aspectRatio, + child: Stack( + alignment: Alignment.bottomCenter, + children: [ + VideoPlayer(videoController), + Align( + alignment: Alignment.center, + child: Icon( + Icons.play_arrow, + color: Colors.white.withOpacity(.7), + size: 56, + ), + ) + ], + ), + )); + } +} \ No newline at end of file diff --git a/lib/ui/chat/group_chat_detaied_screen.dart b/lib/ui/chat/group_chat_detaied_screen.dart index 84ae3bd..83fb09e 100644 --- a/lib/ui/chat/group_chat_detaied_screen.dart +++ b/lib/ui/chat/group_chat_detaied_screen.dart @@ -58,11 +58,11 @@ class _GroupChatDetailScreenState extends State { data.paginationVal = data.paginationVal + 10; if (params != null) { data.getGroupChatHistory(params!.groupChatDetails! - // senderUID: AppState().chatDetails!.response!.id!.toInt(), - // receiverUID: params!.groupChatDetails!.groupId!, - // loadMore: true, - // isNewChat: false, - ); + // senderUID: AppState().chatDetails!.response!.id!.toInt(), + // receiverUID: params!.groupChatDetails!.groupId!, + // loadMore: true, + // isNewChat: false, + ); } } await Future.delayed( @@ -83,13 +83,12 @@ class _GroupChatDetailScreenState extends State { data = Provider.of(context, listen: false); // callPro = Provider.of(context, listen: false); if (params != null) { - data.getGroupChatHistory( - params!.groupChatDetails! - // senderUID: AppState().chatDetails!.response!.id!.toInt(), - // receiverUID: params!.groupChatHistory!.groupId!, - // loadMore: false, - // isNewChat: params!.isNewChat!, - ); + data.getGroupChatHistory(params!.groupChatDetails! + // senderUID: AppState().chatDetails!.response!.id!.toInt(), + // receiverUID: params!.groupChatHistory!.groupId!, + // loadMore: false, + // isNewChat: params!.isNewChat!, + ); data.initAudio(receiverId: params!.groupChatDetails!.groupId!); } @@ -99,8 +98,8 @@ class _GroupChatDetailScreenState extends State { context, title: params!.groupChatDetails!.groupName.toString().replaceAll(".", " ").capitalizeFirstofEach, showHomeButton: false, - // showTyping: true, - // chatUser: params!.groupChatHistory!.groupChatHistoryTargetUserList as ChatUser, + // showTyping: true, + // chatUser: params!.groupChatHistory!.groupChatHistoryTargetUserList as ChatUser, actions: [ // SvgPicture.asset("assets/icons/chat/call.svg", width: 21, height: 23).onPress(() { // makeCall(callType: "AUDIO"); @@ -117,224 +116,219 @@ class _GroupChatDetailScreenState extends State { builder: (BuildContext context, ChatProviderModel m, Widget? child) { return (m.isLoading ? ChatHomeShimmer( - isDetailedScreen: true, - ) + isDetailedScreen: true, + ) : Column( - children: [ - SmartRefresher( - enablePullDown: false, - enablePullUp: true, - onLoading: () { - getMoreChat(); - }, - header: const MaterialClassicHeader( - color: MyColors.gradiantEndColor, - ), - controller: _rc, - reverse: true, - child: ListView.separated( - controller: m.scrollController, - shrinkWrap: true, - physics: const BouncingScrollPhysics(), - reverse: true, - itemCount: m.groupChatHistory.length, - padding: const EdgeInsets.all(21), - separatorBuilder: (BuildContext cxt, int index) => 8.height, - itemBuilder: (BuildContext context, int i) { - return SwipeTo( - iconColor: MyColors.lightGreenColor, - child: GroupChatBubble( - dateTime: m.groupChatHistory[i].createdDate!, - cItem: m.groupChatHistory[i], - ), - onRightSwipe: (val) { - m.groupChatReply( - m.groupChatHistory[i], - ); + children: [ + SmartRefresher( + enablePullDown: false, + enablePullUp: true, + onLoading: () { + getMoreChat(); }, - ).onPress(() async { - logger.w(m.userChatHistory[i].toJson()); - if (m.userChatHistory[i].fileTypeResponse != null && m.userChatHistory[i].fileTypeId != null) { - if (m.userChatHistory[i].fileTypeId! == 1 || - m.userChatHistory[i].fileTypeId! == 5 || - m.userChatHistory[i].fileTypeId! == 7 || - m.userChatHistory[i].fileTypeId! == 6 || - m.userChatHistory[i].fileTypeId! == 8 - // || m.userChatHistory[i].fileTypeId! == 2 - ) { - m.getChatMedia(context, - fileTypeName: m.userChatHistory[i].fileTypeResponse!.fileTypeName ?? "", fileTypeID: m.userChatHistory[i].fileTypeId!, fileName: m.userChatHistory[i].contant!); - } - } - }); - }, - ), - ).expanded, - if (m.isReplyMsg) - SizedBox( - height: 82, - child: Row( - children: [ - Container(height: 82, color: MyColors.textMixColor, width: 6), - Container( - color: MyColors.darkTextColor.withOpacity(0.10), - padding: const EdgeInsets.only(top: 11, left: 14, bottom: 14, right: 21), + header: const MaterialClassicHeader( + color: MyColors.gradiantEndColor, + ), + controller: _rc, + reverse: true, + child: ListView.separated( + controller: m.scrollController, + shrinkWrap: true, + physics: const BouncingScrollPhysics(), + reverse: true, + itemCount: m.groupChatHistory.length, + padding: const EdgeInsets.all(21), + separatorBuilder: (BuildContext cxt, int index) => 8.height, + itemBuilder: (BuildContext context, int i) { + return SwipeTo( + iconColor: MyColors.lightGreenColor, + child: GroupChatBubble( + dateTime: m.groupChatHistory[i].createdDate!, + cItem: m.groupChatHistory[i], + ), + onRightSwipe: (val) { + m.groupChatReply( + m.groupChatHistory[i], + ); + }, + ).onPress(() async { + logger.w(m.userChatHistory[i].toJson()); + if (m.userChatHistory[i].fileTypeResponse != null && m.userChatHistory[i].fileTypeId != null) { + if (m.userChatHistory[i].fileTypeId! == 1 || + m.userChatHistory[i].fileTypeId! == 5 || + m.userChatHistory[i].fileTypeId! == 7 || + m.userChatHistory[i].fileTypeId! == 6 || + m.userChatHistory[i].fileTypeId! == 8 || + m.userChatHistory[i].fileTypeId! == 16) { + m.getChatMedia(context, + fileTypeName: m.userChatHistory[i].fileTypeResponse!.fileTypeName ?? "", fileTypeID: m.userChatHistory[i].fileTypeId!, fileName: m.userChatHistory[i].contant!, fileSource: 2); + } + } + }); + }, + ), + ).expanded, + if (m.isReplyMsg) + SizedBox( + height: 82, child: Row( - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - (AppState().chatDetails!.response!.userName == m.groupChatReplyData.first.currentUserName.toString() - ? "You" - : m.groupChatReplyData.first.currentUserName.toString().replaceAll(".", " ")) - .toText14(color: MyColors.lightGreenColor), - (m.groupChatReplyData.isNotEmpty ? m.groupChatReplyData.first.contant! : "").toText12(color: MyColors.grey71Color, maxLine: 2) - ], + children: [ + Container(height: 82, color: MyColors.textMixColor, width: 6), + Container( + color: MyColors.darkTextColor.withOpacity(0.10), + padding: const EdgeInsets.only(top: 11, left: 14, bottom: 14, right: 21), + child: Row( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + (AppState().chatDetails!.response!.userName == m.groupChatReplyData.first.currentUserName.toString() + ? "You" + : m.groupChatReplyData.first.currentUserName.toString().replaceAll(".", " ")) + .toText14(color: MyColors.lightGreenColor), + (m.groupChatReplyData.isNotEmpty ? m.groupChatReplyData.first.contant! : "").toText12(color: MyColors.grey71Color, maxLine: 2) + ], + ).expanded, + 12.width, + if (m.isReplyMsg && m.groupChatReplyData.isNotEmpty) showReplyImage(m.groupChatReplyData, m), + 12.width, + const Icon(Icons.cancel, size: 23, color: MyColors.grey7BColor).onPress(m.closeMe), + ], + ), ).expanded, - 12.width, - if (m.isReplyMsg && m.groupChatReplyData.isNotEmpty) showReplyImage(m.groupChatReplyData, m), - 12.width, - const Icon(Icons.cancel, size: 23, color: MyColors.grey7BColor).onPress(m.closeMe), ], ), - ).expanded, - ], - ), - ), - if (m.isAttachmentMsg && m.sFileType == ".png" || m.sFileType == ".jpeg" || m.sFileType == ".jpg") - SizedBox(height: 200, width: double.infinity, child: Image.file(m.selectedFile, fit: BoxFit.cover)).paddingOnly(left: 21, right: 21, top: 21), - const Divider(height: 1, color: MyColors.lightGreyEFColor), - if (m.isRecoding) - Column( - children: [ - Row( - children: [ - Text(m.buildTimer()).paddingAll(10), - if (m.isRecoding && m.isPlaying) - WaveBubble( - playerController: m.playerController, - isPlaying: m.playerController.playerState == PlayerState.playing, - onTap: () {}, - ).expanded - else - AudioWaveforms( - waveStyle: const WaveStyle( - waveColor: MyColors.lightGreenColor, - middleLineColor: Colors.transparent, - extendWaveform: true, - showBottom: true, - showTop: true, - waveThickness: 2, - showMiddleLine: false, - middleLineThickness: 0, - ), - padding: const EdgeInsets.all(5), - shouldCalculateScrolledPosition: false, - margin: EdgeInsets.zero, - size: const Size(double.infinity, 30.0), - recorderController: m.recorderController, - backgroundColor: Colors.white, - ).expanded, - ], - ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Icon( - Icons.delete_outlined, - size: 26, - color: MyColors.lightGreenColor, - ).paddingAll(10).onPress(() { - m.deleteRecoding(); - }), - SvgPicture.asset("assets/icons/chat/chat_send_icon.svg", height: 26, width: 26) - .onPress( - () => m.sendGroupChatMessage(context, - targetUserId: params!.groupChatDetails!.groupId!, - userStatus: 0, - userEmail: "", - targetUserName: params!.groupChatDetails!.groupName!, - userList: params!.groupChatDetails!.groupUserList! - ), - ) - .paddingOnly(right: 21), - ], - ), - ], - ).objectContainerView(disablePadding: true, radius: 0), - if (!m.isRecoding) - Row( - children: [ - CustomAutoDirection( - onDirectionChange: (bool isRTL) => m.onDirectionChange(isRTL), - text: m.msgText, - child: TextField( - // textDirection: m.textDirection, - controller: m.message, - decoration: InputDecoration( - hintTextDirection: m.textDirection, - hintText: m.isAttachmentMsg ? m.selectedFile.path.split("/").last : LocaleKeys.typeheretoreply.tr(), - hintStyle: TextStyle(color: m.isAttachmentMsg ? MyColors.darkTextColor : MyColors.grey98Color, fontSize: 14), - border: InputBorder.none, - focusedBorder: InputBorder.none, - enabledBorder: InputBorder.none, - errorBorder: InputBorder.none, - disabledBorder: InputBorder.none, - filled: true, - fillColor: MyColors.white, - contentPadding: const EdgeInsets.only( - left: 21, - top: 20, - bottom: 20, - ), - prefixIconConstraints: const BoxConstraints(), - prefixIcon: m.sFileType.isNotEmpty - ? SvgPicture.asset(m.getType(m.sFileType), height: 30, width: 22, alignment: Alignment.center, fit: BoxFit.cover).paddingOnly(left: 21, right: 15) - : null, - ), - onChanged: (String val) { - m.inputBoxDirection(val); - m.groupTypingInvoke(groupDetails: params!.groupChatDetails!, groupId: params!.groupChatDetails!.groupId!); - }, - ).expanded, - ), - if (m.sFileType.isNotEmpty) - Row( + ), + if (m.isAttachmentMsg && m.sFileType == ".png" || m.sFileType == ".jpeg" || m.sFileType == ".jpg") + SizedBox(height: 200, width: double.infinity, child: Image.file(m.selectedFile, fit: BoxFit.cover)).paddingOnly(left: 21, right: 21, top: 21), + const Divider(height: 1, color: MyColors.lightGreyEFColor), + if (m.isRecoding) + Column( children: [ - const Icon(Icons.cancel, size: 15, color: MyColors.redA3Color).paddingOnly(right: 5), - ("Clear").toText11(color: MyColors.redA3Color, isUnderLine: true).paddingOnly(left: 0), + Row( + children: [ + Text(m.buildTimer()).paddingAll(10), + if (m.isRecoding && m.isPlaying) + WaveBubble( + playerController: m.playerController, + isPlaying: m.playerController.playerState == PlayerState.playing, + onTap: () {}, + ).expanded + else + AudioWaveforms( + waveStyle: const WaveStyle( + waveColor: MyColors.lightGreenColor, + middleLineColor: Colors.transparent, + extendWaveform: true, + showBottom: true, + showTop: true, + waveThickness: 2, + showMiddleLine: false, + middleLineThickness: 0, + ), + padding: const EdgeInsets.all(5), + shouldCalculateScrolledPosition: false, + margin: EdgeInsets.zero, + size: const Size(double.infinity, 30.0), + recorderController: m.recorderController, + backgroundColor: Colors.white, + ).expanded, + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Icon( + Icons.delete_outlined, + size: 26, + color: MyColors.lightGreenColor, + ).paddingAll(10).onPress(() { + m.deleteRecoding(); + }), + SvgPicture.asset("assets/icons/chat/chat_send_icon.svg", height: 26, width: 26) + .onPress( + () => m.sendGroupChatMessage(context, + targetUserId: params!.groupChatDetails!.groupId!, + userStatus: 0, + userEmail: "", + targetUserName: params!.groupChatDetails!.groupName!, + userList: params!.groupChatDetails!.groupUserList!), + ) + .paddingOnly(right: 21), + ], + ), ], - ).onPress(() => m.removeAttachment()).paddingOnly(right: 15), - if (m.sFileType.isEmpty) - RotationTransition( - turns: const AlwaysStoppedAnimation(45 / 360), - child: const Icon(Icons.attach_file_rounded, size: 26, color: MyColors.grey3AColor).onPress( - () => { - m.selectImageToUpload(context) + ).objectContainerView(disablePadding: true, radius: 0), + if (!m.isRecoding) + Row( + children: [ + CustomAutoDirection( + onDirectionChange: (bool isRTL) => m.onDirectionChange(isRTL), + text: m.msgText, + child: TextField( + // textDirection: m.textDirection, + controller: m.message, + decoration: InputDecoration( + hintTextDirection: m.textDirection, + hintText: m.isAttachmentMsg ? m.selectedFile.path.split("/").last : LocaleKeys.typeheretoreply.tr(), + hintStyle: TextStyle(color: m.isAttachmentMsg ? MyColors.darkTextColor : MyColors.grey98Color, fontSize: 14), + border: InputBorder.none, + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + errorBorder: InputBorder.none, + disabledBorder: InputBorder.none, + filled: true, + fillColor: MyColors.white, + contentPadding: const EdgeInsets.only( + left: 21, + top: 20, + bottom: 20, + ), + prefixIconConstraints: const BoxConstraints(), + prefixIcon: m.sFileType.isNotEmpty + ? SvgPicture.asset(m.getType(m.sFileType), height: 30, width: 22, alignment: Alignment.center, fit: BoxFit.cover).paddingOnly(left: 21, right: 15) + : null, + ), + onChanged: (String val) { + m.inputBoxDirection(val); + m.groupTypingInvoke(groupDetails: params!.groupChatDetails!, groupId: params!.groupChatDetails!.groupId!); }, - ), - ).paddingOnly(right: 15), - const Icon( - Icons.mic, - color: MyColors.lightGreenColor, - ).paddingOnly(right: 15).onPress(() { - m.startRecoding(context); - }), - SvgPicture.asset("assets/icons/chat/chat_send_icon.svg", height: 26, width: 26) - .onPress( - () =>m.sendGroupChatMessage(context, - targetUserId: params!.groupChatDetails!.groupId!, - userStatus: 0, - userEmail: "", - targetUserName: params!.groupChatDetails!.groupName!, - userList: params!.groupChatDetails!.groupUserList! + ).expanded, ), - ) - .paddingOnly(right: 21), + if (m.sFileType.isNotEmpty) + Row( + children: [ + const Icon(Icons.cancel, size: 15, color: MyColors.redA3Color).paddingOnly(right: 5), + ("Clear").toText11(color: MyColors.redA3Color, isUnderLine: true).paddingOnly(left: 0), + ], + ).onPress(() => m.removeAttachment()).paddingOnly(right: 15), + if (m.sFileType.isEmpty) + RotationTransition( + turns: const AlwaysStoppedAnimation(45 / 360), + child: const Icon(Icons.attach_file_rounded, size: 26, color: MyColors.grey3AColor).onPress( + () => {m.selectImageToUpload(context)}, + ), + ).paddingOnly(right: 15), + const Icon( + Icons.mic, + color: MyColors.lightGreenColor, + ).paddingOnly(right: 15).onPress(() { + m.startRecoding(context); + }), + SvgPicture.asset("assets/icons/chat/chat_send_icon.svg", height: 26, width: 26) + .onPress( + () => m.sendGroupChatMessage(context, + targetUserId: params!.groupChatDetails!.groupId!, + userStatus: 0, + userEmail: "", + targetUserName: params!.groupChatDetails!.groupName!, + userList: params!.groupChatDetails!.groupUserList!), + ) + .paddingOnly(right: 21), + ], + ).objectContainerView(disablePadding: true, radius: 0), ], - ).objectContainerView(disablePadding: true, radius: 0), - ], - )); + )); }, ), ), @@ -352,11 +346,11 @@ class _GroupChatDetailScreenState extends State { } else { return data.first.fileTypeResponse != null && data.first.fileTypeResponse!.fileTypeName != null ? Container( - width: 43, - height: 43, - constraints: const BoxConstraints(), - decoration: BoxDecoration(border: Border.all(color: MyColors.darkGrey3BColor, width: 1), borderRadius: BorderRadius.circular(10.0), color: Colors.white), - child: SvgPicture.asset(m.getType(data.first.fileTypeResponse!.fileTypeName ?? ""), alignment: Alignment.center, fit: BoxFit.cover).paddingOnly(left: 5, right: 5, top: 5, bottom: 5)) + width: 43, + height: 43, + constraints: const BoxConstraints(), + decoration: BoxDecoration(border: Border.all(color: MyColors.darkGrey3BColor, width: 1), borderRadius: BorderRadius.circular(10.0), color: Colors.white), + child: SvgPicture.asset(m.getType(data.first.fileTypeResponse!.fileTypeName ?? ""), alignment: Alignment.center, fit: BoxFit.cover).paddingOnly(left: 5, right: 5, top: 5, bottom: 5)) : const SizedBox(); } } @@ -373,22 +367,22 @@ class _GroupChatDetailScreenState extends State { // "calltype": callType == "VIDEO" ? "Video" : "Audio", // }; logger.w(json); - // CallDataModel callData = CallDataModel.fromJson(json); - // await Navigator.push( - // context, - // MaterialPageRoute( - // builder: (BuildContext context) => OutGoingCall( - // isVideoCall: callType == "VIDEO" ? true : false, - // outGoingCallData: callData, - // ), - // ), - // ).then((value) { - // print("then"); - // callPro.stopListeners(); - // }); + // CallDataModel callData = CallDataModel.fromJson(json); + // await Navigator.push( + // context, + // MaterialPageRoute( + // builder: (BuildContext context) => OutGoingCall( + // isVideoCall: callType == "VIDEO" ? true : false, + // outGoingCallData: callData, + // ), + // ), + // ).then((value) { + // print("then"); + // callPro.stopListeners(); + // }); } + GroupUserList getCurrentUser(int id, GroupResponse groupChatDetails) { - return groupChatDetails.groupUserList!.firstWhere((GroupUserList item) => item.id ==id); + return groupChatDetails.groupUserList!.firstWhere((GroupUserList item) => item.id == id); } - } diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index 9a91fe3..9b02c06 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -184,7 +184,7 @@ class _DashboardScreenState extends State with WidgetsBindingOb handleErmChannel(list); } catch (ex) { Utils.hideLoading(context); - Utils.handleException(ex, context, null); + // Utils.handleException(ex, context, null); return; } } diff --git a/lib/widgets/image_picker.dart b/lib/widgets/image_picker.dart index 38fcdef..943d68e 100644 --- a/lib/widgets/image_picker.dart +++ b/lib/widgets/image_picker.dart @@ -8,23 +8,25 @@ import 'package:mohem_flutter_app/classes/colors.dart'; import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/widgets/bottom_sheet.dart'; import 'package:mohem_flutter_app/widgets/bottom_sheets/attachment_options.dart'; -import 'package:mohem_flutter_app/widgets/dialogs/confirm_dialog.dart'; -import 'package:permission_handler/permission_handler.dart'; - +final ImagePicker picker = ImagePicker(); class ImageOptions { + static void showImageOptionsNew(BuildContext context, bool showFilesOption, Function(String, File) image) { + showMyBottomSheet( context, callBackFunc: () {}, child: AttachmentOptions( showFilesOption: showFilesOption, onCameraTap: () async { + if (Platform.isAndroid) { cameraImageAndroid(image); } else { File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.camera, imageQuality: 20))?.path ?? ""); - String fileName = _image.path; - var bytes = File(fileName).readAsBytesSync(); + // XFile? media = await picker.pickMedia(); + String? fileName = _image?.path; + var bytes = File(fileName!).readAsBytesSync(); String base64Encode = base64.encode(bytes); if (base64Encode != null) { image(base64Encode, _image); @@ -35,7 +37,7 @@ class ImageOptions { if (Platform.isAndroid) { galleryImageAndroid(image); } else { - File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.gallery, imageQuality: 20))?.path ?? ""); + File _image = File((await picker.pickMedia())?.path ?? ""); String fileName = _image.path; var bytes = File(fileName).readAsBytesSync(); String base64Encode = base64.encode(bytes); @@ -45,61 +47,24 @@ class ImageOptions { } }, onFilesTap: () async { - Permission.storage.isGranted.then((isGranted) async { - if (!isGranted) { - Permission.storage.request().then((granted) async { - if (granted == PermissionStatus.granted) { - FilePickerResult? result = await FilePicker.platform.pickFiles( - type: FileType.custom, - allowedExtensions: [ - 'jpg', - 'jpeg ', - 'pdf', - 'txt', - 'docx', - 'doc', - 'pptx', - 'xlsx', - 'png', - 'rar', - 'zip', - ], - ); - List files = result!.paths.map((path) => File(path!)).toList(); - image(result.files.first.path.toString(), files.first); - } else { - showDialog( - context: context, - builder: (BuildContext cxt) => ConfirmDialog( - message: "You need to give storage permission to upload files.", - onTap: () { - Navigator.pop(context); - }, - ), - ); - } - }); - } else { - FilePickerResult? result = await FilePicker.platform.pickFiles( - type: FileType.custom, - allowedExtensions: [ - 'jpg', - 'jpeg ', - 'pdf', - 'txt', - 'docx', - 'doc', - 'pptx', - 'xlsx', - 'png', - 'rar', - 'zip', - ], - ); - List files = result!.paths.map((path) => File(path!)).toList(); - image(result.files.first.path.toString(), files.first); - } - }); + FilePickerResult? result = await FilePicker.platform.pickFiles( + type: FileType.custom, + allowedExtensions: [ + 'jpg', + 'jpeg ', + 'pdf', + 'txt', + 'docx', + 'doc', + 'pptx', + 'xlsx', + 'png', + 'rar', + 'zip', + ], + ); + List files = result!.paths.map((path) => File(path!)).toList(); + image(result.files.first.path.toString(), files.first); }, ), ); @@ -165,7 +130,7 @@ class ImageOptions { } void galleryImageAndroid(Function(String, File) image) async { - File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.gallery, imageQuality: 20))?.path ?? ""); + File _image = File((await picker.pickMedia())?.path ?? ""); String fileName = _image.path; var bytes = File(fileName).readAsBytesSync(); @@ -176,7 +141,7 @@ void galleryImageAndroid(Function(String, File) image) async { } void cameraImageAndroid(Function(String, File) image) async { - File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.camera, imageQuality: 20))?.path ?? ""); + File _image = File(( await picker.pickMedia())?.path ?? ""); String fileName = _image.path; var bytes = File(fileName).readAsBytesSync(); String base64Encode = base64.encode(bytes); -- 2.30.2 From 22af6fa2f90be4e15c47a7eaf56264e407aeadf0 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Tue, 13 Feb 2024 17:33:36 +0300 Subject: [PATCH 017/135] Huawei location fix --- lib/provider/chat_provider_model.dart | 2 +- lib/widgets/mark_attendance_widget.dart | 4 +++- pubspec.yaml | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/provider/chat_provider_model.dart b/lib/provider/chat_provider_model.dart index 0c73a4b..380278d 100644 --- a/lib/provider/chat_provider_model.dart +++ b/lib/provider/chat_provider_model.dart @@ -1260,7 +1260,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } bool checkFileSize(String path) { - int fileSizeLimit = 1024; + int fileSizeLimit = 5120; File f = File(path); double fileSizeInKB = f.lengthSync() / 5000; double fileSizeInMB = fileSizeInKB / 5000; diff --git a/lib/widgets/mark_attendance_widget.dart b/lib/widgets/mark_attendance_widget.dart index 982e316..75a5ef5 100644 --- a/lib/widgets/mark_attendance_widget.dart +++ b/lib/widgets/mark_attendance_widget.dart @@ -313,7 +313,7 @@ class _MarkAttendanceWidgetState extends State { void getHuaweiCurrentLocation(String attendanceType) async { try { Utils.showLoading(context); - FusedLocationProviderClient locationService = FusedLocationProviderClient(); + FusedLocationProviderClient locationService = FusedLocationProviderClient()..initFusedLocationService(); LocationRequest locationRequest = LocationRequest(); locationRequest.priority = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY; locationRequest.interval = 500; @@ -377,6 +377,8 @@ class _MarkAttendanceWidgetState extends State { } catch (error) { print("HUAWEI LOCATION ERROR!!!!!"); print(error); + Utils.hideLoading(context); + Utils.handleException(error, context, null); } } diff --git a/pubspec.yaml b/pubspec.yaml index f7264a4..0db0731 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html #version: 3.3.01+300040 -version: 3.3.5+300045 +version: 3.4.1+300051 environment: sdk: ">=2.16.0 <3.0.0" -- 2.30.2 From 10a337ddd700c24fa3eedf5643587209d6545a66 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Tue, 27 Feb 2024 13:53:04 +0300 Subject: [PATCH 018/135] Added additional details in VIDA Access Request in ITG --- lib/classes/consts.dart | 5 +- lib/ui/landing/dashboard_screen.dart | 7 +- lib/ui/work_list/itg_detail_screen.dart | 6 +- .../request_detail_fragment.dart | 69 +++++++++++++++---- 4 files changed, 67 insertions(+), 20 deletions(-) diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index a6eaad2..aaee117 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -1,9 +1,12 @@ import 'package:mohem_flutter_app/ui/marathon/widgets/question_card.dart'; class ApiConsts { - //static String baseUrl = "http://10.200.204.20:2801/"; // Local server + // static String baseUrl = "http://10.200.204.11"; // Local server // static String baseUrl = "https://erptstapp.srca.org.sa"; // SRCA server // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver + + // static String baseUrl = "https://webservices.hmg.com"; // PreProd + static String baseUrl = "https://hmgwebservices.com"; // Live server static String baseUrlServices = baseUrl + "/Services/"; // server // static String baseUrlServices = "https://api.cssynapses.com/tangheem/"; // Live server diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index 9b02c06..333d271 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -167,9 +167,9 @@ class _DashboardScreenState extends State with WidgetsBindingOb if (ermIndex == list.length) { return; } - Utils.showLoading(context); + // Utils.showLoading(context); ItgMainRes? response = await DashboardApiClient().getAdvertisementDetail(list[ermIndex].notificationMasterId ?? ""); - Utils.hideLoading(context); + // Utils.hideLoading(context); if (response!.mohemmItgResponseItem!.result!.data != null) { if (list[ermIndex].notificationType == "Survey") { await Navigator.pushNamed(context, AppRoutes.survey, arguments: response.mohemmItgResponseItem!.result!.data!.first); @@ -183,7 +183,8 @@ class _DashboardScreenState extends State with WidgetsBindingOb ermIndex++; handleErmChannel(list); } catch (ex) { - Utils.hideLoading(context); + print(ex); + // Utils.hideLoading(context); // Utils.handleException(ex, context, null); return; } diff --git a/lib/ui/work_list/itg_detail_screen.dart b/lib/ui/work_list/itg_detail_screen.dart index 546d320..e0c65cc 100644 --- a/lib/ui/work_list/itg_detail_screen.dart +++ b/lib/ui/work_list/itg_detail_screen.dart @@ -159,7 +159,11 @@ class _ItgDetailScreenState extends State { }); }, children: [ - RequestDetailFragment(fields: itgRequest?.fieldGoups?[1].fields ?? []), + RequestDetailFragment( + fields: itgRequest?.fieldGoups?[1].fields ?? [], + fieldGoups: itgRequest?.fieldGoups ?? [], + taskID: itgRequest?.fieldGoups?[0].fields?[0].value ?? "", + ), ApprovalLevelfragment( wFHistory: itgRequest?.wFHistory ?? [], voidCallback: reloadITG, diff --git a/lib/ui/work_list/itg_fragments/request_detail_fragment.dart b/lib/ui/work_list/itg_fragments/request_detail_fragment.dart index 72b20d4..83f574f 100644 --- a/lib/ui/work_list/itg_fragments/request_detail_fragment.dart +++ b/lib/ui/work_list/itg_fragments/request_detail_fragment.dart @@ -4,34 +4,72 @@ 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/itg_forms_models/field_goups_model.dart'; import 'package:mohem_flutter_app/models/itg_forms_models/fields_model.dart'; import 'package:mohem_flutter_app/widgets/item_detail_view_widget.dart'; class RequestDetailFragment extends StatelessWidget { List fields; + List? fieldGoups; + String taskID; - RequestDetailFragment({Key? key, this.fields = const []}) : super(key: key); + RequestDetailFragment({Key? key, this.fields = const [], this.fieldGoups = const [], this.taskID = ""}) : super(key: key); double itemHeight = 0; double itemWidth = 0; + @override Widget build(BuildContext context) { var size = MediaQuery.of(context).size; itemHeight = (size.height - kToolbarHeight - 24) / 9; itemWidth = size.width / 2; - List uiList = [detailView()]; - return Container( - width: double.infinity, - height: double.infinity, - child: fields.isEmpty - ? LocaleKeys.noDataAvailable.tr().toText16().center - : ListView( + List uiList = [detailView(fields)]; + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Expanded( + child: SingleChildScrollView( + child: Padding( padding: const EdgeInsets.all(21), - children: uiList, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: double.infinity, + // height: double.infinity, + child: fields.isEmpty + ? LocaleKeys.noDataAvailable.tr().toText16().center + : ListView( + shrinkWrap: true, + children: uiList, + ), + ), + 12.height, + if (taskID.toLowerCase().contains("vida")) + Column( + children: [ + fieldGoups![2].title!.toText14(), + 6.height, + detailView(fieldGoups![2].fields!), + 12.height, + fieldGoups![3].title!.toText14(), + 6.height, + detailView(fieldGoups![3].fields!), + 12.height, + fieldGoups![4].title!.toText14(), + 6.height, + detailView(fieldGoups![4].fields!), + ], + ) + ], + ), ), + ), + ), + ], ); } - Widget detailView() { + Widget detailView(List fields) { bool isOdd = false; if (fields.length % 2 != 0) { isOdd = true; @@ -45,11 +83,12 @@ class RequestDetailFragment extends StatelessWidget { if (fields[index].value == null) { return ItemDetailViewGridItem( index, - fields[index].title, fields[index].multipleValue?.join(", ") ?? "", + fields[index].title, + fields[index].multipleValue?.join(", ") ?? "", isNeedToShowEmptyDivider: (fields.length == index + 1) ? isOdd - ? true - : false + ? true + : false : false, type: fields[index].type, ); @@ -60,8 +99,8 @@ class RequestDetailFragment extends StatelessWidget { fields[index].value ?? "", isNeedToShowEmptyDivider: (fields.length == index + 1) ? isOdd - ? true - : false + ? true + : false : false, type: fields[index].type, ); -- 2.30.2 From 2b7df41f3513254f0423d175f678eb5c870b9ba6 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Wed, 6 Mar 2024 10:44:12 +0300 Subject: [PATCH 019/135] advance search bottom sheet issue when keyboard appear. --- lib/widgets/bottom_sheet.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/widgets/bottom_sheet.dart b/lib/widgets/bottom_sheet.dart index a15fc3b..5eab25a 100644 --- a/lib/widgets/bottom_sheet.dart +++ b/lib/widgets/bottom_sheet.dart @@ -15,6 +15,7 @@ void showMyBottomSheet(BuildContext context, {required Widget child, required Vo topLeft: Radius.circular(25), ), ), + padding: MediaQuery.of(context).viewInsets, clipBehavior: Clip.antiAlias, child: Column( mainAxisAlignment: MainAxisAlignment.center, -- 2.30.2 From f77854c79421fac2f047d9184c933343259249e5 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Tue, 12 Mar 2024 17:37:54 +0300 Subject: [PATCH 020/135] update to stores version 5.9 --- lib/app_state/app_state.dart | 2 +- pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/app_state/app_state.dart b/lib/app_state/app_state.dart index 202584b..3ae2097 100644 --- a/lib/app_state/app_state.dart +++ b/lib/app_state/app_state.dart @@ -90,7 +90,7 @@ class AppState { String get getHuaweiPushToken => _huaweiPushToken; - final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 5.8, mobileType: Platform.isAndroid ? "android" : "ios"); + final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 5.9, mobileType: Platform.isAndroid ? "android" : "ios"); void setPostParamsInitConfig() { isAuthenticated = false; diff --git a/pubspec.yaml b/pubspec.yaml index 0db0731..a8853ce 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html #version: 3.3.01+300040 -version: 3.4.1+300051 +version: 3.7.92+1 environment: sdk: ">=2.16.0 <3.0.0" -- 2.30.2 From 348e4713ec8190b15139d36ad1e13b10fc426064 Mon Sep 17 00:00:00 2001 From: Sultan khan <> Date: Thu, 14 Mar 2024 15:01:00 +0300 Subject: [PATCH 021/135] worklist-PO-PR issue fixed. --- lib/ui/work_list/worklist_detail_screen.dart | 31 +++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/lib/ui/work_list/worklist_detail_screen.dart b/lib/ui/work_list/worklist_detail_screen.dart index c80f1b4..3bb3b5d 100644 --- a/lib/ui/work_list/worklist_detail_screen.dart +++ b/lib/ui/work_list/worklist_detail_screen.dart @@ -245,7 +245,7 @@ class _WorkListDetailScreenState extends State { if ((workListData?.sUBJECT ?? "").isNotEmpty) workListData!.sUBJECT!.toText14().paddingOnly(top: 20, right: 21, left: 21), PageView( controller: controller, - onPageChanged: (pageIndex) { + onPageChanged: (int pageIndex) { setState(() { tabIndex = pageIndex; }); @@ -586,7 +586,7 @@ class _WorkListDetailScreenState extends State { Future performNetworkCall(BuildContext context, {String? email, String? userId}) async { showDialog( context: context, - builder: (cxt) => ConfirmDialog( + builder: (BuildContext cxt) => ConfirmDialog( message: LocaleKeys.wantToReject.tr(), okTitle: LocaleKeys.reject.tr(), onTap: () async { @@ -668,25 +668,28 @@ class _WorkListDetailScreenState extends State { void performAction(String actionMode, {String? title}) { showDialog( context: context, - builder: (cxt) => AcceptRejectInputDialog( + builder: (BuildContext cxt) => AcceptRejectInputDialog( message: title != null ? null : LocaleKeys.requestedItems.tr(), title: title, notificationGetRespond: notificationNoteInput, actionMode: actionMode, - onTap: (note) { + onTap: (String note) { + List> responseAttribute = []; + + for (var element in getNotificationRespondAttributes!) { + responseAttribute.add({ + "ATTRIBUTE_NAME": element!.attributeName, + if (element!.attributeType == "number") "ATTRIBUTE_NUMBER_VALUE": note else if (element!.attributeType == "VARCHAR2") "ATTRIBUTE_TEXT_VALUE": note + }); + } + Map payload = { "P_ACTION_MODE": actionMode, "P_APPROVER_INDEX": null, "P_COMMENTS": note, "P_FORWARD_TO_USER_NAME": "", "P_NOTIFICATION_ID": workListData!.nOTIFICATIONID, - "RespondAttributeList": [ - if (notificationNoteInput != null) - { - "ATTRIBUTE_NAME": notificationNoteInput!.attributeName, - if (notificationNoteInput!.attributeType == "number") "ATTRIBUTE_NUMBER_VALUE": note else if (notificationNoteInput!.attributeType == "VARCHAR2") "ATTRIBUTE_TEXT_VALUE": note - } - ], + "RespondAttributeList":responseAttribute, }; if (actionMode == "APPROVED" || actionMode == "APPROVE" || actionMode == "CLOSE" || actionMode == "ANSWER_INFO" || actionMode == "RFC") { performNotificationAction(payload); @@ -999,15 +1002,15 @@ class _WorkListDetailScreenState extends State { notificationButtonsList.clear(); notificationButtonsList = await WorkListApiClient().getNotificationButtons(workListData!.nOTIFICATIONID!); if (notificationButtonsList.isNotEmpty) { - isCloseAvailable = notificationButtonsList.any((element) => element.bUTTONACTION == "CLOSE"); - isApproveAvailable = notificationButtonsList.any((element) { + isCloseAvailable = notificationButtonsList.any((GetNotificationButtonsList element) => element.bUTTONACTION == "CLOSE"); + isApproveAvailable = notificationButtonsList.any((GetNotificationButtonsList element) { if (element.bUTTONACTION == "APPROVED" || element.bUTTONACTION == "APPROVE") { approveAction = element.bUTTONACTION!; return true; } return false; }); - isRejectAvailable = notificationButtonsList.any((element) { + isRejectAvailable = notificationButtonsList.any((GetNotificationButtonsList element) { if (element.bUTTONACTION == "REJECTED" || element.bUTTONACTION == "REJECT") { rejectAction = element.bUTTONACTION!; return true; -- 2.30.2 From c7a4e4023e015f5d5aae46b6fdaabb6921cc795d Mon Sep 17 00:00:00 2001 From: Sultan khan <> Date: Tue, 21 May 2024 10:11:51 +0300 Subject: [PATCH 022/135] error code 699 fixes --- lib/api/api_client.dart | 13 +++++++------ lib/classes/consts.dart | 5 +++-- lib/ui/login/verify_last_login_screen.dart | 9 +++++++++ lib/ui/login/verify_login_screen.dart | 9 +++++++++ 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/lib/api/api_client.dart b/lib/api/api_client.dart index 3fbe57c..e3cbee1 100644 --- a/lib/api/api_client.dart +++ b/lib/api/api_client.dart @@ -16,13 +16,14 @@ class APIError { int? errorCode; int? errorType; String? errorMessage; - - APIError(this.errorCode, this.errorMessage, this.errorType); + int? errorStatusCode; + APIError(this.errorCode, this.errorMessage, this.errorType, this.errorStatusCode); Map toJson() => { 'errorCode': errorCode, 'errorMessage': errorMessage, 'errorType': errorType, + 'ErrorStatusCode': errorStatusCode }; @override @@ -38,14 +39,14 @@ APIException _throwAPIException(Response response) { if (response.body != null && response.body.isNotEmpty) { var jsonError = jsonDecode(response.body); print(jsonError); - apiError = APIError(jsonError['ErrorCode'], jsonError['ErrorMessage'], jsonError['ErrorType']); + apiError = APIError(jsonError['ErrorCode'], jsonError['ErrorMessage'], jsonError['ErrorType'], jsonError['ErrorStatusCode']); } return APIException(APIException.BAD_REQUEST, error: apiError); case 400: APIError? apiError; if (response.body != null && response.body.isNotEmpty) { var jsonError = jsonDecode(response.body); - apiError = APIError(jsonError['ErrorCode'], jsonError['ErrorMessage'], jsonError['ErrorType']); + apiError = APIError(jsonError['ErrorCode'], jsonError['ErrorMessage'], jsonError['ErrorType'],jsonError['ErrorStatusCode']); } return APIException(APIException.BAD_REQUEST, error: apiError); case 401: @@ -96,7 +97,7 @@ class ApiClient { return factoryConstructor(jsonData); } else { APIError? apiError; - apiError = APIError(jsonData['ErrorCode'], jsonData['ErrorEndUserMessage'], jsonData['ErrorType'] ?? 0); + apiError = APIError(jsonData['ErrorCode'], jsonData['ErrorEndUserMessage'], jsonData['ErrorType'] ?? 0, jsonData['ErrorStatusCode']); throw APIException(APIException.BAD_REQUEST, error: apiError); } } catch (ex) { @@ -146,7 +147,7 @@ class ApiClient { } var response = await _post(Uri.parse(url), body: requestBody, headers: _headers).timeout(Duration(seconds: 120)); - if (response.statusCode >= 200 && response.statusCode < 300) { + if (response. statusCode >= 200 && response.statusCode < 300) { return response; } else { throw _throwAPIException(response); diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index aaee117..4ed76b1 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -3,11 +3,12 @@ import 'package:mohem_flutter_app/ui/marathon/widgets/question_card.dart'; class ApiConsts { // static String baseUrl = "http://10.200.204.11"; // Local server // static String baseUrl = "https://erptstapp.srca.org.sa"; // SRCA server - // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver + static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver + // static String baseUrl = "http://10.201.204.101:2024"; // static String baseUrl = "https://webservices.hmg.com"; // PreProd - static String baseUrl = "https://hmgwebservices.com"; // Live server + // static String baseUrl = "https://hmgwebservices.com"; // Live server static String baseUrlServices = baseUrl + "/Services/"; // server // static String baseUrlServices = "https://api.cssynapses.com/tangheem/"; // Live server static String utilitiesRest = baseUrlServices + "Utilities.svc/REST/"; diff --git a/lib/ui/login/verify_last_login_screen.dart b/lib/ui/login/verify_last_login_screen.dart index c48d1f3..c6bd0f3 100644 --- a/lib/ui/login/verify_last_login_screen.dart +++ b/lib/ui/login/verify_last_login_screen.dart @@ -390,6 +390,15 @@ class _VerifyLastLoginScreenState extends State { } Utils.hideLoading(context); Utils.handleException(ex, context, null); + dynamic errorCode = ex; + if(errorCode.error.errorStatusCode ==699){ + Future.delayed(const Duration(seconds: 2), () + { + Navigator.pop(context); + Navigator.pushNamedAndRemoveUntil( + context, AppRoutes.login, (Route route) => false); + }); + } } } diff --git a/lib/ui/login/verify_login_screen.dart b/lib/ui/login/verify_login_screen.dart index 0147472..ac3c454 100644 --- a/lib/ui/login/verify_login_screen.dart +++ b/lib/ui/login/verify_login_screen.dart @@ -654,6 +654,15 @@ class _VerifyLoginScreenState extends State { otpFieldClear.value = ""; Utils.hideLoading(context); Utils.handleException(ex, context, null); + dynamic errorCode = ex; + if(errorCode.error.errorStatusCode ==699){ + Future.delayed(const Duration(seconds: 2), () + { + Navigator.pop(context); + Navigator.pushNamedAndRemoveUntil( + context, AppRoutes.login, (Route route) => false); + }); + } } }, () => { -- 2.30.2 From f09f08be822021f7452626995450fad422ea4d0c Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Wed, 29 May 2024 15:26:15 +0300 Subject: [PATCH 023/135] Store update to version 6.0 --- lib/api/dashboard_api_client.dart | 5 +++-- lib/app_state/app_state.dart | 2 +- lib/classes/consts.dart | 7 ++++--- pubspec.yaml | 2 +- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/api/dashboard_api_client.dart b/lib/api/dashboard_api_client.dart index 77cc37d..bc0fece 100644 --- a/lib/api/dashboard_api_client.dart +++ b/lib/api/dashboard_api_client.dart @@ -106,7 +106,7 @@ class DashboardApiClient { } //Mark Attendance - Future markAttendance({String lat = "0", String? long = "0", required int pointType, String nfcValue = "", bool isGpsRequired = false, String QRValue = ""}) async { + Future markAttendance({String lat = "0", String? long = "0", required int pointType, String nfcValue = "", bool isGpsRequired = false, String QRValue = "", String payrollCode = ""}) async { String url = "${ApiConsts.swpRest}AuthenticateAndSwipeUserSupportNFC"; var uuid = Uuid(); // Generate a v4 (random) id @@ -120,7 +120,8 @@ class DashboardApiClient { "PointType": pointType, // NFC=2, Wifi = 3, QR= 1, "NFCValue": nfcValue, "WifiValue": pointType == 3 ? "100" : "", - "IsGpsRequired": isGpsRequired + "IsGpsRequired": isGpsRequired, + "PayrollCodeStr": AppState().postParamsObject?.payrollCodeStr.toString() ?? "" }; postParams.addAll(AppState().postParamsJson); return await ApiClient().postJsonForObject((json) { diff --git a/lib/app_state/app_state.dart b/lib/app_state/app_state.dart index 3ae2097..2e8e2ad 100644 --- a/lib/app_state/app_state.dart +++ b/lib/app_state/app_state.dart @@ -90,7 +90,7 @@ class AppState { String get getHuaweiPushToken => _huaweiPushToken; - final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 5.9, mobileType: Platform.isAndroid ? "android" : "ios"); + final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 6.0, mobileType: Platform.isAndroid ? "android" : "ios"); void setPostParamsInitConfig() { isAuthenticated = false; diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 4ed76b1..f5c055b 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -3,12 +3,13 @@ import 'package:mohem_flutter_app/ui/marathon/widgets/question_card.dart'; class ApiConsts { // static String baseUrl = "http://10.200.204.11"; // Local server // static String baseUrl = "https://erptstapp.srca.org.sa"; // SRCA server - static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver + // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.201.204.101:2024"; - // static String baseUrl = "https://webservices.hmg.com"; // PreProd - // static String baseUrl = "https://hmgwebservices.com"; // Live server + + static String baseUrl = "https://mohemm.hmg.com"; // New Live server + static String baseUrlServices = baseUrl + "/Services/"; // server // static String baseUrlServices = "https://api.cssynapses.com/tangheem/"; // Live server static String utilitiesRest = baseUrlServices + "Utilities.svc/REST/"; diff --git a/pubspec.yaml b/pubspec.yaml index a8853ce..20ed5c2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html #version: 3.3.01+300040 -version: 3.7.92+1 +version: 3.4.4+300054 environment: sdk: ">=2.16.0 <3.0.0" -- 2.30.2 From e8fbffdc9c537678af346e5dc8afcda3a613e1e9 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Wed, 5 Jun 2024 14:58:07 +0300 Subject: [PATCH 024/135] scroll, padding & content by language added on image ad. --- .../itg/its_add_screen_video_image.dart | 57 ++++++++++--------- 1 file changed, 29 insertions(+), 28 deletions(-) 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 60bd4ba..cf2d92b 100644 --- a/lib/ui/landing/itg/its_add_screen_video_image.dart +++ b/lib/ui/landing/itg/its_add_screen_video_image.dart @@ -1,8 +1,3 @@ -import 'dart:convert'; -import 'dart:io' as Io; -import 'dart:io'; -import 'dart:typed_data'; - import 'package:flutter/material.dart'; import 'package:flutter_countdown_timer/index.dart'; import 'package:lottie/lottie.dart'; @@ -17,7 +12,6 @@ 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'; class ITGAdsScreen extends StatefulWidget { @@ -51,6 +45,10 @@ class _ITGAdsScreenState extends State { void checkFileType() { String? rFile = advertisementData!.viewAttachFileColl!.first.base64String; + try { + rFile = advertisementData!.viewAttachFileColl!.where((element) => element.languageId == AppState().getLanguageID(context)).toList().first.base64String; + } catch (ex) {} + String? rFileExt = advertisementData!.viewAttachFileColl!.first.fileName; ext = "." + rFileExt!.split(".").last.toLowerCase(); if (ext == ".png" || ext == ".jpg" || ext == ".jpeg" || ext == ".gif") { @@ -65,8 +63,8 @@ class _ITGAdsScreenState extends State { _futureController = createVideoPlayer(rFile!); } - // advertisementData?.actionButtonsColl!.forEach((element) { - advertisementData?.actionButtonsColl!.removeWhere((element1) => element1.actionButtonId == advertisementData?.skipButtonId); + // advertisementData?.actionButtonsColl!.forEach((element) { + advertisementData?.actionButtonsColl!.removeWhere((element1) => element1.actionButtonId == advertisementData?.skipButtonId); //}); // setState(() {}); @@ -264,26 +262,29 @@ class _ITGAdsScreenState extends State { }, ), if (isImage) - Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Image.network(imageUrl), - 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 { - Navigator.pop(context); - DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, "Like").then((value) { - logger.d(value); - }); - } catch (ex) { - logger.wtf(ex); - Utils.handleException(ex, context, null); - } - }, - ), - ], + SingleChildScrollView( + padding: const EdgeInsets.only(top: 60, left: 12, right: 12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.network(imageUrl), + 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 { + Navigator.pop(context); + DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, "Like").then((value) { + logger.d(value); + }); + } catch (ex) { + logger.wtf(ex); + Utils.handleException(ex, context, null); + } + }, + ), + ], + ), ), ], ), -- 2.30.2 From 030887452da4960450bbd6c30c0ab1e51d84fad8 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Thu, 25 Jul 2024 10:40:33 +0300 Subject: [PATCH 025/135] generate QR Api added. --- assets/langs/ar-SA.json | 1 + assets/langs/en-US.json | 3 +- lib/api/worklist/worklist_api_client.dart | 31 +++++++++++++---- lib/generated/codegen_loader.g.dart | 4 ++- lib/generated/locale_keys.g.dart | 1 + lib/ui/login/login_screen.dart | 9 ++--- lib/ui/work_list/itg_detail_screen.dart | 41 +++++++++++++++++++++-- 7 files changed, 75 insertions(+), 15 deletions(-) diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 8f127f2..c59641b 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -97,6 +97,7 @@ "reject": "يرفض", "approve": "يوافق", "cancel": "إلغاء", + "generate": "يولد", "requestedItems": "العناصر المطلوبة", "request": "طلب", "myRequest": "طلبي", diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index eec20d4..275864f 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -93,6 +93,7 @@ "whatsapp": "Whatsapp", "reject": "Reject", "approve": "Approve", + "generate": "Generate", "cancel": "Cancel", "requestedItems": "Requested Items", "request": "Request", @@ -547,7 +548,7 @@ "manageGroup": "Manage Group", "admin": "Admin", "addUsers": "Add users to the group", - "editGroups":"Edit Group", + "editGroups": "Edit Group", "groupNameshouldbe": "Group name should be minimum 10 character long", "enterGroupName": "Please enter valid group Name", "groupName": "Group Name", diff --git a/lib/api/worklist/worklist_api_client.dart b/lib/api/worklist/worklist_api_client.dart index d2389ab..732ed06 100644 --- a/lib/api/worklist/worklist_api_client.dart +++ b/lib/api/worklist/worklist_api_client.dart @@ -380,7 +380,7 @@ class WorkListApiClient { }, url, postParams); } - Future rejectITGRequest(String requestType, taskId, itemId, String employeeNumber, String comments) async { + Future rejectITGRequest(String requestType, taskId, itemId, String employeeNumber, String comments) async { String url = "${ApiConsts.cocRest}ITGRejectRequest"; Map postParams = { "RequestType": requestType, @@ -396,7 +396,7 @@ class WorkListApiClient { }, url, postParams); } - Future approveITGRequest(String requestType, taskId, itemId, String employeeNumber, String comments) async { + Future approveITGRequest(String requestType, taskId, itemId, String employeeNumber, String comments) async { String url = "${ApiConsts.cocRest}ITGApproveRequest"; Map postParams = { "RequestType": requestType, @@ -412,7 +412,7 @@ class WorkListApiClient { }, url, postParams); } - Future delegateITGRequest(String requestType, taskId, itemId, String employeeNumber, String newUserEMPId, String comments) async { + Future delegateITGRequest(String requestType, taskId, itemId, String employeeNumber, String newUserEMPId, String comments) async { String url = "${ApiConsts.cocRest}ITGDelegateRequest"; Map postParams = { "RequestType": requestType, @@ -431,7 +431,7 @@ class WorkListApiClient { // ANSWER = 'Services/COCWS.svc/REST/ITGAnswer'; - Future answerITGRequest(String requestType, taskId, itemId, String employeeNumber, String newUserEMPId, String comments) async { + Future answerITGRequest(String requestType, taskId, itemId, String employeeNumber, String newUserEMPId, String comments) async { String url = "${ApiConsts.cocRest}ITGAnswer"; Map postParams = { "RequestType": requestType, @@ -447,6 +447,25 @@ class WorkListApiClient { }, url, postParams); } + Future requestActionITGRequest(String requestType, taskId, itemId, String employeeNumber, String newUserEMPId, String comments) async { + String url = "${ApiConsts.cocRest}Mohemm_ITG_GenerateQR_RequestAction"; + Map postParams = { + "RequestType": requestType, + "TaskID": taskId, + "ItemIDStr":itemId, + "EmployeeNumber": employeeNumber, + "Comments": comments, + "RequestID": itemId, + "RequestActionId": 3, + "IsQRCodeGenerate": true, + }; + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject((json) { + ItgFormsModel responseData = ItgFormsModel.fromJson(json); + return responseData.itgRequest; + }, url, postParams); + } + Future grantITGRequest(String requestType, int taskId, int itemId, String employeeNumber, String newUserEMPId, String comments) async { String url = "${ApiConsts.cocRest}ITGGrantAccess"; Map postParams = { @@ -465,7 +484,7 @@ class WorkListApiClient { }, url, postParams); } - Future informationITGRequest(String requestType, taskId, itemId, String employeeNumber, String newUserEMPId, String comments) async { + Future informationITGRequest(String requestType, taskId, itemId, String employeeNumber, String newUserEMPId, String comments) async { String url = "${ApiConsts.cocRest}ITGRequestInformation"; Map postParams = { "RequestType": requestType, @@ -581,8 +600,6 @@ class WorkListApiClient { }, url, postParams); } - - Future?> getFavoriteReplacementWithoutImage() async { String url = "${ApiConsts.erpRest}Mohemm_GetFavoriteReplacementsWithoutImage"; Map postParams = {}; diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index af972f6..1251dd6 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -551,6 +551,7 @@ class CodegenLoader extends AssetLoader { "uploadedDocuments": "المستندات التي تم تحميلها", "youCannotJoinTheMarathon": "لا يمكنك الانضمام إلى الماراثون لأنك تجاوزت الحد الزمني", "pleaseClickButtonToJoinMarathon": "الرجاء الضغط على الزر أدناه للانضمام إلى الماراثون", + "generate": "يولد", }; static const Map en_US = { "mohemm": "Mohemm", @@ -1107,7 +1108,8 @@ class CodegenLoader extends AssetLoader { "userName": "User Name", "userId": "UserID", "pleaseClickButtonToJoinMarathon": "Press the button below to join the Marathon.", - "youCannotJoinTheMarathon": "You cannot join the Marathon because you have exceeded the time limit." + "youCannotJoinTheMarathon": "You cannot join the Marathon because you have exceeded the time limit.", + "generate": "Generate" }; static const Map> mapLocales = {"ar_SA": ar_SA, "en_US": en_US}; } diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index a6fd43d..cc7f2b4 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -550,4 +550,5 @@ abstract class LocaleKeys { static const pleaseClickButtonToJoinMarathon ='pleaseClickButtonToJoinMarathon'; static const youCannotJoinTheMarathon ='youCannotJoinTheMarathon'; static const open ='open'; + static const generate = 'generate'; } diff --git a/lib/ui/login/login_screen.dart b/lib/ui/login/login_screen.dart index c85ecb7..d4f1644 100644 --- a/lib/ui/login/login_screen.dart +++ b/lib/ui/login/login_screen.dart @@ -8,7 +8,6 @@ import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; - // import 'package:huawei_hmsavailability/huawei_hmsavailability.dart'; import 'package:mohem_flutter_app/api/login_api_client.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; @@ -31,7 +30,6 @@ import 'package:mohem_flutter_app/models/member_login_list_model.dart'; import 'package:mohem_flutter_app/models/privilege_list_model.dart'; import 'package:mohem_flutter_app/widgets/button/default_button.dart'; import 'package:mohem_flutter_app/widgets/input_widget.dart'; - // import 'package:safe_device/safe_device.dart'; import 'package:wifi_iot/wifi_iot.dart'; @@ -116,8 +114,11 @@ class _LoginScreenState extends State { print("GOOGLE PLAY STOREEEE!!!!"); await Firebase.initializeApp(); _firebaseMessaging = FirebaseMessaging.instance; - firebaseToken = await _firebaseMessaging.getToken(); - print(firebaseToken); + try { + firebaseToken = await _firebaseMessaging.getToken(); + } catch (ex) { + firebaseToken = ""; + } AppNotifications().init(firebaseToken, context); checkLoginInfo(); await FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(true); diff --git a/lib/ui/work_list/itg_detail_screen.dart b/lib/ui/work_list/itg_detail_screen.dart index e0c65cc..2aa9490 100644 --- a/lib/ui/work_list/itg_detail_screen.dart +++ b/lib/ui/work_list/itg_detail_screen.dart @@ -45,6 +45,7 @@ class _ItgDetailScreenState extends State { bool isCloseAvailable = false; bool isApproveAvailable = false; bool isRejectAvailable = false; + bool isGenerateAvailable = false; List allowedActionList = []; List itgFormAttachmentsList = []; @@ -76,6 +77,7 @@ class _ItgDetailScreenState extends State { isCloseAvailable = allowedActionList.any((element) => element.action == "CLOSE"); isApproveAvailable = itgRequest!.allowedActions!.any((element) => element.action == "Approve"); isRejectAvailable = itgRequest!.allowedActions!.any((element) => element.action == "Reject"); + isGenerateAvailable = itgRequest!.allowedActions!.any((element) => element.action == "Generate"); } Utils.hideLoading(context); setState(() { @@ -209,6 +211,16 @@ class _ItgDetailScreenState extends State { Color(0xff1BB271), ], ).expanded, + if ((isApproveAvailable ||isRejectAvailable) && isGenerateAvailable) 8.width, + if (isGenerateAvailable) + DefaultButton( + LocaleKeys.generate.tr(), + () => performAction("Generate"), + colors: const [ + Color(0xff28C884), + Color(0xff1BB271), + ], + ).expanded, if (isCloseAvailable) DefaultButton( LocaleKeys.ok.tr(), @@ -279,7 +291,7 @@ class _ItgDetailScreenState extends State { ], ), ), - floatingActionButton: (!isApproveAvailable && !isRejectAvailable && !isCloseAvailable) + floatingActionButton: (!isApproveAvailable && !isRejectAvailable && !isCloseAvailable && !isGenerateAvailable) ? Container( height: 43, width: 43, @@ -300,7 +312,7 @@ class _ItgDetailScreenState extends State { List viewApiButtonsList(List allowedActionList) { List fabs = []; for (int i = 0; i < allowedActionList.length; i++) { - if (allowedActionList[i].action! == "Reject" || allowedActionList[i].action! == "Approve" || allowedActionList[i].action! == "CLOSE") { + if (allowedActionList[i].action! == "Reject" || allowedActionList[i].action! == "Approve" || allowedActionList[i].action! == "CLOSE" || allowedActionList[i].action! == "Generate") { continue; } fabs.add(myFab(getFabActionTitle(allowedActionList[i].action!), getFabActionImages(allowedActionList[i].action!)).paddingOnly(bottom: 12).onPress(() => handleFabAction(allowedActionList[i]))); @@ -487,6 +499,8 @@ class _ItgDetailScreenState extends State { performApproveAction(requestDetails!.requestType!, requestDetails!.iD, requestDetails!.itemID, AppState().memberInformationList?.eMPLOYEENUMBER ?? "", note); } else if (actionMode == "Answer") { performAnswerAction(requestDetails!.requestType!, requestDetails!.iD, requestDetails!.itemID, AppState().memberInformationList?.eMPLOYEENUMBER ?? "", note); + } else if (actionMode == "Generate") { + performGenerateQrAction(requestDetails!.requestType!, requestDetails!.iD, requestDetails!.itemID, AppState().memberInformationList?.eMPLOYEENUMBER ?? "", note); } else { performRejectAction(requestDetails!.requestType!, requestDetails!.iD, requestDetails!.itemID, AppState().memberInformationList?.eMPLOYEENUMBER ?? "", note); } @@ -495,6 +509,29 @@ class _ItgDetailScreenState extends State { ); } + void performGenerateQrAction(String requestType, taskId, itemId, String employeeNumber, String comments) async { + try { + Utils.showLoading(context); + ITGRequest? itgRequest = await WorkListApiClient().requestActionITGRequest(requestType, taskId, itemId, employeeNumber, "", comments); + Utils.hideLoading(context); + Utils.showToast(LocaleKeys.yourChangeHasBeenSavedSuccessfully.tr()); + // Navigator.pop(context, "delegate_reload"); + AppState().requestAllList!.removeAt(AppState().itgWorkListIndex!); + if (AppState().requestAllList!.isEmpty) { + Navigator.pop(context, "delegate_reload"); + } else { + if (AppState().requestAllList!.length <= AppState().itgWorkListIndex!) { + Navigator.pop(context, "delegate_reload"); + } else { + requestDetails = null; + getDataFromState(); + } + } + } catch (ex) { + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + } + } void performAnswerAction(String requestType, taskId, itemId, String employeeNumber, String comments) async { try { Utils.showLoading(context); -- 2.30.2 From 550992ccf40b275e0e63b2b71f5d73cba74df628 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Sun, 28 Jul 2024 10:54:50 +0300 Subject: [PATCH 026/135] generate QR Api email parameter added. --- lib/api/worklist/worklist_api_client.dart | 5 +++-- lib/ui/work_list/itg_detail_screen.dart | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/api/worklist/worklist_api_client.dart b/lib/api/worklist/worklist_api_client.dart index 732ed06..91cd04f 100644 --- a/lib/api/worklist/worklist_api_client.dart +++ b/lib/api/worklist/worklist_api_client.dart @@ -447,14 +447,15 @@ class WorkListApiClient { }, url, postParams); } - Future requestActionITGRequest(String requestType, taskId, itemId, String employeeNumber, String newUserEMPId, String comments) async { + Future requestActionITGRequest(String requestType, taskId, itemId, String employeeNumber, String newUserEMPId, String comments, String email) async { String url = "${ApiConsts.cocRest}Mohemm_ITG_GenerateQR_RequestAction"; Map postParams = { "RequestType": requestType, "TaskID": taskId, - "ItemIDStr":itemId, + "ItemIDStr": itemId, "EmployeeNumber": employeeNumber, "Comments": comments, + "EmailAddress": email, "RequestID": itemId, "RequestActionId": 3, "IsQRCodeGenerate": true, diff --git a/lib/ui/work_list/itg_detail_screen.dart b/lib/ui/work_list/itg_detail_screen.dart index 2aa9490..2381b70 100644 --- a/lib/ui/work_list/itg_detail_screen.dart +++ b/lib/ui/work_list/itg_detail_screen.dart @@ -211,11 +211,11 @@ class _ItgDetailScreenState extends State { Color(0xff1BB271), ], ).expanded, - if ((isApproveAvailable ||isRejectAvailable) && isGenerateAvailable) 8.width, + if ((isApproveAvailable || isRejectAvailable) && isGenerateAvailable) 8.width, if (isGenerateAvailable) DefaultButton( LocaleKeys.generate.tr(), - () => performAction("Generate"), + () => performAction("Generate"), colors: const [ Color(0xff28C884), Color(0xff1BB271), @@ -512,7 +512,8 @@ class _ItgDetailScreenState extends State { void performGenerateQrAction(String requestType, taskId, itemId, String employeeNumber, String comments) async { try { Utils.showLoading(context); - ITGRequest? itgRequest = await WorkListApiClient().requestActionITGRequest(requestType, taskId, itemId, employeeNumber, "", comments); + ITGRequest? itgRequest = + await WorkListApiClient().requestActionITGRequest(requestType, taskId, itemId, employeeNumber, "", comments, AppState().memberInformationList?.eMPLOYEEEMAILADDRESS ?? ""); Utils.hideLoading(context); Utils.showToast(LocaleKeys.yourChangeHasBeenSavedSuccessfully.tr()); // Navigator.pop(context, "delegate_reload"); -- 2.30.2 From 3327130e74d4e64624975d2333c04792fde5042f Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Thu, 27 Jun 2024 17:04:40 +0300 Subject: [PATCH 027/135] Attendance location updates --- lib/app_state/app_state.dart | 2 +- lib/widgets/location/Location.dart | 4 +++- lib/widgets/mark_attendance_widget.dart | 21 +++++++++++++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/lib/app_state/app_state.dart b/lib/app_state/app_state.dart index 2e8e2ad..cc11126 100644 --- a/lib/app_state/app_state.dart +++ b/lib/app_state/app_state.dart @@ -90,7 +90,7 @@ class AppState { String get getHuaweiPushToken => _huaweiPushToken; - final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 6.0, mobileType: Platform.isAndroid ? "android" : "ios"); + final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 8.0, mobileType: Platform.isAndroid ? "android" : "ios"); void setPostParamsInitConfig() { isAuthenticated = false; diff --git a/lib/widgets/location/Location.dart b/lib/widgets/location/Location.dart index 67d3cdd..47babca 100644 --- a/lib/widgets/location/Location.dart +++ b/lib/widgets/location/Location.dart @@ -35,7 +35,7 @@ class Location { }); } - static void getCurrentLocation(Function(Position position, bool isMocked) callback, BuildContext context) { + static void getCurrentLocation(Function(Position position, bool isMocked) callback, Function errorCallBack, BuildContext context) { void done(Position position) { //AppStorage.sp.saveLocation(position); bool isMocked = position.isMocked; @@ -46,6 +46,8 @@ class Location { if (granted) { Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.medium, timeLimit: const Duration(seconds: 5)).then((value) { done(value); + }).catchError((err) { + errorCallBack(); }); } else { // AppPermissions diff --git a/lib/widgets/mark_attendance_widget.dart b/lib/widgets/mark_attendance_widget.dart index 75a5ef5..508ed00 100644 --- a/lib/widgets/mark_attendance_widget.dart +++ b/lib/widgets/mark_attendance_widget.dart @@ -171,14 +171,21 @@ class _MarkAttendanceWidgetState extends State { if (isEnabled) { location.Location.havePermission((bool permission) { if (permission) { + Utils.showLoading(context); location.Location.getCurrentLocation( (Position position, bool isMocked) { if (isMocked) { + Utils.hideLoading(context); markFakeAttendance("NFC", position.latitude.toString() ?? "", position.longitude.toString() ?? ""); } else { + Utils.hideLoading(context); performNfcAttendance(widget.model, lat: position.latitude.toString() ?? "", lng: position.longitude.toString() ?? ""); } }, + () { + Utils.hideLoading(context); + Utils.confirmDialog(context, "Unable to determine your location, Please make sure that your location services are turned on & working."); + }, context, ); } else { @@ -218,14 +225,21 @@ class _MarkAttendanceWidgetState extends State { if (isEnabled) { location.Location.havePermission((bool permission) { if (permission) { + Utils.showLoading(context); location.Location.getCurrentLocation( (Position position, bool isMocked) { if (isMocked) { + Utils.hideLoading(context); markFakeAttendance("WIFI", position.latitude.toString() ?? "", position.longitude.toString() ?? ""); } else { + Utils.hideLoading(context); performWifiAttendance(widget.model, lat: position.latitude.toString() ?? "", lng: position.longitude.toString() ?? ""); } }, + () { + Utils.hideLoading(context); + Utils.confirmDialog(context, "Unable to determine your location, Please make sure that your location services are turned on & working."); + }, context, ); } else { @@ -265,14 +279,21 @@ class _MarkAttendanceWidgetState extends State { if (isEnabled) { location.Location.havePermission((bool permission) { if (permission) { + Utils.showLoading(context); location.Location.getCurrentLocation( (Position position, bool isMocked) { if (isMocked) { + Utils.hideLoading(context); markFakeAttendance("QR", position.latitude.toString() ?? "", position.longitude.toString() ?? ""); } else { + Utils.hideLoading(context); performQrCodeAttendance(widget.model, lat: position.latitude.toString() ?? "", lng: position.longitude.toString() ?? ""); } }, + () { + Utils.hideLoading(context); + Utils.confirmDialog(context, "Unable to determine your location, Please make sure that your location services are turned on & working."); + }, context, ); } else { -- 2.30.2 From 096c52d979a611cd7189a28eae0fb4b3528bfa90 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Sun, 28 Jul 2024 10:14:40 +0300 Subject: [PATCH 028/135] worklist updates --- android/app/build.gradle | 2 +- android/build.gradle | 2 +- lib/ui/work_list/worklist_detail_screen.dart | 8 +++++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 5279c1f..20bf8fb 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -34,7 +34,7 @@ apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" apply plugin: 'com.huawei.agconnect' android { - compileSdkVersion 33 + compileSdkVersion 34 compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 diff --git a/android/build.gradle b/android/build.gradle index 5effa33..23ea6ba 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -7,7 +7,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:7.0.3' + classpath 'com.android.tools.build:gradle:7.1.3' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath 'com.google.gms:google-services:4.3.8' classpath 'com.huawei.agconnect:agcp:1.8.0.300' diff --git a/lib/ui/work_list/worklist_detail_screen.dart b/lib/ui/work_list/worklist_detail_screen.dart index 3bb3b5d..146bd44 100644 --- a/lib/ui/work_list/worklist_detail_screen.dart +++ b/lib/ui/work_list/worklist_detail_screen.dart @@ -499,6 +499,12 @@ class _WorkListDetailScreenState extends State { case "APPROVE": performAction(notificationButton.bUTTONACTION!); break; + case "TRY_APPROVE_AGAIN": + performAction(notificationButton.bUTTONACTION!); + break; + case "SEND_BACK_TO_PREPARER": + performAction(notificationButton.bUTTONACTION!); + break; case "UPDATE_ACTION": showMyBottomSheet( context, @@ -691,7 +697,7 @@ class _WorkListDetailScreenState extends State { "P_NOTIFICATION_ID": workListData!.nOTIFICATIONID, "RespondAttributeList":responseAttribute, }; - if (actionMode == "APPROVED" || actionMode == "APPROVE" || actionMode == "CLOSE" || actionMode == "ANSWER_INFO" || actionMode == "RFC") { + if (actionMode == "APPROVED" || actionMode == "APPROVE" || actionMode == "CLOSE" || actionMode == "ANSWER_INFO" || actionMode == "RFC" || actionMode == "TRY_APPROVE_AGAIN" || actionMode == "SEND_BACK_TO_PREPARER") { performNotificationAction(payload); } else if (note.isNotEmpty && (actionMode != "APPROVED" || actionMode != "APPROVE")) { performNotificationAction(payload); -- 2.30.2 From 2bdaaf9e16da41ad193b82a4bd00bde1f2b80308 Mon Sep 17 00:00:00 2001 From: "taha.alam" Date: Wed, 31 Jul 2024 11:50:29 +0300 Subject: [PATCH 029/135] WD: flutter upgrade fron 3.7 to 3.19.0 --- lib/classes/notifications.dart | 4 +-- lib/dialogs/otp_dialog.dart | 1 + lib/theme/app_theme.dart | 4 +-- .../attendance/monthly_attendance_screen.dart | 6 ++-- lib/ui/chat/chat_home_screen.dart | 2 ++ lib/ui/login/verify_last_login_screen.dart | 28 +++++++++++++++---- lib/ui/login/verify_login_screen.dart | 21 ++++++++++++-- lib/ui/my_team/view_attendance.dart | 6 ++-- lib/ui/profile/delete_family_member.dart | 5 ++-- .../offers_and_discounts_details.dart | 2 +- lib/widgets/app_bar_widget.dart | 2 ++ lib/widgets/chat_app_bar_widge.dart | 2 ++ lib/widgets/nfc/nfc_reader_sheet.dart | 1 + pubspec.yaml | 14 +++++----- 14 files changed, 69 insertions(+), 29 deletions(-) diff --git a/lib/classes/notifications.dart b/lib/classes/notifications.dart index 8f432d7..058606c 100644 --- a/lib/classes/notifications.dart +++ b/lib/classes/notifications.dart @@ -34,8 +34,8 @@ class AppNotifications { if (Platform.isIOS) { await flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation()?.requestPermissions(alert: true, badge: true, sound: true); } else if (Platform.isAndroid) { - AndroidFlutterLocalNotificationsPlugin? androidImplementation = flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation(); - bool? granted = await androidImplementation?.requestPermission(); + AndroidFlutterLocalNotificationsPlugin? androidImplementation = flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation(); + bool? granted = await androidImplementation?.requestNotificationsPermission(); if (granted == false) { if (kDebugMode) { print("-------------------- Permission Granted ------------------------"); diff --git a/lib/dialogs/otp_dialog.dart b/lib/dialogs/otp_dialog.dart index 9f7c82e..1404131 100644 --- a/lib/dialogs/otp_dialog.dart +++ b/lib/dialogs/otp_dialog.dart @@ -67,6 +67,7 @@ class OtpDialog { // projectProvider = Provider.of(context); return Dialog( backgroundColor: Colors.white, + surfaceTintColor: Colors.transparent, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), insetPadding: const EdgeInsets.only(left: 21, right: 21), child: StatefulBuilder(builder: (context, setState) { diff --git a/lib/theme/app_theme.dart b/lib/theme/app_theme.dart index 586c3aa..e46ee34 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,6 @@ class AppTheme { splashColor: Colors.transparent, primaryColor: primaryColor, primaryColorDark: primaryColor, - buttonColor: Colors.black, toggleableActiveColor: secondaryColor, indicatorColor: secondaryColor, bottomSheetTheme: const BottomSheetThemeData( @@ -44,7 +44,7 @@ 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), 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 65f101b..821a4f0 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,8 @@ 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()), ).then((selectedDate) { if (selectedDate != null) { searchMonth = getMonth(selectedDate.month); diff --git a/lib/ui/chat/chat_home_screen.dart b/lib/ui/chat/chat_home_screen.dart index 04d7c2e..68cc7fb 100644 --- a/lib/ui/chat/chat_home_screen.dart +++ b/lib/ui/chat/chat_home_screen.dart @@ -214,6 +214,8 @@ class _ChatHomeScreenState extends State { }, ), floatingActionButton: FloatingActionButton( + elevation: 0, + backgroundColor : Colors.transparent, child: Container( width: 60, height: 60, diff --git a/lib/ui/login/verify_last_login_screen.dart b/lib/ui/login/verify_last_login_screen.dart index c6bd0f3..b63fb84 100644 --- a/lib/ui/login/verify_last_login_screen.dart +++ b/lib/ui/login/verify_last_login_screen.dart @@ -4,8 +4,9 @@ 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:local_auth_darwin/local_auth_darwin.dart'; +import 'package:local_auth_android/local_auth_android.dart'; import 'package:mohem_flutter_app/api/login_api_client.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; @@ -63,6 +64,7 @@ class _VerifyLastLoginScreenState extends State { return Scaffold( appBar: AppBar( + surfaceTintColor: Colors.transparent, backgroundColor: Colors.transparent, automaticallyImplyLeading: false, title: (mobileLoginInfoListModel?.businessCardPrivilege ?? false) @@ -219,11 +221,17 @@ 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'); + IOSAuthMessages iosStrings = 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', options: const AuthenticationOptions( + useErrorDialogs: true, stickyAuth: true, biometricOnly: true, + ), + authMessages: [ + iosStrings, + const AndroidAuthMessages(), + ], + ); } on PlatformException catch (e) { print(e); Utils.hideLoading(context); @@ -233,7 +241,17 @@ class _VerifyLastLoginScreenState extends State { } Widget _loginOptionButton(String _title, String _icon, int _flag, int? _loginIndex) { - bool isDisable = ((_flag == 3 && !checkBiometricIsAvailable(BiometricType.face)) || (_flag == 4 && !checkBiometricIsAvailable(BiometricType.fingerprint))); + bool isDisable = false; + if(_flag >= 3 && _flag <= 4) { + bool isFaceEnabled = (_flag == 3 && (checkBiometricIsAvailable(BiometricType.face) || + checkBiometricIsAvailable(BiometricType.weak))); + + bool isThumbEnabled = + (_flag == 4 && (checkBiometricIsAvailable(BiometricType.fingerprint) || + checkBiometricIsAvailable(BiometricType.strong))); + + isDisable = !(isFaceEnabled || isThumbEnabled); + } return InkWell( onTap: isDisable ? null diff --git a/lib/ui/login/verify_login_screen.dart b/lib/ui/login/verify_login_screen.dart index ac3c454..4358190 100644 --- a/lib/ui/login/verify_login_screen.dart +++ b/lib/ui/login/verify_login_screen.dart @@ -4,7 +4,8 @@ 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_darwin/local_auth_darwin.dart'; +import 'package:local_auth_android/local_auth_android.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'; @@ -516,7 +517,11 @@ 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', + options: const AuthenticationOptions(useErrorDialogs: true, stickyAuth: true, biometricOnly: true,), authMessages: [ + iosStrings, + const AndroidAuthMessages(), + ],); } on PlatformException catch (e) { print(e); Utils.hideLoading(context); @@ -526,7 +531,17 @@ class _VerifyLoginScreenState extends State { } Widget _loginOptionButton(String _title, String _icon, int _flag, int? _loginIndex) { - bool isDisable = ((_flag == 3 && !checkBiometricIsAvailable(BiometricType.face)) || (_flag == 4 && !checkBiometricIsAvailable(BiometricType.fingerprint))); + bool isDisable = false; + if(_flag >= 3 && _flag <= 4) { + bool isFaceEnabled = (_flag == 3 && (checkBiometricIsAvailable(BiometricType.face) || + checkBiometricIsAvailable(BiometricType.weak))); + + bool isThumbEnabled = + (_flag == 4 && (checkBiometricIsAvailable(BiometricType.fingerprint) || + checkBiometricIsAvailable(BiometricType.strong))); + + isDisable = !(isFaceEnabled || isThumbEnabled); + } return InkWell( onTap: isDisable ? null diff --git a/lib/ui/my_team/view_attendance.dart b/lib/ui/my_team/view_attendance.dart index a45f35c..15c4325 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,8 @@ 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()), ).then( (selectedDate) { if (selectedDate != null) { diff --git a/lib/ui/profile/delete_family_member.dart b/lib/ui/profile/delete_family_member.dart index 3b73512..d2c8c94 100644 --- a/lib/ui/profile/delete_family_member.dart +++ b/lib/ui/profile/delete_family_member.dart @@ -115,9 +115,8 @@ class _DeleteFamilyMemberState extends State { padding: EdgeInsets.only(left: 50, right: 50), child: TextButton( style: TextButton.styleFrom( - primary: MyColors.white, - onSurface: MyColors.white, - backgroundColor: MyColors.gradiantEndColor, + backgroundColor: MyColors.white, + foregroundColor: MyColors.white, ), onPressed: () { deleteFamilyMember(datePar); diff --git a/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart b/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart index b4cb242..30a9fa2 100644 --- a/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart +++ b/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart @@ -76,7 +76,7 @@ class _OffersAndDiscountsDetailsState extends State { : getOffersList[0].titleEn!.toText22(isBold: true, color: const Color(0xff2B353E)).center, Html( data: AppState().isArabic(context) ? getOffersList[0].descriptionAr! : getOffersList[0].descriptionEn ?? "", - onLinkTap: (String? url, RenderContext context, Map attributes, _) { + onLinkTap: (String? url, Map attributes, _) { launchUrl(Uri.parse(url!)); }, ), diff --git a/lib/widgets/app_bar_widget.dart b/lib/widgets/app_bar_widget.dart index 6f9898e..6737945 100644 --- a/lib/widgets/app_bar_widget.dart +++ b/lib/widgets/app_bar_widget.dart @@ -15,6 +15,8 @@ AppBar AppBarWidget(BuildContext context, void Function()? onBackTapped}) { return AppBar( leadingWidth: 0, + automaticallyImplyLeading: false, + surfaceTintColor: Colors.transparent, title: Row( children: [ GestureDetector( diff --git a/lib/widgets/chat_app_bar_widge.dart b/lib/widgets/chat_app_bar_widge.dart index cc252ec..1291f9f 100644 --- a/lib/widgets/chat_app_bar_widge.dart +++ b/lib/widgets/chat_app_bar_widge.dart @@ -13,6 +13,8 @@ AppBar ChatAppBarWidget(BuildContext context, {required String title, bool showHomeButton = true, ChatUser? chatUser, bool showTyping = false, List? actions, void Function()? onHomeTapped, void Function()? onBackTapped}) { return AppBar( leadingWidth: 0, + automaticallyImplyLeading: false, + surfaceTintColor: Colors.transparent, title: Consumer(builder: (BuildContext cxt, ChatProviderModel data, Widget? child) { return Row( children: [ diff --git a/lib/widgets/nfc/nfc_reader_sheet.dart b/lib/widgets/nfc/nfc_reader_sheet.dart index b7b97a7..5e0b62d 100644 --- a/lib/widgets/nfc/nfc_reader_sheet.dart +++ b/lib/widgets/nfc/nfc_reader_sheet.dart @@ -80,6 +80,7 @@ class _NfcLayoutState extends State { Widget scanNfc() { return Container( key: ValueKey(1), + width: double.infinity, child: Column( mainAxisSize: MainAxisSize.min, children: [ diff --git a/pubspec.yaml b/pubspec.yaml index 20ed5c2..fb73b69 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -20,7 +20,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 3.4.4+300054 environment: - sdk: ">=2.16.0 <3.0.0" + sdk: ">=2.16.0 <3.5.0" # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions @@ -44,9 +44,9 @@ dependencies: permission_handler: ^10.2.0 flutter_svg: any sizer: ^2.0.15 - local_auth: ^1.1.9 + local_auth: ^2.2.0 fluttertoast: ^8.0.8 - syncfusion_flutter_calendar: ^19.4.48 + syncfusion_flutter_calendar: 21.2.9 # flutter_calendar_carousel: ^2.1.0 pie_chart: ^5.1.0 shared_preferences: ^2.0.12 @@ -62,8 +62,8 @@ dependencies: image_picker: ^0.8.5+3 file_picker: 5.2.5 geolocator: ^9.0.2 - month_year_picker: ^0.2.0+1 - month_picker_dialog_2: ^0.5.5 + month_year_picker: ^0.3.0+1 + month_picker_dialog: ^2.12.0 # open_file: ^3.2.1 open_filex: ^4.4.0 wifi_iot: ^0.3.18 @@ -91,7 +91,7 @@ dependencies: swipe_to: ^1.0.2 flutter_webrtc: ^0.9.17 camera: ^0.10.3 - flutter_local_notifications: ^10.0.0 + flutter_local_notifications: ^17.2.1+2 #firebase_analytics: any #Chat Voice Message Recoding & Play @@ -119,7 +119,7 @@ dependencies: #Huawei Specified # store_checker: ^1.1.0 google_api_availability: ^3.0.1 - + google_maps_flutter_web: ^0.5.4 in_app_update: 3.0.0 #todo its for temporary purpose, later will remove this. -- 2.30.2 From 2e3abed42efd0c18d0fb472a89068fdda10cbcc1 Mon Sep 17 00:00:00 2001 From: "taha.alam" Date: Sun, 4 Aug 2024 11:17:39 +0300 Subject: [PATCH 030/135] WD: dialog color changes. --- lib/theme/app_theme.dart | 3 ++- lib/ui/dialogs/id/business_card_dialog.dart | 1 - lib/ui/login/verify_last_login_screen.dart | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/theme/app_theme.dart b/lib/theme/app_theme.dart index e46ee34..f3f756f 100644 --- a/lib/theme/app_theme.dart +++ b/lib/theme/app_theme.dart @@ -16,9 +16,10 @@ class AppTheme { }, ), hintColor: Colors.grey[400], - colorScheme: ColorScheme.fromSwatch(accentColor: MyColors.backgroundColor), + colorScheme: ColorScheme.fromSwatch(accentColor: MyColors.backgroundColor).copyWith(surfaceTint : Colors.transparent), disabledColor: Colors.grey[300], errorColor: const Color.fromRGBO(235, 80, 60, 1.0), + applyElevationOverlayColor: false, scaffoldBackgroundColor: MyColors.backgroundColor, textSelectionTheme: const TextSelectionThemeData(cursorColor: Colors.grey, selectionColor: Color.fromRGBO(80, 100, 253, 0.5), selectionHandleColor: Colors.grey), canvasColor: Colors.white, diff --git a/lib/ui/dialogs/id/business_card_dialog.dart b/lib/ui/dialogs/id/business_card_dialog.dart index ed9f260..a405ccf 100644 --- a/lib/ui/dialogs/id/business_card_dialog.dart +++ b/lib/ui/dialogs/id/business_card_dialog.dart @@ -21,7 +21,6 @@ class BusinessCardDialog extends StatelessWidget { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, - children: [ Row( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/ui/login/verify_last_login_screen.dart b/lib/ui/login/verify_last_login_screen.dart index b63fb84..8f6751c 100644 --- a/lib/ui/login/verify_last_login_screen.dart +++ b/lib/ui/login/verify_last_login_screen.dart @@ -69,13 +69,13 @@ class _VerifyLastLoginScreenState extends State { automaticallyImplyLeading: false, title: (mobileLoginInfoListModel?.businessCardPrivilege ?? false) ? LocaleKeys.viewBusinessCard.tr().toText12(color: MyColors.textMixColor, isUnderLine: true).onPress(() { - showMDialog(context, child: BusinessCardDialog()); + showMDialog(context, child: BusinessCardDialog(),backgroundColor: Colors.white); }) : Container(), actions: [ Center( child: LocaleKeys.employeeDigitalID.tr().toText12(color: MyColors.textMixColor, isUnderLine: true).onPress(() { - showMDialog(context, child: EmployeeDigitialIdDialog()); + showMDialog(context, child: EmployeeDigitialIdDialog(),backgroundColor: Colors.white); })), 21.width ], -- 2.30.2 From db40f42a0861053013428afe7bd5bb0be99d9401 Mon Sep 17 00:00:00 2001 From: Sultan khan <> Date: Wed, 21 Aug 2024 17:55:23 +0300 Subject: [PATCH 031/135] payment CR 6939 done --- lib/models/worklist/payment_details_list.dart | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 lib/models/worklist/payment_details_list.dart diff --git a/lib/models/worklist/payment_details_list.dart b/lib/models/worklist/payment_details_list.dart new file mode 100644 index 0000000..e69de29 -- 2.30.2 From 423e8551f188d1c8223b5aaad78e30381524f226 Mon Sep 17 00:00:00 2001 From: Sultan khan <> Date: Wed, 21 Aug 2024 17:58:08 +0300 Subject: [PATCH 032/135] changes updated --- lib/api/worklist/worklist_api_client.dart | 31 + lib/app_state/app_state.dart | 2 +- lib/classes/consts.dart | 4 +- lib/generated/codegen_loader.g.dart | 53 +- lib/generated/locale_keys.g.dart | 25 + lib/models/generic_response_model.dart | 10 + lib/models/worklist/payment_details_list.dart | 285 +++++++++ lib/ui/login/verify_last_login_screen.dart | 12 +- lib/ui/work_list/work_list_screen.dart | 5 +- lib/ui/work_list/worklist_detail_screen.dart | 330 +++++++---- .../worklist_fragments/actions_fragment.dart | 2 +- .../worklist_fragments/info_fragments.dart | 545 +++++++++++++----- 12 files changed, 1052 insertions(+), 252 deletions(-) diff --git a/lib/api/worklist/worklist_api_client.dart b/lib/api/worklist/worklist_api_client.dart index d2389ab..19fe52c 100644 --- a/lib/api/worklist/worklist_api_client.dart +++ b/lib/api/worklist/worklist_api_client.dart @@ -36,6 +36,7 @@ import 'package:mohem_flutter_app/models/worklist/hr/get_contact_notification_bo import 'package:mohem_flutter_app/models/worklist/hr/get_phones_notification_body_list_model.dart'; import 'package:mohem_flutter_app/models/worklist/replacement_list_model.dart'; import 'package:mohem_flutter_app/models/worklist_response_model.dart'; +import 'package:mohem_flutter_app/models/worklist/payment_details_list.dart'; class WorkListApiClient { static final WorkListApiClient _instance = WorkListApiClient._internal(); @@ -290,6 +291,22 @@ class WorkListApiClient { return responseData.getPrNotificationBodyList; }, url, postParams); } + Future getPaymentNotificationBody(int pNotificationID, int pTransactionID) async { + String url = "${ApiConsts.erpRest}GET_PAY_REQ_NOTIFICATION_BODY"; + Map postParams = { + "P_NOTIFICATION_ID": pNotificationID, + "P_TRANSACTION_ID": pTransactionID, + "P_PAGE_LIMIT": 100, + "P_PAGE_NUM": 1, + }; + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject((json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getPaymentNotificationBodyList; + }, url, postParams); + } + + Future> getMoItemHistory(int pItemID, int pOrgID) async { String url = "${ApiConsts.erpRest}GET_MO_ITEM_HISTORY"; @@ -700,4 +717,18 @@ class WorkListApiClient { return responseData.getPRInformationList; }, url, postParams); } + + Future?> getPaymentDetailsNotification(int? notificationId) async { + String url = "${ApiConsts.erpRest}GET_PAY_REQ_NOTIFICATION_BODY"; + Map postParams = { + "P_NOTIFICATION_ID": notificationId, + "P_PAGE_LIMIT": 100, + "P_PAGE_NUM": 1, + }; + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject((json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getAbsenceCollectionNotificationBodyList; + }, url, postParams); + } } diff --git a/lib/app_state/app_state.dart b/lib/app_state/app_state.dart index 3ae2097..2e8e2ad 100644 --- a/lib/app_state/app_state.dart +++ b/lib/app_state/app_state.dart @@ -90,7 +90,7 @@ class AppState { String get getHuaweiPushToken => _huaweiPushToken; - final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 5.9, mobileType: Platform.isAndroid ? "android" : "ios"); + final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 6.0, mobileType: Platform.isAndroid ? "android" : "ios"); void setPostParamsInitConfig() { isAuthenticated = false; diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 4ed76b1..bee7a99 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -4,10 +4,10 @@ class ApiConsts { // static String baseUrl = "http://10.200.204.11"; // Local server // static String baseUrl = "https://erptstapp.srca.org.sa"; // SRCA server static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver - // static String baseUrl = "http://10.201.204.101:2024"; + // static String baseUrl = "http://10.20.200.111:1010/"; // static String baseUrl = "https://webservices.hmg.com"; // PreProd - + // static String baseUrl = "https://mohemm.hmg.com"; // static String baseUrl = "https://hmgwebservices.com"; // Live server static String baseUrlServices = baseUrl + "/Services/"; // server // static String baseUrlServices = "https://api.cssynapses.com/tangheem/"; // Live server diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index af972f6..aa461eb 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -551,6 +551,32 @@ class CodegenLoader extends AssetLoader { "uploadedDocuments": "المستندات التي تم تحميلها", "youCannotJoinTheMarathon": "لا يمكنك الانضمام إلى الماراثون لأنك تجاوزت الحد الزمني", "pleaseClickButtonToJoinMarathon": "الرجاء الضغط على الزر أدناه للانضمام إلى الماراثون", + "paymentRequest":"طلب الدفع", + + "paymentDetails":"تفاصيل الدفع", + "requestNo":"رقم الطلب", + "requesterEmpNum":"رقم الموظف الذي قدم الطلب", + "requesterEmpName":"اسم الموظف مقدم الطلب", + "prepareEmpName":"إعداد اسم الموظف", + "requesterPositionName":"اسم الوظيفة لمقدم الطلب", + "preparePositionName":"إعداد اسم الوظيفة", + "requesterPayrollName":"اسم مقدم الطلب", + "payingORGName":"اسم المنظمة الدافعة", + "requestAmount":"مبلغ الطلب", + "typeofPayment":"نوع الدفع", + "beneficiaryDetails":"تفاصيل المستفيد", + "beneficiaryName":"اسم المستفيد", + "idIqama":"الهوية السعودية / الإقامة", + "beneficiaryBankName":"اسم البنك المستفيد", + "sadadNumber":"رقم سداد", + "beneficiaryIBAN":"رقم IBAN للمستفيد", + "purchaseOrders":"طلبات الشراء", + "approvalDate":"تاريخ الموافقة", + "pOAmount":"مبلغ الطلب", + "versionStatus":"حالة الإصدار", + "supplierNo":"رقم المورد", + "general":"عام" + }; static const Map en_US = { "mohemm": "Mohemm", @@ -1107,7 +1133,32 @@ class CodegenLoader extends AssetLoader { "userName": "User Name", "userId": "UserID", "pleaseClickButtonToJoinMarathon": "Press the button below to join the Marathon.", - "youCannotJoinTheMarathon": "You cannot join the Marathon because you have exceeded the time limit." + "youCannotJoinTheMarathon": "You cannot join the Marathon because you have exceeded the time limit.", + + "paymentRequest":"Pay Request", + "paymentDetails":"Payment Details", + "requestNo":"Request No", + "requesterEmpNum":"Requester Employee Num", + "requesterEmpName":"Requester Employee Name", + "prepareEmpName":"Prepare Employee Name", + "requesterPositionName":"Requester Position Name", + "preparePositionName":"Prepare Position Name", + "requesterPayrollName":"Requester Payroll Name", + "payingORGName":"Paying Organization Name", + "requestAmount":"Request Amount", + "typeofPayment":"Type of Payment", + "beneficiaryDetails":"Beneficiary Details", + "beneficiaryName":"Beneficiary Name", + "idIqama":"Saudi ID / Iqama", + "beneficiaryBankName":"Beneficiary Bank Name", + "sadadNumber":"Sadad Number", + "beneficiaryIBAN":"Beneficiary IBAN", + "purchaseOrders":"Purchase Orders", + "approvalDate":"Approval Date", + "pOAmount":"PO Amount", + "versionStatus":"Version Status", + "supplierNo":"Supplier No", + "general":"General" }; static const Map> mapLocales = {"ar_SA": ar_SA, "en_US": en_US}; } diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index a6fd43d..bf2c095 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -403,6 +403,7 @@ abstract class LocaleKeys { static const purchaseOrder = 'purchaseOrder'; static const ITGForms = 'ITGForms'; static const itemCreation = 'itemCreation'; + static const paymentRequest = 'paymentRequest'; static const stamp = 'stamp'; static const addFavoriteList = 'addFavoriteList'; static const feedbackUserExperience = 'feedbackUserExperience'; @@ -550,4 +551,28 @@ abstract class LocaleKeys { static const pleaseClickButtonToJoinMarathon ='pleaseClickButtonToJoinMarathon'; static const youCannotJoinTheMarathon ='youCannotJoinTheMarathon'; static const open ='open'; + static const paymentDetails ='paymentDetails'; + static const requestNo ='requestNo'; + static const requesterEmpNum ='requesterEmpNum'; + static const requesterEmpName ='requesterEmpName'; + static const prepareEmpName ='prepareEmpName'; + static const requesterPositionName ='requesterPositionName'; + static const preparePositionName ='preparePositionName'; + static const requesterPayrollName ='requesterPayrollName'; + static const payingORGName ='payingORGName'; + static const requestAmount ='requestAmount'; + static const typeofPayment ='typeofPayment'; + static const beneficiaryDetails ='beneficiaryDetails'; + static const beneficiaryName ='beneficiaryName'; + static const idIqama ='idIqama'; + static const beneficiaryBankName ='beneficiaryBankName'; + static const sadadNumber ='sadadNumber'; + static const beneficiaryIBAN ='beneficiaryIBAN'; + static const purchaseOrders ='purchaseOrders'; + static const pOAmount ='pOAmount'; + static const approvalDate ='approvalDate'; + static const versionStatus ='versionStatus'; + static const supplierNo ='supplierNo'; + static const general ="general"; + } diff --git a/lib/models/generic_response_model.dart b/lib/models/generic_response_model.dart index 893b5b9..e9daeb4 100644 --- a/lib/models/generic_response_model.dart +++ b/lib/models/generic_response_model.dart @@ -110,6 +110,7 @@ import 'package:mohem_flutter_app/models/worklist/hr/get_address_notification_bo import 'package:mohem_flutter_app/models/worklist/hr/get_basic_det_ntf_body_list_model.dart'; import 'package:mohem_flutter_app/models/worklist/hr/get_contact_notification_body_list_model.dart'; import 'package:mohem_flutter_app/models/worklist/hr/get_phones_notification_body_list_model.dart'; +import 'package:mohem_flutter_app/models/worklist/payment_details_list.dart'; import 'package:mohem_flutter_app/models/worklist/replacement_list_model.dart'; import 'package:mohem_flutter_app/models/worklist/resubmit_eit_response_model.dart'; import 'package:mohem_flutter_app/models/worklist_response_model.dart'; @@ -187,6 +188,7 @@ class GenericResponseModel { List? getCEIDFFStructureList; List? getCEITransactionList; List? getCcpTransactionsList; + List? getContactColsStructureList; List? getContactDetailsList; List? getContactDffStructureList; @@ -232,6 +234,7 @@ class GenericResponseModel { List? getPoItemHistoryList; GetPoNotificationBodyList? getPoNotificationBodyList; GetPrNotificationBodyList? getPrNotificationBodyList; + GetPaymentNotificationBodyList? getPaymentNotificationBodyList; GetPRInformationList? getPRInformationList; List? getQuotationAnalysisList; List? getRFCEmployeeListList; @@ -500,6 +503,7 @@ class GenericResponseModel { this.getPoItemHistoryList, this.getPoNotificationBodyList, this.getPrNotificationBodyList, + this.getPaymentNotificationBodyList, this.getPRInformationList, this.getQuotationAnalysisList, this.getRFCEmployeeListList, @@ -1022,6 +1026,9 @@ class GenericResponseModel { } getPoNotificationBodyList = json['GetPoNotificationBodyList'] != null ? GetPoNotificationBodyList.fromJson(json['GetPoNotificationBodyList']) : null; getPrNotificationBodyList = json['GetPrNotificationBodyList'] != null ? GetPrNotificationBodyList.fromJson(json['GetPrNotificationBodyList']) : null; + getPaymentNotificationBodyList = json['Pay_ReqNotificationBody'] != null ? GetPaymentNotificationBodyList.fromJson(json['Pay_ReqNotificationBody']) : null; + + getPRInformationList = json['PR_Information_List'] != null ? GetPRInformationList.fromJson(json['PR_Information_List']) : null; if (json['GetQuotationAnalysisList'] != null) { getQuotationAnalysisList = []; @@ -1650,6 +1657,9 @@ class GenericResponseModel { if (this.getPrNotificationBodyList != null) { data['GetPrNotificationBodyList'] = this.getPrNotificationBodyList!.toJson(); } + if (this.getPaymentNotificationBodyList != null) { + data['Pay_ReqNotificationBody'] = this.getPaymentNotificationBodyList!.toJson(); + } if (this.getPRInformationList != null) { data['PR_Information_List'] = this.getPRInformationList!.toJson(); diff --git a/lib/models/worklist/payment_details_list.dart b/lib/models/worklist/payment_details_list.dart index e69de29..be7bada 100644 --- a/lib/models/worklist/payment_details_list.dart +++ b/lib/models/worklist/payment_details_list.dart @@ -0,0 +1,285 @@ +import 'dart:convert'; + +class GetPaymentNotificationBodyList { + List? beneficieryList; + dynamic pInformation; + dynamic pQuestion; + List? paymentDetailsList; + List? purchaseOrdersList; + List? refundInvoiceList; + List? supplierInformationList; + + GetPaymentNotificationBodyList({ + this.beneficieryList, + this.pInformation, + this.pQuestion, + this.paymentDetailsList, + this.purchaseOrdersList, + this.refundInvoiceList, + this.supplierInformationList, + }); + + factory GetPaymentNotificationBodyList.fromRawJson(String str) => GetPaymentNotificationBodyList.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory GetPaymentNotificationBodyList.fromJson(Map json) => GetPaymentNotificationBodyList( + beneficieryList: json["Beneficiery_List"] == null ? [] : List.from(json["Beneficiery_List"]!.map((x) => BeneficieryList.fromJson(x))), + pInformation: json["P_INFORMATION"], + pQuestion: json["P_QUESTION"], + paymentDetailsList: json["PaymentDetails_List"] == null ? [] : List.from(json["PaymentDetails_List"]!.map((x) => PaymentDetailsList.fromJson(x))), + purchaseOrdersList: json["PurchaseOrders_List"] == null ? [] : List.from(json["PurchaseOrders_List"]!.map((x) => PurchaseOrdersList.fromJson(x))), + refundInvoiceList: json["RefundInvoice_List"] == null ? [] : List.from(json["RefundInvoice_List"]!.map((x) => RefundInvoiceList.fromJson(x))), + supplierInformationList: json["SupplierInformation_List"] == null ? [] : List.from(json["SupplierInformation_List"]!.map((x) => SupplierInformationList.fromJson(x))), + ); + + Map toJson() => { + "Beneficiery_List": beneficieryList == null ? [] : List.from(beneficieryList!.map((x) => x.toJson())), + "P_INFORMATION": pInformation, + "P_QUESTION": pQuestion, + "PaymentDetails_List": paymentDetailsList == null ? [] : List.from(paymentDetailsList!.map((x) => x.toJson())), + "PurchaseOrders_List": purchaseOrdersList == null ? [] : List.from(purchaseOrdersList!.map((x) => x.toJson())), + "RefundInvoice_List": refundInvoiceList == null ? [] : List.from(refundInvoiceList!.map((x) => x.toJson())), + "SupplierInformation_List": supplierInformationList == null ? [] : List.from(supplierInformationList!.map((x) => x.toJson())), + }; +} + +class BeneficieryList { + String? beneficiaryBankName; + String? beneficiaryIban; + String? beneficiaryName; + String? iqamaNumber; + String? saddadNumber; + + BeneficieryList({ + this.beneficiaryBankName, + this.beneficiaryIban, + this.beneficiaryName, + this.iqamaNumber, + this.saddadNumber, + }); + + factory BeneficieryList.fromRawJson(String str) => BeneficieryList.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory BeneficieryList.fromJson(Map json) => BeneficieryList( + beneficiaryBankName: json["BENEFICIARY_BANK_NAME"], + beneficiaryIban: json["BENEFICIARY_IBAN"], + beneficiaryName: json["BENEFICIARY_NAME"], + iqamaNumber: json["IQAMA_NUMBER"], + saddadNumber: json["SADDAD_NUMBER"], + ); + + Map toJson() => { + "BENEFICIARY_BANK_NAME": beneficiaryBankName, + "BENEFICIARY_IBAN": beneficiaryIban, + "BENEFICIARY_NAME": beneficiaryName, + "IQAMA_NUMBER": iqamaNumber, + "SADDAD_NUMBER": saddadNumber, + }; +} + +class PaymentDetailsList { + String? currency; + String? payingOrganizationName; + String? paymentDetails; + String? paymentMethodName; + String? prepareEmployeeName; + String? prepareEmployeeNumber; + String? preparePositionName; + String? requesterEmployeeName; + String? requesterEmployeeNumber; + String? requesterOperatingUnits; + String? requesterPayrollName; + String? requesterPositionName; + String? requestAmount; + String? requestDate; + String? requestNumber; + String? typeOfPayment; + + PaymentDetailsList({ + this.currency, + this.payingOrganizationName, + this.paymentDetails, + this.paymentMethodName, + this.prepareEmployeeName, + this.prepareEmployeeNumber, + this.preparePositionName, + this.requesterEmployeeName, + this.requesterEmployeeNumber, + this.requesterOperatingUnits, + this.requesterPayrollName, + this.requesterPositionName, + this.requestAmount, + this.requestDate, + this.requestNumber, + this.typeOfPayment, + }); + + factory PaymentDetailsList.fromRawJson(String str) => PaymentDetailsList.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory PaymentDetailsList.fromJson(Map json) => PaymentDetailsList( + currency: json["CURRENCY"], + payingOrganizationName: json["PAYING_ORGANIZATION_NAME"], + paymentDetails: json["PAYMENT_DETAILS"], + paymentMethodName: json["PAYMENT_METHOD_NAME"], + prepareEmployeeName: json["PREPARE_EMPLOYEE_NAME"], + prepareEmployeeNumber: json["PREPARE_EMPLOYEE_NUMBER"], + preparePositionName: json["PREPARE_POSITION_NAME"], + requesterEmployeeName: json["REQUESTER_EMPLOYEE_NAME"], + requesterEmployeeNumber: json["REQUESTER_EMPLOYEE_NUMBER"], + requesterOperatingUnits: json["REQUESTER_OPERATING_UNITS"], + requesterPayrollName: json["REQUESTER_PAYROLL_NAME"], + requesterPositionName: json["REQUESTER_POSITION_NAME"], + requestAmount: json["REQUEST_AMOUNT"], + requestDate: json["REQUEST_DATE"], + requestNumber: json["REQUEST_NUMBER"], + typeOfPayment: json["TYPE_OF_PAYMENT"], + ); + + Map toJson() => { + "CURRENCY": currency, + "PAYING_ORGANIZATION_NAME": payingOrganizationName, + "PAYMENT_DETAILS": paymentDetails, + "PAYMENT_METHOD_NAME": paymentMethodName, + "PREPARE_EMPLOYEE_NAME": prepareEmployeeName, + "PREPARE_EMPLOYEE_NUMBER": prepareEmployeeNumber, + "PREPARE_POSITION_NAME": preparePositionName, + "REQUESTER_EMPLOYEE_NAME": requesterEmployeeName, + "REQUESTER_EMPLOYEE_NUMBER": requesterEmployeeNumber, + "REQUESTER_OPERATING_UNITS": requesterOperatingUnits, + "REQUESTER_PAYROLL_NAME": requesterPayrollName, + "REQUESTER_POSITION_NAME": requesterPositionName, + "REQUEST_AMOUNT": requestAmount, + "REQUEST_DATE": requestDate, + "REQUEST_NUMBER": requestNumber, + "TYPE_OF_PAYMENT": typeOfPayment, + }; +} + +class PurchaseOrdersList { + dynamic poAmount; + dynamic poApprovalDate; + String? poNumber; + String? prNumber; + String? supplierName; + String? supplierNumber; + String? versionStatus; + + PurchaseOrdersList({ + this.poAmount, + this.poApprovalDate, + this.poNumber, + this.prNumber, + this.supplierName, + this.supplierNumber, + this.versionStatus, + }); + + factory PurchaseOrdersList.fromRawJson(String str) => PurchaseOrdersList.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory PurchaseOrdersList.fromJson(Map json) => PurchaseOrdersList( + poAmount: json["PO_AMOUNT"], + poApprovalDate: json["PO_APPROVAL_DATE"], + poNumber: json["PO_NUMBER"], + prNumber: json["PR_NUMBER"], + supplierName: json["SUPPLIER_NAME"], + supplierNumber: json["SUPPLIER_NUMBER"], + versionStatus: json["VERSION_STATUS"], + ); + + Map toJson() => { + "PO_AMOUNT": poAmount, + "PO_APPROVAL_DATE": poApprovalDate, + "PO_NUMBER": poNumber, + "PR_NUMBER": prNumber, + "SUPPLIER_NAME": supplierName, + "SUPPLIER_NUMBER": supplierNumber, + "VERSION_STATUS": versionStatus, + }; +} + +class RefundInvoiceList { + dynamic amount; + String? hospitalClinic; + dynamic invoicedDate; + String? invoiceNumber; + String? patientName; + String? patientNumber; + + RefundInvoiceList({ + this.amount, + this.hospitalClinic, + this.invoicedDate, + this.invoiceNumber, + this.patientName, + this.patientNumber, + }); + + factory RefundInvoiceList.fromRawJson(String str) => RefundInvoiceList.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory RefundInvoiceList.fromJson(Map json) => RefundInvoiceList( + amount: json["AMOUNT"], + hospitalClinic: json["HOSPITAL_CLINIC"], + invoicedDate: json["INVOICED_DATE"], + invoiceNumber: json["INVOICE_NUMBER"], + patientName: json["PATIENT_NAME"], + patientNumber: json["PATIENT_NUMBER"], + ); + + Map toJson() => { + "AMOUNT": amount, + "HOSPITAL_CLINIC": hospitalClinic, + "INVOICED_DATE": invoicedDate, + "INVOICE_NUMBER": invoiceNumber, + "PATIENT_NAME": patientName, + "PATIENT_NUMBER": patientNumber, + }; +} + +class SupplierInformationList { + String? crNumber; + String? supplierBankAccountName; + String? supplierBankAccountNumber; + String? supplierBankIban; + String? supplierName; + String? supplierNumber; + + SupplierInformationList({ + this.crNumber, + this.supplierBankAccountName, + this.supplierBankAccountNumber, + this.supplierBankIban, + this.supplierName, + this.supplierNumber, + }); + + factory SupplierInformationList.fromRawJson(String str) => SupplierInformationList.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory SupplierInformationList.fromJson(Map json) => SupplierInformationList( + crNumber: json["CR_NUMBER"], + supplierBankAccountName: json["SUPPLIER_BANK_ACCOUNT_NAME"], + supplierBankAccountNumber: json["SUPPLIER_BANK_ACCOUNT_NUMBER"], + supplierBankIban: json["SUPPLIER_BANK_IBAN"], + supplierName: json["SUPPLIER_NAME"], + supplierNumber: json["SUPPLIER_NUMBER"], + ); + + Map toJson() => { + "CR_NUMBER": crNumber, + "SUPPLIER_BANK_ACCOUNT_NAME": supplierBankAccountName, + "SUPPLIER_BANK_ACCOUNT_NUMBER": supplierBankAccountNumber, + "SUPPLIER_BANK_IBAN": supplierBankIban, + "SUPPLIER_NAME": supplierName, + "SUPPLIER_NUMBER": supplierNumber, + }; +} diff --git a/lib/ui/login/verify_last_login_screen.dart b/lib/ui/login/verify_last_login_screen.dart index c6bd0f3..d6d041d 100644 --- a/lib/ui/login/verify_last_login_screen.dart +++ b/lib/ui/login/verify_last_login_screen.dart @@ -57,9 +57,15 @@ class _VerifyLastLoginScreenState extends State { @override Widget build(BuildContext context) { - mobileLoginInfoListModel ??= ModalRoute.of(context)!.settings.arguments as GetMobileLoginInfoListModel; - // String empName = AppState().isArabic(context) ? AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEAr! : AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEEn!; - String empName = mobileLoginInfoListModel!.employeeName!; + if(ModalRoute.of(context)!.settings.arguments != null) { + mobileLoginInfoListModel ??= ModalRoute + .of(context)! + .settings + .arguments as GetMobileLoginInfoListModel; + // String empName = AppState().isArabic(context) ? AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEAr! : AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEEn!; + String empName = mobileLoginInfoListModel!.employeeName!; + + } return Scaffold( appBar: AppBar( diff --git a/lib/ui/work_list/work_list_screen.dart b/lib/ui/work_list/work_list_screen.dart index 9dea0a1..d0360fd 100644 --- a/lib/ui/work_list/work_list_screen.dart +++ b/lib/ui/work_list/work_list_screen.dart @@ -78,7 +78,10 @@ class _WorkListScreenState extends State { WorkListItemTypeModelData( value: 0, name: 'STAMP', fullName: LocaleKeys.stamp.tr(), active: false, color: [Color(0xff32D892), Color(0xff1AB170)], icon: "assets/images/miss_swipe.svg", key: 'STAMP', disable: false), WorkListItemTypeModelData( - value: 0, name: 'COC', fullName: LocaleKeys.itemCreation.tr(), active: false, color: [Color(0xff787299), Color(0xff1AB170)], icon: "assets/images/miss_swipe.svg", key: 'COC', disable: true) + value: 0, name: 'COC', fullName: LocaleKeys.itemCreation.tr(), active: false, color: [Color(0xff787299), Color(0xff1AB170)], icon: "assets/images/miss_swipe.svg", key: 'COC', disable: true), + WorkListItemTypeModelData( + value: 0, name: 'Payment Req', fullName: LocaleKeys.paymentRequest.tr(), active: false, color: [Color(0xffB06F1A), Color(0xff1AB170)], icon: "assets/images/miss_swipe.svg", key: 'PAY_REQ', disable: false) + ]; int? workListItemIndex; diff --git a/lib/ui/work_list/worklist_detail_screen.dart b/lib/ui/work_list/worklist_detail_screen.dart index 3bb3b5d..06fd7c3 100644 --- a/lib/ui/work_list/worklist_detail_screen.dart +++ b/lib/ui/work_list/worklist_detail_screen.dart @@ -29,6 +29,7 @@ import 'package:mohem_flutter_app/models/worklist/hr/get_address_notification_bo import 'package:mohem_flutter_app/models/worklist/hr/get_basic_det_ntf_body_list_model.dart'; import 'package:mohem_flutter_app/models/worklist/hr/get_contact_notification_body_list_model.dart'; import 'package:mohem_flutter_app/models/worklist/hr/get_phones_notification_body_list_model.dart'; +import 'package:mohem_flutter_app/models/worklist/payment_details_list.dart'; import 'package:mohem_flutter_app/models/worklist_response_model.dart'; import 'package:mohem_flutter_app/ui/my_attendance/dynamic_screens/dynamic_listview_screen.dart'; import 'package:mohem_flutter_app/ui/work_list/sheets/delegate_sheet.dart'; @@ -46,7 +47,6 @@ import 'package:mohem_flutter_app/widgets/dialogs/accept_reject_input_dialog.dar import 'package:mohem_flutter_app/widgets/dialogs/confirm_dialog.dart'; import 'package:mohem_flutter_app/models/termination/termination_notification_body.dart'; - class WorkListDetailScreen extends StatefulWidget { WorkListDetailScreen({Key? key}) : super(key: key); @@ -70,27 +70,30 @@ class _WorkListDetailScreenState extends State { List getStampMsNotifications = []; List getStampNsNotifications = []; List getMoNotificationBodyList = []; - List getNotificationRespondAttributes = []; + List getNotificationRespondAttributes = + []; NotificationGetRespondAttributesList? notificationNoteInput; List getRFCEmployeeList = []; //HR Details Screen Requests - List? getEitCollectionNotificationBodyList = []; + List? + getEitCollectionNotificationBodyList = []; List? getPhonesNotificationBodyList = []; List? getBasicDetNtfBodyList = []; - List? getAbsenceCollectionNotificationBodyList = []; + List? + getAbsenceCollectionNotificationBodyList = []; GetContactNotificationBodyList? getContactNotificationBodyList; List? getAddressNotificationBodyList = []; List? getTerminationNotificationBodyList = []; - GenericResponseModel? getBasicNTFBody; GenericResponseModel? getICBody; GenericResponseModel? subordinatesLeavesModel; GetPoNotificationBodyList? getPoNotificationBody; GetPrNotificationBodyList? getPrNotificationBody; GetItemCreationNtfBodyList? getItemCreationNtfBody; + GetPaymentNotificationBodyList? getPaymentNotificationBodyList; bool isCloseAvailable = false; bool isApproveAvailable = false; @@ -129,8 +132,9 @@ class _WorkListDetailScreenState extends State { getAbsenceCollectionNotificationBodyList!.clear(); getContactNotificationBodyList = null; getAddressNotificationBodyList!.clear(); - - if (workListData!.iTEMTYPE == "HRSSA" || workListData!.iTEMTYPE == "STAMP") { + getPaymentNotificationBodyList = null; + if (workListData!.iTEMTYPE == "HRSSA" || + workListData!.iTEMTYPE == "STAMP") { getUserInformation(); } @@ -152,7 +156,7 @@ class _WorkListDetailScreenState extends State { getContactNotificationBody(); } else if (workListData!.rEQUESTTYPE == "ADDRESS") { getAddressNotificationBody(); - } else if(workListData!.rEQUESTTYPE =='TERMINATION'){ + } else if (workListData!.rEQUESTTYPE == 'TERMINATION') { getTerminationNotificationBody(); } } @@ -171,6 +175,9 @@ class _WorkListDetailScreenState extends State { if (workListData!.iTEMTYPE == "REQAPPRV") { getPRNotification(); } + if (workListData!.iTEMTYPE == "PAY_REQ") { + getPaymentNotification(); + } if (controller.hasClients) { controller.jumpToPage(0); @@ -184,7 +191,8 @@ class _WorkListDetailScreenState extends State { void getDataFromState() { if (workListData == null) { - workListData = AppState().workList![AppState().workListIndex!]; // ModalRoute.of(context)!.settings.arguments as WorkListResponseModel; + workListData = AppState().workList![AppState() + .workListIndex!]; // ModalRoute.of(context)!.settings.arguments as WorkListResponseModel; getData(); } } @@ -217,7 +225,8 @@ class _WorkListDetailScreenState extends State { Column( children: [ Container( - padding: const EdgeInsets.only(left: 21, right: 21, top: 16, bottom: 16), + padding: const EdgeInsets.only( + left: 21, right: 21, top: 16, bottom: 16), decoration: const BoxDecoration( borderRadius: BorderRadius.only( bottomLeft: Radius.circular(25), @@ -236,13 +245,19 @@ class _WorkListDetailScreenState extends State { child: Row( children: [ myTab(LocaleKeys.info.tr(), 0), - (workListData!.iTEMTYPE == "HRSSA" || workListData!.iTEMTYPE == "STAMP") ? myTab(LocaleKeys.details.tr(), 1) : myTab(LocaleKeys.request.tr(), 1), + (workListData!.iTEMTYPE == "HRSSA" || + workListData!.iTEMTYPE == "STAMP") + ? myTab(LocaleKeys.details.tr(), 1) + : myTab(LocaleKeys.request.tr(), 1), myTab(LocaleKeys.actions.tr(), 2), myTab(LocaleKeys.attachments.tr(), 3), ], ), ), - if ((workListData?.sUBJECT ?? "").isNotEmpty) workListData!.sUBJECT!.toText14().paddingOnly(top: 20, right: 21, left: 21), + if ((workListData?.sUBJECT ?? "").isNotEmpty) + workListData!.sUBJECT! + .toText14() + .paddingOnly(top: 20, right: 21, left: 21), PageView( controller: controller, onPageChanged: (int pageIndex) { @@ -254,25 +269,38 @@ class _WorkListDetailScreenState extends State { InfoFragment( poHeaderList: getPoNotificationBody?.pOHeader ?? [], workListData: workListData, - itemCreationHeader: getItemCreationNtfBody?.itemCreationHeader ?? [], + itemCreationHeader: + getItemCreationNtfBody?.itemCreationHeader ?? [], getStampMsNotifications: getStampMsNotifications, getStampNsNotifications: getStampNsNotifications, - getEitCollectionNotificationBodyList: getEitCollectionNotificationBodyList, - getPhonesNotificationBodyList: getPhonesNotificationBodyList, + getEitCollectionNotificationBodyList: + getEitCollectionNotificationBodyList, + getPhonesNotificationBodyList: + getPhonesNotificationBodyList, getBasicDetNtfBodyList: getBasicDetNtfBodyList, - getAddressNotificationBodyList: getAddressNotificationBodyList, - getAbsenceCollectionNotificationBodyList: getAbsenceCollectionNotificationBodyList, - getContactNotificationBodyList: getContactNotificationBodyList, + getAddressNotificationBodyList: + getAddressNotificationBodyList, + getAbsenceCollectionNotificationBodyList: + getAbsenceCollectionNotificationBodyList, + getContactNotificationBodyList: + getContactNotificationBodyList, getPrNotificationBodyList: getPrNotificationBody, - getTerminationNotificationBodyList:getTerminationNotificationBodyList + getTerminationNotificationBodyList: + getTerminationNotificationBodyList, + getPaymentNotificationBodyList: + getPaymentNotificationBodyList, ), - (workListData!.iTEMTYPE == "HRSSA" || workListData!.iTEMTYPE == "STAMP") - ? DetailFragment(workListData, memberInformationListModel) + (workListData!.iTEMTYPE == "HRSSA" || + workListData!.iTEMTYPE == "STAMP" || workListData!.iTEMTYPE == "PAY_REQ") + ? DetailFragment( + workListData, memberInformationListModel) : RequestFragment( moNotificationBodyList: getMoNotificationBodyList, poLinesList: getPoNotificationBody?.pOLines ?? [], - itemCreationLines: getItemCreationNtfBody?.itemCreationLines ?? [], + itemCreationLines: + getItemCreationNtfBody?.itemCreationLines ?? [], prLinesList: getPrNotificationBody?.pRLines ?? [], + ), isActionHistoryLoaded ? actionHistoryList.isEmpty @@ -292,11 +320,13 @@ class _WorkListDetailScreenState extends State { ).expanded, if (isApproveAvailable || isRejectAvailable || isCloseAvailable) Container( - padding: const EdgeInsets.only(top: 14, bottom: 14, left: 21, right: 21), + padding: const EdgeInsets.only( + top: 14, bottom: 14, left: 21, right: 21), decoration: const BoxDecoration( color: Colors.white, border: Border( - top: BorderSide(color: MyColors.lightGreyEFColor, width: 1.0), + top: BorderSide( + color: MyColors.lightGreyEFColor, width: 1.0), ), ), child: Row( @@ -305,20 +335,29 @@ class _WorkListDetailScreenState extends State { DefaultButton( LocaleKeys.reject.tr(), () => performAction(rejectAction), - colors: const [Color(0xffE47A7E), Color(0xffDE6D71)], + colors: const [ + Color(0xffE47A7E), + Color(0xffDE6D71) + ], ).expanded, if (isApproveAvailable && isRejectAvailable) 8.width, if (isApproveAvailable) DefaultButton( LocaleKeys.approve.tr(), () => performAction(approveAction), - colors: const [Color(0xff28C884), Color(0xff1BB271)], + colors: const [ + Color(0xff28C884), + Color(0xff1BB271) + ], ).expanded, if (isCloseAvailable) DefaultButton( LocaleKeys.ok.tr(), () => performAction("CLOSE"), - colors: const [Color(0xff32D892), Color(0xff1AB170)], + colors: const [ + Color(0xff32D892), + Color(0xff1AB170) + ], ).expanded, 8.width, Container( @@ -328,7 +367,11 @@ class _WorkListDetailScreenState extends State { shape: BoxShape.circle, color: MyColors.lightGreyE6Color, ), - child: Icon(showFabOptions ? Icons.more_vert_rounded : Icons.more_horiz_rounded, color: MyColors.darkIconColor), + child: Icon( + showFabOptions + ? Icons.more_vert_rounded + : Icons.more_horiz_rounded, + color: MyColors.darkIconColor), ).onPress(() { setState(() { showFabOptions = true; @@ -345,7 +388,8 @@ class _WorkListDetailScreenState extends State { opacity: showFabOptions ? 1 : 0, duration: const Duration(milliseconds: 250), child: Container( - padding: const EdgeInsets.only(left: 21, right: 21, bottom: 75 - 12), + padding: const EdgeInsets.only( + left: 21, right: 21, bottom: 75 - 12), width: double.infinity, height: double.infinity, color: Colors.white.withOpacity(.67), @@ -354,15 +398,19 @@ class _WorkListDetailScreenState extends State { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.end, children: [ - myFab(LocaleKeys.skip.tr(), "assets/images/skip.svg").onPress(() { - if (AppState().workList!.length - 1 > AppState().workListIndex!) { + myFab(LocaleKeys.skip.tr(), "assets/images/skip.svg") + .onPress(() { + if (AppState().workList!.length - 1 > + AppState().workListIndex!) { animationIndex = animationIndex + 1; - AppState().setWorkListIndex = AppState().workListIndex! + 1; + AppState().setWorkListIndex = + AppState().workListIndex! + 1; workListData = null; showFabOptions = false; tabIndex = 0; getDataFromState(); - } else if (AppState().workList!.length - 1 == AppState().workListIndex!) { + } else if (AppState().workList!.length - 1 == + AppState().workListIndex!) { Navigator.pop(context); } }), @@ -380,25 +428,31 @@ class _WorkListDetailScreenState extends State { ], ), ), - floatingActionButton: (!isApproveAvailable && !isRejectAvailable && !isCloseAvailable) - ? Container( - height: 43, - width: 43, - decoration: const BoxDecoration( - shape: BoxShape.circle, - color: MyColors.lightGreyE6Color, - ), - child: Icon(showFabOptions ? Icons.more_vert_rounded : Icons.more_horiz_rounded, color: MyColors.darkIconColor), - ).onPress(() { - setState(() { - showFabOptions = true; - }); - }) - : null, + floatingActionButton: + (!isApproveAvailable && !isRejectAvailable && !isCloseAvailable) + ? Container( + height: 43, + width: 43, + decoration: const BoxDecoration( + shape: BoxShape.circle, + color: MyColors.lightGreyE6Color, + ), + child: Icon( + showFabOptions + ? Icons.more_vert_rounded + : Icons.more_horiz_rounded, + color: MyColors.darkIconColor), + ).onPress(() { + setState(() { + showFabOptions = true; + }); + }) + : null, ); } - List viewApiButtonsList(List notificationButtonsList) { + List viewApiButtonsList( + List notificationButtonsList) { List fabs = []; for (int i = 0; i < notificationButtonsList.length; i++) { if (notificationButtonsList[i].bUTTONACTION! == "REJECTED" || @@ -412,7 +466,9 @@ class _WorkListDetailScreenState extends State { notificationButtonsList[i].bUTTONLABEL!, getActionImage(notificationButtonsList[i].bUTTONACTION!), isIconAsset: true, - ).paddingOnly(bottom: 12).onPress(() => handleFabAction(notificationButtonsList[i]))); + ) + .paddingOnly(bottom: 12) + .onPress(() => handleFabAction(notificationButtonsList[i]))); } return fabs; } @@ -491,7 +547,8 @@ class _WorkListDetailScreenState extends State { )); break; case "ANSWER_INFO": - performAction(notificationButton.bUTTONACTION!, title: notificationButton.bUTTONLABEL); + performAction(notificationButton.bUTTONACTION!, + title: notificationButton.bUTTONLABEL); break; case "RFC": getRFCEmployeeListFunc(); @@ -505,9 +562,14 @@ class _WorkListDetailScreenState extends State { callBackFunc: reloadWorkList, child: UpdateContinueSheet( workListData: workListData, - getEitCollectionNotificationBodyList: getEitCollectionNotificationBodyList, - dynamicParams: DynamicListViewParams(workListData!.sUBJECT!, workListData!.fUNCTIONNAME!, - isUpdate: true, collectionNotificationList: getEitCollectionNotificationBodyList![0].collectionNotification)), + getEitCollectionNotificationBodyList: + getEitCollectionNotificationBodyList, + dynamicParams: DynamicListViewParams( + workListData!.sUBJECT!, workListData!.fUNCTIONNAME!, + isUpdate: true, + collectionNotificationList: + getEitCollectionNotificationBodyList![0] + .collectionNotification)), ); break; case "CONTINUE_ACTION": @@ -516,9 +578,14 @@ class _WorkListDetailScreenState extends State { callBackFunc: reloadWorkList, child: UpdateContinueSheet( workListData: workListData, - getEitCollectionNotificationBodyList: getEitCollectionNotificationBodyList, - dynamicParams: DynamicListViewParams(workListData!.sUBJECT!, workListData!.fUNCTIONNAME!, - isUpdate: true, collectionNotificationList: getEitCollectionNotificationBodyList![0].collectionNotification)), + getEitCollectionNotificationBodyList: + getEitCollectionNotificationBodyList, + dynamicParams: DynamicListViewParams( + workListData!.sUBJECT!, workListData!.fUNCTIONNAME!, + isUpdate: true, + collectionNotificationList: + getEitCollectionNotificationBodyList![0] + .collectionNotification)), ); break; case "APPROVE_AND_FORWARD": @@ -530,7 +597,8 @@ class _WorkListDetailScreenState extends State { notificationID: workListData!.nOTIFICATIONID, actionHistoryList: actionHistoryList, callBackFunc: reloadWorkList, - getNotificationRespondAttributes: getNotificationRespondAttributes, + getNotificationRespondAttributes: + getNotificationRespondAttributes, )); break; case "FORWARD": @@ -542,7 +610,8 @@ class _WorkListDetailScreenState extends State { notificationID: workListData!.nOTIFICATIONID, actionHistoryList: actionHistoryList, callBackFunc: reloadWorkList, - getNotificationRespondAttributes: getNotificationRespondAttributes, + getNotificationRespondAttributes: + getNotificationRespondAttributes, )); break; case "DEL": @@ -563,7 +632,8 @@ class _WorkListDetailScreenState extends State { void getRFCEmployeeListFunc() async { try { Utils.showLoading(context); - getRFCEmployeeList = await WorkListApiClient().getRFCEmployeeeList(workListData!.nOTIFICATIONID!); + getRFCEmployeeList = await WorkListApiClient() + .getRFCEmployeeeList(workListData!.nOTIFICATIONID!); Utils.hideLoading(context); actionHistoryList.last.sEQUENCE = getRFCEmployeeList[0].sEQ; showMyBottomSheet(context, @@ -583,7 +653,8 @@ class _WorkListDetailScreenState extends State { } } - Future performNetworkCall(BuildContext context, {String? email, String? userId}) async { + Future performNetworkCall(BuildContext context, + {String? email, String? userId}) async { showDialog( context: context, builder: (BuildContext cxt) => ConfirmDialog( @@ -593,7 +664,12 @@ class _WorkListDetailScreenState extends State { Navigator.pop(cxt); Utils.showLoading(context); try { - await WorkListApiClient().submitComment(comment: "", email: email, userId: userId, notificationId: workListData!.nOTIFICATIONID, apiMode: "REJECT"); + await WorkListApiClient().submitComment( + comment: "", + email: email, + userId: userId, + notificationId: workListData!.nOTIFICATIONID, + apiMode: "REJECT"); Utils.hideLoading(context); Navigator.pop(context, "delegate_reload"); } catch (ex) { @@ -611,7 +687,9 @@ class _WorkListDetailScreenState extends State { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ - title.toText12(color: isSelected ? Colors.white : Colors.white.withOpacity(.74), isCenter: true), + title.toText12( + color: isSelected ? Colors.white : Colors.white.withOpacity(.74), + isCenter: true), 4.height, Container( height: 8, @@ -674,14 +752,17 @@ class _WorkListDetailScreenState extends State { notificationGetRespond: notificationNoteInput, actionMode: actionMode, onTap: (String note) { - List> responseAttribute = []; + List> responseAttribute = []; - for (var element in getNotificationRespondAttributes!) { - responseAttribute.add({ - "ATTRIBUTE_NAME": element!.attributeName, - if (element!.attributeType == "number") "ATTRIBUTE_NUMBER_VALUE": note else if (element!.attributeType == "VARCHAR2") "ATTRIBUTE_TEXT_VALUE": note - }); - } + for (var element in getNotificationRespondAttributes!) { + responseAttribute.add({ + "ATTRIBUTE_NAME": element!.attributeName, + if (element!.attributeType == "number") + "ATTRIBUTE_NUMBER_VALUE": note + else if (element!.attributeType == "VARCHAR2") + "ATTRIBUTE_TEXT_VALUE": note + }); + } Map payload = { "P_ACTION_MODE": actionMode, @@ -689,11 +770,16 @@ class _WorkListDetailScreenState extends State { "P_COMMENTS": note, "P_FORWARD_TO_USER_NAME": "", "P_NOTIFICATION_ID": workListData!.nOTIFICATIONID, - "RespondAttributeList":responseAttribute, + "RespondAttributeList": responseAttribute, }; - if (actionMode == "APPROVED" || actionMode == "APPROVE" || actionMode == "CLOSE" || actionMode == "ANSWER_INFO" || actionMode == "RFC") { + if (actionMode == "APPROVED" || + actionMode == "APPROVE" || + actionMode == "CLOSE" || + actionMode == "ANSWER_INFO" || + actionMode == "RFC") { performNotificationAction(payload); - } else if (note.isNotEmpty && (actionMode != "APPROVED" || actionMode != "APPROVE")) { + } else if (note.isNotEmpty && + (actionMode != "APPROVED" || actionMode != "APPROVE")) { performNotificationAction(payload); } else { Utils.showToast(LocaleKeys.pleaseEnterComments.tr()); @@ -706,7 +792,8 @@ class _WorkListDetailScreenState extends State { void performNotificationAction(Map payload) async { try { Utils.showLoading(context); - GenericResponseModel model = await WorkListApiClient().postNotificationActions(payload); + GenericResponseModel model = + await WorkListApiClient().postNotificationActions(payload); Utils.hideLoading(context); Utils.showToast(LocaleKeys.yourChangeHasBeenSavedSuccessfully.tr()); animationIndex = animationIndex + 1; @@ -747,7 +834,8 @@ class _WorkListDetailScreenState extends State { if (apiCallCount == 0) Utils.showLoading(context); apiCallCount++; getEitCollectionNotificationBodyList!.clear(); - getEitCollectionNotificationBodyList = await WorkListApiClient().GetEitNotificationBody(workListData!.nOTIFICATIONID); + getEitCollectionNotificationBodyList = await WorkListApiClient() + .GetEitNotificationBody(workListData!.nOTIFICATIONID); apiCallCount--; if (apiCallCount == 0) { Utils.hideLoading(context); @@ -765,7 +853,8 @@ class _WorkListDetailScreenState extends State { if (apiCallCount == 0) Utils.showLoading(context); apiCallCount++; memberInformationListModel = null; - memberInformationListModel = await WorkListApiClient().getUserInformation(-999, workListData!.sELECTEDEMPLOYEENUMBER!); + memberInformationListModel = await WorkListApiClient() + .getUserInformation(-999, workListData!.sELECTEDEMPLOYEENUMBER!); apiCallCount--; if (apiCallCount == 0) { Utils.hideLoading(context); @@ -783,7 +872,8 @@ class _WorkListDetailScreenState extends State { if (apiCallCount == 0) Utils.showLoading(context); apiCallCount++; getPhonesNotificationBodyList!.clear(); - getPhonesNotificationBodyList = await WorkListApiClient().getPhonesNotificationBodyList(workListData!.nOTIFICATIONID); + getPhonesNotificationBodyList = await WorkListApiClient() + .getPhonesNotificationBodyList(workListData!.nOTIFICATIONID); apiCallCount--; if (apiCallCount == 0) { Utils.hideLoading(context); @@ -801,7 +891,8 @@ class _WorkListDetailScreenState extends State { if (apiCallCount == 0) Utils.showLoading(context); apiCallCount++; getBasicDetNtfBodyList!.clear(); - getBasicDetNtfBodyList = await WorkListApiClient().getBasicDetNtfBodyList(workListData!.nOTIFICATIONID); + getBasicDetNtfBodyList = await WorkListApiClient() + .getBasicDetNtfBodyList(workListData!.nOTIFICATIONID); apiCallCount--; if (apiCallCount == 0) { Utils.hideLoading(context); @@ -819,7 +910,8 @@ class _WorkListDetailScreenState extends State { if (apiCallCount == 0) Utils.showLoading(context); apiCallCount++; getAbsenceCollectionNotificationBodyList!.clear(); - getAbsenceCollectionNotificationBodyList = await WorkListApiClient().getAbsenceNotificationBody(workListData!.nOTIFICATIONID); + getAbsenceCollectionNotificationBodyList = await WorkListApiClient() + .getAbsenceNotificationBody(workListData!.nOTIFICATIONID); apiCallCount--; if (apiCallCount == 0) { Utils.hideLoading(context); @@ -836,7 +928,8 @@ class _WorkListDetailScreenState extends State { try { if (apiCallCount == 0) Utils.showLoading(context); apiCallCount++; - getContactNotificationBodyList = await WorkListApiClient().getContactNotificationBodyList(workListData!.nOTIFICATIONID); + getContactNotificationBodyList = await WorkListApiClient() + .getContactNotificationBodyList(workListData!.nOTIFICATIONID); apiCallCount--; if (apiCallCount == 0) { Utils.hideLoading(context); @@ -853,7 +946,8 @@ class _WorkListDetailScreenState extends State { try { if (apiCallCount == 0) Utils.showLoading(context); apiCallCount++; - getAddressNotificationBodyList = await WorkListApiClient().getAddressNotificationBodyList(workListData!.nOTIFICATIONID); + getAddressNotificationBodyList = await WorkListApiClient() + .getAddressNotificationBodyList(workListData!.nOTIFICATIONID); apiCallCount--; if (apiCallCount == 0) { Utils.hideLoading(context); @@ -865,15 +959,15 @@ class _WorkListDetailScreenState extends State { Utils.handleException(ex, context, null); } } + void getTerminationNotificationBody() async { try { - if (apiCallCount == 0) - apiCallCount++; - getTerminationNotificationBodyList = await WorkListApiClient().getTerminationNotificationBodyList(workListData!.nOTIFICATIONID); + if (apiCallCount == 0) apiCallCount++; + getTerminationNotificationBodyList = await WorkListApiClient() + .getTerminationNotificationBodyList(workListData!.nOTIFICATIONID); Utils.hideLoading(context); apiCallCount--; if (apiCallCount == 0) { - setState(() {}); } } catch (ex) { @@ -883,16 +977,16 @@ class _WorkListDetailScreenState extends State { } } - - void getStampNotificationBody() async { try { if (apiCallCount == 0) Utils.showLoading(context); apiCallCount++; if (workListData!.rEQUESTTYPE == "STAMP_MS") { - getStampMsNotifications = await WorkListApiClient().getStampMsNotificationBody(workListData!.nOTIFICATIONID!, -999); + getStampMsNotifications = await WorkListApiClient() + .getStampMsNotificationBody(workListData!.nOTIFICATIONID!, -999); } else { - getStampNsNotifications = await WorkListApiClient().getStampNsNotificationBody(workListData!.nOTIFICATIONID!, -999); + getStampNsNotifications = await WorkListApiClient() + .getStampNsNotificationBody(workListData!.nOTIFICATIONID!, -999); } apiCallCount--; if (apiCallCount == 0) { @@ -910,7 +1004,8 @@ class _WorkListDetailScreenState extends State { try { if (apiCallCount == 0) Utils.showLoading(context); apiCallCount++; - getMoNotificationBodyList = await WorkListApiClient().getMoNotificationBody(workListData!.nOTIFICATIONID!, -999); + getMoNotificationBodyList = await WorkListApiClient() + .getMoNotificationBody(workListData!.nOTIFICATIONID!, -999); apiCallCount--; if (apiCallCount == 0) { Utils.hideLoading(context); @@ -927,7 +1022,8 @@ class _WorkListDetailScreenState extends State { try { if (apiCallCount == 0) Utils.showLoading(context); apiCallCount++; - getItemCreationNtfBody = await WorkListApiClient().getItemCreationNtfBody(workListData!.nOTIFICATIONID!, -999); + getItemCreationNtfBody = await WorkListApiClient() + .getItemCreationNtfBody(workListData!.nOTIFICATIONID!, -999); apiCallCount--; if (apiCallCount == 0) { Utils.hideLoading(context); @@ -944,7 +1040,8 @@ class _WorkListDetailScreenState extends State { try { if (apiCallCount == 0) Utils.showLoading(context); apiCallCount++; - getPoNotificationBody = await WorkListApiClient().getPoNotificationBody(workListData!.nOTIFICATIONID!, -999); + getPoNotificationBody = await WorkListApiClient() + .getPoNotificationBody(workListData!.nOTIFICATIONID!, -999); apiCallCount--; if (apiCallCount == 0) { Utils.hideLoading(context); @@ -961,7 +1058,26 @@ class _WorkListDetailScreenState extends State { try { if (apiCallCount == 0) Utils.showLoading(context); apiCallCount++; - getPrNotificationBody = await WorkListApiClient().getPRNotificationBody(workListData!.nOTIFICATIONID!, -999); + getPrNotificationBody = await WorkListApiClient() + .getPRNotificationBody(workListData!.nOTIFICATIONID!, -999); + apiCallCount--; + if (apiCallCount == 0) { + Utils.hideLoading(context); + setState(() {}); + } + } catch (ex) { + apiCallCount--; + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + } + } + + void getPaymentNotification() async { + try { + if (apiCallCount == 0) Utils.showLoading(context); + apiCallCount++; + getPaymentNotificationBodyList = await WorkListApiClient() + .getPaymentNotificationBody(workListData!.nOTIFICATIONID!, -999); apiCallCount--; if (apiCallCount == 0) { Utils.hideLoading(context); @@ -979,7 +1095,8 @@ class _WorkListDetailScreenState extends State { if (apiCallCount == 0) Utils.showLoading(context); apiCallCount++; getNotificationRespondAttributes.clear(); - getNotificationRespondAttributes = await WorkListApiClient().notificationGetRespondAttributes(workListData!.nOTIFICATIONID!); + getNotificationRespondAttributes = await WorkListApiClient() + .notificationGetRespondAttributes(workListData!.nOTIFICATIONID!); if (getNotificationRespondAttributes.isNotEmpty) { notificationNoteInput = getNotificationRespondAttributes.first; } @@ -1000,18 +1117,25 @@ class _WorkListDetailScreenState extends State { if (apiCallCount == 0) Utils.showLoading(context); apiCallCount++; notificationButtonsList.clear(); - notificationButtonsList = await WorkListApiClient().getNotificationButtons(workListData!.nOTIFICATIONID!); + notificationButtonsList = await WorkListApiClient() + .getNotificationButtons(workListData!.nOTIFICATIONID!); if (notificationButtonsList.isNotEmpty) { - isCloseAvailable = notificationButtonsList.any((GetNotificationButtonsList element) => element.bUTTONACTION == "CLOSE"); - isApproveAvailable = notificationButtonsList.any((GetNotificationButtonsList element) { - if (element.bUTTONACTION == "APPROVED" || element.bUTTONACTION == "APPROVE") { + isCloseAvailable = notificationButtonsList.any( + (GetNotificationButtonsList element) => + element.bUTTONACTION == "CLOSE"); + isApproveAvailable = + notificationButtonsList.any((GetNotificationButtonsList element) { + if (element.bUTTONACTION == "APPROVED" || + element.bUTTONACTION == "APPROVE") { approveAction = element.bUTTONACTION!; return true; } return false; }); - isRejectAvailable = notificationButtonsList.any((GetNotificationButtonsList element) { - if (element.bUTTONACTION == "REJECTED" || element.bUTTONACTION == "REJECT") { + isRejectAvailable = + notificationButtonsList.any((GetNotificationButtonsList element) { + if (element.bUTTONACTION == "REJECTED" || + element.bUTTONACTION == "REJECT") { rejectAction = element.bUTTONACTION!; return true; } @@ -1034,7 +1158,8 @@ class _WorkListDetailScreenState extends State { try { isActionHistoryLoaded = false; actionHistoryList.clear(); - actionHistoryList = await WorkListApiClient().getActionHistory(workListData!.nOTIFICATIONID!); + actionHistoryList = await WorkListApiClient() + .getActionHistory(workListData!.nOTIFICATIONID!); setState(() { isActionHistoryLoaded = true; }); @@ -1047,7 +1172,8 @@ class _WorkListDetailScreenState extends State { try { isAttachmentLoaded = false; getAttachmentList.clear(); - getAttachmentList = await WorkListApiClient().getAttachments(workListData!.nOTIFICATIONID!); + getAttachmentList = await WorkListApiClient() + .getAttachments(workListData!.nOTIFICATIONID!); setState(() { isAttachmentLoaded = true; }); diff --git a/lib/ui/work_list/worklist_fragments/actions_fragment.dart b/lib/ui/work_list/worklist_fragments/actions_fragment.dart index 10d027a..41de635 100644 --- a/lib/ui/work_list/worklist_fragments/actions_fragment.dart +++ b/lib/ui/work_list/worklist_fragments/actions_fragment.dart @@ -167,7 +167,7 @@ class ActionsFragment extends StatelessWidget { Duration duration = DateTime.now().difference(dateTimeFrom); return "Action duration: " + DateUtil.formatDuration(duration); } else { - if (actionHistoryList[index + 1].nOTIFICATIONDATE!.isEmpty) { + if (actionHistoryList[index].nOTIFICATIONDATE!.isEmpty) { return ""; } else { DateTime dateTimeTo = DateUtil.convertSimpleStringDateToDate(actionHistoryList[index].nOTIFICATIONDATE!); diff --git a/lib/ui/work_list/worklist_fragments/info_fragments.dart b/lib/ui/work_list/worklist_fragments/info_fragments.dart index 7e1cd1c..1351126 100644 --- a/lib/ui/work_list/worklist_fragments/info_fragments.dart +++ b/lib/ui/work_list/worklist_fragments/info_fragments.dart @@ -19,8 +19,8 @@ import 'package:mohem_flutter_app/models/worklist/hr/get_contact_notification_bo import 'package:mohem_flutter_app/models/worklist/hr/get_phones_notification_body_list_model.dart'; import 'package:mohem_flutter_app/models/worklist_response_model.dart'; import 'package:mohem_flutter_app/widgets/item_detail_view_widget.dart'; - import 'package:mohem_flutter_app/models/termination/termination_notification_body.dart'; +import 'package:mohem_flutter_app/models/worklist/payment_details_list.dart'; class InfoFragment extends StatelessWidget { WorkListResponseModel? workListData; @@ -28,14 +28,18 @@ class InfoFragment extends StatelessWidget { List? getStampMsNotifications; List? getStampNsNotifications; List itemCreationHeader; - List? getEitCollectionNotificationBodyList; + List? + getEitCollectionNotificationBodyList; List? getPhonesNotificationBodyList; List? getBasicDetNtfBodyList; - List? getAbsenceCollectionNotificationBodyList; + List? + getAbsenceCollectionNotificationBodyList; GetContactNotificationBodyList? getContactNotificationBodyList; GetPrNotificationBodyList? getPrNotificationBodyList; List? getAddressNotificationBodyList = []; - List? getTerminationNotificationBodyList =[]; + List? getTerminationNotificationBodyList = []; + GetPaymentNotificationBodyList? getPaymentNotificationBodyList; + InfoFragment( {this.workListData, this.poHeaderList = const [], @@ -49,15 +53,18 @@ class InfoFragment extends StatelessWidget { this.getContactNotificationBodyList, this.getPrNotificationBodyList, this.getAddressNotificationBodyList, - this.getTerminationNotificationBodyList - }); + this.getTerminationNotificationBodyList, + this.getPaymentNotificationBodyList}); double itemHeight = 0; double itemWidth = 0; + + + @override Widget build(BuildContext context) { - var size = MediaQuery.of(context).size; + Size size = MediaQuery.of(context).size; itemHeight = (size.height - kToolbarHeight - 24) / 9; itemWidth = size.width / 2; @@ -68,36 +75,62 @@ class InfoFragment extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.from.tr(), workListData!.fROMUSER ?? ""), + ItemDetailViewCol( + LocaleKeys.from.tr(), workListData!.fROMUSER ?? ""), ItemDetailViewCol(LocaleKeys.to.tr(), workListData!.tOUSER ?? ""), ), ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.sent.tr(), workListData!.bEGINDATE ?? ""), - ItemDetailViewCol(LocaleKeys.closed.tr(), workListData!.eNDDATE ?? ""), + ItemDetailViewCol( + LocaleKeys.sent.tr(), workListData!.bEGINDATE ?? ""), + ItemDetailViewCol( + LocaleKeys.closed.tr(), workListData!.eNDDATE ?? ""), ), ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.id.tr(), workListData!.nOTIFICATIONID?.toString() ?? ""), - ItemDetailViewCol(LocaleKeys.responder.tr(), workListData!.rESPONDER ?? ""), + ItemDetailViewCol(LocaleKeys.id.tr(), + workListData!.nOTIFICATIONID?.toString() ?? ""), + ItemDetailViewCol( + LocaleKeys.responder.tr(), workListData!.rESPONDER ?? ""), ), ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.subject.tr(), workListData!.sUBJECT ?? ""), + ItemDetailViewCol( + LocaleKeys.subject.tr(), workListData!.sUBJECT ?? ""), Container(), isItLast: true, ), ], ).objectContainerView(), - if (getPrNotificationBodyList != null) getPRNotificationBodyListWidget(getPrNotificationBodyList!), - if (getStampMsNotifications?.isNotEmpty ?? false) getStampMsNotificationsListView(getStampMsNotifications ?? []), - if (getStampNsNotifications?.isNotEmpty ?? false) getStampNsNotificationsListView(getStampNsNotifications ?? []), + if (getPrNotificationBodyList != null) + getPRNotificationBodyListWidget(getPrNotificationBodyList!), + if (getStampMsNotifications?.isNotEmpty ?? false) + getStampMsNotificationsListView(getStampMsNotifications ?? []), + if (getStampNsNotifications?.isNotEmpty ?? false) + getStampNsNotificationsListView(getStampNsNotifications ?? []), if (poHeaderList.isNotEmpty) getPoNotificationsListView(), if (itemCreationHeader.isNotEmpty) getItemCreationHeaderView(), - if (getEitCollectionNotificationBodyList?.isNotEmpty ?? false) getEitNotificationsListView(getEitCollectionNotificationBodyList ?? []), - if (getPhonesNotificationBodyList?.isNotEmpty ?? false) getPhonesNotificationBodyListWidget(getPhonesNotificationBodyList ?? []).objectContainerView(title: "Mobile Numbers"), - if (getBasicDetNtfBodyList?.isNotEmpty ?? false) getBasicDetNtfBodyListWidget(getBasicDetNtfBodyList ?? []).objectContainerView(title: "Basic Information"), - if (getAbsenceCollectionNotificationBodyList?.isNotEmpty ?? false) getAbsenceCollectionNotificationBodyListWidget(getAbsenceCollectionNotificationBodyList ?? []), - if (getContactNotificationBodyList != null) getContactNotificationBodyListWidget(getContactNotificationBodyList ?? GetContactNotificationBodyList()).objectContainerView(), - if (getAddressNotificationBodyList?.isNotEmpty ?? false) getAddressNotificationBodyListWidget(getAddressNotificationBodyList!), - if (getTerminationNotificationBodyList?.isNotEmpty ?? false) getTerminationNotificationBodyListWidget(getTerminationNotificationBodyList!), + if (getEitCollectionNotificationBodyList?.isNotEmpty ?? false) + getEitNotificationsListView(getEitCollectionNotificationBodyList ?? []), + if (getPhonesNotificationBodyList?.isNotEmpty ?? false) + getPhonesNotificationBodyListWidget(getPhonesNotificationBodyList ?? []) + .objectContainerView(title: "Mobile Numbers"), + if (getBasicDetNtfBodyList?.isNotEmpty ?? false) + getBasicDetNtfBodyListWidget(getBasicDetNtfBodyList ?? []) + .objectContainerView(title: "Basic Information"), + if (getAbsenceCollectionNotificationBodyList?.isNotEmpty ?? false) + getAbsenceCollectionNotificationBodyListWidget( + getAbsenceCollectionNotificationBodyList ?? []), + if (getContactNotificationBodyList != null) + getContactNotificationBodyListWidget(getContactNotificationBodyList ?? + GetContactNotificationBodyList()) + .objectContainerView(), + if (getAddressNotificationBodyList?.isNotEmpty ?? false) + getAddressNotificationBodyListWidget(getAddressNotificationBodyList!), + if (getTerminationNotificationBodyList?.isNotEmpty ?? false) + getTerminationNotificationBodyListWidget( + getTerminationNotificationBodyList!), + if (getPaymentNotificationBodyList != null) + getPaymentNotificationBodyListWidget(getPaymentNotificationBodyList ?? + GetPaymentNotificationBodyList()) + .objectContainerView(), ]; return Container( width: double.infinity, @@ -115,43 +148,59 @@ class InfoFragment extends StatelessWidget { return ListView.separated( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), - itemBuilder: (cxt, index) => Column( + itemBuilder: (BuildContext cxt, int index) => Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Column( children: [ ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.description.tr(), workListData!.fROMUSER ?? ""), - ItemDetailViewCol(LocaleKeys.from.tr(), workListData!.fROMUSER ?? ""), + ItemDetailViewCol(LocaleKeys.description.tr(), + workListData!.fROMUSER ?? ""), + ItemDetailViewCol( + LocaleKeys.from.tr(), workListData!.fROMUSER ?? ""), ), ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.to.tr(), workListData!.tOUSER ?? ""), - ItemDetailViewCol(LocaleKeys.sent.tr(), workListData!.bEGINDATE ?? ""), + ItemDetailViewCol( + LocaleKeys.to.tr(), workListData!.tOUSER ?? ""), + ItemDetailViewCol( + LocaleKeys.sent.tr(), workListData!.bEGINDATE ?? ""), ), ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.closed.tr(), workListData!.eNDDATE ?? ""), - ItemDetailViewCol(LocaleKeys.id.tr(), workListData!.nOTIFICATIONID?.toString() ?? ""), + ItemDetailViewCol( + LocaleKeys.closed.tr(), workListData!.eNDDATE ?? ""), + ItemDetailViewCol(LocaleKeys.id.tr(), + workListData!.nOTIFICATIONID?.toString() ?? ""), ), ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.supplier.tr(), poHeaderList[index].vENDORNAME ?? ""), - ItemDetailViewCol(LocaleKeys.site.tr(), poHeaderList[index].vENDORSITECODE ?? ""), + ItemDetailViewCol(LocaleKeys.supplier.tr(), + poHeaderList[index].vENDORNAME ?? ""), + ItemDetailViewCol(LocaleKeys.site.tr(), + poHeaderList[index].vENDORSITECODE ?? ""), ), ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.buyer.tr(), poHeaderList[index].bUYER ?? ""), - ItemDetailViewCol(LocaleKeys.preparer.tr(), poHeaderList[index].pREPARER ?? ""), + ItemDetailViewCol(LocaleKeys.buyer.tr(), + poHeaderList[index].bUYER ?? ""), + ItemDetailViewCol(LocaleKeys.preparer.tr(), + poHeaderList[index].pREPARER ?? ""), ), ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.creationDate.tr(), poHeaderList[index].cREATIONDATE ?? ""), - ItemDetailViewCol(LocaleKeys.shipToLocation.tr(), poHeaderList[index].sHIPTOLOCATIONNAME ?? ""), + ItemDetailViewCol(LocaleKeys.creationDate.tr(), + poHeaderList[index].cREATIONDATE ?? ""), + ItemDetailViewCol(LocaleKeys.shipToLocation.tr(), + poHeaderList[index].sHIPTOLOCATIONNAME ?? ""), ), ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.quotationNumber.tr(), poHeaderList[index].qUOTATIONNUMBER ?? ""), - ItemDetailViewCol(LocaleKeys.quotationDate.tr(), poHeaderList[index].qUOTATIONDATE ?? ""), + ItemDetailViewCol(LocaleKeys.quotationNumber.tr(), + poHeaderList[index].qUOTATIONNUMBER ?? ""), + ItemDetailViewCol(LocaleKeys.quotationDate.tr(), + poHeaderList[index].qUOTATIONDATE ?? ""), ), ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.paymentTerms.tr(), poHeaderList[index].pAYMENTTERMS ?? ""), - ItemDetailViewCol(LocaleKeys.currency.tr(), poHeaderList[index].cURRENCYNAME ?? ""), + ItemDetailViewCol(LocaleKeys.paymentTerms.tr(), + poHeaderList[index].pAYMENTTERMS ?? ""), + ItemDetailViewCol(LocaleKeys.currency.tr(), + poHeaderList[index].cURRENCYNAME ?? ""), isItLast: true, ), ], @@ -160,19 +209,26 @@ class InfoFragment extends StatelessWidget { Column( children: [ ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.grossAmount.tr(), poHeaderList[index].gROSSAMOUNT?.toString() ?? ""), - ItemDetailViewCol(LocaleKeys.discountAmount.tr(), poHeaderList[index].dISCOUNTAMOUNT?.toString() ?? ""), + ItemDetailViewCol(LocaleKeys.grossAmount.tr(), + poHeaderList[index].gROSSAMOUNT?.toString() ?? ""), + ItemDetailViewCol(LocaleKeys.discountAmount.tr(), + poHeaderList[index].dISCOUNTAMOUNT?.toString() ?? ""), ), ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.customDuty.tr(), poHeaderList[index].cUSTOMDUTY?.toString() ?? ""), - ItemDetailViewCol(LocaleKeys.shipHandle.tr(), poHeaderList[index].sHIPHANDLE?.toString() ?? ""), + ItemDetailViewCol(LocaleKeys.customDuty.tr(), + poHeaderList[index].cUSTOMDUTY?.toString() ?? ""), + ItemDetailViewCol(LocaleKeys.shipHandle.tr(), + poHeaderList[index].sHIPHANDLE?.toString() ?? ""), ), ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.otherCharges.tr(), poHeaderList[index].oTHERCHARGES?.toString() ?? ""), - ItemDetailViewCol(LocaleKeys.totalPOAmountWithVAT.tr(), poHeaderList[index].lOCCURTOTPOAMT.toString() ?? ""), + ItemDetailViewCol(LocaleKeys.otherCharges.tr(), + poHeaderList[index].oTHERCHARGES?.toString() ?? ""), + ItemDetailViewCol(LocaleKeys.totalPOAmountWithVAT.tr(), + poHeaderList[index].lOCCURTOTPOAMT.toString() ?? ""), ), ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.totalPOAmountInWords.tr(), poHeaderList[index].tOTPOAMTWORD ?? ""), + ItemDetailViewCol(LocaleKeys.totalPOAmountInWords.tr(), + poHeaderList[index].tOTPOAMTWORD ?? ""), Container(), isItLast: true, ), @@ -180,7 +236,7 @@ class InfoFragment extends StatelessWidget { ).objectContainerView(title: LocaleKeys.amount_detail.tr()), ], ), - separatorBuilder: (cxt, index) => 4.height, + separatorBuilder: (BuildContext cxt, int index) => 4.height, itemCount: poHeaderList.length); } @@ -194,67 +250,95 @@ class InfoFragment extends StatelessWidget { // itemCount: dataList.length); // } - Widget getStampMsNotificationsListView(List list) { + Widget getStampMsNotificationsListView( + List list) { return ListView.separated( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), - itemBuilder: (cxt, index) => Column( + itemBuilder: (BuildContext cxt, int index) => Column( mainAxisSize: MainAxisSize.min, children: [ ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.employeeNumber.tr(), list[index].eMPLOYEENUMBER.toString()), - ItemDetailViewCol(LocaleKeys.assignmentNumber.tr(), list[index].aSSIGNMENTNUMBER.toString()), + ItemDetailViewCol(LocaleKeys.employeeNumber.tr(), + list[index].eMPLOYEENUMBER.toString()), + ItemDetailViewCol(LocaleKeys.assignmentNumber.tr(), + list[index].aSSIGNMENTNUMBER.toString()), ), ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.employeeName.tr(), list[index].eMPLOYEENAME.toString()), - ItemDetailViewCol(LocaleKeys.scheduleDate.tr(), DateUtil.formatDateToDate(DateUtil.convertStringToDate(list[index].sCHEDULEDATE.toString()), false)), + ItemDetailViewCol(LocaleKeys.employeeName.tr(), + list[index].eMPLOYEENAME.toString()), + ItemDetailViewCol( + LocaleKeys.scheduleDate.tr(), + DateUtil.formatDateToDate( + DateUtil.convertStringToDate( + list[index].sCHEDULEDATE.toString()), + false)), ), ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.shiftType.tr(), list[index].sHTTYPEDESC.toString()), - ItemDetailViewCol(LocaleKeys.shift.tr(), list[index].sHTNAME.toString()), + ItemDetailViewCol(LocaleKeys.shiftType.tr(), + list[index].sHTTYPEDESC.toString()), + ItemDetailViewCol( + LocaleKeys.shift.tr(), list[index].sHTNAME.toString()), ), ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.breakText.tr(), list[index].bREAKNAME.toString()), - ItemDetailViewCol(LocaleKeys.actualSwipeStart.tr(), list[index].sHTACTUALSTARTTIME.toString()), + ItemDetailViewCol(LocaleKeys.breakText.tr(), + list[index].bREAKNAME.toString()), + ItemDetailViewCol(LocaleKeys.actualSwipeStart.tr(), + list[index].sHTACTUALSTARTTIME.toString()), ), ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.actualSwipeEnd.tr(), list[index].sHTACTUALENDTIME.toString()), - ItemDetailViewCol(LocaleKeys.approvedSwipeStart.tr(), list[index].aPPROVEDSTARTTIME.toString()), + ItemDetailViewCol(LocaleKeys.actualSwipeEnd.tr(), + list[index].sHTACTUALENDTIME.toString()), + ItemDetailViewCol(LocaleKeys.approvedSwipeStart.tr(), + list[index].aPPROVEDSTARTTIME.toString()), ), ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.approvedSwipeStartReason.tr(), list[index].aPPROVEDSTARTREASON.toString()), + ItemDetailViewCol(LocaleKeys.approvedSwipeStartReason.tr(), + list[index].aPPROVEDSTARTREASON.toString()), ItemDetailViewCol(LocaleKeys.approvedSwipeEnd.tr(), ""), ), ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.approvedSwipeEndReason.tr(), list[index].aPPROVEDENDREASONDESC.toString()), + ItemDetailViewCol(LocaleKeys.approvedSwipeEndReason.tr(), + list[index].aPPROVEDENDREASONDESC.toString()), Container(), isItLast: true, ), ], ).objectContainerView(), - separatorBuilder: (cxt, index) => 1.height.paddingOnly(top: 8, bottom: 8), + separatorBuilder: (BuildContext cxt, int index) => + 1.height.paddingOnly(top: 8, bottom: 8), itemCount: list.length); } - Widget getStampNsNotificationsListView(List list) { + Widget getStampNsNotificationsListView( + List list) { return ListView.separated( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), - itemBuilder: (cxt, index) => Column( + itemBuilder: (BuildContext cxt, int index) => Column( mainAxisSize: MainAxisSize.min, children: [ ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.employeeNumber.tr(), list[index].eMPLOYEENUMBER.toString()), - ItemDetailViewCol(LocaleKeys.assignmentNumber.tr(), list[index].aSSIGNMENTNUMBER.toString()), + ItemDetailViewCol(LocaleKeys.employeeNumber.tr(), + list[index].eMPLOYEENUMBER.toString()), + ItemDetailViewCol(LocaleKeys.assignmentNumber.tr(), + list[index].aSSIGNMENTNUMBER.toString()), ), ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.employeeName.tr(), list[index].eMPLOYEENAME.toString()), - ItemDetailViewCol(LocaleKeys.scheduleDate.tr(), DateUtil.formatDateToDate(DateUtil.convertStringToDate(list[index].sCHEDULEDATE.toString()), false)), + ItemDetailViewCol(LocaleKeys.employeeName.tr(), + list[index].eMPLOYEENAME.toString()), + ItemDetailViewCol( + LocaleKeys.scheduleDate.tr(), + DateUtil.formatDateToDate( + DateUtil.convertStringToDate( + list[index].sCHEDULEDATE.toString()), + false)), isItLast: true, ), ], ).objectContainerView(), - separatorBuilder: (cxt, index) => 1.height.paddingOnly(top: 8, bottom: 8), + separatorBuilder: (BuildContext cxt, int index) => + 1.height.paddingOnly(top: 8, bottom: 8), itemCount: list.length); } @@ -262,43 +346,65 @@ class InfoFragment extends StatelessWidget { return ListView.separated( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), - itemBuilder: (cxt, index) => Column( + itemBuilder: (BuildContext cxt, int index) => Column( mainAxisSize: MainAxisSize.min, children: [ ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.operatingUnit.tr(), itemCreationHeader[index].oPERATINGUNIT?.toString() ?? ""), - ItemDetailViewCol(LocaleKeys.category.tr(), itemCreationHeader[index].cATEGORY?.toString() ?? ""), + ItemDetailViewCol( + LocaleKeys.operatingUnit.tr(), + itemCreationHeader[index].oPERATINGUNIT?.toString() ?? + ""), + ItemDetailViewCol(LocaleKeys.category.tr(), + itemCreationHeader[index].cATEGORY?.toString() ?? ""), ), ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.requester.tr(), itemCreationHeader[index].rEQUESTER?.toString() ?? ""), - ItemDetailViewCol(LocaleKeys.analyzedBy.tr(), itemCreationHeader[index].aNALYZEDBY?.toString() ?? ""), + ItemDetailViewCol(LocaleKeys.requester.tr(), + itemCreationHeader[index].rEQUESTER?.toString() ?? ""), + ItemDetailViewCol(LocaleKeys.analyzedBy.tr(), + itemCreationHeader[index].aNALYZEDBY?.toString() ?? ""), ), ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.approvedDate.tr(), itemCreationHeader[index].aPPROVEDDATE?.toString() ?? ""), - ItemDetailViewCol(LocaleKeys.itemType.tr(), itemCreationHeader[index].iTEMTYPE?.toString() ?? ""), + ItemDetailViewCol(LocaleKeys.approvedDate.tr(), + itemCreationHeader[index].aPPROVEDDATE?.toString() ?? ""), + ItemDetailViewCol(LocaleKeys.itemType.tr(), + itemCreationHeader[index].iTEMTYPE?.toString() ?? ""), ), ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.relatedTo.tr(), itemCreationHeader[index].rELATEDTO?.toString() ?? ""), - ItemDetailViewCol(LocaleKeys.requestDate.tr(), DateUtil.formatDateToDate(DateUtil.convertStringToDate(itemCreationHeader[index].rEQUESTDATE.toString()), false)), + ItemDetailViewCol(LocaleKeys.relatedTo.tr(), + itemCreationHeader[index].rELATEDTO?.toString() ?? ""), + ItemDetailViewCol( + LocaleKeys.requestDate.tr(), + DateUtil.formatDateToDate( + DateUtil.convertStringToDate( + itemCreationHeader[index].rEQUESTDATE.toString()), + false)), ), ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.analyzedDate.tr(), itemCreationHeader[index].aNALYZEDDATE?.toString() ?? ""), - ItemDetailViewCol(LocaleKeys.urgent.tr(), itemCreationHeader[index].uRGENTFLAGDISP?.toString() ?? ""), + ItemDetailViewCol(LocaleKeys.analyzedDate.tr(), + itemCreationHeader[index].aNALYZEDDATE?.toString() ?? ""), + ItemDetailViewCol( + LocaleKeys.urgent.tr(), + itemCreationHeader[index].uRGENTFLAGDISP?.toString() ?? + ""), ), ], ).objectContainerView(), - separatorBuilder: (cxt, index) => 18.height, + separatorBuilder: (BuildContext cxt, int index) => 18.height, itemCount: itemCreationHeader.length); } //HR multiple type requests - Widget getEitNotificationsListView(List list) { + Widget getEitNotificationsListView( + List list) { return ListView.separated( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), - itemBuilder: (cxt, index) { - List dataList = list.isEmpty ? [] : (list[index].collectionNotification ?? []); - dataList = dataList.where((o) => o.displayFlag == "Y").toList(); + itemBuilder: (BuildContext cxt, int index) { + List dataList = + list.isEmpty ? [] : (list[index].collectionNotification ?? []); + dataList = dataList + .where((CollectionNotificationEit o) => o.displayFlag == "Y") + .toList(); bool isOdd = false; if (dataList.length % 2 != 0) { isOdd = true; @@ -308,7 +414,8 @@ class InfoFragment extends StatelessWidget { itemCount: dataList.length, shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), - itemBuilder: (context, index) => ItemDetailViewGridItem( + itemBuilder: (BuildContext context, int index) => + ItemDetailViewGridItem( index, dataList[index].segmentPrompt, dataList[index].segmentValueDsp, @@ -324,12 +431,13 @@ class InfoFragment extends StatelessWidget { ), ).objectContainerView(); }, - separatorBuilder: (cxt, index) => 12.height, + separatorBuilder: (BuildContext cxt, int index) => 12.height, itemCount: list.length, ); } - Widget getPhonesNotificationBodyListWidget(List list) { + Widget getPhonesNotificationBodyListWidget( + List list) { bool isOdd = false; if (list.length % 2 != 0) { isOdd = true; @@ -339,7 +447,7 @@ class InfoFragment extends StatelessWidget { itemCount: list.length, shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), - itemBuilder: (context, index) => ItemDetailViewGridItem( + itemBuilder: (BuildContext context, int index) => ItemDetailViewGridItem( index, LocaleKeys.subject.tr(), list[index].proposedPhoneNumber ?? "", @@ -359,8 +467,9 @@ class InfoFragment extends StatelessWidget { child: ListView.separated( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), - itemBuilder: (cxt, index) => ItemDetailViewCol(LocaleKeys.subject.tr(), list[index].proposedPhoneNumber ?? ""), - separatorBuilder: (cxt, index) => 4.height, + itemBuilder: (BuildContext cxt, int index) => ItemDetailViewCol( + LocaleKeys.subject.tr(), list[index].proposedPhoneNumber ?? ""), + separatorBuilder: (BuildContext cxt, int index) => 4.height, itemCount: list.length), ); } @@ -375,7 +484,7 @@ class InfoFragment extends StatelessWidget { itemCount: list.length, shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), - itemBuilder: (context, index) => ItemDetailViewGridItem( + itemBuilder: (BuildContext context, int index) => ItemDetailViewGridItem( index, list[index].segmentPrompt, list[index].segmentValueDsp, @@ -395,19 +504,24 @@ class InfoFragment extends StatelessWidget { child: ListView.separated( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), - itemBuilder: (cxt, index) => ItemDetailViewCol(list[index].segmentPrompt!, list[index].segmentValueDsp!), - separatorBuilder: (cxt, index) => 4.height, + itemBuilder: (BuildContext cxt, int index) => ItemDetailViewCol( + list[index].segmentPrompt!, list[index].segmentValueDsp!), + separatorBuilder: (BuildContext cxt, int index) => 4.height, itemCount: list.length), ); } - Widget getAbsenceCollectionNotificationBodyListWidget(List list) { + Widget getAbsenceCollectionNotificationBodyListWidget( + List list) { return ListView.separated( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), - itemBuilder: (cxt, index) { - List dataList = list.isEmpty ? [] : (list[index].collectionNotification ?? []); - dataList = dataList.where((o) => o.dISPLAYFLAG == "Y").toList(); + itemBuilder: (BuildContext cxt, int index) { + List dataList = + list.isEmpty ? [] : (list[index].collectionNotification ?? []); + dataList = dataList + .where((CollectionNotificationAbsence o) => o.dISPLAYFLAG == "Y") + .toList(); bool isOdd = false; if (dataList.length % 2 != 0) { isOdd = true; @@ -418,7 +532,8 @@ class InfoFragment extends StatelessWidget { itemCount: dataList.length, shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), - itemBuilder: (context, index) => ItemDetailViewGridItem( + itemBuilder: (BuildContext context, int index) => + ItemDetailViewGridItem( index, dataList[index].sEGMENTPROMPT, dataList[index].sEGMENTVALUEDSP, @@ -436,34 +551,50 @@ class InfoFragment extends StatelessWidget { return ListView.separated( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), - itemBuilder: (cxt, index) => dataList[index].dISPLAYFLAG == "Y" ? ItemDetailViewCol(dataList[index].sEGMENTPROMPT!, dataList[index].sEGMENTVALUEDSP!) : Container(), - separatorBuilder: (cxt, index) => dataList[index].dISPLAYFLAG == "Y" ? 4.height : 0.height, + itemBuilder: (BuildContext cxt, int index) => + dataList[index].dISPLAYFLAG == "Y" + ? ItemDetailViewCol(dataList[index].sEGMENTPROMPT!, + dataList[index].sEGMENTVALUEDSP!) + : Container(), + separatorBuilder: (BuildContext cxt, int index) => + dataList[index].dISPLAYFLAG == "Y" ? 4.height : 0.height, itemCount: dataList.length) .objectContainerView(); }, - separatorBuilder: (cxt, index) => 12.height, + separatorBuilder: (BuildContext cxt, int index) => 12.height, itemCount: list.length, ); } - Widget getPRNotificationBodyListWidget(GetPrNotificationBodyList getPrNotificationBodyList) { + Widget getPRNotificationBodyListWidget( + GetPrNotificationBodyList getPrNotificationBodyList) { return Column( children: [ - getPrNotificationBodyList.pINFORMATION != null ? getPrNotificationBodyList.pINFORMATION.toString().toText14(color: MyColors.textMixColor).objectContainerView() : Container(), + getPrNotificationBodyList.pINFORMATION != null + ? getPrNotificationBodyList.pINFORMATION + .toString() + .toText14(color: MyColors.textMixColor) + .objectContainerView() + : Container(), 12.height, Column( children: [ ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.from.tr(), workListData!.fROMUSER ?? ""), + ItemDetailViewCol( + LocaleKeys.from.tr(), workListData!.fROMUSER ?? ""), ItemDetailViewCol(LocaleKeys.to.tr(), workListData!.tOUSER ?? ""), ), ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.sent.tr(), workListData!.bEGINDATE ?? ""), - ItemDetailViewCol(LocaleKeys.closed.tr(), workListData!.eNDDATE ?? ""), + ItemDetailViewCol( + LocaleKeys.sent.tr(), workListData!.bEGINDATE ?? ""), + ItemDetailViewCol( + LocaleKeys.closed.tr(), workListData!.eNDDATE ?? ""), ), ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.id.tr(), workListData!.nOTIFICATIONID?.toString() ?? ""), - ItemDetailViewCol(LocaleKeys.responder.tr(), workListData!.rESPONDER ?? ""), + ItemDetailViewCol(LocaleKeys.id.tr(), + workListData!.nOTIFICATIONID?.toString() ?? ""), + ItemDetailViewCol( + LocaleKeys.responder.tr(), workListData!.rESPONDER ?? ""), ), Column( children: getPRHeaderValues(), @@ -474,12 +605,14 @@ class InfoFragment extends StatelessWidget { ); } - Widget getAddressNotificationBodyListWidget(List getAddressNotificationBodyList) { + Widget getAddressNotificationBodyListWidget( + List getAddressNotificationBodyList) { bool isOdd = false; try { if (getAddressNotificationBodyList.length % 2 != 0) { isOdd = true; - getAddressNotificationBodyList.add(GetAddressNotificationBodyList(sEGMENTPROMPT: "--", sEGMENTVALUEDSP: "--")); + getAddressNotificationBodyList.add(GetAddressNotificationBodyList( + sEGMENTPROMPT: "--", sEGMENTVALUEDSP: "--")); } } catch (e) {} @@ -487,15 +620,16 @@ class InfoFragment extends StatelessWidget { itemCount: getAddressNotificationBodyList!.length, shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), - itemBuilder: (context, index) => ItemDetailViewGridItem( + itemBuilder: (BuildContext context, int index) => ItemDetailViewGridItem( index, getAddressNotificationBodyList[index].sEGMENTPROMPT, getAddressNotificationBodyList[index].sEGMENTVALUEDSP, - isNeedToShowEmptyDivider: (getAddressNotificationBodyList.length == index + 1) - ? isOdd - ? true - : false - : false, + isNeedToShowEmptyDivider: + (getAddressNotificationBodyList.length == index + 1) + ? isOdd + ? true + : false + : false, ), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, @@ -504,13 +638,14 @@ class InfoFragment extends StatelessWidget { ).objectContainerView(); } - - Widget getTerminationNotificationBodyListWidget(List getterminationNotificationBodyList) { + Widget getTerminationNotificationBodyListWidget( + List getterminationNotificationBodyList) { bool isOdd = false; try { if (getterminationNotificationBodyList.length % 2 != 0) { isOdd = true; - getterminationNotificationBodyList.add(TerminationNotificationBody(sEGMENTPROMPT: "--", sEGMENTVALUEDSP: "--")); + getterminationNotificationBodyList.add(TerminationNotificationBody( + sEGMENTPROMPT: "--", sEGMENTVALUEDSP: "--")); } } catch (e) {} @@ -518,15 +653,16 @@ class InfoFragment extends StatelessWidget { itemCount: getterminationNotificationBodyList!.length, shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), - itemBuilder: (context, index) => ItemDetailViewGridItem( + itemBuilder: (BuildContext context, int index) => ItemDetailViewGridItem( index, getterminationNotificationBodyList[index].sEGMENTPROMPT, getterminationNotificationBodyList[index].sEGMENTVALUEDSP, - isNeedToShowEmptyDivider: (getterminationNotificationBodyList.length == index + 1) - ? isOdd - ? true - : false - : false, + isNeedToShowEmptyDivider: + (getterminationNotificationBodyList.length == index + 1) + ? isOdd + ? true + : false + : false, ), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, @@ -535,22 +671,25 @@ class InfoFragment extends StatelessWidget { ).objectContainerView(); } - - List getPRHeaderValues() { List pRHeaders = []; - getPrNotificationBodyList!.pRHeader!.forEach((element) { - pRHeaders.add(ItemDetailGrid(ItemDetailViewCol(element.hDRATTRIBUTENAME!, element.hDRATTRIBUTEVALUE!), Container())); + getPrNotificationBodyList!.pRHeader!.forEach((PRHeader element) { + pRHeaders.add(ItemDetailGrid( + ItemDetailViewCol( + element.hDRATTRIBUTENAME!, element.hDRATTRIBUTEVALUE!), + Container())); }); return pRHeaders; } - Widget getContactNotificationBodyListWidget(GetContactNotificationBodyList data) { + Widget getContactNotificationBodyListWidget( + GetContactNotificationBodyList data) { bool isOdd = false; try { if (data.contactNotificationBody!.length % 2 != 0) { isOdd = true; - data.contactNotificationBody!.add(ContactNotificationBody(segmentPrompt: "--", segmentValueDsp: "--")); + data.contactNotificationBody!.add(ContactNotificationBody( + segmentPrompt: "--", segmentValueDsp: "--")); } } catch (e) {} @@ -558,15 +697,16 @@ class InfoFragment extends StatelessWidget { itemCount: data.contactNotificationBody!.length, shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), - itemBuilder: (context, index) => ItemDetailViewGridItem( + itemBuilder: (BuildContext context, int index) => ItemDetailViewGridItem( index, data.contactNotificationBody![index].segmentPrompt, data.contactNotificationBody![index].segmentValueDsp, - isNeedToShowEmptyDivider: (data.contactNotificationBody!.length == index + 1) - ? isOdd - ? true - : false - : false, + isNeedToShowEmptyDivider: + (data.contactNotificationBody!.length == index + 1) + ? isOdd + ? true + : false + : false, ), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, @@ -578,9 +718,132 @@ class InfoFragment extends StatelessWidget { child: ListView.separated( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), - itemBuilder: (cxt, index) => ItemDetailViewCol(data.contactNotificationBody![index].segmentPrompt!, data.contactNotificationBody![index].segmentValueDsp!), - separatorBuilder: (cxt, index) => 4.height, + itemBuilder: (BuildContext cxt, int index) => ItemDetailViewCol( + data.contactNotificationBody![index].segmentPrompt!, + data.contactNotificationBody![index].segmentValueDsp!), + separatorBuilder: (BuildContext cxt, int index) => 4.height, itemCount: data.contactNotificationBody!.length), ); } + + Widget getPaymentNotificationBodyListWidget( + GetPaymentNotificationBodyList? data) { + return Column( + children: [ + 12.height, + if (data!.paymentDetailsList!.isNotEmpty) + Column( + children: [ + LocaleKeys.paymentDetails.tr().toText14(color: MyColors.textMixColor), + ItemDetailGrid( + ItemDetailViewCol( + LocaleKeys.requestNumber.tr(), data.paymentDetailsList![0].requestNumber ?? ""), + ItemDetailViewCol( LocaleKeys.requesterEmpNum.tr(), + data.paymentDetailsList![0].requesterEmployeeName ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol( LocaleKeys.requestDate.tr(), + DateUtil.formatDateToDate( + DateUtil.convertStringToDate(data.paymentDetailsList![0].requestDate!), false) ?? ""), + ItemDetailViewCol( + LocaleKeys.requesterEmpName.tr(), data.paymentDetailsList![0].requesterEmployeeName ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol( LocaleKeys.prepareEmpName.tr(), + data.paymentDetailsList![0].prepareEmployeeName ?? ""), + ItemDetailViewCol( + LocaleKeys.requesterPositionName.tr(), data.paymentDetailsList![0].requesterPositionName ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol( LocaleKeys.preparePositionName.tr(), + data.paymentDetailsList![0].preparePositionName ?? ""), + ItemDetailViewCol( + LocaleKeys.requesterPayrollName.tr(), data.paymentDetailsList![0].requesterPayrollName ?? ""), + ), + ], + ).objectContainerView(), + if (data!.paymentDetailsList!.isNotEmpty) + Column( + children: [ + LocaleKeys.general.tr().toText14(color: MyColors.textMixColor), + ItemDetailGrid( + ItemDetailViewCol( + LocaleKeys.payingORGName.tr(), data.paymentDetailsList![0].payingOrganizationName ?? ""), + ItemDetailViewCol(LocaleKeys.requestAmount.tr(), + data.paymentDetailsList![0].requestAmount ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.paymentMethodName.tr(), + data.paymentDetailsList![0].paymentMethodName ?? ""), + ItemDetailViewCol( + LocaleKeys.currency.tr(), data.paymentDetailsList![0].currency ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.typeofPayment.tr(), + data.paymentDetailsList![0].typeOfPayment ?? ""), + ItemDetailViewCol( + LocaleKeys.paymentDetails.tr(), data.paymentDetailsList![0].paymentDetails ?? ""), + ), + + ], + ).objectContainerView(), + + if (data!.beneficieryList!.isNotEmpty) + Column( + children: [ + LocaleKeys.beneficiaryDetails.tr().toText14(color: MyColors.textMixColor), + ItemDetailGrid( + ItemDetailViewCol( + LocaleKeys.beneficiaryName.tr(), data.beneficieryList![0].beneficiaryName ?? ""), + ItemDetailViewCol(LocaleKeys.idIqama.tr(), + data.beneficieryList![0].iqamaNumber ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.beneficiaryBankName.tr(), + data.beneficieryList![0] .beneficiaryBankName ?? ""), + ItemDetailViewCol( + LocaleKeys.sadadNumber.tr(), data.beneficieryList![0].saddadNumber ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.beneficiaryIBAN.tr(), + data.beneficieryList![0].beneficiaryIban ?? ""), + Container(), + ), + + ], + ).objectContainerView(), + + if (data!.purchaseOrdersList!.isNotEmpty && data.purchaseOrdersList![0].poAmount !=null) + Column( + children: [ + LocaleKeys.purchaseOrders.tr().toText14(color: MyColors.textMixColor), + ItemDetailGrid( + ItemDetailViewCol( + LocaleKeys.poNumber.tr(), data.purchaseOrdersList![0].poNumber ?? ""), + ItemDetailViewCol(LocaleKeys.pOAmount.tr(), + data.purchaseOrdersList![0].poAmount.toString() ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.supplierName.tr(), + data.purchaseOrdersList![0].supplierName ?? ""), + ItemDetailViewCol( + LocaleKeys.approvalDate.tr(), data.purchaseOrdersList![0].poApprovalDate!=null ? DateUtil.formatDateToDate( + DateUtil.convertStringToDate(data.purchaseOrdersList![0].poApprovalDate), false) :"" ), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.requestNumber.tr(), + data.purchaseOrdersList![0].prNumber?? ""), + ItemDetailViewCol(LocaleKeys.versionStatus.tr(), + data.purchaseOrdersList![0].versionStatus?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.supplierNo.tr(), + data.purchaseOrdersList![0].supplierNumber?? ""), + Container(), + ), + ], + ).objectContainerView(), + ], + ); + } } -- 2.30.2 From 39375f48ff1db3f737cd915485c0e112217fff07 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Sun, 25 Aug 2024 11:33:05 +0300 Subject: [PATCH 033/135] updates --- android/app/build.gradle | 2 +- android/app/src/main/AndroidManifest.xml | 3 +++ ios/Runner.xcodeproj/project.pbxproj | 6 +++--- lib/app_state/app_state.dart | 2 +- lib/classes/consts.dart | 4 ++-- pubspec.yaml | 2 +- 6 files changed, 11 insertions(+), 8 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 20bf8fb..512fe2a 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -53,7 +53,7 @@ android { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "hmg.cloudSolutions.mohem" minSdkVersion 28 - targetSdkVersion 33 + targetSdkVersion 34 versionCode flutterVersionCode.toInteger() versionName flutterVersionName } diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 64edcac..51a1253 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -9,6 +9,9 @@ + + + diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 00c3cac..1eb87d0 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -376,7 +376,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 3.7.9; + MARKETING_VERSION = 3.7.95; PRODUCT_BUNDLE_IDENTIFIER = com.cloudsolutions.mohemm; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -514,7 +514,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 3.7.9; + MARKETING_VERSION = 3.7.95; PRODUCT_BUNDLE_IDENTIFIER = com.cloudsolutions.mohemm; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -544,7 +544,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 3.7.9; + MARKETING_VERSION = 3.7.95; PRODUCT_BUNDLE_IDENTIFIER = com.cloudsolutions.mohemm; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/lib/app_state/app_state.dart b/lib/app_state/app_state.dart index cc11126..a6dea92 100644 --- a/lib/app_state/app_state.dart +++ b/lib/app_state/app_state.dart @@ -90,7 +90,7 @@ class AppState { String get getHuaweiPushToken => _huaweiPushToken; - final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 8.0, mobileType: Platform.isAndroid ? "android" : "ios"); + final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 8.1, mobileType: Platform.isAndroid ? "android" : "ios"); void setPostParamsInitConfig() { isAuthenticated = false; diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index f5c055b..4e77928 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -3,12 +3,12 @@ import 'package:mohem_flutter_app/ui/marathon/widgets/question_card.dart'; class ApiConsts { // static String baseUrl = "http://10.200.204.11"; // Local server // static String baseUrl = "https://erptstapp.srca.org.sa"; // SRCA server - // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver + static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.201.204.101:2024"; // static String baseUrl = "https://webservices.hmg.com"; // PreProd // static String baseUrl = "https://hmgwebservices.com"; // Live server - static String baseUrl = "https://mohemm.hmg.com"; // New Live server + // static String baseUrl = "https://mohemm.hmg.com"; // New Live server static String baseUrlServices = baseUrl + "/Services/"; // server // static String baseUrlServices = "https://api.cssynapses.com/tangheem/"; // Live server diff --git a/pubspec.yaml b/pubspec.yaml index 20ed5c2..5bc1373 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html #version: 3.3.01+300040 -version: 3.4.4+300054 +version: 3.7.95+1 environment: sdk: ">=2.16.0 <3.0.0" -- 2.30.2 From d55d2dee500042d8787338acbe2c7bcb257665ec Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Mon, 2 Sep 2024 17:27:20 +0300 Subject: [PATCH 034/135] Mohemm identity updated --- .../AppIcon.appiconset/100.png | Bin 0 -> 5597 bytes .../AppIcon.appiconset/1024.png | Bin 0 -> 123080 bytes .../AppIcon.appiconset/114.png | Bin 0 -> 6676 bytes .../AppIcon.appiconset/120.png | Bin 0 -> 7122 bytes .../AppIcon.appiconset/144.png | Bin 0 -> 9016 bytes .../AppIcon.appiconset/152.png | Bin 0 -> 9641 bytes .../AppIcon.appiconset/167.png | Bin 0 -> 10681 bytes .../AppIcon.appiconset/180.png | Bin 0 -> 11974 bytes .../Assets.xcassets/AppIcon.appiconset/20.png | Bin 0 -> 859 bytes .../Assets.xcassets/AppIcon.appiconset/29.png | Bin 0 -> 1287 bytes .../Assets.xcassets/AppIcon.appiconset/40.png | Bin 0 -> 1915 bytes .../Assets.xcassets/AppIcon.appiconset/50.png | Bin 0 -> 2485 bytes .../Assets.xcassets/AppIcon.appiconset/57.png | Bin 0 -> 2898 bytes .../Assets.xcassets/AppIcon.appiconset/58.png | Bin 0 -> 2940 bytes .../Assets.xcassets/AppIcon.appiconset/60.png | Bin 0 -> 3139 bytes .../Assets.xcassets/AppIcon.appiconset/72.png | Bin 0 -> 3765 bytes .../Assets.xcassets/AppIcon.appiconset/76.png | Bin 0 -> 3941 bytes .../Assets.xcassets/AppIcon.appiconset/80.png | Bin 0 -> 4281 bytes .../Assets.xcassets/AppIcon.appiconset/87.png | Bin 0 -> 4771 bytes .../AppIcon.appiconset/Contents.json | 1 + AppIcons/appstore.png | Bin 0 -> 123080 bytes AppIcons/playstore.png | Bin 0 -> 45099 bytes android/app/src/main/AndroidManifest.xml | 2 +- .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 3408 -> 3355 bytes .../mipmap-hdpi/ic_launcher_foreground.png | Bin 8033 -> 8247 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 5544 -> 4638 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 1873 -> 2148 bytes .../mipmap-mdpi/ic_launcher_foreground.png | Bin 4200 -> 5175 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 3073 -> 2891 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 3856 -> 4552 bytes .../mipmap-xhdpi/ic_launcher_foreground.png | Bin 9718 -> 10712 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 6763 -> 6450 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 7524 -> 7152 bytes .../mipmap-xxhdpi/ic_launcher_foreground.png | Bin 34556 -> 17215 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 11927 -> 10152 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 9348 -> 9609 bytes .../mipmap-xxxhdpi/ic_launcher_foreground.png | Bin 45316 -> 23092 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 15240 -> 13675 bytes assets/images/logos/loading_mohemm_logo.gif | Bin 97273 -> 91449 bytes .../images/logos/loading_mohemm_logo_old.gif | Bin 0 -> 97273 bytes assets/images/logos/main_mohemm_logo.png | Bin 7448 -> 5345 bytes assets/images/logos/main_mohemm_logo_old.png | Bin 0 -> 7448 bytes .../AppIcon.appiconset/Contents.json | 129 +----------------- lib/app_state/app_state.dart | 2 +- lib/classes/consts.dart | 6 +- lib/classes/utils.dart | 1 + pubspec.yaml | 4 +- 47 files changed, 10 insertions(+), 135 deletions(-) create mode 100644 AppIcons/Assets.xcassets/AppIcon.appiconset/100.png create mode 100644 AppIcons/Assets.xcassets/AppIcon.appiconset/1024.png create mode 100644 AppIcons/Assets.xcassets/AppIcon.appiconset/114.png create mode 100644 AppIcons/Assets.xcassets/AppIcon.appiconset/120.png create mode 100644 AppIcons/Assets.xcassets/AppIcon.appiconset/144.png create mode 100644 AppIcons/Assets.xcassets/AppIcon.appiconset/152.png create mode 100644 AppIcons/Assets.xcassets/AppIcon.appiconset/167.png create mode 100644 AppIcons/Assets.xcassets/AppIcon.appiconset/180.png create mode 100644 AppIcons/Assets.xcassets/AppIcon.appiconset/20.png create mode 100644 AppIcons/Assets.xcassets/AppIcon.appiconset/29.png create mode 100644 AppIcons/Assets.xcassets/AppIcon.appiconset/40.png create mode 100644 AppIcons/Assets.xcassets/AppIcon.appiconset/50.png create mode 100644 AppIcons/Assets.xcassets/AppIcon.appiconset/57.png create mode 100644 AppIcons/Assets.xcassets/AppIcon.appiconset/58.png create mode 100644 AppIcons/Assets.xcassets/AppIcon.appiconset/60.png create mode 100644 AppIcons/Assets.xcassets/AppIcon.appiconset/72.png create mode 100644 AppIcons/Assets.xcassets/AppIcon.appiconset/76.png create mode 100644 AppIcons/Assets.xcassets/AppIcon.appiconset/80.png create mode 100644 AppIcons/Assets.xcassets/AppIcon.appiconset/87.png create mode 100644 AppIcons/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 AppIcons/appstore.png create mode 100644 AppIcons/playstore.png create mode 100644 assets/images/logos/loading_mohemm_logo_old.gif create mode 100644 assets/images/logos/main_mohemm_logo_old.png diff --git a/AppIcons/Assets.xcassets/AppIcon.appiconset/100.png b/AppIcons/Assets.xcassets/AppIcon.appiconset/100.png new file mode 100644 index 0000000000000000000000000000000000000000..8583b245f5eff5ee4b00c3610876e35ff04abcd4 GIT binary patch literal 5597 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 literal 0 HcmV?d00001 diff --git a/AppIcons/Assets.xcassets/AppIcon.appiconset/1024.png b/AppIcons/Assets.xcassets/AppIcon.appiconset/1024.png new file mode 100644 index 0000000000000000000000000000000000000000..fffa7bfe28152a489f3edb1165d586de2ed7d1ff GIT binary patch literal 123080 zcmeFY=UY?Vw*|UGM?^qW6r|WdR0O0%I*NiKMXAz3lnz1Z#1OE6sECS44Mjj|DAG$v z5CoMHI#NRs5(p4VLJ281?>YCJqrdwP+z;=UWIqpNuQlgdYs@*vm@D?Si2?sU(R}~_ z@ZY>~%?toISdSb44;SkTE`I(g>kAZMW^ffK?K!>(08+rsYga5n9hWD$(@&4M;CA8o z#hV&w?2!)6pyiY9?{9EO9hABednK3c!OQn&h&^8}*yOME;Z4-xJsSo!o{O%TKC$Yf zmq_<*P8M=Jxq14E;psvACzU7~nf`Fj^`|*E2MRD*50;ip2%&-0RX4W5hfCBdam*y+ zP~0p;Hk=Fh0g0*Zf2n7?uJ-)ix1-2AsN{~I^| z1(1IMBx8ZQ?`$KaiF>{Jxo3Ejw+&pF}bQTvK^cxXg6TYB77&Sz`u_CiLZq4sDkzo z(lB2s^{lB!Nua*;@f+Zrrwv}VIP?|v-7AHC zy|*K76jQCd3(5_P_nrFb_UNaZ(OG8(!csbs|ELgGAS`h)mH#wANOfq5{*#&2t=;!b zY;*yiVt6xgsf0pm#lIo!3_cVW)hJNPt5mlWwNyk{t0$T%n%_Q`_$3^4zk7iGntoqr ze*fVcc^1Xi_n$;oiCTHw_O-BpSXdTfJsg<&zDIw3qR`W-OW{v1ItHce8-4OEl-fVUo5Wu%dZeiotqN@+S7@Iy z)T{(qN;EH9+RJyklV>$_yT(I>)-4R%%+POry<65C+ zGJTk^R_b-QlykUXGTcbY`3XpPp9S$jw}lL{omulvydiAU!FC*d=Nm0@Bjsw=wJC6A zal!=_ll~iJI{GJ*jyb#rrgg(ju|0&YK^qve%~30aeBHRm#7oNDLeaZ{e2b#ry)+Eb zS`bj#S>dA1asXBk5bg=vLI83KR9HocAC0zkwHipg!+(e?h~C~9_$`&F(vPWOz@bBmk*oEb2^sxa_aLabcV*CLhovV3(9fO+=2^2XG_@g_) z*D&J2&fz?{{li7%WFoDr4E zOX(_MxaYT%+geBjB6r5{jbL5+=#%RGPN>}~T*?Qm#8bEnI{?;vk<5-s5tgchHHUGh zIvg(9W$S8-S}Yklm1Ut-Y*(vUKm_CR-pw{#TM5~BOW;2Qq0_gW!)tP_O`1#55xYW( z=guHk#rA8i$4fjVb^n&s;*OL*?cYHd&yK3x7dc)KfA{b|_O*-tIuEKcVf&>BctqUw zKl!!l%i?RpL|)4LULY<{a_Hl`PK)nbGUZ&SE5DP08w(NngMXZo(}tL^B}fA!EuWEz z+cQS_(;gsy@Sj7dqCj3#I}x}`kApSFa6pJCxn}~@eOqd9dRuhuAv++iSuQOSm^p30 z4GahGHV^EL);2k(#quf@zP2n%Svux`nmI7pG#`Onb;>NDz8(B}5I7x#HTU}iDGr{T zR%W<+A70Ub-DbLuB&pcRd0xhqd7<1)SMh0|A1W!maGAe9hGp zjc*`txGC}i@9S~0Dt|<_*n?*+e^M9HaKlMX@T;w(pS~EI)9&rtZ6j%$?ACv0O0sFIS0c2TQ~AAxkUqUScxH2QiPEP zc9z~G*avnO zq3v=4ChR!h*Vu|fSxOa|!dI(I$lws5x3q=yTol=Q@X_KEX}5S{Dt`!Z_?6_KKQ5JH z_(P)8eYVI%biC||KMg#5Sv|rGUO_BYSAS?mA8k_EM8nOR3)(3Yu4_5$Kw}gs?KygM zpMc3%yzxl_2b)P5I}F62SOB%X2US#tg06Mln*IpBckipcbiP@Tq4yq`;9yOw z(tjy-&<;&Hq{9A>Z`0EWA*(_?$JMoa^_ps@fKw|^;$g8e{N*8bq;80FP)s;4hOo# zfnTJ!)OsAE0te>6c;4oApR7e=!_-;@KScwVi300S(aHk)9 z<}#YM@HQf7X)x4IVD_oi{eQ z!kaxHT_w#IM*~Qt4U%#*f{Q+}DcDuXt-IMehrRXIOf}KcQaBvf<22l!?R&HI-uYU; zIyK<`?FIO>%mJLg2R7sRob!|!>hQ8GE>r*ibm(?SS6r*{0BcV zj*$myMe#J{v7=6~F>Y=xqz0jbPF^jG(QORlStivwF>Zn;F(=!vJu@kL7ApPaYeJxU zakIUnfc>s%by1ym{b66u59xq2=km3ee?Y#j8Rt@5bbsN8b~kB?Q#1YT8(-5nu8a3T zkDLNts8)!-E*ssLX|@b^?!bCWq0bc#A@QBYK<{SbTed%Ps<%d<{Bd}-PaALn-2(ACiy7bxE~~LTX)aeheqG&T z*(y;tK1V-ZeJM)5k%#Q3F#rAYCTr{=x<-WKxRsN^^<_m?bB4sYi_gWsjP-A)OCHzA z)`87*s%t5gK2|@Ux72)dZyCUNcGZZnmA_>@kPVO=(>)_1OYe2I4LMrEc*jhy{gMSd zaMO^L#9kLiHezx5uFx{BJ9ncfPnz61!nnnMc=$9*eam8(7YO$Xsi^qtv~nzY5tv~M z0b>CRZ(lB!h+3Ue`87>C4(y2j%wDD3(PCu|XeEv;Yc@dRx5rkr$FYxs2LPIM&)H~a z;O&=oq1-CZ9ka<=dVXT}p@I)uCv}0|QyMS3|7ywju}EbmT4xS{rygISgd2P2-x)s$ zgvQx4a!1lDC#4RUG~hFT;2fgMc3&|v5!khleVfuCGB?|d1PhaDv>$FGSKXff%tP%uiFGSGX}Y?k{J!kD^Us_*>yKZDLEe+)MDgEs8rWEFTMHp<769>~e7q z`NfSR6fG+6<8qNJ#N$ABIffr-%G5Av5FvbX<`(4J2RuH}#yUwnMydp-jb73HS#rfS z#3@#EcPrF&oRniN!Q@^H>#+Zy^&q7M^c_~UGdvKpMVLv->13%4fS~XQFZq zdJ7cI$`CL3H@AU#oxB0(h#%lp9fjA~)!dN-7y)p*ogNQKX^so%lb*@uVn_g6xD*+t z-gC=v(h&NdobdNzC?^ll5P~az@aKM>hEkc|y>WdbQ=yJSw$~RId_q>(fZ7%DWDBeq zsW};>Tc@ba3TWUR6iI*!2xi9}Ywt~$#~@;)CU*RqYj?MUAFN+}7c4BK9uT6i#TmX07#iBa$Hn4M$q66bAuBzFko5(;S8$vOiNW)ZEQ|ELGv27=s| znIn#SZs^5JXZ2FSNBP>y{H4mfi6@G~={*3O>E(i{cdL z^yAv+I0GPRUYI9?uW2=*doO86Yyo*af1IeZY~tc*UGfIv)GMFN_ZBYq@%H`lEbKxzkCcA|+ti9d>#BHIwh6~V zmn(v=N%pOpNII^0u9lUeM%A(P3^4I;mWObwVOJC8J?Af_xSbtWKZbyL9Z=n|V+ZgO z{V5#fqaIr-k5<|%ARbqKAEiyV!H~B=HJQ)kz0O4HChh6I=<_@CWFhZt?=# ztaRw(5wi59bZbP9SZT??s2i=w9&Q7-m9At9D*J~<(t}g{W5xm$D0j9j3;$X^}7 z=N=&VimFp#b<{>)WwWzI*Zg`Jen#jSsan`jh z;>(uPs!Njq28UTa4qWD++sp`rNPr^u9J+NejIaohZg1NZcG&$o7oZIxil+2`J7vAN z+NoV?aSlaJd_WPu*wpD;(1Hdqu{G^ z^Dl!DDZLiepXUZDspFLih7ZiV21WaKJ}6s05?k!9Os21YzVoj8hIfp`cQ=btaG-;B z@wU(L3WncaQG~;#yMy2KU}KkWf4JoNz*y>SXHjxzk^DgTy&R$PL6zrN(rg6&UVji_-uXwfN|dTG+;X&Ld{9URVfnKwV?pnN%(!p=T+_xK<+>Pkv^OFH+) zX!=G<$-We$PQQmeoXUsZ-*%Oqd&I{fx+~IP{gzjR4Z)$dB$A_@98gftwX6ZPfHP*n zfj(Xqu#^(WYX*%C$bU#wNyhI3mfL;Fryq-`0{%54o-Z`o8JTp`C9DjPJbwB(plm#m zE#L?^r+3|tjMKM~Y*=NQ!6QNyi`X(NUa)Zg)r%hn-KH3CGWR%sVLPmg zLN&<}ej>l+ap`;^5Er>S#6Oj&3BtR{+ixrye)C$h_O>+sXsE9F&;;^2&I?DdL20XH zC$(c2;}$&~Qn21Z>d2Wu{bK_OG6*xcsw;&{0iWulj(j{eksL}qw+8{bGp&h1L!xfR zt^pSdiY>|tr`}2vRfw7Np`y?Io|9?{1!)GugqQEC$21iR#EVBfeVLJ$MoV7qHgP>d z5~XU-J8f(!pV4=AVe@l^zlm-hVlTfl;uB<5tv{K1xn~h%0qzJxE%4(P%hg7WtQG^u zsIX1kG2(Go37-3jx7^2@#}RoM47Sa&na>9Ki?NioRT;|nDAGAsL>ekPbG2lvd3Dt< z=dwa3Y#P7wI2C8?w+WmteA~fvMm9! z!YVegdedaX7g~xg9)2LG25csBQ@pUsi}J+}MPMJRUq@I;VTz%w;;zBn>9p6abbWZ8 z%t~N&=?^oT%1TQ_YI@%s1TmD;p-Wt7>-U~e3NFTj`)%>X6FD; zb9mMbPg8BAd)0xN5x>_$()eD6eI#-0)GzSLrM>UUn+)7j$uE0^EH%q1O&Cf&ka8PC zGyhI(c{RKg)mDUP~owuUu{zk_F0%d6U`A0e~~C2J%UVgx_LS zz+k}Nc#H!WrrEzAKH$^GDp2ltMuXCwzB$d}q=CEloVB$BXZU*39?<9S*56avk#YYS zPG0kbtzvG{Co2>eC#nWB2UO}`TRpgR?*72JA+e&nrUbF>_Gaer6r+?dzBn8eac6t7 zFYd`S6q$v2#wIJ9WGD-HPteyB9!d@Fwz8D9&a<~7q3@%#n|x7zqjk1v(cCJxFL-<> zTX;0{uw7Pve?f4Fkf~@oeCte{i79d3T!ykD+(BNfJwTl9s#=xZ^1O_wW>XpX1=a() z;<72G0cOp?tzmSq&1#$rN5t>?){v)1BFc7Qdyk#JwnVG6VLo^_SoK{)7CFox$IS<+yE2dkk74tu1^lR2&h*!!5>R%5_&-pMxAOHQ6NXhx8RSpMWOcRxP_%dURCp zt&~Co*Jb>-Ng08q0UZ5vPuJ^WXU;-~BDGmRuv2(vS{Rrv zC6+)E$XM3Jc&};1ZL?~D34gF4k4p1XknU#XRV8wa7!9u_e}#4OAsTjg(eJsJiUy_0 z@5CYu=)0Ebga%fhMAoa|cEiaJ1^IO0N=sv-q@d-A+~z7~Zu8?n3;E;fa`XKSrEdp{ zd~6E?ZI#?cMU>uIZx%ZKI=dPN>ul3$PWa4Jn&SZO$UY6rTs-0YHS((M&ty;Tb1GU+ z7jGptSV4~Vp{K$sR_j9%s{8pp3ecuc)!;`l37AA%rfiaoV2~0?nTqW;BJR2xPG-{6&DF5k$Lx{LQqz;qQfKrRcwKwKXZw0B z@;;d-et9!QYICCK65CgoiAMab_E)}k|27VGiZ>`TTn zNdtPrK-$!cL~!x`gneg^-nUq?v6!ynk{>qf(ec#nXr!7pf}5+`b!h4I@8h)y$%Dz! z=!C<`zLi*!Eq0K`exqXBvLf5E!r_8K`!bIv^}Kh@E)L3dcgCY@2^&Lp)h^B`D&O_P zU&1Ihrj;=K_ZN?3>a{N?FkvoObLvu>ybVeLB{Q*-G#P;H7P58npPOOp5w)|4!N1YpZ5NFy=m>G#Dg100R-o$x@p3U#9JjOqNDb@3P z_)n+mj8)F-C&lmqnh3t;#?5c2FbSVg{+1N>RJiz9@>-2rl&+KQxm>eU;n%zdlq9+28KFHS*znD#j z5FkD2!@i3jY7SFNEWt*4xMQy%{GG9|l3LMr7^L&z$YaqtW?S8fY;?>!UUnl=x0LH{Zp;7!_*<#t+dR^X`Rf?_SuP3btkS=y5F|- z^gi&!7UjjsmN0aTIMZ(FUE{s?{Y*nJJyBG))NFXa@J|Z&?Payt_b@Jhwn&}OjR5M_ z4|ZDwsq(6Lt&mQ~qd-P`CG;XcC)>kt;4%r($kz-%rsc%mSfB0dJ_Au&)#;r+u;0!D zER-F9~I?|nlqnXc}mx?vsxLP9A_$S0)c(8ng4w#M-Sm% zhFZOAH$03;OYPeo5BB`QlyOp={UFMJk!cRYC|*Z!jYZHeAxGFTs@|**CEjQ;2KW7*W}c)08~*82V4B!`<+sCd z6JjFUL4f=-V<~E7KbU4}ny8|xhBRH#F2PO0uAS>%YL9A)4mf74nn_M8rQZ=Dd{5iC z-c*MTp`ojJh2)-_fFdgw7oZ3QOo^3(x?LaNXLn3*B%_mmoPycvw$)J1vgCx!O1YbT zl_+5IImxz#3@i{M{_1*d@;aUv+Zsb&1Uru8;Pol3dadW&E?JF4D23&3wv~3DP$fwK z?-HQb5w}j7std(E`M%xmt@#Y+)o>s!>>BHoEqYxq>o)QvuAPI?eiF%BuWCHIF>kpx z9YtnxRXHw~SY_z$9CwjkN=uRRW{#e+%3*#>DD(WHi5#j2QSckXx#7bX7~T1_Td??P z3vuOAzMtUqOw2P~Z*RB9;d}@Xhn9}w@09bGP@wmxpEK&0o^iu6hb;F`tNBNQORE62Rn2G%ZySKnJWhKaFNZ!W)vR01TSc)eVP_ zWn5e9yIGm;;)sT}J_sk}r3L;Nv$S=nf-r3K%hS9x$NNpB9-G5UE&8LB+{r1{j>DM} zYPpEQ4>e?p&565(^@EPT6KY?`^JL1*2EUHm<0z+WKI!C8PYcv`aY|2})x1)%uwNlT zTv;^SHT>#R*mW4;3nCoSfKv}wuIfX2>_D0(7Wh@&1-d!Uya^cyQ+O!VZI8=ec!^{Ld6_$r~b~6rFU8H zc+Ers@|1}8FQd~0yE{_6S0Zgb_g!e*0pp4;j5-K=9==6(DkDC-d)8YmhR_#-w2$hsALP2Nv`Czff4|4jb5euuslBCu5W zG(X5!u~=odq-RKMxQ-EQ`h`X0x52)EaiuWED??{y+l}pUR4uI5xe#~Zf%KxC`I$ni zkut}CLdFjY%U=yctG$4X5a}EBt7@5jR4_kNXS~u54JTwp6kv_QQz{p>3hv_Bm@IY3 zbaYOVh-}{!0GjfzGfW+d01W@pu4|uCswi1Y7M`{;gS|RqHF_iz&C8*|4Mp8tP`w=f zzADkK^{h=9-wsyj^Bo;+rNY`C#GsM^x-36_^-k%#{?xB;Dc2?fSHL6cA@xl!c6B~! ze(i9hZR$5kXg-XmKPMlovOav%?nI$Y&zgm&#kiGkpIn;XV6|AV2L-c)X^T3q#`8~z zdAzY1zBL$uR27zP2+H0}h7z^A#yp!ZlCv{gE7!(J>#R7F=|WNUFSYXnrXkKDs~|zY zqZ&F`ErBRFbatC1_@7sHg%7f_#b))*LtVc8vcOssqMoxWBz0G<23dcF^lMA_XYSL^ znJsEP(z=!vZLGH^F8PIoJ}NRdKZ6Q;WK^ruY#mN4@e^G&S4`>)MP-ln8bv%5ruwgc z!ntR9s86PEUj?S8Xt&O}^)H#;gnl+uAATFbtU*wx-@K}J`4z}rW19Y&*Rh>FvMiYM zE1nG>iyl~G>Sm_QXy>Oi!1N@wGA;40m;Fv@f4L(Vuz~q5!C8S5D+39^9QhJ)BlF7M zSFb2p6xjERRTo7tHoPg*i6ewh?^ITggVOmfOEubHaJq6sZYmC`!$kK3#7>ANas(?r z6g}~l>yg{N+Gv$4Ze&XM>TXn1yUFcOBJ2QDkIg%*&tf=L*T3mfcJt#qknzAAztP7} zhYyrk!KX5m{m(=LCMi9M?qmZ~_!Vf!8}G|$PN9Ia<;Us%$R5hKdafNj|C)5)W=6rD zSWOSEvGZV$qMD-ui*Nn;Us9FFe{sHLN-f8zX}G?^f7Hf_*nM+GMg)_Kgvpq_7$=UW zTsB(vFLxv8y(;LNK<^nDAGXMgqe7@J#~AsH{QS-__(r<+`YcF`MpZ<)D#$)&(G__2$I*Y`{igPAKenLB9oZW~US)~zWyOus&^y@y}}pa*jZ z?E&t6b@*669$+kSfCKd0!q&iDS|y=-G1D<9VRb6_xhg;M{jLW7$c5GN7d>7yE;c^l zwM@ybovn(+hb!ug)MoO6l4x2=??SWCe7}u%z2?9vOxVMCL0G9$fK+k~<+Py!zN= z^Zb!X6h(YYxv5WFwEX=OAfM3`z92^*eFZNQHpg33Swa0vMG!KR0Yr;}79AW*w2-M4 zdrBhpllb`9I*;g^eib>);t(J2jV(&HPjfD^G*wm*4WLuNYluAN#9a4EDWtet{AH*f zV4u*t_R8OsUHE>tg(lw_VszD9&K{ly(mar8)kyurbW=v zIGqx2?nj~*?+4Zlula4Ay0NfF#=%dL;XV^$d-DX)^lQ{UKS)#fLC0W!sf3SV+8f*E z5BLvk6Dvt|Rw2IQxkL1=3oZNkUf_R1 z!fw(EqOu3>LbAcSU4|`Xaw(B$A+H63j+SCk(i>D!*)rTJVP4kvY{{4QEo(6qsGk__ zyq_t$ATAyX7ZQIT)S>spB$U%qgdU`+kZXZBHqwUZEJwD(gll2k5;^r5MjRgR_W2J)tut&nDKEv{zp^b35 zqigK;m9t0(#N^5`>Zx#Gr%ddP9`XK*Zv94Yg>9@j^vtv9BhPA290!tj<%%etljymm zs)vM^XEc~=E$b|aXV&h_7MN~I7l<=nEQaFxb)d_ZE6bf8z9)(+q8FD)XLfpSD(^qC z%{J*RvQ5Zf-{RHq4-np5x4#T1WV)0>rFj$r*fq5+`#a<(OK=TzTZb=hiQo&757>pF zuN@1X?1?2CbaYS#TiB@-QgiM~b*ie!p30=pPA&SK0K`*-8+hRU3h_U^09GgNDc`<# zQF6E;epX)c=vEaJ7^?OTzp7J1*$3MxN(qSlh@c40Pj4Gm-MELZ7y-lhyh;Kq(gb_@8q>?^lNV@4*_}T1}9W z_V|b!jbTYgAo22(GAUtFM#s?9rA_K=GpWF_%%&v<-H9@H8bcb8YJyn(IR2}ac)w+8 zQr|09#h59+Odr+;)=E{ZPNBnA)|2D~0cG$6KgUTK9ddkKz|U!o)vKm7gal~as0Ym* zIhr(Ndo#q3DeKU%;P$z~p+Qe(OGX%I`)oKRPZeX#Ra&BG!^cpY>!_lP%lT02!$A#J z)}yc280F7fxNf*9q}o{v3VE7PJV=1cBs z*h-!#VSN{r&I{;l_Scf*^cs;T-nkv$z4~9Y`F_xgkza8KfQfBt#QJu^i~Amv7S7Pbwnb)Q>-9KG&iM3fvIcVmoP5dW2ANNh}S zZGa4XqwWMjMux;{zwa0EkC1W0=SY<1`A{G6UPc)ku`}Ctj%jUBE2%N9ja7vTx%X5v3;*=d(B} zgRBmBaGQE+s=dpp6|`ZD{E>1ZzWr;8u(akvbG6Wtg*<$2Xf<^;twM*a@WXRCJm_cI z({|YGs_NQP)32`FKr>hE_6OW~>;#M9Dv_u^80Bye602>H<-lr3`RF^#C!n6n0R>;< zNBhT%fCX<9_7yDtFF8L*AUtDD9Tujcn_N(E*Go3P>v>}VU60rASdV4iw1R89gKXbKDTO^r&sFtt) zWns&q`?4&eBC_Wrd17Xgx;zDubtv|9z?HiZRlL=78m}MRyd19yvEKo*8drtxjoI)c zKd4lEN|DS;EnU>JZZ@@sOcc&sB^fs?Z~*X~9Xxq(k=-^;zF{P7?NU(R++-U6eD8p_ z4B$}{w(^kDOszi(ilmHoN0*uBAu{d6+Pn4IzR0~himMBv*q6`u5OrR-E>{?_8^ zJ8feYwNxzDGt-UT9NvMY#`!KZc?hYZS~X{GkHeNRqs z5N6p+J5;;FmYk3yfuZEOp-JX9bBISk%Q3v<(&4JeIfZkySIvH0Ofs!UEW2L&h(E%K z7Q?a54j5q4xw~?`bLJ}>ye1EzwtwzbKL`yl9lGSs!wL_y6IxJe)^HUE;OMGq0!%C0 z&anz!cc|8ZWtrcsZX-O=rk9gdX z0w0b32)&{#YNqLG}(``0j}cs4H-_+|0#Jbv+MCj0<@>^-6_hqr5tOj+n3By=Q)a`G6mcVN zeI#kJBc5pL7=F`9E!={1^!T6}vCxrt7qiphvjf%xPrd61ZxWmSuHV8YDsf93coy$M zq=~8vee;sKoew)+=#HKn|J6;9~T0YroMc;Y4Rmz!6ePq5uFr8C1xIfg?-(H{Z@ z_F#VIi!j9_{>R&SflpA8G5#aW^Hd(f7W7#U9v!T8WM4{CyCJ^B5s<83c)HpI@D;L) z%%V&%%Gw$^I^i39;ky$L`Q7=tf1ILse$|)fBxDBRw9BZ`e0AV2JtfqsTxgFIr_79Z z^T^60(&YZeDBZN!z1hIH?dD2KY$LjvD@L)62%4U(++#tx17igp&rmB$y1w&kD_S&g zAJD`ielgE4KbeJbgLF0XuhE9@))yH#s(s1~^(pgHyw&5T=Smk*173Kw8BDdw7u@Mx z5!rU0nN{AGo)Bzd{b+{Qu zwU$Taz8keco;#%MnL#zsK9+{#FG5u#{CeqNsN?Re>Vvrh;&<kw&R4(mn|hQp6)@ju(KV{~q=7y^ zSe=uQLxo@?u0u@HhjoWnFRf-izSzU6QMHC|4tlSR3p{$PgRNhMT?RZ>6TU0%AfP~9 z$BVL<$it_v?bjn5VwJ9km3gtfxC`E!tz#-Xt$KhDSpM?Ehyy<60oq*5>MopED-q;8 za+#%aj=VDfdL8y$M{5?4>&NK3xArJ$xClMc@uh)STfK#=lCXhr1}jkV!Vc+@p&DTI zW$eq4faXChU{?F_D;?>}4MNTgSE))cf;wIzCE%e&gs1M|tFP8fB;&T{Tm z<82IXNAi3k`I{D$93QgMA20IiTxZ4%u0DAWtaGXSELZ?OD{{<-ggPu>X3{@ zDyzfW+9J=fGNVhq?78@@?71(aw~4u5zL12}pXUZ}1M{~3bmU(ljqmDWIf0J+o<-A) z-7iyjomo|WQ$x_1D&^^kI0wiXU^|`En6x1}-JHSoP7hdy_B*%!TKv{K#*Xn+-Ya|H zSH@m@Me@M)d;c^nhOkGy$Yjm>m*nA98)t6d6kUu0=mF}8{)^vn!hpTt!YboExW|Yv zA_2SZ^my}`pX9lvYt_TYiIO?*#2-ez@iVFwZCf0}>wviYW?i-KynyCt;(#oejh@Jg zs_FLEbA0?jI`&q6Zj^;#{6{y+fZgz-FsZ>f&6VP!p zjgOSbaNK?U)crX;df@Q*p-p>FGdPnPLZ-0Gdq^QHRTC_cyMsFZzJ92JZ-hl*t){oo zXGgc4h4f<5xsp@(vMl6S^dCwTc)f_$-VDJ{vSa)dxbgQkKK6NA^@ec)Z;)W`W^{}A z0brR6U8~h80_+$!3AT;gcG3l=Q+Jk5f^@f?j4GCLEdc7$;JRcZo{`b}=3O;)G>z16oK|Zq*>x>j>ruJmboc&? z%rN^*_`D*FNd_T%D8;4vo%T`;>XBcAhpBJ>$&A}HwyVWb6K_6Hwn^!4ti=_FI0ol$ zq|i7^uW#Lp?yZ84$?-hFnihY;R~7Ymc_;C)P8p7 z2=2Cns8@hF$Q*}u?(LYi1>kJPC9Bd|}iqnk;jW9Tj(*hz3lf1=OjtGwM@0PfxZriUjnU&0aX(^z@Hzx9b)=IcF~ zOZ&H^JW>L&{Bo(3ldS%YksZHi?x+))Q}1D{*4T_#dCeC}teXG_BGo!aY5p>gU3hf2 zk4Ld?-&M+A{PppJ7e6e3Bt-88ZxN=h>KhQ*C4|43V|_Wp-?lTiX+ej@gctv2lmECj>tXV`)JB ze5hfbm!&x~;9faAWZRfJZJG4L=%BvH^cihJ!}1(zv`LKGpP@xv+r$z(Ho}Z=SqUB` zNFOV>ttf^Onn#dMNB*OwwLNTLHiECpA?eBBDMguMaTCo)NpS&=-r(O^6x3F;%9+m3 z{f2ZbFkK=_%@ZT_vRkvNy-}Bj3u$xqd`9fcq%G|{G;BpS?mqQH=Y0#`LAE4}BTFzl ze#^wwt$7AFi#ye(DNtP>v&j}2ugo4fMF2U|h|(`i@+p~;%=8ScAl>3kH_oTS0LJ%& z0jnjO_*Ei&7P9Iv86BLKKRHEdLBDp~lnvYL-lA;KK1%Or>15y?`bh3B7qI2d0hPNO zoSn%1m7j4Lr0cxLwkfuQ%vm_%!3BJyG{Eul=hJGSforzfte(C3O7t{tS(PC0Cd%}zda{h}r-SG+cL|1SKfYs8bI;9o1Ez+^vr7Jc9aOZz)san+EOyIYv# zks-XGi#v*S6HWvcTF&e>QchuY%Hk;^DpqB7m0vZ=zNgJ|rpvId4f1IWpXzZ@#2?5~=;T1TGf9qBTks^SHi@zeV$A-%%R^#VN)7!mjh1v@06 zxJ(;qaGdEF@X6KNAmQHIh@NRI}TzvIEe@ zCJCSi%V_A;2Fl|~eAl|or)kR(RtCcPIra*7*OD~un(Upm(I~%8YTgj}a00lypwxT~ zC|_=z{^}FyNzG4p1QQXbu8S89ehBhABjWGMqDiHeemIhiH)xP$JUr)d_Qlnf zFW-EPu0;zAg|7IW?fT-}A{aRXh%B77pMu2t(YC#-+~OB0Xx16_(2;e-3(BvW)4m57 zut=~P$Xe{prcK;C8$qjHC|zjMhV1P~2Ts%3|Fpv&z^k zf?rZ6YGrew14v#vEg=hcJiuH!Cs~=JAgj-XF21F`nL&uLKKTMnY_2RDrvU!@KUtsT z5e*w^b&6g)2)$DOMjz=Fo>m%O0QUMiMmp7ilX zzd`QO8a-f`3$4pN&&d!i^DZN=Z8t--c9{nB&+Cu|N_*oKfe;8k_#PI|rNV0ORa_4# zCNnNwN`J9tzodWb{;sQ^JM#Zi8*l`AojK~@G@{h8 z<>e585halZtM~#gJTHwA(xSg-Q7AH}eJvmM$hQE~(HSZ1m=E7mUd>kGU=~g~J1|O$ z%dPIT!p)UOl78t>(?-+@$V_`FT>|nwYV#O_3q1gYlyb6eD#BZTA+&UQa-mT!d@S84 zbY%WHH*h7vzgJL#&6zR9cckC2csO~eI&CUXtVXjSFuu#6g62-h8)svS%&S~^X{s9Y z+uiZ8xg?XCF)YLEInqCw z3{>|YSucFBw`q%4)3>daV=RG?xW+mypv3pqO*fRk21fxH%4QFtAKrX=VY8*N&54vQ z)|CLyUq`EgvkY6)ma+AV0uaLzZ>?<}IjBN}|IxXoC8Gv4m}{f(W+&`_*T= zTY<{4T3h!&I6dCAf$dU6kXh;o!}^huO;+?RZQY{$44Z}EeskcP*0&G(FTv`pqxK@4 zL}>H-fzM?|g7Z9}pasGV1?^ z@?}3;Corcy`pT!gO=5gJjD`+r@kYZI%=dNA0K$fg+obyIB=nNm06#`_`zB90xdU$o z*9$E~JHfZqe32t6o;~c{yv$kU*&LbLR3^U{3vKWNr4t@SeZ2*|Aip~EZLkbiu63`OWM1dy?ooh{T@UPgZb|T1`NG%bWzyetsat4iwvGf4#01 zrhvA(kss(&Q{+wMqawIhd*jkZY{U#qBd4_0cD8Yw22=eVl2H4R0vBVz)33DYT>q}@ z|3lMPMn(DlPv5&NT?!%yQc{W_4N8MbNP~1N4N7;jOM?<3(y^$3gp^2kcXyX`=Tf`- z?Duz`|7*_S#l2U|%x7k24r~7pPkyO@1s@KTJNjM@yzj5O_>q3Tl87uy+1pFy#AXziC90r^rHlN5ukf(w z#%QyNd%&-fD&ZQG@%Zbag#iJq&-*)y#^32#OFjbxU2=jBKmAX#_TzIW1H>thXgs_2 z{FoIQdR>okoflNhM^y}S_W>mh z({Xyg$Ny{ak}%-BvmNv6tXU%#y|htNQ;p!RcDwd_0Yr`#wSNH8`YoWMxu^ z7;nr$UC=$#&WuMUVgYg(^p1_Yz5V-ZBh?Mx#p*kahV+4d*hH#|_OG+$u$=?SlJGNP zvbiu=@ogm*Ru;Qf{t!aFzNt+=n!=Ks`{3Ux6+zUS6SN)y2a`7EJ?O1OyPV=#vma}@ zFC{)S@RnEOzz^%>BfT86?D7#ip2j7K9^-j*=S`X9`6&WQI~QI36LRC^Cky-0lGp#X zumPUX@ZV8b54fN4;JR|%*0-5Q;LV9HYT&X?H}eo6jQvmlzkpia^i)vP0&a1`^drmgxb zHr;u+(!P~fdEqv^mzDZ8cH)3I@Rr#9x%8c4tGP+`lW1z}O^h+(JhyZM8K3L80xL$Y zpLV{H4eNMZnv#m9h(cU2=WiNE%3^l5Daf5?DsH6 zyu56q*!)~I(kD>=?pM+Y?Yc%HhpP9zt%iryt!vGSWcF%GJk0fvQq*jO46;UZi>9`> z9Gm2)9UFScKxrZy5?<0}t=!B*(;@tg?^za zNL{y3R35%`fx#5Fq2pMH*wUgF2tLcGs+K6_z2@e7`A;V1p9*<6_Rcv(Ih$%WZs!8^ z|5=ms$3K79!m1j_V)E{{K#Rah7`_WT`#Gru0iJ-#Fqrb6peCsUZIcnw5%VYs*#EkB zA0(Z;AK5t!7+{@(?H-jz=6u$F3M?^QHB09rwqmiS0*d#J^kcn;61V*dDECVW`_8bD81 zkM))cH_zPd`RlSfXGM!mYr?4gFqMB7HQ|n>B_j=xrPGK_t>DIocmKt)%a)G(6ll^~ zoDNOyuV&$)S0ADQrs6ctI+rs)_k&HZa&U_#<4Zm%1i-}pp6AZMc#Ki1Laq6{!>-PS zx71Cjw8*JG{VdG=AO`lcA%z+_ME&-5er+*BUWzK(){nQ1_GsA3-Xn8rTuR?q_(g}OPz0x)kMO`O@_0d;t-$>IVIlPD1BxAdRn{Bo-t?5!~yj;TUL{XJ5XqsU5`1WWns7jRdMAHi$_a(7OufA)#JEwmT`WjN}%P z$1ESwxM%v-z0Ix;vgG?$Z?T#C5RbgNf4*<9J`piFL)GzlfsKl>%`A?!c1$~k# zzNJ0C-VuL%;NCRSrLz6AubJY-A$AoHMTy#%JqE!&q7)Q6-@hx>wYzDJu{(EKLXkN< z-v6J9b`B2c@*-m#y=}h8KkT>mC~;g~=`L1t8KR62(tb0$IgeVd)%fs=-Ta2z<0qS= zDRqEJI;`CS-MV>=4_qFYzec5I#44+852+YlR8%ki;(pCC^^Tc@^ppOh`jzR7l8J7P zq5mxGbtd$FN=2>#g;OE@sJBzoY=m53`7849KK=>XOi3B_EfW1ND;e_vFKGFI&$yPJ1%j+`G_vS%)UMmXt3ZC z#hL)07h(sp?5a+@PPRc>=_oU0_C)Pm$pXga9ZF71KO2TmFJ5}^?6BVhxSkz_-5#TC zI4V)&!@HUKJJ~`z(59y*A?llu~$`&JGE!xb$|f2Ejr}a0euQmk`jN@Etdg2iy!#XCuVE7xv-939 zs#GuLO4zG~+hX*m;cxE6{rTmm_)<(mGfkc%TP}$GL5!mQp5C2FIxx~SQhE6IteA3> z|K*o=A9QnnFfQ53!o~LQWiP3V7D`?FKj%F%ER!}}z<6a%AMFR~dll18Sx(mX#xd9| z)s~ALeJN9s*iXXh)M^n!>@MslcGX(zO!PjJnP|8II2^JquGdx$Q#kdBIkyE3KVXhUqJ?Q}0K13~;Ai zx`@k}Gho1CpwSEZ59^kBq&bVAHaZ=f&0Q)BvgW<_@mNd=B+4wqD`+di#Vo$L#3<^0 zF}9RvYWw(cm-8wPFwgf_rD+m3gLVgxt>D|o%0G_tH_QhM&ecLZxTS~K#^CK(6z@?n zFF6wZaT*k`zvt(^XevWF=z=My^&|HFQ$4Yc;dukxL-sDc!_qK>ct^ueS_P%yq~|wR zNf$Sb_(x+3%%uj6-$|HT8sg?V{eQY8IH6JhO;zy`-kMT;;=e201ksJ_MQ#>eY!JYu zz1MrI@=ERGCwcj`u=u7FzO@gyuSeiFsat|93JbIhFXX99}W_OG4S0YoM z(rr==OB%nxgjJhNLJzN#-c?xHjY&P{jW#;xnJ_hO(Yo{Q)px#RlBWKw?!N=R>lo;Sv?iWCaUB~M+|;i|3TrQBo1u_n_<7P#vY*M<~5Y*9xeOG z+{{JYNc~oSkK$EuBf$?uw8$R%8k?@C>0047oTvTtzh01>qf3HqTZ$|@CYo<4c(7dI z0&-&{54M=2DYg?%EQ>(I4taUZ;g|1{||b!dA;%l zI?|s$U)zDDvp%`$Vp@tpVGoJS2taRs%GHh0307&hpQ>#*tZ;KhWq48KwfMWqKKx#` z(hxm1b==6IwgVNvNeO>Wr6Oj`kv?BTBO!a&8AHYULW>+;Q-uEp>li-g@F`BTN0*Dcl}D>f8M5Xa1gXJ}^@fe+!L2an@!F=rS=BN9kn zuN#73N>q7Rq%6O@!9IEM=84P~K%hW5>Pg}=&KTC`^DMJ=vwx=7-)e)9Iy51I}FYYISs|Jb~F`oorvhey67a&lRF(s=SnyC0o1yQ=-HQVanHXgT_L>!$jK4@kIuAqU$$r(=UNow!>P~{R-@^cDJal=PtEhQgrSZUt+wHM)x~qvU5yBMXoEzu=-S&KPLgG& z5I&v5Y*rF75wE@FFCJ9s&j4)>9PQc^D>+Tm%<#LZ+nH|&J{T$zN+fOLeb3g?y6{rc z|4?nnAGUBuFv_!=wdCVWTnMX55@s(s zxyX`UaUrFjN&*cd@!2`qH z7y{q<&8q;B17iBIG}}v(q?*inADbM>77Um4jORFvH|sZWj_H>E7Cr& z0^9W2fHx)+!F}Ck>{w6S9Z49ayr`EdQ0A8A6ilp2BX={qCm-+`TcyN3k`FaG|zdug^B)lTmMpQzCWbuswYKR!(g;XeM+@ zpc~qXkn$#uRgF!FQB2gS{D1*h=}Uo`3pwCr>(u}Rely)g1mC9yi2=$E9THfD9`%GuOAu;OO_N|dIF3HBYNou%YQ6RJr*GV;ap5XD%DgdF2Hf9` zfuy!N$Jbx(@xWp~|G|rW@cuPo?iXcHz)J`~9qmpBVzRRMp#bO&2?QzEM&lE|y=&d{ zxEk#DlyRwZVUunl&Zxuu7(-faj^CNtX1EcT>v-6#K-Z5OsFIS}D3^Mq%hh zkrwbCFJQL8>Z;}XsLj-~%r)ACF0qWXy6WOa3U$ZmvOM}aCAsg1(IVc;l1FplEm@0` z6KJKSL>YKrTHGJ1E93iCi+I<7%=AmrCOP?Y)>;n=*z{ z+=Jg-r#y}}h|yXA<0O5j4)I=95-y7)0<8$$Iz93qs{Qgcg`HhHJ-98R=O7pey{n*q0cyie1(zh?s4s%pk_EOf94}MEOXa(iXwui#ZLPt zXusthXYjA(k)Z^s*ZL@_AZcl-r>dA|dUJf2?Ut$?(`5s2rB(1eEM+{zlZ*zDzt0LT zVDo#`Sqo*DYEC4AGj@eLy$QbYdT&FZyPYrLMC&<4Bq998`!IYH(Wph3A5YbV6|ZJt z`OTy$qGu?z`2zO=AwFAA(zAnc93ro=R^Oay=~+KYY2nXDH%XjH$k=vho@{ zeUiz4ocOtVoqnshG7>atoMt6i=X~(is;4T0F>r%w|E{;#8w%x7rTR4XwJND@y7Gm| zbVJv9P=l8F0_|q6q|7u9E6{Wl-Db^jymav z7ah?S%3${;gBicvBiN3j|7{EX(+8((@x^BLAXE3=KiWA6mi5o3y?<3Z2!6->yKA`7 zW>0Nx9c{mwPKMzsMTFP?0k?d6R~y}H&VX4hIa-YxFSRh?)KZiaN*b8%wivu!-Ydja z4lAmkqS~)g1!mB?PuL3Uc5K^pm$!#aC^d26RL|YyK~p8A91zYw&Vo<=;tBjkxyxFbL7YZxOW7lp_IcQPahHbdn}VRIE)+QC{sw|WsK^-U6lCxalN@$@lFc4 z@VOr9ONf(7ateNA+g#8vybwStAlybI%gXekH?>0LfE~D-6^b=Iubx_rq7*B0M{7PI zPitZ!V18JZs{e$=>`*`|hF`MLgQsNCIS~6bX9i|GSFtBD47C#HaumN+HZg#n_EM_G zqhbZEIB_d_{_H1!w^%@?*k9S^AyeJswT?B-A<}G!i+}FF=YnqT(i&vw>anc?j z-ooztd+CQl6yO;6awfo=8u6)Pfe@Z%?75tDj}6>XMZB59i8D?KT=2U%3O!99MCTD% z)c7w(lzEQE)?7p1P#Y=(Z`{q@+i!ZuOVoJ{$@DWJ&&j6nvARI23M;P;*Ap86_ScEJWd84zCh zuI#=6-O{}LLMLaqBUTXfO#qdeI1y!5zJa zWj?)^oXH~=tj^+y?oU}HO`aDF`}&pQ?4UVI-Tgni>+9=RbBj{lTBVF{MHAo1l!MdA ziQ)rtQ2FZSJW;!2h*(UwNs4YtKK6Jqc z_XV{6)qnq#c-P60GkJg?8=qn9tY)aC8b$=tqjrARl7<*#hRl4SN=9+nv`ioTU1=ad zMUs1<(tjA;S zpmcoSlZzsrt|}`f`{|k7&TtJOl6P~2;>T-BGpL`2$A{lR(I06svrhNIRrNr@tgnS@ zJcielylkq;yi0)snVjdDWxk>sh?-N9LNi+3H*m)E8~s0%!2w1SX!26&OQw6 zjmg0;>7E<%rwy+*qt_6}13S|r$pd;E;E8Mcg1x{&4q6PPh&0w6;dcC(MsJ!-;NYYc=uO5SgNCG-T; zg_~+pDEm<+i528!I$Y{OCccdY0@LH3+%-gi@Y(iaiANT|TaEWfFauB|pA2|0Y zKurIQ?~3pJd3D;vV?H}FCj7y|#?fx?j-E$6xY=*b@!Pw%Iiwy;E*3t1jXWRi+o(xE z>M^L@y8S&u;9{?fD0o*mh>Q~OG*XA1!r#hXu>fD?h!VoIyw7S8t%bN-9uB2ZL$)qg zYEgvn|Pff=IE}O$1QPt--&u=l54Su#GLbr?$LD?M5G+;O}yd8)8 zG2A(JxONH!hoKro5pzD^7FwA{61@*%)l^r0`+Pn=G1fIbJMQai){~#?M3}OghJ1(l z@2lP&R3J^QhQG{Sl_pj)E*VhVQE7m9>n$K%a;||*Xx+m5D+LAP-ou-8Wp1SQu-ub( za(x_^3&V&sHFhNWrSx#*V`nWs=_L(V+H*u`T_9n`Cd3VyhH|p{-xnjn?%5*q*0Fb= zA-vAEA8G0EZjX-nhc$&x#}WGN7*%EQ~fYUtqG-!GD$t?>K|$*9s-{i22_J?VG; zTvQ5p#oad#I{62~v*yImNXo%3_ocuRW2k@ohsSKH$RDimn5E{{48~e;i^^5=%{HR1(ZXze12e7ikC)D*NXcet|Lq5LUM5e zPHI=0>|-jC7_1pPlsGW|59T!u_pTU5_ICQ5Y0`7O>OPPd`!;x zGkgDI1!WHZY22?jW6P#6i_@|_kS~?#A0+~3x z5%P9klRXKyckV~MP#<{$=syD7LNl8y4;u{FF*V$f$DozJJP)o!B4+)4gU<{qIG?7r zJx{QxvEJ})fNkZ{95T9U&0j4Wv#JlG86~2fB&ry(GYF=i{MjBH!Mt`*Bu%(`oCPF` zbtMu9rlMJE^AeVO13Vt2?{qRg-P7Y6F6`RbjQjAY-zs|J*Ky2kQyhnCLp0j5ZtOkJ z43;95799zwg9a1BOuyoK1Q5`wQs*C?Ls5-!5=g4CHY~mGTGXpFMZU||VSR5h)RcU^ zYzYP95I*R~<=Qn2+7pI7EF_n{+aV+DfJldKDW;Zk#AdWkHDBXaS%0M|?nkHZC0GWf z2X3-dbbq_tkpZQ4KHLl?l>6OZ11vrR6Yld5G&vY$zP2V*$3}M+1z0Do=x|&_TS0ur zQ*y?OPOQg81>%msSwNq1`M-wKh{|~jg^LKL1Kyk48uoXsaV{3ZpRtj%`cjT6;wyVL zz?Ml#o9tNM-^IcAuS%VdH31O+(w*S#-+(mmkhM=8B~Yb(sFruUaP_FcXA;lfd3uA7 zaAiDa2GW9LY$k?X3>fPz3Y69%mz#v>SbCZ|=tdd42?ob3QFqFdf)`#FqNRn(eq2)F z)fu;VMh%-!p2}v=OI?b3pKgD?8i%3?ux)wUDg{W*8^h&alNhyy>NulEG*14$l9K=avC>BU|M9tmqS|5DwFmY!f)VbSw< zbphOeMbRmMt+qM+T_gA%0)@Q;XDj5tr~$b04Z|;kvT<%5-42z%{KlOz_>rSQ=)H9) z!E4G1*t0C%dpe+=HP1_1YWcNYUvznd9dwB3TSxULuPis2F+RMsHcLMAaDL^n@$+{Z zj7gVkEkaE^ihSuzslmtgUc%-m%!Ck#o%w(y1S;WuG$7rz2d$ zN?^R6D){^9TiUPf33yf$0rlzBDyGyfH_Bfpd5Lt+XC?jRIk2ZoWGk)wv$>ek*o+o0 zhQo0FJF&rqfSiYHwKU4x*c)zB+h+X;Q zCK>4#!E;Ep2-xTNPesWdW~^{^#Xo5k z^LmkQT5&a0&lmdTh4<-C%7LcAtT*6@PjCG#4?g-|pDu1IvfbAO*U&MFjled}A1(Or z1(K+$Fe4P+_xW$(fm)_Mm1)aj^(tMn2V9^L+v!KgPEv>hAfH^5&R@9&0!Kak1o8H~ z6I`mYW|8z=)u!pY>_W*bsK~VQ6n1AzAeqqJlwPJL{GTaC(`A*2US%z(Rfxy@(T)5TB z=C1hamnXlp1W0GFP#5H7p)DhTl}~hWKJcFPLMlo8C3e)S!@lpZf}J4J+-N)T7o)@= zQ&!C$DmAmSul>%~bzbtid~5L^*zQpR_qAjF3$Q2GB}JeghEnf~qD~yT2+xxhN1Tom zn6VF?K85u^B{Jm<#X`o<9sAdtH+ zZiAVJg4ET-3#+l$qH^3i4xQ&(rXi19m9L|O64Kp#^6l9p&-JQue=-bG*id& zQ5z3K;O-ul-D?;sx`y#(2*CtOW}PYd3$kkVV1kRC(LX;C!Xs7FI6utY9{BP3xIVVn zaLxTvAUsnBzV*}v6jmA2W449C(ynv+4W4wM?5?6J)UUo4t*|G70pqW(*4V^G(^WfX zrD8}6@dRrhqtAn&tBi;MvdVOmVh@66 zb?Un^uTOIlTSEF2b)!S1VYB(;v3ORH(pTYk*;KN6STo=^BE4o??xou6gH0FsVjwM? zo3x&PbEIJUL?rI8`#DSZ7rw8PgC{XSLoC2ct-QW0;I&#RG+8v~=|Ud3E*xwPmX^?4 z3Mrj;gF@rg$*=7EE;C~Y=rE3~PdPC+cJW>~t)bCsCw=1|d^gNK4QXB~cODn25;LtpaUQ?omF<`g;aAEHIr&RI$ zU%hu{K3`QpXMTJa{y#4O>Yjxb<+h?VC(vB-dkJ*aNC9X!XFIg%iV>+7GUan%Gg+yL zxE^+8=pzFztIi1>D%qIGN=ymz{zW4Bpv4H{jj6WK1lri4K%E}5WktPu>T%Ter?tW+ z@o=Cr8B47QhH6BY_L?QV31IF>0U8B1z75;`@lS3}BA}L+o^}m~Od8bcZ)R&Nf*PgN zrTbJ6a-*+1AS(yyF`S!C#v-VxZ9HgJb8ylMDdrEA$S`C{(sI3%UYYJe-ZL&Ir zs+VHvsJUD8WP~u|_WJj`daOaYB*kZ*=AA^>%1!k`imH*r8zoi*K%?=QEO7h_Ur`9Mw7U|1LTO*w&ad^gb%ywhnGKpQzS^r=1)BNr2(#r5%=FDKp&3I zpX~SQjv|JHg)nw(a`zTx;1D2JsX|ol-c*!rsKV{r8y_E&Vka#*qHZ^ilXwTl6zzFn z->XUy4rP#pJ4u{q{UgS$XzOt#vhB`!s8`}oo3`5vG_c=bshB-rg1a@Q0Z+vCa)hhn zm+he!!FNK91sFpm;5~SolR10#X5^0S5CX5O+`WX#-B);UGNpp(`1HN9+~?5sKPU#_ zP#2P~-*h_ajH3KW!!w=!d(Kn>|B{MD12boD>Ll{+LsOMT6kl-t0QX9t#Otc~ zsp?B%xX0(IweZ0sX=t6-ls!(_a($H!*-9z--GeZ5P-CxUB3D8z_&4Z^;2z*{sr>}t zGR`jo@;fg1L8fw4d563ZX)5*^Dq#0Ka!qiofc5fs6PaO>F;{`^opG`v6FczarCDi= zvT3Kt;Y1RqdJU4Yl7;K1T&64Zn5@2sUwqgRoz&eA!JrmF;arE%nY98ROf$))5Ipy=`(tAf znu+D<>bfCvHSJ<6ow}1%`scpA`7tA7J1&3%C z?6m5;DFMLdaV7|Fdm3mlyu~YCW2sX&Z(b0Y6WMAanG7r z1$QzL0%uWC{D0)YKd+yh%7LNt^~6r|e}@*xvSq*5DuZT%uqt$8bSCER=SL*wqw`TJ zuo66g)&FN+teA&OXiiEFRrWZ5oSTBlW<-YVZq)!R2%a!ZHw<}al_5ij5XER3(I)_; zeIxI#n|YwJx*Y^rk@*A#!NlDgX7_;6PxoKWKYoJ?R|IIDWu%IR?1>mh5bGZBW3plp zoP@_~Ab;cz!a`8w(~>3LMyRohZj?|YHz2fFEG4H_f!}P7kCksNJqMX~ zUkphC*hLqQk1b850#7Z6n|a(q7plS3#eq0eFXm|FZ7OWzv0Jr+T>#3p`Wkb7kHKdL zl1C}65s7K*+kcx2mL?}zL~eZy(fGyi2J*lb=Q?ktS1b~Vf7zqy{!B+%FQABu&{@>U z0srb|!_Rr+RndFW2A{kmBUX_8sfFc7TG-h!%av0cBUYSjOesvl7?RB&wBvn}p$wC8 z1etCjiYZRz?ZeA)vwcc3PbYgL3jk9!;EPN;k_diNQM-5XGL?4#&BW2q=I?mBQR8~> z@C@M~JD{>G29<1rb)CYZfRzA3!Z&PY-4N-7_g4=u1rlJU3SiWo&4AUx&)`$sc&TTv_#$BP_CEv*9bWlZB1iCQTt9(MDo6BuDka{(cg zUcF>~-3irHO9*u!ol?*thEH$KqUU))rZ{L?_%s5dt`%~_4H5#kG$nuM$8>6tAQ55x zLq1|jOYhhp^J9`zU?nZk8Ri=nyO59~(5mi*Zm_jn8@7 zF0I;iR;2KsgY3)BPE!T0*66*=>@6XL?b79AB!V}h%*F0Ma#Bq8+6+!X;@;*0SP(iW zE-W-Vo{icp6>|nl8;{rxM`lIaW>lo^hd%-JHF(y3TKS_3;cSEkDe-4}SCJMz7zOU-M#1R5#v+I7oSB5U(7~7Bbo#fEv z-;Rkv8(=SYA&yLlx)dsAp5~(=V6V)i4NOeA1yH>Xz=iwD5{`HB{WdPc@f!-nd5Gjj zoLyGiQNhB4us?dJwRS4z7AhGf@!vS~Jcmyhn}gvKQ^UI)^*W3NYKWZdmMb0^@*O^@ z0JqxsEfNAgCUhYWJ(49^g0_C0&WMjhz}zl6XN2Vy0lIB*uk)wE{uue1@@o8bwo1Fv zn*o#mL{lr&Rtf1(a7(Js1rfT4$1Tj4`x2DGf33rME&%&Qwv;hHLdO z#6vV*ne_|LX88wimL-=Zk8Q<^fjLfq4d>P!o{;eKYNrCZT9wQo`zJ#h%IR=3&HpaZ z;v%j7*pT0n5Kg2&B2BA@{Kg3sdR81RZ*Ydn)iVf!vfrV9eSVem6;GIZF6Q%49c{o) zE6tre0SDfzZz%wQW}4(tuBbnzw{dt~Y6%Ix`HGhpwvI7yIg|;Jkks0AR+qI_BM}ef znH^g?WC3dI&A+u~X_v1s_?O9~*BK+sR*ugFr;y0iWgP{0ZQAwitlRMVCqv|V*Yz2n z&fi$fX9}$D?3vb@e@4e=p#n0T?fK*RL;(y}k*i>9G5B)eZ51m`kOX{zORST>p=aI? z*QWZ`ak4-&lv+*0xah++RG|n65dSI?I^GFo@vY57!S;KIuP!aB*9ZR5jP-s?tbKs8 zK1*)k*@2`!#Hu9%6Fy++ozS^ksWis+EuI^aBvS5}Z6X3ky-QE{lXo>+VG$?m)Q9cy zQCca8!;tTukcmt`sWXN<1HypBf5kdL{>j`UPdk$XPB3=1y3JSo=(&EB{hBqnD+{kfMp2% z#TC;%YEQeS8@P^Xh3OX6?yXpWTeRO~-nRa82L)hIs`k&5cs2jf=2V*ZWHwv1Fwo6( zZ{51adR0*X#g-?JBr*ugX6Hd!8JsH)?ZhXOc1SbtY$w&ngw|pUxemiz zGVdAP=1+cH&x_(#V>~&4-9v}lN9E))+%DMe)4^I_%+Be{hvy^~<7>t<<)`N7dHCu& z@}JXGQuN6eUS&LxdiL@^81MY&Jm43#YOL8JVkyc2^(bRB7h^cH+zmmBgIZqAs)9S^ zf-2Z9VssUcc)U7~UVz~U-P1>v5lj8hb+QV0&ngq8Pts+$jz=w@UwN$rJ}K9FNx0cJ6VWdu zr2gQIq)&%h#o+Y&Qa5A$Gia&iI4^RZE`{$S+26mZUZv>5 zx@F&WCH$p-Ktmm@H=HV85@ozKRd=>ngIXLac&Ml%7Hsbw8b0&I-h15Z0J~C(XzVFg z!lDGc#|vX>K6G!mg+t0fee3dMYlfR>%;+N|W-qAtc8a;`XW(NN1ycj^vOP>Eqav0e zkzCRzOnr%xYg-_KvmO@^OY!|G1h^uNOSDgD5UU- zbf&7gFyY_nc&s0-)pt=NsEWG?|L$V%uK`x?t1$qXqK#Rw>eW9v_#k#}XgwuR%t?-W z`0JBJPtKU$t1>dWh-$O(W8s`=<*9mK6BVIAD%-2?8NWToU z7a?L{;`#l0;)XLaQu>EC4gD9ae&sIRGr*EZ^tNGxk)b92rw#9ithU})p7fEVwEJN) zK-p}h=g~n0seghN8;&0y)_LZCVq&R&@2{#myKTi%jYxb;$hEkn+Ysj+Ix#t$BQe8+ z74GxE1*}dAVD?)hj=j{RLaZbtzKa0%on798jwg1FKDdADLD`om#qi*Q%hBaR?6884 zc|OmS4%p2aT~L!=uSjbu$&@NSi+NJu;JJ-=lORN~@{`&q#z&%}UMiA419RLme6pps z7*yfA^)vf&`zHFnB~%uyabkWn?R&x2u((3dfTeW7Y@w72x`jZX1DOtJhO=0(vkQkTKtTH({JROqvkFS@m-4#gW$d*Cars}E&`?@4+13jO2znQJVgkd<9c)_09=UHe z|EhB_qhiF$8ubLRTdn4%>`xjGfiC#Fk=0beq)Iw zsSohZHR_NT$p~4lv849ZdiFrcigj{UqGH9uh962t-}#?)Vwgc9+@5n%owVZ{CLPW# zsHu>K%~lNrUtyJ38;i8*GSl|QZtZZ`ZIh9eRv82?F6nq1YCj#N{P(&ocxfUY7*@^b ziV)uKikZKBV)%+e4Y#6V$AVrliI)zILbczXpk9-kza1XQUCR)j)>jHxcvf<;PO3F#|aUrJkft2jUPYVZMQGGDo zwHX6BDO)hW8+TGML-3%_M>&~&@POz!-ju20GJi&+v&0nFOZ?Zf*PHcv5~ORcnAv~N z8yb|bv(rz^o{$1?#OpqAKa z33W2!ef@!|+bcbwCG_B3^4Qb$RN4E8<(h}hfhRApwrT5#yMJ5+cMjl{m8b;o+c>9A z(QkYXqI)-7W%UDM-zjfQ7izyO;>^!UzTFaCCE>Q?_(w!z?LR2b^JjOH)!uztC{877 z3u~#;LZqdTdexT0RW9+XI9haP$9baO;>MMe0gjZ*-KHM$-tX^+r z8MX+_Bk$CI54zV)K>Me^oOfnMja@OlIZ+KzWXdfBNLHpjhZ{|Rulp0Uzp*x+Ils*r znFiNgp$5TIT9eF|;nQ7ltxs_zdIkA=1;^MwnBE6hhN{Kf`)@v1KkrQe?>jWq51emG z>ccJSX#Vz^AH=n798HC?E6ah=*gedONj#fkN>%7=K@f9nPLyIY0#i`fh~2%hLuj~{!6ur0oV^_&x~9pF7X zBkLrv=7BFLE_g4I);M3_y6wJ!r)E?exa~?^aIi)z$D~q$-5;Ia2Ll|5=nYE`2BvrAVyA@EzW7oI{44=Dx+qJZoJT6~7P_<%vCEa=`60T6yS zY3>nRHaa&55CR_0--5*vbghGQp6kZ*mua)rvttu|fpHNgJ`Z82tAmuRA?+a!B$SQj zX{uZ)+iaeI8O>fqFxz-q5p1Abl;H=5*yDLU|M;8?hs}fVEN^u~kn6?=|C=^7^WGK; zYv0WQr-3K1w|El{X+kB7d#DcUeeqp~atEyUNtECym&uc#A2ki0B|0zo& zgeEpYdq3CYv^~Bn1pnyUd@c0kJ>%z|!DKh~ks~$aPm#&btph+f|7)6e!|l?Z1jIL6 z7G}#&e$yD>zFnGOv=W<;?^JU2JA5Tzb@KTm>wnWh^%(4QP^uRB>Mr8eL>e~M;!ex~ z=ru)Je6jk)wqN1i7fNsmLFn;0TK4|oB|or6z6HOroPE_zM+KH15RcRVU7P${_!39J zI$!h-?bi7OZ|s@>YMX=id>*OwwPAGv@D{j5_~JR$oxND#6^uOjag%p>GKZ5bAjU}2{gXMn0xw~=+QVwEQb@iE&(t*~urIA|V{!BKnYeHu zQFG-1XTwGV@gTyZo?HFM6ahGIxsk8(WT|ri=h-<2_ui-SKvT`VGQUhy)DFEqV_TXs zvoVKgdNyrV3PDR_A&-aSERNEYoDah7lubV%e@068JWgev(FW}{ADDnHR~|4so8LWP z&*N}r7YUBqQT&(3q4AW8mtW$O=IrSKQTEoSSJ7MDyeSOQ!ikmUTYV;|w~fSREz(dm zsT=-An%zfj4NE>L%M~r6b>)W^A^(r7uMCK)jkZ2B3^6oAgLF%ZND2&H5~4`M&?rcE z4h_NJt|s^&Q@O@1O5Ce>ii_v-e(WueF}*#wv5`r|dtmZWl0* zwA&0i^n?DfxA`yH)EwH+b3sTwY=^h5gL&<@Kvc1lS|{i)6Am9=nu#|pkwYP{q_r8i^ z0VWZP1v}vrl3PcDuZ0M`LRY@2u(v8zrj@t`9@ zPFoO!?$yrb)^FE}_ulu11EM-qp;XgN{w>c29^y5B$MJ6uYt*v@)FxLm!QNj|E3`eP4< zH1|tC%uQnNo1)?3=|bN;i^jUw$;eYZ%p>K!kHn%Ph!>a1`i|4rBN9j*j}NT#W)_wg z3M-Q<1z2v`)P%w+8?dj2Rrb0X@>=N~OcDTVE7aK0aVgS@u#rH}j4M2FM{ ziXoYN;++40Fm8kZ2dT+(y%8}H>lTIu?w7J%x%s0@q%FIo@2 z)F}8<;GBI&hq%#9Wk4u0KIt-%x2FgRg zFwian3IjybavfaF3Uxhti9EwAH|uk`(_KG{#4j{2YEIVJzJIV;?HTZ_As`2anX8bA zQF4C`WXyppw<{~K7RIyp!F^feUt(u)YcAGM2T3~NP4f4!G1~D#eQhTg!$eP9nqH1D>ZZBOanGHN4E3YbK=l zpqTHvRcccQ!*wl4UD9bL%snB-yyb@S#v+u7e-@1@B< zqpF;#I$YsTA(6X7pk^ddIUFiU6w zmb{n0qEj<^UiKXBMQGg|3M6T)ieor&17_=*;}Q=yy~u$_w%YUsKPU-y0V$Kpbr~5^ ztZ$+2Vt6MWyP zyIlBbaY~rMxbHIYeT;i|!pjykU-s%TM2F+sSU2$lakKWp1toXvs~4Jg?(&lY&-8Q< zz3waGcGs2x*1dX@wbpNxpc%amRnK|{{TuccUbY->$D|+Zs5tjNo00hSe_DXj_q{)| zzkBdQ785Bp%W2wc9fs~w4YQZb4u4El3yn+esVX5q+po{AviY-i!V?&>jUJe?OGEUoj7r;g}2R#4MFO|IDz_$z}*Zbx2?m z`Bi1dVkmwE)L7qP2OhlE8B~e~e6SaS9A(WIVz?p53XY+VPcHQ|x>y<_4b27fn^%5$ zvN$0;7XtYW4@m8@m8Oy>hJKS%SbR))w>4;c5OOF>>WqyyCfr4m$UzzhehbVr691Yt z-s&j+TezZ;!W9;uddm+u+73IMe28XJMQ?CR^!C5LF@_P)$2HnbPGOjRDpe9R zGq$y?{l}~*;rkeC;t4^+=$n;zeUwiDNue%nq#QG;dFj+l_c08k*|6RFPM+}`jRypk zr8Wx;l^)IC?%%bDo#rZRLin;ZNrK9x79N?Io7kixAKHhwU!5Qfot4}|fn_5hB|h14 zWup@h+o=-AVCTE>sZFkYOeW~zouKxRY+oYppF62@jL3RJ@TpZ>A>NsNu^t)t!M~B;R3t zWe;1sP_xoWhoj`IcPW9tUyO9C8?f$V46QU5#_m^?PsbKwT_tls=)lkH)avm(Jp=V6@S1 zwaMoufw$^|d2qcKOdjfvSEvh*v{=kjNL&&mnN2XG`8bsq6J#?HoGN(FW@}gMvWx@5 zP2Os46eAcKPnKoFdNH`m1<(W+)GFxxx|1m$nq5C1&cN%fXj9U)63s!Xfe8aY2~5~X z=oiJ@zk#Q3R~naFPOU)Xc0h#(Fm|O9tH)Wk;=Iab1{xP<%?loVPx$8e2OUV$dja}k z7qPbu*^$shE$yX$Hl1hs`bMA^<*EG7#o;9)x7MxQRb@cc!PKNYlu>wfeyugYguaIg z5R|m&i`%jsF4v#Ssm^q4;H#G)hF-q#{O|`ddmU`ZF-s4;fY3K#BL@@RzYSdIuh%=t zJEr{Ngb;)D!UNu+Zro-xtdbYll@0(F9#%4Cru@Wu?^WJd;4>c><1M@Jk`gfCAZk!@ zQ8x7+NR$Of36}px2_aC(Mlx0cJXz%l@VSVp@@pG2xqsb-h~^jxyfyeFtv_12k|Jj4 z1SRb#WhmO_#Q5HC%^`V3ig_#$8(NB1?$wh6?8tW8gZJ1cp)*kAUrvwr;_Fufd4Sqt za>>K_Dv-$bTQ%dO-B5Y^RQ|3!J6aR?;>pM>>tx&r$WBX|M2P z0XVa9|MeTWvA=JWiBV^1y_WiZsN~jj{>wfGKqacPie~JPKROf<%$)Z_EKcLYD;tBk zt7mS%s@_w!Clcf)c7cYKTo;Jbx=+Rzx14w#d-C%#^qEsBV6QS;Twh4>3Y(9?&l#DE0=Y}xbuJ^fh8Oi}kh7%yi<)KJ1YAv(@ z)a7tnVTATO`|h*_jH_QR)uq2zVW^^htB#)L0l4-*GR?g@L?FxE95WT~{26#A1(k{9 zwyrh?dp}xbM6x}M${B_>$W^jFC_DX~#{+fDjByF**8}Y3MCFt#-TAlDbY5xo4VgMo zv1IhTjTvop>&6K<3U#Q}6bzP`l z4CGfTf?}Ae*uLdBZc9E<%J>8o&y*%3MM(P=(1q;b|Nx@UM-Poa)mAK36*;71BNG#k4sXO0yK-34-BXf0(# z^m?Dny5M`z{E*W8mycleCX@xVNTX!6pRc0shV?2ZE?Lo^ESk;;DsX1Lx&t3k1&Z;} zFa*4n1J(C+|C>mWY*L><0vOP&;H_IsDZ8+X4_r;Vesk*4BCT7fmi+NzwfNJ=KWZn7 zs|WfnhiN3JiA@6DUpC%%s``90&h)Ebwhgz{{`Yw|6Zu$7AZnT;o&L)JH0>U>TY)nGdt=8~6~uj8mE1OVVLOH>hW?d}az$zy!>1P8q8n*GF%n4*! zYp=P84e6&oi@rR?wM0(lTA!%!2boOlo9QOb>YFkX4HT51Gc|Mh;{_b@qFNq$ zDV*Os(csjvF3^VgwIp;3X~~B!##11|9=owr7vU;`iiCelMzim;=hZ zPxH0~56Bf%<4no8tF@Gay}sCdIG^AveJG#sX{EOpEUp+;5Qfq4)E$Vu1QTEZ9o)$? zWkaaK99h8z;zE-YbT5HaYRK->*SVPZXV9mf4Ubquo}5Esh|#GI2CW#9 zBb;HDTsq64kAgqwh>-z<%%Zb(yI^!md;ui(%yJeE8sMh2fnv|y09oQo2S*t8^k;HF zR~3b@nf>C+RBq5Pn3Ew?8hVKUz-@-3BJWAv)F~WU%htyJ{T`IZ`*Boj4_=Po%Q2?n zkLW4uadt?#i92?=K`^CoAK|Z4c$M-mm61E@9!^w$rdeBG4h-i zC?!7L#%rwzzWAOA2ToDLzdVI?2&c7t=Aal`Mw=_HFuMcG6QiM?=tSmv5}~e-=k$m! zw?jH&2nyrYF|QBN%-T}2ZHrx3A_rN5F?Q0p<($__Y2hM7;2b# zytDZAOVZIMoB4T^YRkN0bJB#Xm%^c$CrO<)j!)oUy)RasQdOrpft+WFYQW8bTtJio zbm#WH)+&7BpBedZiU$RrgU_4bH}G$c`~8MHGyN7x;Y) zhGOQP8UI_I8*Y$NTO4+Ry(ibxeD9g>U;b;a^Bga@D`8QC!&28xL*`qUqi|Sq$8(d0 zB|nqOyE2SINdQZm8efR$?HQeB{`JgBf*ua=)TsQUk)$EZEh51kw3#xpIL!s~Pbh>| zZ~SyH*lt0pEIbAtL;M60n*`Kk0w~Xpd_jvq0o>PNiDWeNY6+S`cb4?R-y~~&aQ)eh4nU7W@r%u6>TQkxa!V?HQ5PuKnpOu$AqDVC#bFIeZp3!P z(kxGJIT_&plExSqsETQCl(OiwzVVc7-@b8PHL5^q=h3T?wT4J@bccKh;c}PQHWgwr zZ&||!%`|x3y6`^HWFQC*)EmB*N!oLQq9@=z7dsESnEDCoK7E5>&MzG&UFdtq=kdFKN%C1e53lBJ9PiUfK6S;`@+Pj&! z7zDr5_6w}cuBYsnl1rXhm)&^r;BGH>f8=Eh2m_f-ZUsG!f1{|uvto6HZuRm$wF!C0 z$ljd3Ud=4yvpyv8GVQJRe0*#9lcCn<0qi_oq(ClQC!&DE;w7$+lVqZppmFFztD|5V z@kv7&0;vKRNY&1Qa@0|HA6l3>yJ9=(cp-P&vU<`F7_cF^HRmnr4_L;6>kAz8xKJZM zU`dXlLVp26mSVzLv?$71}KN4q)L#0)YsE{f4*OD_MR&h&Fz{qB}6<=;u zMW`&hRs_llHn-RK#9Q2)As`Mjt?Cx=ZusS8HM#4`Bel?{tPxeq;wNR(Q5wTdgwiEu ziM(uWd}&C&5a!zjkDTg{Ug=ppbfvKW4^9x{KKu>?vb(7vku((UkO(GS?r->@04F=d z6z$(?jP0-ft~Cb62o^h{{-}eC^t~EYv>WYO<`N|62!@RDQ*R&x`1X^I^G7}R4Es;? z0kBuiD~lH{2i|-Q(iD+ZD3?q@MheMTHi@^3D+C#6zxXPv!;TCV4ol}8UVKHlz8pAH zfmv?z{WX2`j|~*1TZOxfrlQ}KVdCPhbovz!srMFw3c+=@L%Ly6*<}wC1T#$}khZV&(U%MO4W2>z9j=JW zZoFN$Q)5D-;W!o~lIM9@s+jUYX<+9pbT2<^^B{4aa(=hrSKQ5SF1LdUw9!>eY zg$$rr6Ug4#k%6L#lqU=Ln}_B=i1>vXd-C$6D#JGjlrOcJ5Hp$7L4#e!Y%=l(Vd_v1 zw%hQ7*%0ZkM%Yq}^dt)=gj^sb}ems;sv$XpXObW{zM$92YFlETex@t04(o%$bQ&piSv30pS`!UcVGFwhr2L;MJ-!0Co^ zyJp2E$4(q1EU9GAe2*FT&--*bKftC6+oIxQqsV|Ode!*yyv4t zF!&~u-@QVtY3=u7nr|eNt}5_e5$^BcVCr{&TuZ!yC=DQm@B(CJz?R8yvn?%feaPF7M)r8!tJx$RP-f*Ch`~^{oI{M&} z#;@keXREnk>5Gl=Ba6DycbvaIdNoBmxG?a} zAB^ykMdiiPpaa;%y!<0$;0QQPAtH~5>fqdcVx`94>#bleaX1VQl(Ilwogtqxd=HgQ z>h!sekZEiYbSl02#3Hg{IrsqnH-c*=h`$(998&3NCKTP&I_LPG?glBVaTMfaDKt8~E+UESh2Qg9BLMHWWN1n5! z_{2v8`E7(f=A=*{ncH zlIsYE2kIM_(~QoE$sO&pcrukiV&x0X!|agI?YHV|HOv+$}g=bF=^JX@d3yra%xKGd{S@bfV?cj=3J7rSYqD|U z;kK!}#JJ!*>ROmvp8x;*Ucu45fXMeL80j^;VV1`$<=rlay*oR{P(cy5flfbk5}syI?6q`m}2B_v}`oJUfh^PyxsPTKFlb2chgLB!|aQ z;eY$6d-iiT*QdXSi0Yn>KsHeDX4r%kFd!Agt!Hm%HXAV8(&IWSldtyrl~>w8HblLJ z#6sG*OM}>$PDXN}176%38r<)sDmpnQV65D`RR^~w!s1ew2=F+hY5J_IDzm&XXXLs&}CJUjMW2~AcTz~x4a9R2!ZSWvi^9@YL zL4<|>*RwlLmov8m9N6+%c;&WW!1}{Wp{85qoQqay>ju-_Xt9oNWP<02+ei;~wVZy0 z&-{WNaX5=tBl59%{h!9XUtIOp#-ijl_cvryhq3zDgHGR>`W*HUsd6Cr)A@%$sAINO zqt7KtV%^CCh!`~a1`9$?6zO>$V&X-rChWn1ti)0-IS2>sN^$UZFn#4!-ArIIFb@a3 zlkCYjO!$@(QLEd2_gUCYd#8yKFa&~Xivr%kU0UAVc#@`1#{jlbJE33q!}}*p;)y!x z?o&WK~S0ieVhl_PI1^AN2pBKcN1^jYv2?qYX7+AqbmAG z0OM$6NX714yx2>F3Q>V~Ig5uB!VsOvY7!@=G#&gDil5Ztjj7U?MtfSh#n8u0%;VKD zKaISDsQDlT*i(#mfe-2=49Vbyc)XOPnv2OP^xmwGI!(rFE2F~%8K{yk8OX!?f6rbRliJ_ca>UU9qU*yZvkC`4ZaUPKE))F2Lz;aR zpNje2MHqwt$#i4PpZ4Mxkm#Q|Uz^hcy6%MvG+L|b4(WS?n-LDR0{f%a$vqoK zwAQ1BCT;)dJ~PQQEPX)x7$d(SIfDZ9Z;^z2UcD1DF!{N3LinJV927&R%iSZukA7Mq z%DZ8vYoDMAGkYW?pP)$!5KR6?M*0haID!v6_puz`!3F16(2Qf2mDjV@4!PVd^mo0k zw#b6vMclSZWv&mjZ0oUn(oPLp8#`IlP$Y;SS*3m-cS8(`yIyIYd^o-L}I|d(Ge=+WIKZ*LcmcHb`XSP=`?lgSWkE3U231XHr)pcv!#wD-~&fC5@F!gez zi#s1Efa4a^$Tg>xogBymlkyKrAwW)^OpH6VQ->1ospVit4H#4R()VS=os-)}LJGgd z7~e)mc%Vp_lx6r1|KwTBXWIoO2a z2br~QDUM#?QxZ%Qa=;n0T$2eI{fMw|i$1!{F9O$#)qzxS9XOHQGF2!$sKC(rOqMBz zs5uMpcF@}U0#0u%?68dvEJ=kE38vW~D5iv*4^{KRk-oRzY%3OEep&OuJxwsnci<=8 zk7G)!Xsq?aUvaj-#tZ(aeWo*tJIxQK6y-OZL+HdnZ=(}kMFYWRnzLioe`Z7fXRf^8 zA(tgwDwSPl3{Yc>De0h4#xHW2+AIaZGSz28m-;4tOzmGAJsV}=bC%wlgB2@yI1flo z;63?gn~qvcPykIbr;M02NBkAf>>xufW-MkqFlai@OAI(7p}@9N#4g^QV%(YhmWm7Z z3rVaK$(7k`q-ZkF33Y*+wJz`Bi)T=pTjXysy2yNe+Aq+4-k;X&g>|Za+hvd3{@QX~ z+BB#dvqL-*S2uD@K^0lqhT?r+iaQVtV0a)VX<78AyMqN_Cl#ErJALpu4612Oq9$3% zo;>|NNAn|yE+fYjG+Yi(N~>I5BVg#Cb(wPNQg9Gn5>Gj~Y^4vLfE4_O8eeY<_Gj{k zYTrYADqz4K$s^Ud{fzy!I#ELGlhhar<&WAdnb2~hE2^AUd;TZesKEcxQ7bT1Lc8uqHLv|CAh9^M8=cu>Hjif_+~sXiZP0S|lvJ zqwC%OX#s+T_et59wKyG_7w%5hsG-A}cpUS@!Yj-@X+`;rqAg3pKUmoCWHF;S99++S z^UQjHjQ{ub$EpUs(St_^j}R|7uX26(K~R|fr1 ze`4@r+zz1)mcUI4b4{vMnvf$+)&nHsVA;+hBMiV&l}cx)n93M zUT9FWzs0Qs?syt{gn75 z%aez&vZ%HR%*9&`fH)g8Q7y;R--TAZ~Qu&gGAoOHd9fm>EL~qFllR%>>j+2j$sh zxtLY=2y2b(w?|Mn(BDiW_e<|xv$~yFXEfPBmCik=3Vzk$G_meC2`1q`in0x-$0!@^w&vP z>%1bAL|b#IXSIJ{Dt+gH8c>43G-0D$WfGl00b~fj!U_DJI?gL_w_-3u@rNAv#t0w` zthXZ*E58gciV9ubF4fm9!#gG%z~|K>Edtd{MU0vf>`1UziC3WW@7p&9!r~?` zsqBr2YnHW4YFXI+=UKUKpEc)mH`m|;C=v%d=SkdCj7risM+w*0i9oF?73)4}Z8q2K z6hi#F5ZC=**HGdioVDscR^|sk=);`;B~xDg#nbXe3Ic!sELF5JbWzj*hGb1K29AEG zOI7CcO8!u%%ICVs`3f4P(0G$dB;7CbT|UXqP?|{QVyY$L!;%MIUbN>Ck~Q)Z3|@a{ zg%E4!biCmeU22`F=vbx&O`Gb#z%ETlRdT2-#W#U@CztCH?d9kgGV7Ge%x`S+yoY0+ zZCx)Y?8zWSAGHc(M`H=ncDkn{)-4Y(LXmziy0ZVajJHk}MH131g9{-%om=rmfl%x0 zr`zr=7fbw|TE{UM(`y}TVBQWL;06^E%)^_oEnC9^8s+*1Jt(pyK$|sW{jYC8K&Mf_ z?sDu%s`>*FoVdFXOj?oKVA=1KeeNwqaQ|5S%5297^d;bV#XPD?%XlBHkZIy51}R`; zY$PX{JtWiE0m?`gAzV@|T|LepFOm5~kQL_!0LeXO}1(zY3u-E-c zahi!JI*DzXHoSF#>ClL)*eV|s{HOBAPoei{7qQ#BCOm5X8%L&ML2aI`X{#{i{=KHb zCo2zhPTJN}u@BssJ3;$Er&C`{KjF86$txqOE?lNsxD^{Z3eR9baPB@MU-YS1MO~?0 zB#WWIQlTZ8`E)%c(^MVSCx!yL5;~1uIPkJNv;la-1{@jE_YmT$;s4p8BiP+k8OUcG zxildL`kQxifr9Pkb2jh5q@J~PJY?Vac?mF*FkIrHI0kVRI}!y?G;w@>#{-A@#W1Pz zZsf;?KOd5uSO9KQR^C1j(OlCDi>Gj$x8%p4zWww4Ayy}$OgfQ*;(ABL#!mjpuplI+ zgN8G9g@(}};bmt_m8JaysuTXMFZ0+$MQ)SU$k~TU2Ls@pjC!{(_3waZC_u{a+Wzfa z$P->-NgpndzwoZ44{&E%&g4g*c}aOctH!e_?UKUuSo zUKL#l2U_P`xFR~(Qs0BAid*3yzNRtk2Be@)y6_%Mm8@Wm1>>(ml@IN7)G4Zbe|UX1 zt|W`SNVhcG3m~G^dAmvetRm!$Tm$vr;zT~Ldx#XsS+NisrwYKvcB!~bZ@7ywE*K@!D7$D~u8Qt_Vz+-yM7{EFFdamXpWe&9k=|ejmj@0F z-FSY;xnglX9`^p2L)?Hj6zPxfMAQn#fi^Xu#H#nR;svdL3P9MBMHJrmEwlF= z+TCUk|BJ}3^15y^m=uc(*#`dATy1EOh(tFVG3fY~WRT*~Dt0HH@`0sopRXAuaHIgh z7$!k!*%kxZ-&bI(fOeT#9fnr)>QVvJ2O!iwhnWurXsp0MjNF00=A9U}CY~>L-NKhc zl<5|a%?0rb5x+8fuHoQqW>?AbDLX59{Wvd&xWHe8mb8>eS&fv5o#%I*b<;^6ag!LF zIfo4}grYgjtn(LlNj@~$Mw8!2c9i2HK@_bSznp4Z(KEIsC^V)KLU_#drs~V-{>s_f z%0)7dG5gynF-et_qI!HC^^R8;dR3&!!1kS|U@jpfT4qrNEFYr%k)8 z%9=ICtts5Z0+WKJCq zN2<#^hGS75JT8m+p)wWe{}In1>IeI{UFPkEn3Rd~);OTr_{@5viFuT1lC6}y>t5=L zyU9!@@Mdrtj1(}S016Ut1K9I>(}!oGwao*_5NlP6a!-LI;nTO;ZjovJ0>NqC?`I8{ zk(^3>RT1)l2u`u^4=yQM;@aEpj>%J9y{Bm6jp+C=RFbl+2<2gSsTPkH-1g)3DtkDQ z<8slc69Xb`7#S)RHN9Z8jQpYxMb&SGgS!E+Jd&$eIFdW^E4#3%?a1ruQKIy4xRLpS zYe|Bd7VN>$SpRgZ?nSy(Qk|Q*^c@w^v9P?_e>XB85Ip<{ovzU1lGK1J_NP8r>tB8) zN|p=n!)urOmHwM@UbT}0Cdeh+ZSX%%YF7oRbfdL7i`CA_nIbl&u1$F2YT)NEVvt!9 zge+1Od_uCB^Su+xZg)2IU@158PvChqr3+!+(q)_U3|G8wv<#}4CI{Yox2&~73bb|~ z9fxaG-?go#M&!XLknAeIc_I8lR$XP? z&%l1xl~|PezgZALe-VsH(u(eIpMX0A-T7T~UL-{}yxBF&3c#9@MSIw>o^D|j5fQqO z(QcmK{StAMS{9AY98|{w-5v85eA}j>O0At6YNxDk9o+N&s9RU|xp}6ib2B%b=wFEjXfo!w=k>OkL|?sI`uR5o>8KO)qhPw@#c`41Vzy z_gRL?xXozala<}6!Ud?U|FPg_;se1Brb%`xx3;~U_f}{=hf#Kb8S4ZE2X@Y)QBCm6 zY%DKaKDo4;L$?*}aEsO5KrETP}Ynup_u%+ z#c^j9RhCd-}!iFXAUgAmj!p>DR1_+ z8}!~_rJlpBQ)rJQ|B;3h8ZY+_BmVnB$R+6U0L~dU+$RA-%hFGJa047sq)(rha-?oZ zdiTl2{tn;g$hJx8BPQb?Ar}rIJVWXK%YbhaMB2rDD37ae! z{46^6swWrI&!F?i^Mh-^fRV2L(Wj5-rqr|T`i8}ybu(`h1TVUmdiP}+zqY=`Mav3j z8b@7^rzoVY4bBFFH;puI5pC;RX*+q3}= z*?I)T(r~B6a;LrGPCHyX2|>Kd5YT+5lcgMNOR6vxu|}7XZ)%wWeL=HnG`8(7x5sMz zB=F=dW^Ic~13M?{;frgp1qo;2J+fd+IP5>fshh>POKAf|66e8im0BW{$TGH$0@cSR~(%1n}Do(4dV6#Fg5nPNKTZqY9w6C=E+2(4x(804?@)wr6hN_14P|))#0I1Pu@Me)rs7mv5)t5~y!ot{|QbiIaT& z_9raK^kS)ugKN?q_vSiK4fBDtD$>`yV_H>?3vapWb*{MCZWAF3-=OwUDy;n}Fj*r^ z&f~Z@DyDr@g7>sc|2V(;9oF}5{L10%g0CN?;J^Dvx!>RuwLLY>);wX;zti1ax_}1b zc}mqpy7CR6a<}`6(3B6o7q!^{s+|!l$H;ZWa#1eyk;Dk$NE3O&oS*(~=HC{#i5?iz zAIvdtXRIJE+o+VJ+rO}~IwQ#zUHmq^7OeY!rwXiQ_ zGd#)nwP&bt#WiTN-vlQZtqbjtn-{fP#EiAo?B7yBQzIPq*u9Ll^w43Rsj*)ZcakDA z?Ouv_9(^|lIG3kVw_+u>{o}hnRFFk}eL-2Q9%&5to83+{%&PJ~hlk5(+FP^~rIdAQ zHneub*Ga%+f`?U|WTG$T##5m~2GjqV;XWVEFAC1EU^8I7L4U! z-gwcpq|T#xVSpi=e9Y#qz&~{u09E-Qk|1 z#r7mz{C*wu*-(h7A|YXMB$MojJ#{T}(T!Aa(BbgD?SGTYr%m+mvPuMi+Rn0O6R~|F zRCsr8_N@N%z|~V=L)dX}*vq_=@4WYnOv7n+xR$-=d^S_K9yF&i(grdFf7!ErL{W4w z*z2V5309-wI|2iwD(0xzHdNDWEmbn^v(|6aYBhF$%;N=W_tcZ58A`5?z`w3VH8_~v z?eLLeIZUXISL6K2&FOYFlCaQ)@@mVz+jYaJflfi1K#(ydfwF(qZ^snxZ1?q(zQ~%J zuWvADi&Kv3+oIf#TkOcJox){ZDgK0sKyOz}kFP@&IJ{3Ar=^|U-nP3UF*%B`o0lUX z@oBUZU&wq(#SyCL=H%l-{Xxs+cLJdS&B(IV&DYS(m*BVM2%W@t9r=I=*}^MYzh7oi zcfv(5I$3K^iQ|v6-_fVH&UJ~EU!AAjWu6DM z`bw3Jb~kk&*p!C8I}bX-$>AfI3BROkqyi%+#X)+P$Gs?q{!`0^DQEegBTP~oAGr>` z_97~86Hi&TLQ{bZQsE#l?cl%BgX0cGrf+f>nKK8f4DF*9L4$nTKhg&V-OLo{0Hn3< zdymj`MBrUts3&adS-r%N^AuL-(c%LBmv0z_XG0&I4Fmr+tY;c-b@(TTynFO2B}DAG z)t7Ql-&_|zFk?UBcH{`MJ$}&rZAMjXb9YK&&+X8dOnEb>pYE9`IR0ZU^MWWeI3E2j z`s5V?@qbtDWzFyEkRhUZR28Ac>IVM&|GYUI%Sp@;;Ao_+C^2rCjsRYiWf(&~YA;J0 z%Z5E57>|lG0lNgwe_f*H8`E(Df_PFN zanU{~uTx#I+KyCxk=pM2;W9*AZudG1+wm1lXVHA_2PgJa9aCN)QNnHLSVK@tJjJV2 zSc-saTlf@b;UPVtL`fL&cAZ;JK_c1Rbt0760(7==bp_0Eii|T`?)7f@4^h(Q@WRly zHZ=~rBu8y(dh4hq7$}P+S~GO+#|gN@ox$IGp{klZ$~7)`A5=g_J+zN$)>74V#XaGR zCLyVH0XigPY|CoGlY+|JF>RUKE4O5kI^edh&5l{)(y3xNCV7Zt&i^ zR+DVdC`R&KG<$fbvBo?edWwNfNK`i|o0sy=6^$GxT!M5@JLkjaU7B3U zgoc;@ghcu03}5om2*<@REfoIGno#S1HRU(!VUu~97P_-w=smsYjIr>c)*Jsc$gx;H zk2{Q?VG64Udwr?uVmIUt!Lm(MFE)-G0!03Mg7zy=r9j{O6~F3tU7%zOEln#ff-B`W z^0Rnr9Gw1hLVv)IMaFQ)VH@K&nM@~{JM%ZreK9q`)z>u>&H8rH4ym(}BM(J0HvA^HMtl%INXY|uP*gxnP_}{yCQo*sotD9iU&0DDbuE#9xD4hApL!zgZcaJCT)_gFE;#1=sdEXqb zH$*waNp72Fn5%2VT^go>wv3?BQ4FDb&q$F(t3lS~0>RFgUPY3P9%o|vUn3zrQo<`M zV@+G_c^7Aw*e^Q*$S?{;u@7TbcMGltOFbUY7mNoLU8lbwEFS-m^V}1rY<=o_VY`{P ziP!Ntxi|@ce<1AKRw_`19R6Bby(BpK^ z@kR`1D@7J=wL>42LM!*AEzMerWq|hJk(tWmG4kKtAI{e|+pX|g&R)HB-><7XdUw@q ze8tj)Z20RQmG?^wjE#pU#vXkIhUtXZ8)G?**E##i!rI#SO#_?6tXLRLoZq zzHGbk{=uipiYfl>CsnyPu&Tv}!-?>#bBq%cAqrpBW-nlaKmbYI`#yH92q6Z)RXaDlhOIwji&^&QsdYy|n`6_2rhdKUBV)9&70x&Cv7GWpK2yF}xk zYJWLB>BNQ+bK6U~hFnBh`}?R64sRDqHx+53C3?qG)jZG)>t@!ED#@QZX=S%{_6GBA z7EF_X{J{;*iwDgvE=ilml4Fw3Vx<-m(io*CB9$}!Ijf5P6;ZGK`PT7}NUv06)bZ!; zx$nCk#N#q8rqVI{0^PT1DRv9<@U zDl$GC&md^W?P3oG2x(DmHd^)*pEqu(>liUD-b1`r{U6V$9AV9nA9BaDQP>Q#G_Iwg z1`I?^!m8mzVQ=;4LKc6yk0GLo2rhM~vSL+{JHG?Ko{1)O#vWV;~|6C5{ z+Z!}2%$N+spHkZgy0T;yJ>x;Cer%r=3daSk?8NNb%PGiS#N zI>%9o-mjlpb&QURYURV33f`(ml$W3WP^zON8vFEXeYWND z;d*8ODpsQXTk8wEhcs_l_PT1$>H(muyzD!75Y+-N(bl!m(>13V5eWLlqbMe7BF7Q5 zrWmu!P5^Oxo)tCS4rg64rNK=pTAsz8>?K?7^Olgaf!yEiZNNF>iN!xeac(}>EX zdmOb8F7D5N^n}0QV+C}s%6_b{X9sCg0|j2tT<01nFjR#$qr{YfjvGhKO6(u;BJH+t zJfO14+s%HaZ%WC?UgXcf(Vf8|!Jo62teT)oa$}ZtCp+VPZ;$PtvJwdre8RCmSXX*} z=H~Ht$L{jiez^(8=|hF*_gjuClLMa8PpP2e}6=0MPktq}`M< z`1Tx(nC&r;0OIvIucZH!$`2UbdP;sPh`zjtTLprEE5oTHp<#52A zH$m+wJzw;(QAW_CiU@((_t2(#U{5K*e?>7AO&-DhmW`lwSZ-bB^H<3VH|S2=i(FB{ z1Re9TU7VF`CSA>X;o!2zki~~T;g>~ew$Cjs#`y*FoCSWKEfYSN(WEOmZgDB7FnZtq zBKO4@-5Bo!?@M17%!0;;_b(;3$*t29ljbuF{@gI0kolO}c_h~*XE0`+UN!Pa(>eMr zY?`h=g%BPckEV;=Xp1m&L4Pl^QC<~70lp16m0T&V!`f_$gkkBhOa@qbVbRVtVxfFRRd;bqV56$L#-mM4C1!jf5tVUq&MEXmk{gT~ag~I6K z$6bU?zRiiP`YqP?L#*<-xxaNiCxA)qHYkS?d4)qc`g2q5*0T>YX2*y>$u{ZRTRx8w zXkCQ<+tGF|bXYi*c~NV`s}hn~OC~q7Qj3|wMcNSLNXu(!Y5(|B!jqMi`}Th76Au@+ z&=bvs(O7cw+F*;kdhnql{pL)27WpV$+|qKra8(g4`O%?a%keR_J9J)9fN6jFF{FTz z4MLxcsS=ZA`ar!c5pu5Ro)`4T%Df=)%T}1kf`Q5SW4?>MtY^rBJF+M**F0P5wYkqX zy6@%OW8G_iy%;&`pwJW?Y(Xy`&5CRC5B->mQ2SIHt-N_9@^q)@`V%fBH(lZlzF7o- z*Mb#EG!_iQf4g6yYSmGboI?^iSg3SJ)+hlPTm}o2^g?1o6JcevIOKZ?G{gDPsO&|T z^Un)`Gf1jH$iq?DY1V`>E&ebcuXd?q>PMaQ7`A8qccKjFTc=h z3&+TfS&<*ec+t~|=LKf(&!5fADHM!iBk%h^uei~twW@s`o9bXsZLr4S_=n|C$m0*d z1cZ=NT+G`?Y4S+nZ412&3-c*&FIXY6JxC5RojJ#sfxwNLD_ljlXX|PegU|aMHone$ znd1MkXM%&?tljmLq1iWHy%C#;tZ{c2k(7{I86EYoynNW|aYEQCDj`Rrsr56>?~TmJ zf_7kCRzqL0WhTITh=_x;Cmo}UzbEfqG8o@f3{<**BL7E(1q7t#l5>nRy5{UC+^>H& zi2E6Mw?j%-iCrkJQ#P7CTJ-0%{KD|xkxl-H-j?Die{Gt*)AJBp>UI17N7Z-uQysqV zKWEsp$XNf@jUl^UDtix_wDD|O+m3m=Z^OGf7j7rL}-bZQC8E?wB3rjogrpv%>TLG zXJT{wY|3gb8~y8#NCD<@=NpB#8a_AN-1VgPsl}|%Dc&=wlSy>uC)5QkS8YlB(z#dD zVV2P2Ea%iCe77fzf8XruUET=IhU!CXx*h^7QTg;C`82*U$_(Hum@L%mmjZ4__*lOO zckD;tT9i@TwL+mx+J#YyINI}sEGoH%FTkyJLn>h44YBR+#ML!3uOd2%o+7HTBjO*j zVM#78ITATCkHQwkKTC*9OmC^Ype%P;d+kPYx?oSXqo>oj<)y-W^%+UqbwhUZSFo13 zkEOXztWD`ZrIok<@ygjU4c4O$`)l-^HjZncfg4&zdcn$lY9CvqWg`$ic)su3tMT`P z@NWP{TaX*=5c$)5%H{&GU zi&VgrDy*!bmDs=Cbqynz;1Pc2zNC2buPKD6G}m%kM_ztI?C+UyL&9Oj>wt?~Kv!e1 zCv`Nr_F4Fe?*pf|wf@|h-G@Y$Q8 z@p=9{s8&&S`Hq5{0N^#M0x0W&B7@~YU}3V0ReJvjhSGg1uJMhMSq$>a`J(shL?TEq z?Df^fwQbT{rsD?XKO+nh#Os&%>H80e+h0r$8ZMrMmiz75-r)@Fn+;Ck39|XSJc>-_ z(YThu;y~OZar(F{GbhJ$XTM(*l1Xb=TuX9O)lGtf9E!)@yaEc9Vi-NZ*fe<|8S?%CoO)sOd9U$ zL6bLRe5Pg;E!BH>JXpN(r!~_jbOw17CCjprR?m|KMap{eDKE#Cu>b9qq|xMl-VznXY8b;9zS_AjoXW+tG&o!eIJL& zHtas`5n1rni698tIxHO2YjWl9dISO&FzJcBbY7bL@y0-~mn}@1=hr3nbM`-4)0mJ} z*Q;rWQBD9q@ys1lDyT5hqCod*%L<*AIpwFyWG1_Z@y03m9sQ8jmZn zV!tq>W9WXkuW}^EsT#PZX#71+bw4D&!i>{U8C0CZexbF=P3ljP4Zvxi0T%bLd`$l z!jKf>D)qB80;=F4d{=Llekbl3M^UwF_PyjxxoLfU^mgO>1%-;InGtp5(~o0e0@|&? zepW4oQt@gcMua7i@SYVr!_`JjCd=0j8aPyH0Qav>NyR60ulsunEPXFy zY#OTbC_tJ?-H*A6`q<<)ig3fE&l$EN&HEFvhII>fD4r}^uRY}(^z1lAR9=njx%xzP z!&A^rO2zf{#M?!GHe=mtIBGu+D3*=ugiwN<9^Ubo$JzNAQilYcOBxIU40NZz(Yn=+ zQo(k4m2Pwmj+nnoVWcOmyCs608TXxfa+#H{6c^{_s=Yd zS}N5mJz67-avbe5)Lo6OSqhF{L)iS}d(lS011e|{k7DK)2=QLT_5EqmVmyM>(JShb z!_;kzA*dM=V6dt)cUsV2piA{l9j-dSO{H>Rd&P_1cY>>2hVh1Ld5q&0SwqVrV6tgO z7O+r$)k!(~4@nJYb)s+F%bn%9NQ{?lstK4HG#lRP&^zc;(|MaU=eSe_OAvY97N~Mk z=ux~E-YKdotruA1r43EDZK-{Dr?e6dG{)a>wxC*yoi}BN3d9_cH0J$WESPB8F%1PH zufz362m6mT%xD2&=sn})x&kA*^zU|525E6413f>5AkFn6E!AZI<_kYJWWWPZ{vP9R z`_rcJBQN@0E2W{wa{zRAZd=OPZTUq?f_0ZZRGwjhQOf56%M<&9nK${RPR;|)@0k$F zxj~F6YFAuSl&%&e`A3b%E9pKMbC-I~LRXer{0;OcUB+92e`7J&6pRU`vdxyxDshg$q; z*5pwJ+1t65)Se1BHj-0h37FMK3`RxvcA{};I-Rsl1Dkj8Ay(S{uC^?G()6jc& zCF4`d6|Ij#cFmrA^-ACJQ&$h#y5sNtx`YYu z=l;%r`&PhJts}u}@`&yodSL+|p!J|F_XW+jAmGZTs!(@zWQRY)by@AYSFQW&d}|HV zRy6I!@;%F}E{WRx7By+j%9FQtg6Y8l9T$w1E_xF%cji_j4v}Z%cFG1$s;|J3C4vFo zkC4vC0&T!>U}s;r6?^~6$zsny&n&l;BuO2Z*w({f9r5$wwH>lC#L9*@#I9i1?h3;c z++!-rFIKr-4|U{Fd;rkceVCkxrI1hAglw-Rf0i^H2Y}j)eXLPo(?v6sA0%xd>IqPr8byoK%}9Q<5HFlUmF>r}`*du<3+X1CCB#eFsxjSVq_i+>2$ zj+RDqD$C&TJE@@yH}9ARb-72;i1uE%TiPwv)qOVD7vKcAcTYj+qSv+s272`87sLk+ z3(zeGyBW^s2e$u#XVM-hT-XX0nB2b1QffPK>VUnVMyu?%@UXHfYWfCep&9@l#?wlE z@`kI9z{dZ%gZ7hF=x^HjF3|GWX;WtEQw7auwaNhgG0YxFPDxH}?%^kku~%)+>6ua+!y?&O#lj;ZuYJTb0&IALkb00t3QuC;U{W@> z|9UE+Z*A;K-#d3~;o)0ke+(7?&a?e`_=)X-v5mM8z8BNHRbCS&2i3vZ#1d{wr(%O% z;vjRg5I_a1^;XJFt!K(rinz}-oJP^8t&M6sT>qq5ejcEv9ZDsn&H8ULyh@r^9pZuNiW&v7e-aQb(o5jz`<*7h#ze@=kugX{P z9bWPU*sAA_Wno|MDIBU;C!aYykN{ZPA1{aLk-mEzuoZT4#|zY8OQ_0@P5y9t!P9-E zD$?KGST^7$VDtPz!cJ)IHI;}uZPzgVEV?DZ)kcToVj#PIsZ!>%k7NraZRV_C&fNW( z&$z>n$RPyiHH_OibvUn-?JR3ya6lAJ#dQYEIOJHZlynrtQVxkgvggkB+fqj}`0>zG zM*yFq#w7xRIQ`+aFzz%P|c%-Ddhwbyp)P{B3dntpw)eJD+91~>jA6sQDj#&@T` zX*{y+FJ2ng#=7`SP-vhuynjpGw9c!$dmpjifjrF&B2h1%KR!6^Hs>xvcQ4PU59}_h z>jsbyPWik*hd%vo6Vf54N=@JudV>I;doQOnG$}0~yyjt|O-FFsJ>0F0-lq(HOuoG~ zS$D?Wd{4rv^oE;`x?WvE@~BGc+!N%B36ktlU-VrAgT4vcKbiex>Mnqj&od|P6E1L*H&xzoP8bS@N`X`-78YH*G_hiO%4uUpH*H`Jm!_3 zuyaaXVhu83Ta@@(Y-7o&A0*+=3FWyUM*0Kf5Z~5O0w2hM?v>qxz*ryuf^HY5%4qLuDba24~++!^Vi6G2OWsgPwhsL7uV}%HilZ)X9VNbH+eEjOuiTEsI z$AAQyVvS+p+lF(h+mf+LeWLEsFO&JL(J;VmOIorxVd7fmUQ8pR)J^X~$Pq0pvTH91 zJ2|v=sOc&CqEzKNU_s)R;!ihX+UdHVc|{+Z_cBNixtS0uEkRNADz_FV5}Rhi`PUj~ zXwk*^(2G)r=%9WCXpVCO`1s6gRmUIoi3%DRHJ7UIqav`YoUw)$(q-RKUOzU^9gQ8= zkZPTyUy~P0nFl3g;{}-(S!Ns;BZU9tUl8L~?4vn~Q3oi`-n;HEQJ$wiR;X3iRBL{C zM1fkbJ$6nWPf^mUJ8F^Ya*!P1$&}1I_6jh=|LNwb@i}Dh`Md6pe)=@2f19E5)y+}u zv^dGBHo6bD&h~1`JhBeDo0d)W=?uV``E5n>-U~?cH6cEQa~vLkM1H}S zyhE^bT}{g<=^@ppJxEv@WEWrpSY+|4oUy?BypwtO6Z^?D8n8FN-~tbUiYFqRC5dr= z&OlB~I9M^p6`a~@3Pd(7Ny0V~!gC$TyImVF(Ux7%qSHXJ~Cvqb=`R*m{59S=VuROWG-fD3 zNMeyMCf}t3p&iND);|{M(9>B<&0naA_F!@c8@1{c`21BzM`+irH=f<$ z)73e3H$@y;Ue*broZQbcJ9yga>YcWclt>X0g)ZI7Rk!cTIw$Q44nz^j6WSv}wYp(V znHIBr_{`U*P~9T(l*v6BMV8vjLn;9i8h-DNpUdy28rsz0GBaxBn)#8^B(pjUh^TXdwwk!mo;|Zp>Qi_ zYIiUTG53NSD&4Jb7X9=T_gw-@VCh04if=HNv7nyXb1vE(Uz68YNq3=t)YGt~dwQZ1 z2He}74i?0pX0*v$odw_-kIx|&45+DtcgOo}iD}iT8?7x{q_S+Qv?inE>|7m6#~)iS zK{>?WHy(zoasLW>{O1D$h`IqM{#P=(#3JxrGvXq^>2ibo&^MlmjmIa+CntMVj~Do@ z{VM?$Z}U8GvbZp*9d^>NHA2kXa#)}`pc++!DW4b@M*UMZMj&iqU!Uu8TWNl3V!QPO zv+&sxhL?Pg4GKW3gJ726GY{aPf9L+;S6t?uhB5ZZd`twv&o;1sm!UcuoJU-dAC89K7QjwIle$04KGX)rWkfvOd4H zl9KkxT+3bJI3$zBZwJdx-G(Y%DbF{Nr{oe0Ztw!px-%C{!aA<{J{MyHC=th!dMm{j zAqdYPmuE>gD&V+<+u%_8h}5Kh9$*)w2iPQT)lc7IAu&~_WV_b7N9OZ!r47Zz9$D}< zKqE$9SqIt|d8@Th0Rb~Vqc0iBH}34ZE5c9|Op2A+b>c5dM?VtPy$S%+lEEdE8<1#vx&MnV#vevV6f^i5? zEAkKr*zIs83Km+qkRW=GZ8RaIejjQXWnpM!l;MQNzcEJN?^q|-5 z2lgW(yk_2xjUGsA>iZwHemP}c9@>JznWwFFbaX2e4BfDgT)F?ix9&HRLRQ_JXxqVN{BWiXOlH z4zgLwIFxY*5=S6{L%;{0R-`EJIWpGHydrCy*Ig48MG9+AT9Ncs{(AvLTU*O4uBgDM;KUml7{BQuseTpf|CByqE;?9B8C-w>eE># z-GT|K1jvsU;8miVFbM{ysR15soqtmw1+byvH}!BV@E<D^edH)n+F;U;Fx6gZ-60(rs)-66T zSal5mn@aPJB3z$XazcE%#>5VCMN#c~;%gnp@=8{7!FYAnpO;#5Txhvves3cCO&E{k z{+qhl?>}ghi-hY_ zG$O9K-6&j(7SeoijEIr0QpjV_+uA-N`5_D1yC$sj`WpRKHQ4cPwsodLrvU+Foy=yQ5*4aERHX?^`0W76{uc`4S95vySEU*wcBj%g2rb1( zfV0t&J3mSbV4x`PQ-FC$iOl55*63x@-~G#^4^Sd@@l0jJny2hnJ|l5QxvVhA~qeQ&1g=fj#(`P!sqmuSo;T@r@$P1fEk=2y|DY zdZ|?xsDIS0e*WHt>fR{iT>pu?yro<-;rdyB!;sfMlaeP>gaMF8JfA9t2y?TsXeQKp zhSwMA=<;A%{=CG^kdS+4Y^%or3S+3pPzHV5v^s`KzN5q9tX@dLE4=fFG)~l$Zh%GY)HF-m>;(jrM3EE*R$+!p>;; zQyxww5_g;~&r1RAuz`zzavX_eJ^lj2-Uh$Q*fgmpmuaMzZ^MyL(`U+y>Qib8dLO}( zlB%AuAHWXNz`)?(hur_+wwckW?CF!{V_VX+QO)(#4Ebd1e0az?;yo1B;a%kOPQ}27 zd}qM7Tc7oIYFxuSKiv-09rgv2Hg9g7m34e8xl3w#30W``#h_4_%2?=2;=s6&r>}-l zZuc$rxm4n4E8SYipepbgOC}qS-PH+JS=} zJvapTRx}IL4FIZO$1lQfx43i7e}%W2sas05Eb%GVLUvDBjPEz|T|54j!7a_eeH$rS z!<^v1j@egMLa(Z9+5<3G9}ckR;#dMMV5k3Tlm|#1wY(o8YHh2VKMeBe+r??7wF49b zk zLjc&m{}E#vGG-dYL7azic)H4S`+HVE8M|efYv-sKDNt!ZEQ6Z-iDi6i^=sQ_@mEUp zP9Bi?4w7RT2@LG?-TRExSmhlEjVvR7`(2$12WT2y(ytIhLJM?vP$qxgl^kZ9e<3`~ z)tm6&zIITeCe_8nRFF}5hh+~b@xHyG(oYNog+qwUOUtBVY6Y1+)s8T+d_Mb`27LEb zs(iDo9J#-n60B(ngRaLtzqfUI#P>~Bnbo`MSHkWDQ!XKTS92iG9F>qBvzpYGCRf>) z5$**~qitlMmjUg2F*>bFf&HzWi85dT#<-4;S?6Q%dxz(ax-z7?)!rC&`BITDtFw=e z&g82UZPn9Qzw1=loU-n^qszS0J#Z>}=2i?48VH!D zIo`lRU4bM8=v}z-tE29Qg%WPq+(MPu{*(sBl*Nx7Hlp3&)W4z+D0(;3VIIXdIH|

&C>(~AQ#-g6;6%8YtLe4k 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⪻AfjL%Et4`4%2VK;lSz@0{f#z?HF@pF( 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%0DJ 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 b`hadV4#7-Ub{h=ff*{SSdTKdWF#i7oPL9RD literal 0 HcmV?d00001 diff --git a/AppIcons/playstore.png b/AppIcons/playstore.png new file mode 100644 index 0000000000000000000000000000000000000000..b34ffe652b5f627364bcfb6b62776bc5b4294df2 GIT binary patch literal 45099 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 z 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 bS>PiDYB73TRY=@N0AK1V+RFJ?twaA0Vu{Yh literal 0 HcmV?d00001 diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 51a1253..d018fec 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -33,7 +33,7 @@ diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png index 99dc318c6b4873b71ce96179f65965d11e3d6856..e352ee9d054f30b551b50af53bcd44234ea72c26 100644 GIT binary patch literal 3355 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 VLK7G#l@0&=GEjyVND{&==0Bu|F@FF6 delta 3405 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 diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png index 6671a95caa4e7e0f8b592203f840ab9fe653cc1c..eb7806f6fcedbb7114c0b4badb918175eac881ae 100644 GIT binary patch literal 8247 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̏x{i*9- z-%k)0o-Oe8>kI~)va5%40{t#G55M3*=KY&9$Q$KFMKof-Z&wcwIqUO=tf%S2?B#yw zkki7jg`Y**TWs4*gPiRE*U$h+Nb&N}+s2>2e68IgtUYAZlz|{Eda7l&x38L(dt2`9 zKaX`zjQ(}yA{zf*GioI&M@98bH{=h&&L6(wNvQ*TD?Es&Lf*Ng;4~JU!F(SK8+}vHpLC#s7bh^{1Dm Y_}>;@{56mG&jemc?z3#Qw0YS70%w)YcmMzZ literal 8033 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 j&E1Eh-v^yt>`00000NkvXXu0mjfAK`T9 diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png index b6b3ca39d0f6a46423501b7c411c6a400f5eb20e..0d295035e9b64e5f5ea6428f055c6251010fd651 100644 GIT binary patch literal 4638 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 Jy@q|%{{R5Jk*)v$ literal 5544 zcmV;Z6<6wsP)s#lZq zdL#VJB>O(ps&6Rotk^fB4!+ho=foS~=}qQu8WF5dgZ|$TL8W#GG;Usvs;lVe=%CL& z`>b-;U3YC(RkcS^lx>8NJpg(LA)BR?+Xx|HXJ0904#0H)vjC>0l!HQu>xN-Wzxn2y zvkyM_Ae)()5$lj=&Aeh2>NwJ>b8gq`mIoeqK)HPRvcFg??lw*He$M%0oby*W=YyQ{ z1tEkkgpizb$vKy`c&q4~^98H#E1dJkOw+tSm&@IL{`~pi;lqa&7dbbIuQ*X%+yJY- zzT*6`W5*QJG-rD7ySqoS+3dQbn452@=aZDPXV3bJ z#o|8B`6$-l(O4j%%1)N5CUZO!=*AKn++H3wbXi?onkpiGSJv~&@w0*W&ZKR*rC=F_~ z4`b|9u~^*K-rim>&nuVeDCT-B7K^)8RsB98f*hojex<9c>vmN7-!kv9 z!2}>JpyVTuJVK8gIr0P{c1md^l}f$%?z`{W zH~RAu;`0+n3n9^H|NhQLS+{iU)vei*cNt{1Cd};DSI%3N8tz(g~cK z7+CSJ+;~dq1HHYyy^2z)ZBFMbjvqfxeLmmq0B)^?xP5e*o)8kTR2s2V8oWVM%j!Bt zZ!92HEHu=fOM&^^62?+<73ZatNNWWY389=In$u3n@Z@>Tk z`zr!gMdhJ~9#Sc#cMw84R}>8-*$$!~+2WAqj*9l9Yf~QOiI&L3QCfJs!^;k38~- z>YS%jpXin?TeeY34*{UHLbUT}aE?{S00Ms65Hk-wXOP6u( z`ZWZ-6tTq{IIv}FO~D!G7)s9JsSB^d4>V>V;PsW|=xy!Br`oq-V0HwY0004j zMA#R?fh~O%U^*YJleePvq3zqZZv!w=2E{Q4p{i;RA!KvCr|AT10HPv4jkCB3p-l65pejQMhbu^rF75nL}K!1Nf+S=MEA*82f@0Ek0$Y5zhWf@#p!p|>X#k;eKitL+l2`*3x zs-(!93~x+a!!JMl07cU%-$P0XCQ;HhERWA6!E|N`zaDxIBgt7X%O7n}>FMd|q2X{C zKq-?Z_uhLicJJQp@9XP(lu{aXf>1AtogAJkg;NkPX|GmFU?lPdynbyO3xxtq&LO10 zRHlIOr5pePlk?@)1TZX48y7{}EcDP(m6LP~HcA!R8-Nt8_R;_Miv zGf8mCK}pF+DIR6r>qaT17#<$}$=h$gZKl)d5k~_9e7KOrrFa4%Rl%2U+krzp-H7^BWOM^LgMkoP z1}kgm7*E~6m4!J>XHw|v>c%}gda=E!1(XmhX+?0!K}e~+fIu>z!B}bz(6P7V-t$($a(jn>!KpsW`Ny6TfMW;JNpQkueGurUYC_ayA%v!Bu+>R0#;BB12q82nWwcQf zs}?@!^&q6GR#I0o0S;1rfmE9Ca<)tfLDcU92LP*&Ga)Q3K3DEVHTeRNB||R#+2%%Q z1*p!9ycSir5khFC_oAW<5R%CxIOm3Gnn_hvJKeOyEs8mB;DF8w%MySny;&j>5E25F z`^d5s0wL@+M1nwqQwl(WOHwv5=Y*sznXM$2k025tqO<~YJcMds-0IcmOw&wKN{w_n zEo^|OX`0AnGJA5;e7?YG|+hG7g_erQcm ztjq&|T#jJEib}QvmY|N!%o2I%^1959c;zT4X?emG_mgzFj}-{Y5zPT=mGfQIX$v7V zUDt;%UAn~VKIKn5VzHReb^RLWJfkQ|upZ)WCI$csCGaVp($giSOp#PL-O6#KlxXt# zR%jeAu{BLBsH%{b#t3PTZfOx#QX{#YloFitC0*CA4Gj&I&zJY4CnqP7&*#S(V~M&W z)d9{+3EF}xIF=We&XDa~SK6Sq2USqwvD(<7+Uje8Rz1lUe*lDfT+;&KFtJ)Gi(8!# z0>)S}pU;nvkB?UXROTlqC&!D$;uT?SVA+B-YGMJe2ZwuFAf=~lGR|!ZH=h#pD%iiN zeHk2wxd|(|tiIpw_Et3c0wq(l`q<_yEv;KC2_aA{7OzZBPL4azJ73a^g@uKsLZR>h zW2~^AM3DfvqdS6ITS5RRgyon;*#|8P?=;gt+}?>Mzq(>qKuGuYy)DhSwY3F;Sed#* zi=#6e?f);Nr!LS|*cuU)S~cYKYg022r1azv$b9Ccn4* zW}$2XcJQytrS93$iTv}w$ zPQQQY(k0D#-D4F3Kn@NLk}rMfONB@z(%aP3)L#o2w_L)hU45NlbcKAF&ge)MOw0EW z?Cp%;?rrVxE0rtlCZ893I-4ORFus_BDN0FS(CfkBZQa<>9I3cJ0kEUF3B9e&xO!s| z1(QJt2||D!&CNKlWi$MWcSRyt&j-ch@n6Scv0py==%Z=I%0aCBZe9X_X`1rxyYFU! zK)}=8-TkMEqIhaKJLgTSd4*Ek(j35Nx}u2q6to3YvaMb6; z?Hx_%3J1^@^dag~u_+S3!7ZKG6bY`lKP3d4!a?-5G@&CDMAYv?L{+h?tqprRI-q(Q z+wPE3!Zb~G_3G8{kB*LBe(}W@P3QG;n1{7u8WsKzq<%9@lPf^BziY z$EGgq?QBQZFp$>`1ifDP6{W(lS7*!B^H^M59G{+^ersT0K&!rPzncfFRlvoI7vc4K zv-|e#QzMbcXT4r;(AlAuiB;RXGdBvW3R(jyLaG83Ud>}Nk)kw#TGX`4TJ@}x*6lV{TD z^n09h*DVmI0QRvO99IBp2wIEQ+I}s>ITz`4`n_Z_`TDPZ^()t(VpM#KXY-n-VSIdi zB#}tGoX_V|ZXIhbH(dB?@M;0)2DV+V)uwu^>g#Uzv+MbMK9xu$ULGGGAIazQZqr<8 zV)hur!^38OfB%e>GSJb{@dvgqs%2tMzSdK3B;|LbT0z0B?v$}!8^#!}T)Fa-v9YnA zKla#TsimbQ*Zk7e#86s#h|$r}#Psy^bMy1_R~TcWo{80RfKI-V^-wimJz2NKXT5RU z>WnclKRN(e!RhK9u6y?bwjLLq-R9NrrU1R}LG z$4QO&o_eak*7l9~Dd)At#l^X?v9YJGUcGwi$tRy=i;IgjS0^=141mbxa`Kf|Ug7uL zbI&jU;q&?WLZMJ-HM4Sa()G+_wKny5H;~+leQjZ3ArXtko{Ys}KYjS&hjX<|%L$MT zj(wDlIsiabRr8ixZizF-yiH9_cX+*CrO}9H*WFA3s07#z?A7>2NeF>lE~kx-j{a*r z9)Iq|7hjAI4i2vRBf^>{=HSWT;Gpd9?_VN>j8aPXg~Q>^s;ZVjT5TJ%8Vo0`Hc_|K zq0uDJ*(R6EX=7t!|1&l=_T9^uFHijV$3JE@J2!uf6t~xOnm6Vt;@CJBDGX zs;ce`g+hU9q3a3k1Y@lctzP@pd{82hNR5n)JUccv_TBG%=Q}a$OV);{;uGL1eg%z> zk7HtDV#4S1{R?9(M+kYSrKP3W>-Ey=$=d?EIqD!9&T{6=8P?O&bHnfV59+!e@pwGjg27SQVAOLSI-|V7J|N+YDpuL&Go#V=O``jrx2(&w8@xTIoZ*2xyZK0_k+x zn46osIypIca&B(!pR?KQ#pj=YzHsf@we{@60$7KM!J%2x)6??YxpRzjKHt^Vbt#+8 zPG&M0l@PMS@AoUtkFsxOqNwXS=H}+K(b3VDXJ%%8l1L<;J9+Zt*bjd21ASy!uIB{ab{`V1q%TJ+Jp_;$(R8>_RJa~|P{p(*> zo0^)s1A)M<*4EZPjz**V!r^dlG#c#=1Ok3lRjJqOUEy%uw8VN}1;!W*!w{OLX_-tW zp3P>*Gnvf$sZ{FKVzD@qPN(BfJ@u3^JUlGc>WJ%6Ee)#HCMPxYboTDuOCNstVYIim zHxoj76h+w;jYjVd1OmH#K3{Jr6zcYuhz5f}I03V^K~XFgQ7jgPrfFI}pO0&rHeM_i zhqKx2ImXzCuItkmE?ihTb?OwRrlxMnf6UrY6RXAhd_EjGas>C?cb^i8L{v&?Ga;mh z5Yi2xlMvD_rHnXaF$f`fDP;vdV71()zwAsyz@@l+1W|M;jrTK`4mD3CDun1Qc5AE6uPdnbUMxE=H|q}z<`*U qnZeZ5l;G9}pdSa_G!y&3LjMZ}S6hvMR6n@w?xfl?u8-uaCCls=e+Ol`904c&-=W8J|D#=CDKmeVm%#D*DqZHoCW{@LI43C zNdVu0;yG9Vj~qbYzZw8A=aK)Pw&hX(?coIg61)NYzdcR|{A-X0IJo}Jd<8uJPb}d5 z$ITBY;QOUtRh$G1^S5B~C&9rss&X?(TdBo?skM;C} zI)7vg>FIk5pw3o4idVTN(N_9zVBy(`m=8EOq5>JW4o_AV5*e%&k^3eh`z1-odERhT+cTb?q(Cnnp*X7E~!t({`HAC=G1oMZ~+i zeD!vpl`Gg)aJScaJ6NYYumq%J9-j8#)@%WMQNC+z~xBA>4 zM1?PHVfRR$@2{ts#+o}!!Qy1iX_C3R;qleEaOL0>Y#x|Nqx<@GsyR?VE7QeT-QK!K z`2HKBiN|>FU^UUckPW7z>(eH4+^mlSr$ZpCs1dliI1@U4?F`BfCE#kbCH@i{`P9du zHA!_!Sdad|>bP@6Z`TX^G9vA~_9kUEib^A_LUO4F;aL6NvQ|~1SfM@F z&v^D2(PcC3;32=>x~qk_dXiA&l9kuiR%3SOW>(~BI5e|GYMjODS;6f#KV?2>tCV+K zDJ`{JU773KWPVWM{~?IV$Y&{)^eq3xu%2z&3k{r9c?F9gW?Q~`L!E$Vz~DydCf4QB z=k$n`KgL0;*V^P!6P#=xKP5oaTFBDTIJ6++aS?QC)^!c`G?~?bf`u zBy~}?%h@}Hb0uYUvQ6r{B5^E#ugLjH0Nk+*W%Y?i8=Yi$Cwsx*eR`O-(G9$Vi=OksI$CvYeEs7i7A#8 zelf`lTYs~1&+-Ia`Ms|UyTtj-xSmH-6|%S5BT|XHgK3fKTIz0oTbv47X>n=nC_VI< zAlr)E$QqdCTWi}ZsOab<@>*n`W`W*wQ_mRA9>$5;E7(i>J_{XHH-GdT7&-Itb?p4+ zr*}tFu)Apl;HGJ%DQ8C^-v&~IX6Pi8tY?U3ID?!yZ@%m0+en&fGshDd)#h576SD2d zj!z+qSN*t9w2Q^hy0C)9-DSKOhffxe@}1pn#inDq&@V;sog(S7#&Ml8y#)+|9p{BOM z0CAvquc3;E6c2ta=k4h~y39q%9S!(w<;TeJYsrQ$&-6y9f4@|~+VC9vYKW5{WBb&e ztZ#tik-D=ZRy8l6hx=O%Ft7GrH{Q$*wWqVHnhe7IJso%Pra2il!->Im0U}4|_=h~h z=h;r8bNYE54fWM{k{MDD>cgokZyBb3-Ml3Tw$6^#f0T39A7GRq$bHx@$4BWxSp~V) z;3Z;!wPYWyh_K>_L4;cn&ImP}8vpVTnw&i_Na0Nr&G3+d2j4Vy0@X^DD+yJ@)fQ{0 z;E?lks1_uDpkD6uqI0~@toDx;TO~)9x>PT$S|3 zFvRlq{xl@+n(Sx}DL2IN3$ouu>2*YOLY-f!wNqQQLH^Ep*$0TLdU+?NgD^_hn;@zB zwSPf_gZF8Yq{BC(gr6!wb_JL#;G3YM8UsGDH#TPU1I_NOr#-%ivevaupgjv>BhN4wWCRKQTmox0A`c;2yJfmCG_Z z1al725>o?XIFh8vu}8O~#hT{MS={M}q#KiKk!tCx3mev7!FVCGUf{4RaX{_k=g_qa zL0a3PKY-ZP)vn8PQWsnu8=++cG5LMl@;W~Whk$3(3xNDjk;)w JC^vD7{tvv91#JKT delta 1858 zcmV-I2fg^@5YY~hB!3BTNLh0L01m_e01m_fl`9S#000LANkl7)V6~}*7 z-817E+IH;q2Wuy5lPIe=$$}S5HY5jfAe_(&2_yvfZ~=i7i4)?0BE$tLw+Jb401+Xf z$Z!i1D@9rblC`X`KpaCh$z=US;>7lhKW3(UyvK zuU=Qb7J$wFFK>{ z(_FoJwWq7AtIx8m4k1M31B@}dnZN0H-}hISmX;PTT)6OJa&nSFp-|H=2pDnh+&L~^ zzT7=BGV*iFvVTT}5C@tmAcS~nQfs}el)8K8&YhoJx^yXX^X5%OfIYjqOixcA%;j>w z@qORCs-m@SDzn+_uO}uZ4hHqD^FPONK5bdnC_p3EdDXCOd(?59gKX_V4dGF!TL{qs zTkg>ayWIn=LQ2^K^s%++CDcX$&GsYAo}j!4O{6r&1b-u;t~Njtu}CGRQTdpyT?P98-F!G@<8|Mx?lt-ILL@W<&XzIps4?TG{cw`V`*!>7*> z6#2`edwlNoA(D2SZ-4g7ynE~&q!6THiJG~pWiuCQi2-d4^J^|jOR}zFeEJEq*>w!y z`hPypb48SqC?mKvGson@d}X2+xje2icv_IoEc3US2NaZt6oU3dl266k8m@j+-?kX= z4SeQ6Cwb3hDZfEFljr+4ZgKwbAfvCpMw=a@H`PwIkYjE&$K~6%d9=L5TmAhAA?a`L zVmX(gpgey6uMhb9LYl7}Il(}C7ky4wq<`{_V6pjCW=c|Dym;}j<2dhHmem<#KnOTB z*u^`8uW@fNOQujHuRI>DWSGgWaQ?_4&L0_~;QORASpa5Mm$|>Vz}Ub5UwiX7%4inW zR#CoUrLazVWuBt%alH49hKl;WznaNpZd|!?>LcpIK?VT`~Q0##yT8^`H-g-dApEPvDFUoEsh@X2ro+m2o@yRISN$&Cbq#wOA~sx0_wd z7d=x{%J{x-R7sXgQK?E_uy{%t*Yk|lx?#!Z^RrV^Q(vd{-6bQ_>rqiCD9eb+=$DNZ z2#+;=QX)fEJ?!47)el8f6pGptW#t>i?Xr6W7pIl^qY(M=9<>LWy?-Hh+rM43l>aH$ zt7X`|VeL_48ntf++h(BA{jDgq*GYnH?}0E>8&|!_!;BAJ@7AUEEDE)fijRscVQpd0 zH^$WEtLj|Hb=`H}_t%^4f!#!*X3B@PE2T27>#jF7Ae+rT&FAy?KWR~DZEfvAHk*AK zY_D^n>({R@oH=vmr+;H(W2s~^dCa!$jvdXoNANsvb!~0!;l#wm&(i7i<6wWC0oSfw z)3$9tb{yx&$z<}dl(PD_&Z~y@JnzNE#>SI$I{jdLd|U-@sQb-I=|GoABp4nZrmd|_ zrcx>L`8>&F63_E+9EV&kM{SjR;dtQlD-KX72XoKSCJ(2TY1jLgtO^I{*Lx07*qoM6N<$f>k-8F#rGn diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png index b2f6c856aa52820517f643f2be54bc602efaa832..bb9ced39e2cfe91de696d1c276ab845751895031 100644 GIT binary patch literal 5175 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 literal 4200 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 JPDHLkV1oHc$_fAg diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png index 4d16cb4a29c8f9d4437b82c8838b66d832fbef80..d1ba057c01148ec0af82ddb9fa0142629f1b1102 100644 GIT binary patch literal 4552 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 literal 3856 zcmV+r5AX1aP)bGczPbQKBS^k}rz1YsZ$G__DFxB<^Cj z$*$WNSg#jo(}f%4Wj9D`z-WO!^req&---flQ=r&~qD8xK(JtH;3vavFbr7$!iDM_u zsIW>m>AggU(`29+@%nTyJa<%|qnkMGw z=Vdyb#`*K-<+*d`5Rb=~_4}7)fWg5*oH%hp^!4?rkw_%a+uIxR`~AV?9AmwJnZe95 zola+_rlvC4Y&P@w@nd=B%o*eI<;ztcM@3P2OQwUj-+o&hJ$lr4*`&rH+Io;-O{rcx+U0q!`b?TIQ?AWo_dU|^PR#nwKM5HVwvk^f=nxZJ%!r}0KMN#f<*|H@X zkH`7Jg9l4Gw`cA?eE6{F>+4fPq0k$OqCCHLm%KiqY1#{&ot@tlLIe*SIN;ge(*SS1 z^_I{ytt$`+93vv%nq1{NhN39J_V)H80DAWA+vizlc^W`UDZ=4!yQ->vYjTAf06w2@ zD}WAFRab8SMNx#NX&pj{z?xj$27s!n?V6@_p^BLXPXh=cs_NH72~^wrz4hzap=p2> zftl56W(S&ztr4o7n(;C~(?B&wQ^5^}mjO2XbaAcGjDQBC<||^(+<7IebRA*6pymeH z=nD2iGX*smH8+5hf+}q{I_eSuOBun-K+o#7S~OEogVAsUID_vTV-$mmTLvB_CTe~Sb(;%H=XG40n!&mI zqd2~6JNET<1MnWCO(_ver*L-UCOQHE{N9WEt3G$u$m7$oyBM0dkMAEif>vMYvbHWw zNJ$U`NC;SFAZsHChAF|!&Z=NdP!|@&44k?35NAgoAg$-{%GS-G&DF7tyE8NRkL$x2 zni#{r-kz$@o6hI(i-$Myv%5pc>RH6InMDSO1jA4j6^5yU2w(=72n+^;u&K4PrpgEE zkb>rQ1E;Uu!{1-Nfk%l9k~sszQ!}1&%#5*Q5`TH&m-r<57`n;0{bUBIe9lwWloJ1T z?J~~X_#BB`4h91^r^X<;ba^8j2;#SQyo7)naOHpN6ZW^`8{1!9@$aq{H8;TR=_LMp zBnp!O$pk|JmmbF;Jy=jiH*j|3J|@%ikRV79(z=eDQ!&q}jfe3Wd=$NpoGC3?Cfu8u zEEvz-|EvAG@r~_!p$OH^{e+;e1xI$gjNOreTC1n_Dd<0MjbY?T3f67>3@~9dp2q*) z9mN|v`k@L@mZjX7n#KnYqmXQ;Dz z8&l)BJ{iT~{#_;gJ6l3HHu&rK`j=kB7jv`F6oJj5E(A5db=n$F8rD1lE|1T^U_jat zAldTfpWcn)@m#v1+`ZW(X6N;S4BK+IpG@OdUyN6jo6TkrO(w1WOpve!*tvWT=O5mL zDa)_2w)=w^?B0g$om&dZuLo*s04W*wXXjx`0m-6h07>|4{0aW<(lsQr`LbR%K9@m8 zmoRM^)0Ru*bo|rM=NO)xgi%JB@%b#`*<7K&lmt@(h9rzkPvS?{KS3g!DfB0zHUBIJ zH8nual$PhCbbyl}7;KFN|9;~x;@SKn*}R>dEMH5FSVXEGO~4bG=% z{EN{$ICuYA$r#i~)HVW`3!ZPf6lqF=DFt!{>lZm;eF@41$0zOCQc9kA1;oK;+1WE_;P0#(s>;%st*}855v^KFbn+&#S}3#@et9(6uz=$ z0AKFx!9chN9f4N()cQX3Q&R)9Y6^z_;B`o5+?!3~g9nrNmun9&JD;`L34??Hm@%42 zV=S4%`wvE;fN|=Tm+)s_`xcV9JceU4_}8m9ac6o4CL30n#FpG#PRI3F47Z+4K!CBg zcQgL{_1{ECAc$BdjkC9J;M4I(NM_S;SQr?{Ln4-%!~6HHK@g+Oui?9UzK(-ichyoQ zi%^#bwFMD&c7@R2-U3As{_$7$kj!U6Kp`RoEXG1ig{l+)+WkKK#&eqy4rutnm0?_+ zm;_+ucq@`@@3#MTvGdd1R^V_KtRJX$vi2MNXYiJl?`{ z6A||IZharf-HUcvPY;kokK*IXYv{{WQ z0DwJ}NNmk5nGyg=5DO64Qg9hzwo{IE9tjdwf3o|Vw&BY;Or^ZO77O=vivY(EL}Ynx zfrYp|7zMuW)}h;oPGwDnlm<)rY+7=aA_uOqf&>Vr#e^L8WOb@L>h`{%(kOuK#Q-1* z9t>uX9RaA2%bgq!VZH3ci3DdWD;NMkVXOdKMIfkn9%-|ndZX?s$U!jzxaiRYo5k3y zq>QW}QRq)_jRlS(T{N^*-kDdjC*bTp#MWM;oPXuVn@zVdaNmdvEN_KrZ!x9JcTP0PmnhZ2%;tZ*sm&h{Y%fGt0jQX#wYP{ zG>Sxa9tsI8Em<4X{mr=xdA45_*xM7r-X801Xj#KV){qFOOB+BCp{vD@6MF`5V$T2! zDUmfy06>|qTwuPqod(0XyLva)wZuzzFhli_LqaFjs-0@ zmp|)hvY-Z|$%2|JsL6tAiY5zM8ch~dp}on1nk=Y3Sg$Oo+H3QSfYmNIREzb*f|%Jb z3`5EaPh`5`83Bf2Ad|^tOw-JI9<2;EA`8-WJ!2R~MhM|)focpO)9G|7pU+o*IClwD zx@}{%w{twLU}mJ#=@@_%Gq2tN%q*EXJ~K0O!8Faq&y%j;0xNmZLZejEzFPUUVm{8k zuIt%YEcQ8on6B%d`tmfu+}xaG=G4T*#E02z_MumQFL-&rSITx~ zr>93RUApuS$z<|eKA#_Z@4ffT>FMburURlaod?8udH|p~_m| z%{Si^M~@yAp-`v`Ko5ZD0dy&f(q$W<>~X3syq-l!DGe!Q3cw72`$RM$rHrLgDdXLD z->vG7_o@vL4u`RG=T33z)G6Wj`&A)C2!M~71GbVkTof>~B%(Zkyp%FEK0a<-ym-<0 z@WT&fEVlSP7UfX20T$xKi4zEgLQqu|%nYv~VPIeYqobpq`?IsN0D#WU&Z^p-{dz-6 z3BxcTgg`2l!s*keS9F{e8=#4`K~wn+M$-TdM$-TdM$-TdM$-TdM$-Td#{UEHBjjzx SZLUQC00005R5-eD7hu|9AgAEQL1Pc~Cf#B{oKyV8doC)rd0Kt~; z?c067_wU|&x~uLvReh>&RoAJit~f1CWn64ZY$PNk+*c|JIxlePKLZo}WsalcK6wFA zZw+7BX=osEyx^EfXvjoJC@&cD%Zr3eiG=oFI1-X7GS&aZb&%Qqn+AY{6yu15`rkCh zFYrH)%FB4+{%?r#1^Itg`~vtt)Tl^bQ2q!14;$TH3=I+zJN_#LSv~*UlRUpqri&pP zJvZGqWv;wmftJVwh98g&WdI~VhuQ@0M5j+|smUoe%<;r($>0Kby=E?$T6s7gFNKsj zgG;e4dFMxc>DTN=6;%=}BBoxzd(tE%vR>=BdZ0^QUbeyM1no^%_D$KzC%%7t2NB{I;x&gE1swrV|ZBvni7XeMu@lK=hf(7^ab%XEY-oSlS7 z8=%X^RD@clrJ{hPUicxFC`*o>kQov!$M7E>g-^XC*m3_K5C;Bd%TZ{1U~uRD874g) z9d0t=%MTi~DbZ@gN)*u28L>=^^up7bu^*7dQlDwYtot2UI`W%2ajH9J?Axo7Dke5$ zF-ELwR`l8;XUwjPzE!_Is@dXi^hHJ7R=JVw+kua(^qsVfWMfe^)&EnF<#af|*Ge90t4rY1uXA>12RjCmR} zMyZv6lC%aHBe7IAHuBG7POaCPw9;!At@a-;>Tr!-^rFs&MxS**3A~6U#;8ruFN1}` z4F0?l8Bp_$lRpnYxmBCXBvzc)>W7dX9zDg?Q7jw3j&Ba{*bcmz1$EyYrli(!!;_$3 zo<#Dt>Ijl1X8y@OsJ!0m-p0Ax!I|gCgsXBHOm4@J@8rx7MU&n>WPp14-bE%xJ`ze~ z;eiKq?AdZXh3QNZFhn8f)N6&8FaETsV&v5Zkt=(PIwZR3ffwUh%TTO86tKL}!oS?w z!R>mnAy7-yE$-dqkNAXCIL+RzL4#MI`Sl*Rl)2uS+)-6uB4Od3g5rSFV-mzJ!NY?YK`GeMl* zsG;8MJP7;nDgSE0T|q+DlV^M_ia<*);pxxpG44!7bldLj%(pB5KgWFD3f3N=G3=t; z52#FM4c3?=t&v|ddPmgm`O*Vl{|@=V;ruy!eM`dR0BLhIn9|)mYbb}j+|w?QW>1%* zgrBUJLQsC#a=dr68daG0UiQSn z>0;0K_w{K6*kdD`x4$`;>i(fvvyobdikMoON6%o&4q5ph!UG;|_o3#}eiUgy3aF`J zkhh!+7Dgc|oLWxQ)Ye2-F(9!XRz)Rx*W>htC zjM|X>z}3!wEDB93%e9io$uDN!bMhpGgDZN~addW>vmI&oFPHXvZ}97Y1$vD*4<+f& zyPFwO6QV2b(Vgs#{>Ed%ZCQ`nKOp4|cBbT3--pc^Jf z2F&%pL0P+fm^`X;p13^D>LPqIvjKR1fMW&UZ-%OmPZV+zg%>(oPxiI(YP4MwBK_#z zT~3Wtg0nH(nAB1XxH>N&THHISA1{(&3FAQbK2=0qF|YO6QqGShmTe_eu^Aamuf4ub zmp1L#O9s?hFmZ;BRluT-1mvBFF!wUsWvNPBz*diED2c_|J+ZeUgHeG2U(CD0TPWMa zJ=az>9R(XaHts_3l%9Fq+@%M7fe|w+MdtdC|wkKo~t{`E# zQGv6I7hT*Q4tk$C2_D}6i5hyA5mf8w5ip>zJCU~DB?vp~x)9_Uf6YJ`S13S)v8OH= zFR@6K85wCmSE@^`Eg6w8lHh;1W)IK_N4Sufo4p_pS<`*9StW)0qa72m|b?{ZtnUHR|!~0gN1d~=nV46NmiMI?xco%v}PHl7vBu;$v zcN=W__}CM7TVt{ny`5HDEqICBDfyC7)meCXL{P4pdB!#-BApzjtfLVNqLgj%8rs23 za}tI$tJA;vS)SnFt+u`MUrR>U!wAI((>8itNoX#8#ldFo7ALP{^x{;CEMp@}njf?O z_OFmbpNILr0{LiirZt!MMPO*WnwTAunE| z_J}0g{wK6ReVg|$t&ATNkvaayld3lNN&R4>Hwtqv{`}z}pA{k{LVBo`<@s_j?r?PU z(Z%LVxYjObm9P|lsao-HF90$QtvaEroldC2Hp`bhLT965pF+0BlBw!xnU=#SKns61 z_R;ipKdTb9_kvlB`_}Avwpf*?3VH3K7J~G|3#`EVNub-={KwnnI^FO)3vPec6~B#O zDghunh%&ufk5goIbTGm*Im^ycxa+-i$d;!%)7~LjwtZtjz%c~xb*@~0Z2X<}{*dZ( za1I^9FiS282<{ACi@2!r*q;J)FW*nPLZ~7{V z2g19yu_TTCETM|dL`5^zwG}DPm2e=4^RTyP-lxkt>_o#8cvW53Ci-yso2{LpZ?Nn# z&#ezCo=fir%2Ju!9t)xwRu80i7Og^)!{izsnqxJWR}ctJH!}w^#3$Rh>>d{tAaWVY zsBWisSFC>NFWBoZC7^BW<&u=aZ;jeKq;Oo8P`YM!X(qNP0DJNf1#yU28e91xvrN_Bj)p6*hx$K`x%thIuV{Y)H9` zE^~Go(8%8v?!>T~CW9$UAu{K*VRaZ7ldtu-`I88sxi)9Z4Y3E5@e`dAb!dTavI*#u zH5ucHGp7)BU9ag}P2MDoAK{u)OY8WWeW9{-*clRyDWqu4%I&>94qCoZm5npZyqn?f z@EAV#$Hk=GF=7L?N5yx+p5SNgaSlL94m%Ti@UaQ!@r>N7 zUoobl$Z8c*OG$+;1)KTS0QJ5A4cQIx6=WkL$OQWdX1uQlJL)RzF&QHlE#KZar5-9? zF@xnuvNo;xQRb{-_XGWMd`m;|6? z`0!M!AQ@G%(;F_fU?2U{M@HiJMJFQ$`r$gggr$##ZN*hXS!Mk>k!=Cc%({k28TPs0 z0{Q0r)A22^nKnv!ncc;5xvvdNn$ge9PlAJ?EJnKtn@%ym;;lfzlJjsXI`{fNTig!P5;BZ{3PctLqY1rZ-DK! zXDcmQkDo#tg4+n+wme%dv#~d$YLlpPU9%PPe>ru^dMVc4hfMk6ccvq^8KIh!pV@Q> zIx+jhgjE=^%q$fv-}e-$2##S4RDOTAlvpf6)_1hWvx#4@{Gte%ICIsjKVyTzZaO1Z z;df-upN{=Nd;9V53qSX>KHk@z+P!KD4wnyj+zuTUvA6d57{fHw;s;o1J2# zR@4G1*UKBE{jedDKbS8N^M$(}&|{kVfq@o#4YyB}!I&g0?6w>#=85{rVYYckFro~+ zqVM#BQQ4iDBWV46%nm2y0u<`GP11eaZ>~kRikoA_TK)41kiHR=Kxe0Lo{13}w>Y$6 zre~X=EB1O!v1-;n0fEN$v>`72}#uyW9N-0Rf9tr0Vv3_3Ue0|i}`R9a?R*^D}k)?ouC`1&CO*2(y+jNmT+PWn)_P7Js_ZEfXEq5aoCD{BCoGEw1%VT! zDVcC~{EYr$hJq}+Qz$>OHy`!o&pIFM5;PC%T-z4Z>Uq)L1-s>XT`Mr$HiXnzUTq?^ zGiqBX;)r)jMB=kAqWm;)gnw2?@yaH7+8dJ|-17@D&CNR6_^G`anI>P_m7B#&#FU7t zvjF&;zn&C%b}|rOO^`%H+qUa0(hl+yV8=6 zwwWiwo3CyYT8bd4kWUjJUCse{DxpLG*gXXFtYt_c6 zrhE-HGK?drq|i=2(>NquGxA^VI9!NMfh~HgEa8L4TsrNIwbZxOl=SE$2y9XX?4B!~ z9BU_2PRV80F*QPcaFW;ZT2@BoRAS8ds*wbl@zpnc8A0o9OC!1>Wm!Tr%$Oa+EaNQr zTT}0tF5w}2Wxk&ccp(>kWwBg>;Q<%jZjK^Po6SkFRG(M0<0Ajf3CpwCY>x+1A{u~D z>4N@71YNbZH%N@&T{I3HS4PsTtVKVWXj49?M#*%sF9eX&qCQ?CkY%W{ZT${U;2Q}h zNDK!By|l1KlUJ!qGP?!X|IX!lNNme&6VV0&d42Fyw{;=L^ZKG45o_1`g;K_FNf(Zk z-YNzqkEu?WB65KLShtdS1!i}qxt}^6>Y|e7;w^fMsbRV9baKKOSQnz`zC1N)#|7>X zj3FOlIlqp(f(r7XBq8My;wH*GRTNV$EICG5PV##WpF^5!49%|vz`eiw0m-JHd%G|A zj%jHJZ29BxeDAGs1+e zWI;&1g}M>h>Xi6NiJQ`Eq0W6|1OU1)wI8K=*st@TFxF)1A=`I&k~0nq*IY1*PFw#w zDsq&uFY(~E+S{ARfGo2y6$J#JJI`i;nIHbCd6%S~95p59GmaeL6CFSsm!G`ssw=67PL#=tAtI8o$Pp?kga+vSBACOHgzCOy zd%6+s52oD+lzbYFOxb>3REC(`{eO zS+9^LWe;gfal4+smBp5Iyc^JaE@uKK@bp42))A z97OOA;A#c?b7YuJ*p;nK2`>DYAxgHZv2UOlhCT5FpGCGH7UtC;dBP}?6d#);gxYsUv+KWNPFY#AK#&!4nt%C|l<&MM#=Y+kCpsjj zu3plN&uQ7gh{_uDwtjVICtW{m8;_BC$YZTO{kEU_27ubuF>@)6Zz0KcD--#W$Ef(0 zibJJZ??R7_{nXGHIB{A(d6x7AV&-KKfj)?b)iM?#rf6F!)WofSEPYo1TBtlJh`Jn( zK$7A+2CB`Pi3-;1h=I*UsTQ!?r(KqtCsm{1*k!f{XTbA}(9QNxx=Ed7sgnRplt=m- z&Y5=rln-6+92D)r7M;#i>cigxj&t4PupCguG8-GZB5M^H~!=Lum>N zHYs~3IczYiD(sQ&CaBh9y8QuUUWYZC$htn$3L9*l#L+f^Bq`=zVQ(<9^vOTm6on6G zEUJuQ;}E37P;OgRL|(GOWr3eZ#kWr-hm9r$KRN{-(YLWA`0Gi58SL{SX;<0E^|-9- zRzg%53sz(G8Y;Zj-8G+7xhtXvmsYLp)PUpSTaG0?RDRVa;Q@2#rCXH7RC__#a%);= zCOudoamn>95-|BK2@Ufj-uwqDXLrKIZq;@hu01%qYPwZJP-_Mmh>mLu+#4fY^{qMQ zTihT|FOVDDaAW6h^_a3SWP$E{&}9h{IsWi!xfRuv+A<$|#)cz^baTYIGaT z-lZALMO8X{=8P@t#?D?$czuPY{P03)mx{P(q)cJYSI-2;f%om!loW>X`G%>$ZWNXP zI)5^2{~urX*JVP@&OCfY-pzanw(cMrzr1@{;r(hv+=N=-*7-xc`5LTCzrQl-u?{uE z*SBo}&Y#NL@Jk+cQBKoI5ZXk*Oqw>iH*@OIZJa*{2T9hq2RZF5$Sm* zjh1l%Ed^X>`$YEt48X&if1g(IoBnw4*TW*^%f%S z_IkVg!n_ahcCeihYG%e7w{QZV5pVQZ&AtWE06(l9EC{vY&JR%|KZbEZLPCBCYcvuL0J-8xbICo_Hu0 zROE`PnqE`c93?QMpl@uKZ#K2;LzmyJt;_bB8v1VNm=Rio6Mi=$p8EBX?PLI0Z9Ebp z+;iFJWv{hw?C4%C5uVP_cn{kl4QaXn;#ECZI}gK3p?AtnZ=R9Xf6}x|qUp;kVRX;F zzlY_>)}^&n@S!#hNPL}cn*G&S-pe%m{T;BY|F?;f$J?rltGU<{#irS2KxNBETVTnj zw7dAq*wRTBmoL)a_b;mhX^qxf=a2baOv0lz>h9F*rc5as&DChh_;1eUBYpyJZ5bQ- zG4#Cz+eJ7%#2YoEzs2-IstKir$Q%e)dN8iI6C7VR1bapR(;m;pUfBp7S_>zA9Mf2@ zNF8)k3+EOtOh>3WR{H}7$$aq_ABMj5VtSzoX1TK0I;DEfyvM1CvtduLB*;As)YvJP`I1?%EEFZhrC1P$-<{Xse7(4@GOQiMHO!JO@LW{E+?>6;f((%-M)A81A zuWj?|c6~b*ozca4mg@9D2Vi)B{i{J-YM7>)c^8KiXEF1q6e|#$PmVr&T2LYWcVXMT zH|i-1=T)3Gk`5-A<74wtg^bll+nY1kUY~D8jGH${k!mjXli-$G#@b>@c? zG?oAMo8RMeIoEz=4w*=|{SRkRYgr*LS@=K&6uIR`!{JITYdO))5YaSS)d5dcuU7o; z^1AFj*H}XzCGo><)W@UnO@4=hO;wR!(F@Oq#VkI@FY-sk=Ztkly=Lx>d)>MS4Kz;MEKf|vB-H-h=yO! zHS3NO#dZ@nPygn60MAfGjdqe)-`iGvx+`GO(wZPKA%}-*%h)j;y&?&frQRjPT?Czo z&+ydDIH?hDRJ_7O!bg5%w#Y98i_%NRe#t*+IKKKVa}v1TjPr1*8T%Zj6H2A2`Z0@cwK0)__)hxOx?|DKNITUcplp-DT_Ve_*)Kh9g-= z16{429MswL{VEJ_>QEi@rwCrDcpG~l2CAF@X`h8y^2aB7;;CXb^H4{;De>b$8@Z>y z?cx}};qr;-9p@TG#%mKS93&88ntf362=>7@w_Uv}9hyz` z#=%^^t}cuM7KHJku1d=dHf|)NMlHcXTQmG?I*c^XMzS`Wdm;skq@`Urp_w?#0D|vs z7@2Pt7; zi9wH=>-Bx#I6Mi3Dz$FzOO)zOxKK_rN!DV5nZR^Hj1r75M|dr7QnX(hSm!ywj+Y!G zY?@Ms8>@TgK~W*=FK?inAb3BheucQj@6%tmJ z**DdvQM3}FqR%AzDC0=@ZfN58!c*&y+tqJ&u&YwL@nOMRXskp&;San95AIzF=yGv29+Fk0F)cxb0VfI6o$g7QFqoEAda|+$CToj_F_? zGMl=2@I*zTxpUafzpC5cxIN(|+2|PfZ_|}C%JgLTY`;WpqvS|ORH6&hIY!gfTVjSk z=k$@%Lu6uKs*5@Qf-aI`&iX6X-TXB5?SnP|oG22hlC7RpQcaKMhU4KoOVcVrl zV;u;CfB#CcL2R-xO^7Z^lfk%*EupK&m{D=N@h)cWB2PDrH`a^oLam=B-+R$aI;Gg* z37Mvz7gW^UeD9625O*4Q>)@X;_+&_u zvgU^&<+q|iM>*&sh7b?zki1Z6_Bn8RxG;N0ZTY?)g~o|HSNDaG<3xsH*`Hx97KWij zGbo=Ug_-1}vcj$<*H4WnlEtZM`CcTP>|}wp**wWz`d{d(*Sv8Fn5uz-_&tHOI9Vi#y zgr>&M{Hm4py_tm`y}8lLeMHD>k#6rB&Epyur{AU)~5^nRBe8v2PbG#=E_N z^pZOkt2$oIM!J<4;mv=fN9VKI1O87xO`rl^$ccOkLe#LbJ}Qa?TcI$`dJw!R_b)5@ zMISfq@W`0*#o-bVR3M2v1Xj3?b;jH>4;K<0+G(>!+bwL{wZz*jd#mO#SI-O;m5j7V z${$*9K!EZ-D~$>k64DiE?|-rj62X3dzaXdsm@XSrlQHE4BVH;)wazE{t9+ekF|3oD z^B2WXF;UpJpI{d|c}7%NnJk76w;#MkKkYpcPhc0>!3=xhvc~75dl9RUXO`T2v1C6U zaBubju_44B*<=4RUgW;p>Y!gksMHkh*56?M<|n;=QeH^!ge_fA*7(15n(rIF)K5Fj zN9U(I?43TIfEX55kHA36v=OutSK?P=WXWa)J+VY|6M5S)vw~ReSx3~OwQmm~&0N$< zqobQYuN8A!C6Wc^$RTx*q`Pqm{^aOH8~JNEgX<>%yFg^3tFRDv=!3kH9472u*s|3f z<>M}RQk`}<`vB1jl}^4JC*k)M>v&Wot{Bb8R>D+gMadCjb&Xo|vh>gCU!~#R*z7}A zFMVl*Dfbl3QyS&B`qgZ>zZLo^9I;S1zaOj6J7Zia{oa)EqjXPWc4XT)z)s*5Q`I@NjlfbzFjh~U3f=Q z@&v!(f>5GK3@x(q$qnVt{+iO>2Y+i~NxjOEQeSANDm#Z>CC>9f+!rYKv9 zWYe)zNmU*aSuV#;UQ$Ups>(~sN%<-9TOLxCsyyXVwBwW=n^DPFMq{{q@)V_19k$02F&+#&za# zKTe!^x|P9CxtQ_O>vMzdEBq6torHb=Nw&$M>qQ+Gog~@#yvh*vbHkKjP#(_vLDLPJ zPu2+2PUsNnl49t3k&q7=C9>F)_S52C<@G9$Qz-ZQ_njzNdD;DXX0Ll;d-E`P4SHVK zbXmo(h7Fo-(DkVEODZ4F>qPn^3&JMmeMzNL#7|gFpT_(@2)@dfuu9l z`P3Xtp@@;FhgLzYWD3PdqcoU85hJ54TuOT?QYT9S7PKsbKA)w!DfTI<5h@fhqUK-< zMT{unQYd0X37A3=BTB#&iWpG>rihwRZBwD@HL5Q|p~wWvil|V;h!QS^B1V*eDHJiH z1WcibkvIe_Y%mi=wiwm#G0}P{BZoo}BTBdwiWpG>rclI)5-^1#MwEal6fsf=nJ#p& zobP`3yQMFF@rwsFO{)-Mg=OTN0|4BvF~*>28aU^+`)=vP-{PmZ#~1@4WY2Z^dF67M zH5v^nu5-?9&lkT}t5w!&wJ0G3l(z?9oOO1-2a#rce4L5$i07BfW!7vqsr-)QcOvQzfbQ<@0su5k+w)%KcfdJErBVTm z_<+r36NC_y%VpMXx2f}c5#=*J0{~{doZp=@9{{LSD&~0!&1REQN>M76&}y|@zk6rB zHa9n$-~ayiAASAnUvDEp!dekS3)sfS#_{p-@qf=bzu+b;ZUP2iPlNJG<4h;x6foy? zulr#>A9r5;o-c4~uwLn%jnpq;(s_NyQKxaF`{428$GNe~glf=d`la)_C$9U+)9>fw&TCM5`M#g`XHYMq3?Pa)NUL3CZiqOlmaMR- z4kvP=YTLe^LmfZG@39RNha3lw1VK6x*~F|mpGb(RZToso;`6OmtCe(?3IzZN7p-9l zbRM*Dc~VFH#E6@llAkpF{3aEt;a4e9@n51_s3Yn{Tv0I>{$2a8>YX8jAv8)?7K ztZOhqmZD0VWmNwyXn1fE;Pq3aBk;-DYB2(NiD+~eUfYk`yymOlK443 z$nV~?LDo3G_rsPoZM-zqutuLeX}~b}wH`(`Hw$~vTNnm43b(yne$otcKWteQI$=AU ztnX-!Ow*;|u?ec*#-dhdYvWt<-2_$S=m9I=5zDbP=|#O>zwQ) z8Rv#3K16#EIM220G7!!Jr06;Y8^Ob(gYwV0ZNjShJl>SukSIWiiJ zMyhkLB=a8Cyaag~U8r@i44^`1=Zm2AN@MgSNA^ub*kq^Jto6E4yHF+B!)K)&NfNYP zySuxon(4iQ-$aUEp~{kG7*)--pGfQb@X}zhNxF!O;5SA@RA-3|LzbL_72(+zMvij1 zoT#&}B3_!^7B*YksYGlFO5RSm43}Y{5U3|n!k8@@ofa0iR&Z(YI&QAs!%lk_;2Z@? zFkPF##o1?ZX8I(KjLm?O?AXu>CF+D-i6);svljW@8c zwF<@o4g&G*a8AHM(CT(@XKfyTbmhCax^y$uGCS#ZyNT!NB~;lTP#eT;9a7dnog0tt zTUzK)*gc;@a3#EcCoOPOhasR zTDY_J5N)4Bw@y#*cjdRh9Y1YIbFwaD=<(!-W^SbI$&m=%Za1^1TyoCQ>M_i3ZsUJn zy@7WZm+<9Nv-lSmFQ8J0_EmAt!8ph5^)+pZ`0UsZ9)gCMCLN0x^sj1fU$?go7GmLo0^LNAOs+w zAQ>>#6GAXHHnxA9eX|JX9DjLt9^d|W4j(M9fPiDY*+#S5^AxbKp}@P0;rgQ$ymt8# z?mb>dmv=Gucx~u9cyWDY0e?Mr4Of@uz&Jy-SVo8W(=5}qab0LQzzHz~2_T#R;4owl z9J-*H4T%%fOI1|0cw)i_b)!ooCP(56&BCQ-kT-qUh8xy*@zHJ*e|Ys4{^-No=&&9r zAs`^Qx3PuwMiU1r?u{f&`P#i6{`lH8eDBuB*laaGplgZERvWvW4r&qZTWWSYxb$ES z|LgLP(d@QC2?qhN+i7E~*}&1Use#XU_V5XemuuK+?LxO;0Dvx4vgQH^2$*fy_~e0E zOw}eMtB*|JPA%niutb88CK)>0FI~p)e?Gi}Z{4_ucCTlyCxOWym!MCozhuu!cTC?H=TdgJ@Y_I!zMp-N3 zvqw%tBbv>CAc{&@;W@oZ~O4jRt;r=Q?)UZA;@wb?b4Cx%Fji zxBabA&D6&6i)TNFCngR8vWt}T(_DN8!55x*7B4*UOrU!Bsn;;19rQ-taGAc@rw>uR zD8@NnyL<=lJy_Q@2#g+HtmhbOJ6D$1@Xq4$P(s%1cJX_cKg6B&4fKqj-qc*C2BY|R zbrtVFTnzMVxA*Z^b2o8mabEvYMO^@JM$Njd>~7<|2Y1o+VeHTd#fiy-_*Y-}CH%wB zd;zm#GZ-t?K%nWvL0Z6gsfP21PvciFdm%&(xw0ZI%j8HjEXBgSz=0NOokHq8x6CVQG68SC?0f=X2AP zZCU5^zqdObytOcoube)Mf~JMatJ~}0t%ZAN_Imoz5?r_LaRNpdD1-+F!PVvaIDhyg zrfXxqo_(NF$Cpn(hfmEM$68|xAFnQ;*=gh0#1xK>P2uF^VN6!)nYI=uNgDgXJcT%n z1u%%UQGR~A$M9Ek%UIrS8D2jGlyERkK#Ueo3<;nB{_M^?o;f&;uRe9cce&&;z58Gp zx7Id{VIeVkGXe?@W~?je!$pR77Z>sFg9TiieF9p*H6+eCE-yX6-F3@=Vdh5w4f!-N+`=!O`>fHm^oJ0Fa-oPb(?@XzM{#lXT%hu$N!l?v+=yJGWhHd>Zl{Y6 zA8mjMpE_aKfb7g_%`H}UTlmwD=gAl>4L#1`wD<|(hT)9MLD1-S@Z(Qz_@0a9l`OEzEX?X+-f zZCjdiS%wV`0?sU}7z06%6TJIi1%G(;CbrvyW1P!*wR=6xZ|5cdC{=-M;`fT{kZV&4%YmLoZ|6*eA6afbXFq9e8j|<>Mze`;e)Kkea_zBVd?zlCjR4J z{{{ZwgZHr2YJv6bprpASw=^ab`9Ycka_e)9S@W^qfB#4L&h>Y&yq*3&t|-aE5wfup z)`>UzatJK}09IKzh~!yexULF~U<}>Fd}gcN#s7T&I$pc{5mt8_o{iqADfav=58dQ@ zQeKZ+E&RWmH}LwkE4a7uctFLtSr1VsZtFDc^D?=N3_yGQJ@qY`sPQ&hr?#w6T&AvAIuIyTn7Os z9P?W{c>SZ>xV*H2GY2MdarQ7yOpM_`rHqYc8wINAPv<@3`T9dSku;?7EWN%)y(NJV zbE@rj2j9AJ4L`nj7v~Qj!Bf*SI5&L=l|ljAZQVdopc()UhMwU&BA%y9G#7sf0XN^X zJ-^LX6K~$XiMhv1m>r+Srw`5I_{0pxOI1{hCDe;mXjvKd44P zem2Q`o$R!`c(C00x#ZR1DxR&ZtMF_v~30Jy$?ia_^LBmgDM*uSL@y!88A zceRqQQw|DXvQotC_!z$N(iZ^e`{5WkZm(_N%JM4ST6l={MibmH(2MjM0YEr3L*UHo z)c&{F-&LR-)nXA(Oibb{XP&{y12f>9qsw|&+1bI{i}Sd%zKVs-$3{Me?NTl`;Zi;A z&!^P>cfDA|SgC^F{FzsAV)AgZUtS0}=WjF`jej~eHg+e;d=uATS)pDk;Ow+jea<9h zzVzgAynNyqzWwnX{O!U6Q-g}RpYA)T3%5MPB;b}tHU95$V7J}DcDs#(wHi(zIAG@W z)YLSdJ8~3@Tbuaf4=>~D@aDBUw#RH@9b$*i$yTQYAIq1a%T7NU>v6P(eliY*3+b=0D(p+ zCdy@e`rsjaR(uf$ zai~_tZ(KNq^M?;WIKgsrawg_zV$oQ(4$4LiOOy4ZQYhe8pL-fF96thXXbV$gI6X0J z!sTvt?8kVigs+@Aiwj4NLw7Y61+}c1&hlFror{#GqCZ}dePbi2aHZAzQ9^KRyoztU z_$kaz)~sG$(qc|cwdcCzEis6bljHcU7e9-MQpL7LWeJqz5De&ECZM)^miF<65Q4E% z8DGEfd7Pa&WLxJG3-50Ake|(Lb&KeQC&0e&rq3Hs9~{T|LzC9Jl8a`6)bj(DsayQ+ zmqWEGUYI?iZ*PZPOEH^^ldLf%&1tjk56G)Nh6_iISP??TCd(!K%DGvykuy$=9m$Y12OK>=b2p5W8QJcQ zVR~!8itaRsvZmqX6Q}e*He$I!{%H(t<++|svzo)${7@>DQa5rWLLTN|0*w;PPE;WW zd4W@dNW&$24{urL{4!msV60fQX%G<@$9%3l4>IzH@j1V*mJou8N(EDus!h18V~OM; zsr9?H3&5_mvkvDxmAHtBpAVKd4F&)ujiN~9kY!ZTTykTSdwWU41?W$vs%6a7s-{r6 zYDmDc`fbt&RhbeKhmc zNdoCO`z9{Z%e&874{TlPX{Fud+X`Q-bA2WyPxyoUmW>)HZV40yr}_b8)l zH18AXbQ7N$itm6ySGUBl^fPYk9w1VE#C2&QTAv5zN7S-pMU1T=X;d;QY@QArd*?z< zjbbh`2j~!_VW2a*l|1)hd-BrDqwlxzpPy}A&8Z>f^}apYGPs2_ZL)N_N@j+RQERJk z^EYXWyC#LVK0^w#uBp`Y)QO<)6+axQbn1eCn94-b94RTyX-4WROn+LL3 z>LUpuJfh<;e(HN`bRi9v-rW6IMXWniv#e z)w8UI#yXXGU%qZ>lb{R0d$p4DcVgF|!elSysqn_B!4hfwL9|HJ7Q?X5VrEY-X(&kH zuK`PA0k)mcK`eW6!`3w<)ioFcIMFwSnmeqCeqU%#MuO#~=VwLE0^wjxH{V;@QLn2$ z2jluZ4rmCTSK6czn?9AWZFyU02J8(Vuo{8nG4GxCuR&0Q*#RMC$Y*Sg_4S>>A3LXF2a9cn_};stcHrSUCF1^FG-x z(k;J0dCJe>R$9y7QJ#Z2=b!l+CT77*AGLuUsiO-~Mu z5Iy>o+1tBV56yX#^cfydn?U#8FKL=xBXPUN;n91W z@I}m{H+>r9#!MfV7rx&Ye`czNBBhcBlVW24mIi?3{VwmH@|)LKv4GDVow78eDO}R- zWsx7Z3zluOq)*OHP3b!YY#P_7AGdcNcFk-JEAs#$BokJ|*b&aYdE=RbV<;7bW)a@! zQV&nWbzqP8djJZQ;@DW#SOm8F7}~9eM*c2ZCrG9T>s8c>MI$&5%<_wK#AJ;PNvPz` zMd3~20+uxchu`u%cX%Af$IA9O5S+0%bPscRj}|u@tG~Pm0bV#hgPCf@9GY3{Vv-<< z=Znus!WV>d(+6;3a>9I`IH+4hv$E<1GeTBgcQo(p?4&*iQ+RM{vVx~)>X5z4AvH3) z)zIqky~4Kjqh2cD^GBy(TlW(A*tC{&&L^$G`DCh6!MW)Jl9sfDT0Bdh^U3RdIg_tc zNZi>sk2{(H;84AUubn>zjZ$eYB2GcETi49^fks%gFb(nVKm7!b)T@>?5l+h?F=Hso z`3BtxSuSY!2Tz|ty;zjArG3t2kHrxzT2_`w`v_S-*N3K5Dh>UNI9`+x`hLgTzBD_D zXAX`@)XaC(+4K-k3Mr28ljH$JnJ90vyS;0B67}!Cr7{KsD6SYr*j7E z^-PyW=_BE0)F%PS^T?KPUHA^*;?mfb}J%m+ALgN8YTGk=T70bzxWKMs%6~| zQPNSeWg`-=en+;pS#DI}DHSMQJ$nql^}?s{shJ7e{KsxZbj;5} z@^{aiz`uU+d7PY_Fnl8Iy92CP{L;Ex48-BNV>mf@X`(@dNwdeB-c8_QiSCe|f`L+X#TNM)6OcJ&CWLK7v2^a1L+IKf>*` zO*FbaaH2n7-#sRVZQ=8)6$`jHdj$Xa)i2>kpDf~gx8|_8wTYc}+c+o9*ehl(9mMlp z#?eMJO>wc@26iP?=9H(YuOZj>=OeDw}ld+9Q9 zYQVVD_an^kFv}fAScZ(rA%xSdoqGyy;z4gHrHQ=!u)TJevSo2DA`|vq06`9{unTZf z>4Ma2$kSCqrS%f9*o+-Xxk`m;@WU8LvP=^1BI$P*CS4X{atykz$QfA|{v;V-MU2G& zlDId0tJRA0@d^i7p7SON=Ukj{*-xnq>t(;^UgF;LKt8|pL7E^gP2p!hSDg8e3WN~1 zIhbE(U#AC%GmWRB^12b57Au$I^Js{Zq}Iv2o|{(wQIKTW`sL+v!lhqj66P#(3J-7k zSi`q9o6Wc$J+fq3cohAKJ(91JN~NNPGXcr_`^t*PN3B-tH`I%TR5n~Hh9~brmj(_q zeIji?iA-#p-10gH%Nl778?!Q>3iGTio~{xFHls-tL2u$fX@t?n!-@z54}Fr;LjV8; zoJmAMRAdu~CJ!p#U5t67wLoX^5>RVI6*h)FsKhTw-#>9x@>F zhd*Sg;f)$$-fb55d1V%T`{+75WN4Z>1^+jjJt6;y8g;RA5PYzju^c$@?!(;nN zBg5d~O&=>k*TJ&V>kaG8KI~9PdDExHQ0rqs)#A`39UCGlhV^D2*1DKyZ~Cm@)0^H+ zQ$^}cKd1mBjatXrw>I0;@8<@wpX;6lJcfu-IQx2%xXR4ff@7kn;as}7SP`Rg z_VpySIat`puW>WTeQ4PGLGx9_%IG=!iqP3{oURfDVNWUXdp~Htqe2#3)P@Y59g4&S zEU2?@)*4=3G?dbad&!a&F*BCLtTmLpXs9^z3wwZI+IdN#v%@&6BEJ}O zu%J^QF`^498?Mg2VFWJFkTPiKY^CWGQDN+8mfNdSoAo2qf^-z#^nrSWtcT7{t87_* zC!@lE(^Z1b!+eprH+|NP9Qz?+?tX-Gj%KqNc5j#b*+?~5e< zmHIABm&;|eS}pU75PyrGZl4uDOQjN8trjSy;G9F#G!R12?RL#HoO4jao2*nSv39#n zWdUT2p<1o7cDqgGMo}u2Sf|sWB2B4OV$Eig$^s_xl{JjWt6VO#R;xwDv8RL(^m;ur zFHs(Oe^b3)XRTI?YMSPHz1QpQNh3TPL|&pSrBaCzLSQ@(<#L%d8V$-hN1;$axm;$u zySr2_r+gjI9cx9t;%|``V7e`t*F`${nZmT*YPD#gP;kB8>-A7Bm(BOKfv6IHO9*z2W+h>AfdjWz_S>}Xcxf~*Tw&>hCkbcvwmUn)lK9=0KWv($@hqbIip zNb048OW`E!6d_4X74^1~sPi)U|DCc(C6}xIwg3PC07*qoM6N<$ Ef*>;RkN^Mx diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png index 006bdc22e64db8772480412a86496ab362e26fbf..846b7b884ff7ba0ed5144162443e75d5c42bcfd0 100644 GIT binary patch literal 6450 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 AcmMzZ literal 6763 zcmV-x8kFUUP)y^oHf>qfg>*>k1-jC&WeTJ^+&dra9*hB64xghgDUb*LB_b^2;wPKmPHLFRMB2vJt@k{rmB?uYIk} zWHLPfU@L$d0JIZP3xHYx#&XINLPUuu2w+|a;RJ9B!0Bi-dT@Mv+|}FLTkS`v2$xI% z{r&x{r>CdZVzF!kumiwf1K5HxJGufy0SpKs_UpQS!t3?+|Ms`P4gBzjKfENGK>+0V z-_>eBLZIp8ail0M(=?4S#{NPG@l_)F5@Mz$+oY^C6d}YkfcJ>#_XiIie0%rq-P%QN z!^P78&N&0nE`)f5h`s^fwu@138TdG^6>t3RcfWHz`skw$-lQ zuImRl=i*8_bX`B7Y1;iCeDHzUVzHFdH)S0wW`bsBX6oD8+I9o@2@$PZsd`orTnI4= z;J*fg!8aQk8iFfPN!10Qs;UfNGh^%p0Cy0Pyi}gc9GVc~kD8|asK3Ae?5(%n8m(sG zRqgyA{NM**jNQu^dx40)colR$0LVo2MOl{r@#dRv{_}eSLk5 zh@J-USj8>4a`6}uJ^kjJZ!Sv{DxL!rMQM>``A3Ygzh6!Ru5<_?{zotv{KtldhKlBd ziag=Hd-r0;jvbE^(NjcJQ%S{F5jGhN2CvuaJ%0T7@v<{7r2#p1|IC>)#@^oE`xs-t zK`M~nD^gfM_(jO_HP+i0G~g8hX`22yskR)xR^F&Hd%%Tgv_? zJHNiZp1EAEdP$P@eBSxFAfmer2E!hw(^=oz+FEkHk|*FphYrb&jg1fC@(UwhHXx$g znwy&+djI|ROZJ6InuI$$JMr9e&;18UlAa@?#&Q}ZMDd6&(TYdIFD3}UjZIBW=YqlD z@W&s2ykv%wG~k!N{3TD!eyC}DyMov&6%lJxD{ zZo92xsr!lw;HjscVrH}X5hB{PoW>Lr!cqdd6lWm>bgo0=dd1}s(Jrgi`pDytKVGzt zi(Y*A;fEPx>>ET>TkO882@y@j`MEJ18vY1}hd#u)IXl9tQb|#@jInRrci(+Q`?#PZ z_KRQqf<5-wW4lcz({C!NJ%KBQ1?ik)((l4+r~fbJ7rh|jAP6uLXtvhlk?a2)Yi%8n zm{eA|kx1mxqeqXvdGEdV=H2#FP&yAi^pH)K<*%0c967jBSdcs9$D!d9a4vYkMa%;g zAP4}SPyp|ae1y40Pub>9IB3Jbc_6E6Ua`d!d; zo;LCcLI6Cj1)30;@H@+Xej;j@Bx&cDzVxNM*At$wh@bKEpZ^^9+;fkyx3~8N#@LcH zsu)zA8Y#PsQU5&lpZ*AMUpR?#b5jNHYqHiuP{Q`7?0@>vXensQi$ap5Ywx`C&W^8t z{p&f`ay+&6_I6`)bMphs*-{eGbv*ykX&kaoK;tST00S-$wzs!IVwn?fp^13Z=fgjL zb`mFNroc#mLtuJg0oT}?N@|17Iqcp!?D_aGg3&M};u!JHLDe-Fq|~D&>c3@85A2>< zc*B11M3V#o#6bY+O*OcwP!&6W+9-G7f*u4P+qS2CB(80kW{AqR$95Fk*5Q$>U?<=_-^PwQ#8axGmM2WK+ zLNFS^^g@0n)7{jLot-^M#3s{6K0vs!y%*h0T_x9_4M~!=_V)H#v(s}%xz%dzV2o|4 zw4!0p0{-dKA%s*8Mg#%@ApB|8g8`QZU%aOHv?7E+zjF?64UPcdkQf6X5Y+|V9kJtq zP1nI{Tsqo&*nS@UGgIIoFd$~j1#on15Un*0uo_Gm_tzNB_{(c|qOGO@r<@MVE_y%! zR@KyF%c^y_eeD*oWzc5E*cPkR+JV?xJW1pTK$hip0Bx04bZXWIhj%f?YejsN3jvQ3 z!3U$$_`=%N$;mIF0g1nb5KuH7A5Kg|6M#enE@J$ENMLp`gwLGQxV>{NB*rrGrJr@q z@zLZsqB;j-1Q0;+YlHJMm=(Cd;xqKVEiQ zyl>B@r)QX;7hil4vMg^TqS6d)9vmB=hcBXo$9Z((P<7xB_Hi5?pMj?Hf-K0j7{aMp zcUoQ+Gh>{fbHZ=V3}DbbpOY{BJnWf=GZ+LHEXL(ICI6mU@Zqh&PoZdPQfTQ1BZhjD z6`l1h=&Wx+gSiG0v7GzLJ&34DmgS8vzW8EBe`N^3X0rjn8Y0TERi$Dq5RTjZ_>uTq z02(Lk8yJGa7buuNsA>pAwYWnRn?JZnv669r0B;SRht3PX&@;QZn4EjkxjYvHT>$6i zW^iK44vp)TK4#eBPTH8 z_2=zGMb#12cv{}r=+)!pMRb8H-J6IPosY} z|6V2mO0u8y@_3qedSrYQeSi84ekGg}@Jni7QiD=j$m3-PqfxwLKaHcK=dc*9DB4*z z7-Q|6b9vpmb;-2kNN;a%2N6|40I>&-agRjD2!JOhLjnZw(WDEX&baXKbsKPdXFGbD zY_J++2p~4v1p|Zt#r+0C;v6e?F{0tv_&A2WZrpv%dfd788Z=p~uo{dpA#nl`z&Qg* zfJ7`G2_9<}0~Vqx_MQGCj*XqeS9-Rg%hrk}ODznN1hxW;fAPMRZ8lrd7f6O8cJACs zJv}{^&6_trElE;crImQYDmFFMqS2$&F^3f& zJZ_SBvR+WC91yS&31i4J4ZCL=&Y&C90XG^gHLx10`{Je$A~HBQ_);hoikv)o5; zXqpBggb~Z!UjFp$8ali6BzR^Bu5?r;9wvKL^KZPLKv=K2#f@_u4=;H z-*p?-)Wz0-rUF6yerObLoE<_`S3x``$;3z|CJ<3M>>dvsUNO^M!eC1voWkke0o|HG9=xlcS^y#X0egam5jQe{! z@bGnO!AJtG#?vY#_Ld?j`&B+9&PO*86DhScayuo@uAZepy7a`FN| zi`9bbTbpC-DlfZ9XcncW{;cQesB6I5hQ=gAN@!uWzrxeXSc(2vNTbh50r>rX@EEH8 zhPV&{>uoh?Fqz^bmt~GXLC_QF$n}r`z#uVnH`(G0iBg)xvos^M zf^LY7GJ*h)FGEv;r^lnFMZXv#5c3ZpVzGJwfW=m=csy!KNNGU+_Qd=QCgSyS22KJ< z^ABQ?)BKv4j&jpgRrN5&qLD}>`IzY%z#@@|78gL(km`IS?R;|8DJ|BMWHWgt(Bv9! z+P%qG4^lQ;q+Kh7j5#EYQKj<6&nut=s;YW)UDwj*fTRYDjEwM5D5PncHqANbEN+vk zhZOUHpt$H09&(D;C(J=c&MXZ|jC6oN9I+uAF9)217coH`aScGar=3{)6-iIKm=G%g z=bUSrHtqBIG`roNOwZ`#U@)jfqfsa4ylSuGr%y!bwm%i6OxgA9(VLHzr8B5(_QMlQ zDzU1SCx3c;DphZKxw*bbHNZKKs;cS?27?(SCnM^4=FAx$4u|c!t_NjVu9_bnV+4pt zMJevVW{%{<)+C-bCbDfQ#kB}P+>=e4LquvMC;C0FEf$G+D7Hug7N3jaBR^4YHVewv zrgGACT@Qvrp`o#{v5aXhLj%I$Fcd|Z)-}n4(aRX&3u_x8GnTeu7LNfHu;2Mu%q<Yn*ghCojYdc2=jT7>RZ;^H>t$?euE962 zUmXi8$48)^78ern(Of8&0|57KXvfVR&B-|AKG6=jT6;Mx&$q_U&6*07FAVSX^8TEi5dYh(@EKQaZR8vL~d!zP=rs zTWT}dPckxzr9WP}y3UMmZMi0{N$DPR%9C9R8yf5JMbY89iQs;Y(-78Xt{ zE-nVMH|7F)-V+W40$5mB;5&Bg;0+B8H`UbCENh2!HdfafaeJ2y{mvjfVHJAfN#pCq z9d%~>dG{*V%!a)A84=dmYS3P5!DJu|PdF0uD-wHy0BmZp;qD?k@E8%cu4;kRV8GzK z7b@q;yr7s9uxtG~tf`N!h%JW&c|4v|qoboQJ^Spljtdtqiov_GqW^5;B%yW>f>i2D2jsN_G>v3ymD-5!fF_KHsf?9(C z4_@1i$G2}mZ*xU1V?*q#rqPH?ezQozQMu4{cgA0 zRp`EA0?-;88_&92u2VHNHFwFfydp1YH(3n0XMHnvt!sqN1sD-zR-6f?r!yj~sx@PG zZx=X^ZDUX0$C>upXx{upv0%t`EzRg{Zi3D^1OPcL7FkIsLf3UZH#c{RbAHzCb{Aaa zD)_C4_uhL?Y}~jp)YjI9`uh5ttX6A7p+btGlny|=(CdO{}fbK14~W6S};95ecb2s9e?%JSBnz6q5^O_o$&kpBZGs3FVD`-I;-IpF^yU7|ImhhmtaEU1@MXW>KQcNxTC_iwwCjftACBs}-aj=pbxcu|Wv>$~ zHS+Tbs95^t21QY#)6>((bY1U1eE9H^{k7!xf(8Z#L`O%5($v&6%NSeV($ccNnx>-= z+X0rg+1YmYQiF4jp`oE84u|9Uciwqt@K?Y3)siNoBxdu$2OscYFgW0FI1YHd-er5o z`LGn*St`9;&8gBhlZ?ab^@bb{$AL&BGVsP5ZV2E^gcMnA(k&e2$ zx^9cbVp=L+qLDyx7E}t`DU@F5zVtduP0y~QoOGYh7dU(N?CWl~`-KxHPWaw?@4b@j zWy#+Sot~Z+TeohFS}c~JuIt_H?d>I*qDoj$Iq9XQm6~43-@2~j?Afy)I-Sm6I2?}i zd-v|;*(+a#KqzxRXkTBS*8GFmMANi`-}=_KD*ATxa^gE4A;jB5Lql&&OiUCEHkFDijRj3iOt^-Jhu?_zLB+cX zEB+a)0|yQWm&+Br;f5Pd&CJZWj7H;4H8nL>S(Y=(yV_WgqA1+qaLk@OdGfzUB9VXo z+0TA9vw#2oiao?-{f^k!*ck4(B^^aLna${Zlj=ef!9fBY}el4^|~GRWS=HguQ$B z8XFoK)|t)bC%d}3?%lL$(*~>6T5z-V<;sFM=Lm&D{KAC`BNG!7hZRNHqbSPg_rCYN zs{W2x)qhKJe0*GN+qTUo%kq%l@1F~WLfwq9`ntM0shADU$5cv5&lXatnv*X*y{_r$ z>F9+E7ltP$CibYRx=&Trk-ok@-QjRlH6&Yg4MR+ZEa>*&irE4a#&2YSdb6`nx?_!aw(IOlapg(WB&@^_klp*)S*L%q6ZEfD6gedGIC=7G61UMN!tsvTUrWsiDh-1p$ED?dBsRBmUvx z;kVsx_bZ(9{a&wk^qFU#iGK3QCk68@7b~U#+34%*lO;*2XN>J)jQv?xSJ%C(R;_Ap zZEdYJo6Shqii-hF)1W8{=H}*tPN&m3IXQWlbN)W(`~#226L|8;CojtH312h;baZs! z;fEh)cieG@nTT45=q{7VbZ28@-D}9i9|jWLL3u9%>Vk=zg7+(KAiC?=}O|F2_PFk{pnBHrcIlSvMg@^u!V^3u~;md z)~s2xu|5W?$z)Nho)(WL?TcWg)b~DgaUy;U}|b=I2;aN5JJ2w zgcwj&b>#f{^U-IYefE<5ru-!l!1nFi@x&8Pz+^JXa?Jj;6Hz-6Z8I8;J!Z4{29wFu zVYOP@OeT}nVzC&_W;3%`EHIf&V2ou5f^&{YB$9Z`hlj)AXe1H|g+d`$Bodhphr_2- zRUHyS^a~-J0GxKaUE8;BpEf)^3`My(-weveB@;k4T3cK3#1l_o^XAP=*L4{{JrUW2 z5FLmKrxQRUfF=Oe_>pM420#H20^kAQ6+%n`a1zn95W*LUL;^!YL)z)nr}>d1N8tDS zFZwg)!(}6YbZpzU4R_ytH~fA-+qP{RYiw+kIp;=`$z)`V83D*b2$|wPsUn2nM5F=G zIOowwBod88B2mBJubn%0j*pLzV`OB6FSSMFQsA-_z`rMa-uagp{~uz^nN1FX27Ukl N002ovPDHLkV1fqb7Bc_< diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index 00ee14e8f2dcd6daa5c2d16bd10384b4a8e05b41..89029f4fa30a20281bc1b97e72795abefb2065cb 100644 GIT binary patch literal 7152 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 literal 7524 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%0DLgS)QsX~j4pp_{AxnNsxrPf9`tVG`lWP+P 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 literal 34556 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�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 z%0A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 diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index 258b751eb91aeaed649247f09e378fb1b086a029..4fa82b8166add116c1dd3f851ee55b608d2595c8 100644 GIT binary patch literal 9609 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 CF_Gi| diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png index fcd8bfd3e39f5795b6d6ade467c597fc19d38bed..0b90bff217762de7d0b2845cd737b539b841cdba 100644 GIT binary patch literal 23092 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 RN+qlC{|8oz3nc&m literal 45316 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

m-cdDnTe!T3YkigM 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 literal 15240 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�t5cJCU>`{Fg?JaREI! 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 literal 97273 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]i;9t#<8;Rg6K9PhQ# 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

D+*e(F$VD`)4@PH9li6;PfX6cLGk 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 diff --git a/assets/images/logos/loading_mohemm_logo_old.gif b/assets/images/logos/loading_mohemm_logo_old.gif new file mode 100644 index 0000000000000000000000000000000000000000..ffefdb00a07c0c906a5e135a3ca82b631d1f2f5f GIT binary patch literal 97273 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]i;9t#<8;Rg6K9PhQ# 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

D+*e(F$VD`)4@PH9li6;PfX6cLGk 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 literal 0 HcmV?d00001 diff --git a/assets/images/logos/main_mohemm_logo.png b/assets/images/logos/main_mohemm_logo.png index 5536c07e274c6df66a968e6195f578f3a5750c97..8ea04aadd2cfb2100be3e9ec40eb2ab350d97908 100644 GIT binary patch literal 5345 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 literal 7448 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 RbN_c~Z{uWLe$Y4dKLDoXdJ_Nu diff --git a/assets/images/logos/main_mohemm_logo_old.png b/assets/images/logos/main_mohemm_logo_old.png new file mode 100644 index 0000000000000000000000000000000000000000..5536c07e274c6df66a968e6195f578f3a5750c97 GIT binary patch literal 7448 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 RbN_c~Z{uWLe$Y4dKLDoXdJ_Nu literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json index e83c3bf..65b74d7 100644 --- a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,128 +1 @@ -{ - "images":[ - { - "idiom":"iphone", - "size":"20x20", - "scale":"2x", - "filename":"Icon-App-20x20@2x.png" - }, - { - "idiom":"iphone", - "size":"20x20", - "scale":"3x", - "filename":"Icon-App-20x20@3x.png" - }, - { - "idiom":"iphone", - "size":"29x29", - "scale":"1x", - "filename":"Icon-App-29x29@1x.png" - }, - { - "idiom":"iphone", - "size":"29x29", - "scale":"2x", - "filename":"Icon-App-29x29@2x.png" - }, - { - "idiom":"iphone", - "size":"29x29", - "scale":"3x", - "filename":"Icon-App-29x29@3x.png" - }, - { - "idiom":"iphone", - "size":"40x40", - "scale":"2x", - "filename":"Icon-App-40x40@2x.png" - }, - { - "idiom":"iphone", - "size":"40x40", - "scale":"3x", - "filename":"Icon-App-40x40@3x.png" - }, - { - "idiom":"iphone", - "size":"60x60", - "scale":"2x", - "filename":"Icon-App-60x60@2x.png" - }, - { - "idiom":"iphone", - "size":"60x60", - "scale":"3x", - "filename":"Icon-App-60x60@3x.png" - }, - { - "idiom":"iphone", - "size":"76x76", - "scale":"2x", - "filename":"Icon-App-76x76@2x.png" - }, - { - "idiom":"ipad", - "size":"20x20", - "scale":"1x", - "filename":"Icon-App-20x20@1x.png" - }, - { - "idiom":"ipad", - "size":"20x20", - "scale":"2x", - "filename":"Icon-App-20x20@2x.png" - }, - { - "idiom":"ipad", - "size":"29x29", - "scale":"1x", - "filename":"Icon-App-29x29@1x.png" - }, - { - "idiom":"ipad", - "size":"29x29", - "scale":"2x", - "filename":"Icon-App-29x29@2x.png" - }, - { - "idiom":"ipad", - "size":"40x40", - "scale":"1x", - "filename":"Icon-App-40x40@1x.png" - }, - { - "idiom":"ipad", - "size":"40x40", - "scale":"2x", - "filename":"Icon-App-40x40@2x.png" - }, - { - "idiom":"ipad", - "size":"76x76", - "scale":"1x", - "filename":"Icon-App-76x76@1x.png" - }, - { - "idiom":"ipad", - "size":"76x76", - "scale":"2x", - "filename":"Icon-App-76x76@2x.png" - }, - { - "idiom":"ipad", - "size":"83.5x83.5", - "scale":"2x", - "filename":"Icon-App-83.5x83.5@2x.png" - }, - { - "size" : "1024x1024", - "idiom" : "ios-marketing", - "scale" : "1x", - "filename" : "ItunesArtwork@2x.png" - } - ], - "info":{ - "version":1, - "author":"easyappicon" - } -} +{"images":[{"size":"60x60","expected-size":"180","filename":"180.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"40x40","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"60x60","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"57x57","expected-size":"57","filename":"57.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"87","filename":"87.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"57x57","expected-size":"114","filename":"114.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"60","filename":"60.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"1024x1024","filename":"1024.png","expected-size":"1024","idiom":"ios-marketing","folder":"Assets.xcassets/AppIcon.appiconset/","scale":"1x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"72x72","expected-size":"72","filename":"72.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"76x76","expected-size":"152","filename":"152.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"50x50","expected-size":"100","filename":"100.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"76x76","expected-size":"76","filename":"76.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"50x50","expected-size":"50","filename":"50.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"72x72","expected-size":"144","filename":"144.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"40x40","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"83.5x83.5","expected-size":"167","filename":"167.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"20x20","expected-size":"20","filename":"20.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"}]} \ No newline at end of file diff --git a/lib/app_state/app_state.dart b/lib/app_state/app_state.dart index a6dea92..8f81951 100644 --- a/lib/app_state/app_state.dart +++ b/lib/app_state/app_state.dart @@ -90,7 +90,7 @@ class AppState { String get getHuaweiPushToken => _huaweiPushToken; - final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 8.1, mobileType: Platform.isAndroid ? "android" : "ios"); + final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 8.2, mobileType: Platform.isAndroid ? "android" : "ios"); void setPostParamsInitConfig() { isAuthenticated = false; diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 4e77928..a6fb4d5 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -3,12 +3,12 @@ import 'package:mohem_flutter_app/ui/marathon/widgets/question_card.dart'; class ApiConsts { // static String baseUrl = "http://10.200.204.11"; // Local server // static String baseUrl = "https://erptstapp.srca.org.sa"; // SRCA server - static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver + // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.201.204.101:2024"; - // static String baseUrl = "https://webservices.hmg.com"; // PreProd + // static String baseUrl = "https://webservices.hmg.com"; // PreProd // static String baseUrl = "https://hmgwebservices.com"; // Live server - // static String baseUrl = "https://mohemm.hmg.com"; // New Live server + static String baseUrl = "https://mohemm.hmg.com"; // New Live server static String baseUrlServices = baseUrl + "/Services/"; // server // static String baseUrlServices = "https://api.cssynapses.com/tangheem/"; // Live server diff --git a/lib/classes/utils.dart b/lib/classes/utils.dart index 9c55375..1838cb8 100644 --- a/lib/classes/utils.dart +++ b/lib/classes/utils.dart @@ -401,6 +401,7 @@ class Utils { } return false; } + static bool isDate(String input, String format) { try { DateTime d = DateFormat(format).parseStrict(input); diff --git a/pubspec.yaml b/pubspec.yaml index 5bc1373..2bcc749 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html #version: 3.3.01+300040 -version: 3.7.95+1 +version: 3.7.96+1 environment: sdk: ">=2.16.0 <3.0.0" @@ -120,7 +120,7 @@ dependencies: # store_checker: ^1.1.0 google_api_availability: ^3.0.1 - in_app_update: 3.0.0 + in_app_update: 4.1.0 #todo its for temporary purpose, later will remove this. dotted_border: ^2.0.0+3 -- 2.30.2 From bafb6c8470f169320f5da57bbd737ae2b3a16cc8 Mon Sep 17 00:00:00 2001 From: Sultan khan <> Date: Mon, 16 Sep 2024 11:51:09 +0300 Subject: [PATCH 035/135] missing swipe issue and payment work-list and business trip issue fixed. --- lib/classes/date_uitl.dart | 10 ++++++++++ .../dynamic_screens/dynamic_input_screen.dart | 9 ++++++--- lib/ui/work_list/sheets/update_continue_sheet.dart | 2 +- lib/ui/work_list/work_list_screen.dart | 2 +- lib/ui/work_list/worklist_detail_screen.dart | 1 + lib/widgets/bottom_sheet.dart | 8 +++++--- 6 files changed, 24 insertions(+), 8 deletions(-) diff --git a/lib/classes/date_uitl.dart b/lib/classes/date_uitl.dart index 89e237d..e27843c 100644 --- a/lib/classes/date_uitl.dart +++ b/lib/classes/date_uitl.dart @@ -524,4 +524,14 @@ class DateUtil { // } // return ""; // } + static String replaceArabicNumber(String input) { + const english = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; + const arabic = ['٠', '١', '٢', '٣', '٤', '٥', '٦', '٧', '٨', '٩']; + + for (int i = 0; i < english.length; i++) { + input = input.replaceAll(arabic[i], english[i]); + } + + return input; + } } diff --git a/lib/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart b/lib/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart index 20da2c8..4f67c62 100644 --- a/lib/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart +++ b/lib/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart @@ -6,6 +6,7 @@ import 'package:flutter/material.dart'; import 'package:mohem_flutter_app/api/leave_balance_api_client.dart'; import 'package:mohem_flutter_app/api/my_attendance_api_client.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; +import 'package:mohem_flutter_app/classes/date_uitl.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'; @@ -85,7 +86,7 @@ class _DynamicInputScreenState extends State { // } // } // } - return ValidateEitTransactionModel(dATEVALUE: null, nAME: e.aPPLICATIONCOLUMNNAME, nUMBERVALUE: null, tRANSACTIONNUMBER: 1, vARCHAR2VALUE: tempVar.toString()).toJson(); + return ValidateEitTransactionModel(dATEVALUE: null, nAME: e.aPPLICATIONCOLUMNNAME, nUMBERVALUE: null, tRANSACTIONNUMBER: 1, vARCHAR2VALUE: DateUtil.replaceArabicNumber(tempVar)).toJson(); }).toList(); values.add(ValidateEitTransactionModel(dATEVALUE: null, nAME: "PEI_ACTION", nUMBERVALUE: null, tRANSACTIONNUMBER: 1, vARCHAR2VALUE: "NEW_ROW").toJson()); @@ -773,7 +774,7 @@ class _DynamicInputScreenState extends State { onTap: () async { if ((getEitDffStructureList![index].eSERVICESDV?.pVALUECOLUMNNAME != null)) { var timeString = getEitDffStructureList![index].eSERVICESDV!.pVALUECOLUMNNAME!.split(":"); - selectedDate = DateTime(0, 0, 0, int.parse(timeString[0]), int.parse(timeString[1])); + selectedDate = DateTime(0, 0, 0, int.parse(timeString[0]), int.parse((timeString[1]))); //DateTime.parse(getEitDffStructureList![index].eSERVICESDV!.pVALUECOLUMNNAME!); } @@ -861,7 +862,9 @@ class _DynamicInputScreenState extends State { context: context, initialTime: time, builder: (cxt, child) { - return MediaQuery(data: MediaQuery.of(context).copyWith(alwaysUse24HourFormat: true), child: child ?? Container()); + return MediaQuery(data: MediaQuery.of(context).copyWith(alwaysUse24HourFormat: true), child: Localizations.override( + context: context, + locale: const Locale('en', 'US'),child: child ?? Container())); }); if (picked != null && picked != time) { diff --git a/lib/ui/work_list/sheets/update_continue_sheet.dart b/lib/ui/work_list/sheets/update_continue_sheet.dart index 1240de2..42632a8 100644 --- a/lib/ui/work_list/sheets/update_continue_sheet.dart +++ b/lib/ui/work_list/sheets/update_continue_sheet.dart @@ -38,7 +38,7 @@ class _UpdateContinueSheetState extends State { var size = MediaQuery.of(context).size; itemHeight = (size.height - kToolbarHeight - 24) / 9; itemWidth = size.width / 2; - return Column( + return Column( children: [ if ((widget.workListData?.sUBJECT ?? "").isNotEmpty) widget.workListData!.sUBJECT!.toText14().paddingOnly(top: 10, right: 21, left: 21, bottom: 21), ListView.separated( diff --git a/lib/ui/work_list/work_list_screen.dart b/lib/ui/work_list/work_list_screen.dart index d0360fd..6f93909 100644 --- a/lib/ui/work_list/work_list_screen.dart +++ b/lib/ui/work_list/work_list_screen.dart @@ -80,7 +80,7 @@ class _WorkListScreenState extends State { WorkListItemTypeModelData( value: 0, name: 'COC', fullName: LocaleKeys.itemCreation.tr(), active: false, color: [Color(0xff787299), Color(0xff1AB170)], icon: "assets/images/miss_swipe.svg", key: 'COC', disable: true), WorkListItemTypeModelData( - value: 0, name: 'Payment Req', fullName: LocaleKeys.paymentRequest.tr(), active: false, color: [Color(0xffB06F1A), Color(0xff1AB170)], icon: "assets/images/miss_swipe.svg", key: 'PAY_REQ', disable: false) + value: 0, name: 'Payment Req', fullName: LocaleKeys.paymentRequest.tr(), active: false, color: [Color(0xff42d7bf), Color(0xff42d7bf)], icon: "assets/images/PR.svg", key: 'PAY_REQ', disable: false) ]; diff --git a/lib/ui/work_list/worklist_detail_screen.dart b/lib/ui/work_list/worklist_detail_screen.dart index 06fd7c3..787abb8 100644 --- a/lib/ui/work_list/worklist_detail_screen.dart +++ b/lib/ui/work_list/worklist_detail_screen.dart @@ -575,6 +575,7 @@ class _WorkListDetailScreenState extends State { case "CONTINUE_ACTION": showMyBottomSheet( context, + type:"CONTINUE_ACTION", callBackFunc: reloadWorkList, child: UpdateContinueSheet( workListData: workListData, diff --git a/lib/widgets/bottom_sheet.dart b/lib/widgets/bottom_sheet.dart index 5eab25a..4101746 100644 --- a/lib/widgets/bottom_sheet.dart +++ b/lib/widgets/bottom_sheet.dart @@ -1,13 +1,15 @@ import 'package:flutter/material.dart'; import 'package:mohem_flutter_app/extensions/int_extensions.dart'; -void showMyBottomSheet(BuildContext context, {required Widget child, required VoidCallback callBackFunc}) { +void showMyBottomSheet(BuildContext context, {required Widget child, required VoidCallback callBackFunc, String? type}) { showModalBottomSheet( context: context, isScrollControlled: true, backgroundColor: Colors.transparent, builder: (BuildContext context) { return Container( + constraints: BoxConstraints( + maxHeight: type =='CONTINUE_ACTION' ? MediaQuery.of(context).size.height *.75 : double.infinity,), decoration: const BoxDecoration( color: Colors.white, borderRadius: BorderRadius.only( @@ -17,7 +19,7 @@ void showMyBottomSheet(BuildContext context, {required Widget child, required Vo ), padding: MediaQuery.of(context).viewInsets, clipBehavior: Clip.antiAlias, - child: Column( + child:SingleChildScrollView(child: Column( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ @@ -35,7 +37,7 @@ void showMyBottomSheet(BuildContext context, {required Widget child, required Vo 8.height, child, ], - ), + )), ); }, ).then((value) { -- 2.30.2 From c72189bb6b1680783e78bf028e38fe20fa3ee044 Mon Sep 17 00:00:00 2001 From: "taha.alam" Date: Tue, 17 Sep 2024 15:21:10 +0300 Subject: [PATCH 036/135] version number changed --- lib/app_state/app_state.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/app_state/app_state.dart b/lib/app_state/app_state.dart index 2e8e2ad..568dfaf 100644 --- a/lib/app_state/app_state.dart +++ b/lib/app_state/app_state.dart @@ -90,7 +90,7 @@ class AppState { String get getHuaweiPushToken => _huaweiPushToken; - final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 6.0, mobileType: Platform.isAndroid ? "android" : "ios"); + final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 9.0, mobileType: Platform.isAndroid ? "android" : "ios"); void setPostParamsInitConfig() { isAuthenticated = false; -- 2.30.2 From ea7467502fcb225eef3792e0a6b348221639a219 Mon Sep 17 00:00:00 2001 From: Sultan khan <> Date: Tue, 24 Sep 2024 17:02:50 +0300 Subject: [PATCH 037/135] updated changes for payment worklist. --- assets/langs/ar-SA.json | 16 ++++- assets/langs/en-US.json | 16 ++++- lib/generated/codegen_loader.g.dart | 19 ++++- lib/generated/locale_keys.g.dart | 15 +++- .../worklist_fragments/info_fragments.dart | 72 +++++++++++++++++-- 5 files changed, 129 insertions(+), 9 deletions(-) diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index c59641b..5a27f0b 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -544,5 +544,19 @@ "addAtLeastOneAttachment": "الرجاء إضافة مرفق واحد على الأقل.", "pleaseClickButtonToJoinMarathon": "الرجاء الضغط على الزر أدناه للانضمام إلى الماراثون", "youCannotJoinTheMarathon": "لا يمكنك الانضمام إلى الماراثون لأنك تجاوزت الحد الزمني", - "open": "يفتح" + "open": "يفتح", + "requesterOperatingUnit":"وحدة تشغيل مقدم الطلب", + "prepareEmpNum":"إعداد رقم الموظف", + "supplierInfo" : "معلومات المورد", + "supplierAcNo": "رقم حساب المورد", + "supplierAcName": "اسم حساب المورد", + "supplierIBAN" : "رقم IBAN للمورد", + "supplierCRNo" :"رقم السجل التجاري", + "suppliedAcNo" : "رقم الحساب المقدم", + "patientRefundInvoice" : "فاتورة استرداد الأموال للمريض", + "patientNumber" : "رقم المريض", + "patientName" : "اسم المريض", + "invoiceDate" : "تاريخ الفاتورة", + "refundInvoice" :"فاتورة الاسترجاع", + "hospitalClinic" : "عيادة المستشفى" } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 275864f..2a9ece6 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -563,5 +563,19 @@ "open": "open", "addAtLeastOneAttachment": "Please add at least one attachment.", "pleaseClickButtonToJoinMarathon": "Press the button below to join the Marathon.", - "youCannotJoinTheMarathon": "You cannot join the Marathon because you have exceeded the time limit." + "youCannotJoinTheMarathon": "You cannot join the Marathon because you have exceeded the time limit.", + "requesterOperatingUnit":"Requester Operating Unit", + "prepareEmpNum":"Prepare Employee Num", + "supplierInfo" : "Supplier Information", + "supplierAcNo": "Supplier Account No", + "supplierAcName":"Supplier Account Name", + "supplierIBAN" : "Supplier IBAN", + "supplierCRNo" : "CR Number", + "suppliedAcNo" : "Supplied Account No.", + "patientRefundInvoice" : "Patient Refund Invoice", + "patientNumber" : "Patient Number", + "patientName" : "Patient Name", + "invoiceDate" : "Invoice Date", + "refundInvoice" :"Refund Invoice", + "hospitalClinic" : "Hospital Clinic" } \ No newline at end of file diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index 15cdb5b..2fb8722 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -558,9 +558,11 @@ class CodegenLoader extends AssetLoader { "requesterEmpNum":"رقم الموظف الذي قدم الطلب", "requesterEmpName":"اسم الموظف مقدم الطلب", "prepareEmpName":"إعداد اسم الموظف", + "prepareEmpNum":"إعداد رقم الموظف", "requesterPositionName":"اسم الوظيفة لمقدم الطلب", "preparePositionName":"إعداد اسم الوظيفة", "requesterPayrollName":"اسم مقدم الطلب", + "requesterOperatingUnit":"وحدة تشغيل مقدم الطلب", "payingORGName":"اسم المنظمة الدافعة", "requestAmount":"مبلغ الطلب", "typeofPayment":"نوع الدفع", @@ -1158,7 +1160,22 @@ class CodegenLoader extends AssetLoader { "pOAmount":"PO Amount", "versionStatus":"Version Status", "supplierNo":"Supplier No", - "general":"General" + "general":"General", + "prepareEmpNum":"Prepare Employee Num", + "requesterOperatingUnit":"Requester Operating Unit", + "supplierInfo" : "Supplier Information", + "supplierNum": "Supplier Number", + "supplierAcNo": "Supplier Account Number", + "supplierAcName" : 'Supplier Account Name', + "supplierIBAN" : 'Supplier IBAN', + "supplierCRNo" : 'CR Number', + "suppliedAcNo" : 'Supplied Account No.', + "patientRefundInvoice" : 'Patient Refund Invoice', + "patientNumber" : 'Patient Number', + "patientName" : 'Patient Name', + "invoiceDate" : 'Invoice Date', + "refundInvoice" : 'Refund Invoice', + "hospitalClinic" : 'Hospital Clinic', }; static const Map> mapLocales = {"ar_SA": ar_SA, "en_US": en_US}; } diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 0ec89e4..72bbfc1 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -557,9 +557,11 @@ abstract class LocaleKeys { static const requesterEmpNum ='requesterEmpNum'; static const requesterEmpName ='requesterEmpName'; static const prepareEmpName ='prepareEmpName'; + static const prepareEmpNum ='prepareEmpNum'; static const requesterPositionName ='requesterPositionName'; static const preparePositionName ='preparePositionName'; static const requesterPayrollName ='requesterPayrollName'; + static const requesterOperatingUnit ='requesterOperatingUnit'; static const payingORGName ='payingORGName'; static const requestAmount ='requestAmount'; static const typeofPayment ='typeofPayment'; @@ -575,5 +577,16 @@ abstract class LocaleKeys { static const versionStatus ='versionStatus'; static const supplierNo ='supplierNo'; static const general ="general"; - + static const supplierInfo = 'supplierInfo'; + static const supplierAcNo = 'supplierAcNo'; + static const supplierAcName = 'supplierAcName'; + static const supplierIBAN = 'Supplier IBAN'; + static const supplierCRNo = 'CR Number'; + static const suppliedAcNo = 'Supplied Account No.'; + static const patientRefundInvoice = "patientRefundInvoice"; + static const patientNumber = 'Patient Number'; + static const patientName = 'Patient Name'; + static const invoiceDate = 'Invoice Date'; + static const refundInvoice = 'Refund Invoice'; + static const hospitalClinic = 'Hospital Clinic'; } diff --git a/lib/ui/work_list/worklist_fragments/info_fragments.dart b/lib/ui/work_list/worklist_fragments/info_fragments.dart index 1351126..2d0794c 100644 --- a/lib/ui/work_list/worklist_fragments/info_fragments.dart +++ b/lib/ui/work_list/worklist_fragments/info_fragments.dart @@ -739,7 +739,7 @@ class InfoFragment extends StatelessWidget { ItemDetailViewCol( LocaleKeys.requestNumber.tr(), data.paymentDetailsList![0].requestNumber ?? ""), ItemDetailViewCol( LocaleKeys.requesterEmpNum.tr(), - data.paymentDetailsList![0].requesterEmployeeName ?? ""), + data.paymentDetailsList![0].requesterEmployeeNumber ?? ""), ), ItemDetailGrid( ItemDetailViewCol( LocaleKeys.requestDate.tr(), @@ -748,18 +748,25 @@ class InfoFragment extends StatelessWidget { ItemDetailViewCol( LocaleKeys.requesterEmpName.tr(), data.paymentDetailsList![0].requesterEmployeeName ?? ""), ), + ItemDetailGrid( + ItemDetailViewCol( LocaleKeys.prepareEmpNum.tr(), + data.paymentDetailsList![0].prepareEmployeeNumber ?? ""), + ItemDetailViewCol( + LocaleKeys.requesterPositionName.tr(), data.paymentDetailsList![0].requesterPositionName ?? ""), + ), ItemDetailGrid( ItemDetailViewCol( LocaleKeys.prepareEmpName.tr(), data.paymentDetailsList![0].prepareEmployeeName ?? ""), ItemDetailViewCol( - LocaleKeys.requesterPositionName.tr(), data.paymentDetailsList![0].requesterPositionName ?? ""), + LocaleKeys.requesterPayrollName.tr(), data.paymentDetailsList![0].requesterPayrollName ?? ""), ), ItemDetailGrid( ItemDetailViewCol( LocaleKeys.preparePositionName.tr(), data.paymentDetailsList![0].preparePositionName ?? ""), - ItemDetailViewCol( - LocaleKeys.requesterPayrollName.tr(), data.paymentDetailsList![0].requesterPayrollName ?? ""), + ItemDetailViewCol( LocaleKeys.requesterOperatingUnit.tr(), + data.paymentDetailsList![0].requesterOperatingUnits ?? "") ), + ], ).objectContainerView(), if (data!.paymentDetailsList!.isNotEmpty) @@ -843,7 +850,62 @@ class InfoFragment extends StatelessWidget { ), ], ).objectContainerView(), - ], + + if (data!.supplierInformationList!.isNotEmpty && data.supplierInformationList![0].supplierNumber !="") + Column( + children: [ + LocaleKeys.supplierInfo.tr().toText14(color: MyColors.textMixColor), + ItemDetailGrid( + ItemDetailViewCol( + LocaleKeys.supplierNo.tr(), data.supplierInformationList![0].supplierNumber ?? ""), + ItemDetailViewCol(LocaleKeys.supplierName.tr(), + data.supplierInformationList![0].supplierName.toString() ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.supplierAcNo.tr(), + data.supplierInformationList![0].supplierBankAccountNumber ?? ""), + ItemDetailViewCol( + LocaleKeys.supplierAcName.tr(), data.supplierInformationList![0].supplierBankAccountName ?? + "" ), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.supplierCRNo.tr(), + data.supplierInformationList![0].crNumber?? ""), + ItemDetailViewCol( LocaleKeys.supplierIBAN.tr(), data.supplierInformationList![0].supplierBankIban ?? + "" ), + ), + + ], + ).objectContainerView(), + // + if (data!.refundInvoiceList!.isNotEmpty && data.refundInvoiceList![0].patientNumber !="" ) + Column( + children: [ + LocaleKeys.patientRefundInvoice.tr().toText14(color: MyColors.textMixColor), + ItemDetailGrid( + ItemDetailViewCol( + LocaleKeys.patientNumber.tr(), data.refundInvoiceList![0].patientNumber?? ""), + ItemDetailViewCol(LocaleKeys.hospitalClinic.tr(), + data.refundInvoiceList![0].hospitalClinic.toString() ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.patientName.tr(), + data.refundInvoiceList![0].patientName ?? ""), + ItemDetailViewCol( + LocaleKeys.amount.tr(), data.refundInvoiceList![0].amount.toString() ?? + "" ), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.invoiceDate.tr(), + DateUtil.formatDateToDate( + DateUtil.convertStringToDate( data.refundInvoiceList![0].invoicedDate), false)?? ""), + ItemDetailViewCol( LocaleKeys.refundInvoice.tr(), data.refundInvoiceList![0].invoiceNumber ?? + "" ), + ), + + ], + ).objectContainerView(), + ], ); } } -- 2.30.2 From 368d109d9ffcc82390ee2b3a1137de57417a6a40 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Sun, 6 Oct 2024 09:48:56 +0300 Subject: [PATCH 038/135] absence days fix --- lib/models/leave_balance/calculate_absence_duration_model.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/models/leave_balance/calculate_absence_duration_model.dart b/lib/models/leave_balance/calculate_absence_duration_model.dart index cf32a0e..df6a5d2 100644 --- a/lib/models/leave_balance/calculate_absence_duration_model.dart +++ b/lib/models/leave_balance/calculate_absence_duration_model.dart @@ -1,5 +1,5 @@ class CalculateAbsenceDuration { - double? pABSENCEDAYS; + num? pABSENCEDAYS; double? pABSENCEHOURS; String? pRETURNMSG; String? pRETURNSTATUS; -- 2.30.2 From 11881b0ba1a8792b6a7e270b20c44d0641ba7ac2 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Wed, 16 Oct 2024 18:07:00 +0300 Subject: [PATCH 039/135] hotfix for payment request WL --- assets/langs/ar-SA.json | 17 +- assets/langs/en-US.json | 17 +- lib/generated/codegen_loader.g.dart | 25 +- lib/generated/locale_keys.g.dart | 14 + lib/ui/work_list/itg_detail_screen.dart | 1 + .../worklist_fragments/info_fragments.dart | 656 ++++++++++-------- 6 files changed, 429 insertions(+), 301 deletions(-) diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index c59641b..6370baf 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -544,5 +544,20 @@ "addAtLeastOneAttachment": "الرجاء إضافة مرفق واحد على الأقل.", "pleaseClickButtonToJoinMarathon": "الرجاء الضغط على الزر أدناه للانضمام إلى الماراثون", "youCannotJoinTheMarathon": "لا يمكنك الانضمام إلى الماراثون لأنك تجاوزت الحد الزمني", - "open": "يفتح" + "open": "يفتح", + "requesterOperatingUnit":"وحدة تشغيل مقدم الطلب", + "prepareEmpNum":"إعداد رقم الموظف", + "supplierInfo" : "معلومات المورد", + "supplierAcNo": "رقم حساب المورد", + "supplierAcName": "اسم حساب المورد", + "supplierIBAN" : "رقم IBAN للمورد", + "supplierCRNo" :"رقم السجل التجاري", + "suppliedAcNo" : "رقم الحساب المقدم", + "patientRefundInvoice" : "فاتورة استرداد الأموال للمريض", + "patientNumber" : "رقم المريض", + "patientName" : "اسم المريض", + "invoiceDate" : "تاريخ الفاتورة", + "refundInvoice" :"فاتورة الاسترجاع", + "hospitalClinic" : "عيادة المستشفى" + } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 275864f..61bba1d 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -563,5 +563,20 @@ "open": "open", "addAtLeastOneAttachment": "Please add at least one attachment.", "pleaseClickButtonToJoinMarathon": "Press the button below to join the Marathon.", - "youCannotJoinTheMarathon": "You cannot join the Marathon because you have exceeded the time limit." + "youCannotJoinTheMarathon": "You cannot join the Marathon because you have exceeded the time limit.", + "requesterOperatingUnit":"Requester Operating Unit", + "prepareEmpNum":"Prepare Employee Num", + "supplierInfo" : "Supplier Information", + "supplierAcNo": "Supplier Account No", + "supplierAcName":"Supplier Account Name", + "supplierIBAN" : "Supplier IBAN", + "supplierCRNo" : "CR Number", + "suppliedAcNo" : "Supplied Account No.", + "patientRefundInvoice" : "Patient Refund Invoice", + "patientNumber" : "Patient Number", + "patientName" : "Patient Name", + "invoiceDate" : "Invoice Date", + "refundInvoice" :"Refund Invoice", + "hospitalClinic" : "Hospital Clinic" + } \ No newline at end of file diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index 4a0d665..357d6eb 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -575,7 +575,10 @@ class CodegenLoader extends AssetLoader { "pOAmount":"مبلغ الطلب", "versionStatus":"حالة الإصدار", "supplierNo":"رقم المورد", - "general":"عام" + "general":"عام", + "requesterOperatingUnit":"وحدة تشغيل مقدم الطلب", + "prepareEmpNum":"إعداد رقم الموظف", + }; static const Map en_US = { "mohemm": "Mohemm", @@ -1157,7 +1160,25 @@ class CodegenLoader extends AssetLoader { "pOAmount":"PO Amount", "versionStatus":"Version Status", "supplierNo":"Supplier No", - "general":"General" + "general":"General", + "prepareEmpNum":"Prepare Employee Num", + "requesterOperatingUnit":"Requester Operating Unit", + "supplierInfo" : "Supplier Information", + "supplierNum": "Supplier Number", + "supplierAcNo": "Supplier Account Number", + "supplierAcName" : 'Supplier Account Name', + "supplierIBAN" : 'Supplier IBAN', + "supplierCRNo" : 'CR Number', + "suppliedAcNo" : 'Supplied Account No.', + "patientRefundInvoice" : 'Patient Refund Invoice', + "patientNumber" : 'Patient Number', + "patientName" : 'Patient Name', + "invoiceDate" : 'Invoice Date', + "refundInvoice" : 'Refund Invoice', + "hospitalClinic" : 'Hospital Clinic', + + + }; static const Map> mapLocales = {"ar_SA": ar_SA, "en_US": en_US}; } diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 0ec89e4..9faea5a 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -575,5 +575,19 @@ abstract class LocaleKeys { static const versionStatus ='versionStatus'; static const supplierNo ='supplierNo'; static const general ="general"; + static const supplierInfo = 'supplierInfo'; + static const supplierAcNo = 'supplierAcNo'; + static const supplierAcName = 'supplierAcName'; + static const supplierIBAN = 'Supplier IBAN'; + static const supplierCRNo = 'CR Number'; + static const suppliedAcNo = 'Supplied Account No.'; + static const patientRefundInvoice = "patientRefundInvoice"; + static const patientNumber = 'Patient Number'; + static const patientName = 'Patient Name'; + static const invoiceDate = 'Invoice Date'; + static const refundInvoice = 'Refund Invoice'; + static const hospitalClinic = 'Hospital Clinic'; + static const requesterOperatingUnit ='requesterOperatingUnit'; + static const prepareEmpNum ='prepareEmpNum'; } diff --git a/lib/ui/work_list/itg_detail_screen.dart b/lib/ui/work_list/itg_detail_screen.dart index 2381b70..8cb7944 100644 --- a/lib/ui/work_list/itg_detail_screen.dart +++ b/lib/ui/work_list/itg_detail_screen.dart @@ -95,6 +95,7 @@ class _ItgDetailScreenState extends State { requestDetails = AppState().requestAllList![AppState().itgWorkListIndex!]; // ModalRoute.of(context)!.settings.arguments as WorkListResponseModel; providerData.itgFormsModel!.totalCount = providerData.itgFormsModel!.totalCount! - 1; getItgData(); + Utils.hideLoading(context); getItgRequestAttachments(); } } diff --git a/lib/ui/work_list/worklist_fragments/info_fragments.dart b/lib/ui/work_list/worklist_fragments/info_fragments.dart index 1351126..76f2ace 100644 --- a/lib/ui/work_list/worklist_fragments/info_fragments.dart +++ b/lib/ui/work_list/worklist_fragments/info_fragments.dart @@ -29,11 +29,11 @@ class InfoFragment extends StatelessWidget { List? getStampNsNotifications; List itemCreationHeader; List? - getEitCollectionNotificationBodyList; + getEitCollectionNotificationBodyList; List? getPhonesNotificationBodyList; List? getBasicDetNtfBodyList; List? - getAbsenceCollectionNotificationBodyList; + getAbsenceCollectionNotificationBodyList; GetContactNotificationBodyList? getContactNotificationBodyList; GetPrNotificationBodyList? getPrNotificationBodyList; List? getAddressNotificationBodyList = []; @@ -42,19 +42,19 @@ class InfoFragment extends StatelessWidget { InfoFragment( {this.workListData, - this.poHeaderList = const [], - this.itemCreationHeader = const [], - this.getStampMsNotifications, - this.getStampNsNotifications, - this.getEitCollectionNotificationBodyList, - this.getPhonesNotificationBodyList, - this.getBasicDetNtfBodyList, - this.getAbsenceCollectionNotificationBodyList, - this.getContactNotificationBodyList, - this.getPrNotificationBodyList, - this.getAddressNotificationBodyList, - this.getTerminationNotificationBodyList, - this.getPaymentNotificationBodyList}); + this.poHeaderList = const [], + this.itemCreationHeader = const [], + this.getStampMsNotifications, + this.getStampNsNotifications, + this.getEitCollectionNotificationBodyList, + this.getPhonesNotificationBodyList, + this.getBasicDetNtfBodyList, + this.getAbsenceCollectionNotificationBodyList, + this.getContactNotificationBodyList, + this.getPrNotificationBodyList, + this.getAddressNotificationBodyList, + this.getTerminationNotificationBodyList, + this.getPaymentNotificationBodyList}); double itemHeight = 0; double itemWidth = 0; @@ -120,7 +120,7 @@ class InfoFragment extends StatelessWidget { getAbsenceCollectionNotificationBodyList ?? []), if (getContactNotificationBodyList != null) getContactNotificationBodyListWidget(getContactNotificationBodyList ?? - GetContactNotificationBodyList()) + GetContactNotificationBodyList()) .objectContainerView(), if (getAddressNotificationBodyList?.isNotEmpty ?? false) getAddressNotificationBodyListWidget(getAddressNotificationBodyList!), @@ -129,7 +129,7 @@ class InfoFragment extends StatelessWidget { getTerminationNotificationBodyList!), if (getPaymentNotificationBodyList != null) getPaymentNotificationBodyListWidget(getPaymentNotificationBodyList ?? - GetPaymentNotificationBodyList()) + GetPaymentNotificationBodyList()) .objectContainerView(), ]; return Container( @@ -138,9 +138,9 @@ class InfoFragment extends StatelessWidget { child: uiList.isEmpty ? LocaleKeys.noDataAvailable.tr().toText16().center : ListView( - padding: const EdgeInsets.all(21), - children: uiList, - ), + padding: const EdgeInsets.all(21), + children: uiList, + ), ); } @@ -149,93 +149,93 @@ class InfoFragment extends StatelessWidget { shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemBuilder: (BuildContext cxt, int index) => Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Column( + children: [ + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.description.tr(), + workListData!.fROMUSER ?? ""), + ItemDetailViewCol( + LocaleKeys.from.tr(), workListData!.fROMUSER ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol( + LocaleKeys.to.tr(), workListData!.tOUSER ?? ""), + ItemDetailViewCol( + LocaleKeys.sent.tr(), workListData!.bEGINDATE ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol( + LocaleKeys.closed.tr(), workListData!.eNDDATE ?? ""), + ItemDetailViewCol(LocaleKeys.id.tr(), + workListData!.nOTIFICATIONID?.toString() ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.supplier.tr(), + poHeaderList[index].vENDORNAME ?? ""), + ItemDetailViewCol(LocaleKeys.site.tr(), + poHeaderList[index].vENDORSITECODE ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.buyer.tr(), + poHeaderList[index].bUYER ?? ""), + ItemDetailViewCol(LocaleKeys.preparer.tr(), + poHeaderList[index].pREPARER ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.creationDate.tr(), + poHeaderList[index].cREATIONDATE ?? ""), + ItemDetailViewCol(LocaleKeys.shipToLocation.tr(), + poHeaderList[index].sHIPTOLOCATIONNAME ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.quotationNumber.tr(), + poHeaderList[index].qUOTATIONNUMBER ?? ""), + ItemDetailViewCol(LocaleKeys.quotationDate.tr(), + poHeaderList[index].qUOTATIONDATE ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.paymentTerms.tr(), + poHeaderList[index].pAYMENTTERMS ?? ""), + ItemDetailViewCol(LocaleKeys.currency.tr(), + poHeaderList[index].cURRENCYNAME ?? ""), + isItLast: true, + ), + ], + ).objectContainerView(title: LocaleKeys.infoDetail.tr()), + 12.height, + Column( children: [ - Column( - children: [ - ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.description.tr(), - workListData!.fROMUSER ?? ""), - ItemDetailViewCol( - LocaleKeys.from.tr(), workListData!.fROMUSER ?? ""), - ), - ItemDetailGrid( - ItemDetailViewCol( - LocaleKeys.to.tr(), workListData!.tOUSER ?? ""), - ItemDetailViewCol( - LocaleKeys.sent.tr(), workListData!.bEGINDATE ?? ""), - ), - ItemDetailGrid( - ItemDetailViewCol( - LocaleKeys.closed.tr(), workListData!.eNDDATE ?? ""), - ItemDetailViewCol(LocaleKeys.id.tr(), - workListData!.nOTIFICATIONID?.toString() ?? ""), - ), - ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.supplier.tr(), - poHeaderList[index].vENDORNAME ?? ""), - ItemDetailViewCol(LocaleKeys.site.tr(), - poHeaderList[index].vENDORSITECODE ?? ""), - ), - ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.buyer.tr(), - poHeaderList[index].bUYER ?? ""), - ItemDetailViewCol(LocaleKeys.preparer.tr(), - poHeaderList[index].pREPARER ?? ""), - ), - ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.creationDate.tr(), - poHeaderList[index].cREATIONDATE ?? ""), - ItemDetailViewCol(LocaleKeys.shipToLocation.tr(), - poHeaderList[index].sHIPTOLOCATIONNAME ?? ""), - ), - ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.quotationNumber.tr(), - poHeaderList[index].qUOTATIONNUMBER ?? ""), - ItemDetailViewCol(LocaleKeys.quotationDate.tr(), - poHeaderList[index].qUOTATIONDATE ?? ""), - ), - ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.paymentTerms.tr(), - poHeaderList[index].pAYMENTTERMS ?? ""), - ItemDetailViewCol(LocaleKeys.currency.tr(), - poHeaderList[index].cURRENCYNAME ?? ""), - isItLast: true, - ), - ], - ).objectContainerView(title: LocaleKeys.infoDetail.tr()), - 12.height, - Column( - children: [ - ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.grossAmount.tr(), - poHeaderList[index].gROSSAMOUNT?.toString() ?? ""), - ItemDetailViewCol(LocaleKeys.discountAmount.tr(), - poHeaderList[index].dISCOUNTAMOUNT?.toString() ?? ""), - ), - ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.customDuty.tr(), - poHeaderList[index].cUSTOMDUTY?.toString() ?? ""), - ItemDetailViewCol(LocaleKeys.shipHandle.tr(), - poHeaderList[index].sHIPHANDLE?.toString() ?? ""), - ), - ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.otherCharges.tr(), - poHeaderList[index].oTHERCHARGES?.toString() ?? ""), - ItemDetailViewCol(LocaleKeys.totalPOAmountWithVAT.tr(), - poHeaderList[index].lOCCURTOTPOAMT.toString() ?? ""), - ), - ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.totalPOAmountInWords.tr(), - poHeaderList[index].tOTPOAMTWORD ?? ""), - Container(), - isItLast: true, - ), - ], - ).objectContainerView(title: LocaleKeys.amount_detail.tr()), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.grossAmount.tr(), + poHeaderList[index].gROSSAMOUNT?.toString() ?? ""), + ItemDetailViewCol(LocaleKeys.discountAmount.tr(), + poHeaderList[index].dISCOUNTAMOUNT?.toString() ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.customDuty.tr(), + poHeaderList[index].cUSTOMDUTY?.toString() ?? ""), + ItemDetailViewCol(LocaleKeys.shipHandle.tr(), + poHeaderList[index].sHIPHANDLE?.toString() ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.otherCharges.tr(), + poHeaderList[index].oTHERCHARGES?.toString() ?? ""), + ItemDetailViewCol(LocaleKeys.totalPOAmountWithVAT.tr(), + poHeaderList[index].lOCCURTOTPOAMT.toString() ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.totalPOAmountInWords.tr(), + poHeaderList[index].tOTPOAMTWORD ?? ""), + Container(), + isItLast: true, + ), ], - ), + ).objectContainerView(title: LocaleKeys.amount_detail.tr()), + ], + ), separatorBuilder: (BuildContext cxt, int index) => 4.height, itemCount: poHeaderList.length); } @@ -256,55 +256,55 @@ class InfoFragment extends StatelessWidget { shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemBuilder: (BuildContext cxt, int index) => Column( - mainAxisSize: MainAxisSize.min, - children: [ - ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.employeeNumber.tr(), - list[index].eMPLOYEENUMBER.toString()), - ItemDetailViewCol(LocaleKeys.assignmentNumber.tr(), - list[index].aSSIGNMENTNUMBER.toString()), - ), - ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.employeeName.tr(), - list[index].eMPLOYEENAME.toString()), - ItemDetailViewCol( - LocaleKeys.scheduleDate.tr(), - DateUtil.formatDateToDate( - DateUtil.convertStringToDate( - list[index].sCHEDULEDATE.toString()), - false)), - ), - ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.shiftType.tr(), - list[index].sHTTYPEDESC.toString()), - ItemDetailViewCol( - LocaleKeys.shift.tr(), list[index].sHTNAME.toString()), - ), - ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.breakText.tr(), - list[index].bREAKNAME.toString()), - ItemDetailViewCol(LocaleKeys.actualSwipeStart.tr(), - list[index].sHTACTUALSTARTTIME.toString()), - ), - ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.actualSwipeEnd.tr(), - list[index].sHTACTUALENDTIME.toString()), - ItemDetailViewCol(LocaleKeys.approvedSwipeStart.tr(), - list[index].aPPROVEDSTARTTIME.toString()), - ), - ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.approvedSwipeStartReason.tr(), - list[index].aPPROVEDSTARTREASON.toString()), - ItemDetailViewCol(LocaleKeys.approvedSwipeEnd.tr(), ""), - ), - ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.approvedSwipeEndReason.tr(), - list[index].aPPROVEDENDREASONDESC.toString()), - Container(), - isItLast: true, - ), - ], - ).objectContainerView(), + mainAxisSize: MainAxisSize.min, + children: [ + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.employeeNumber.tr(), + list[index].eMPLOYEENUMBER.toString()), + ItemDetailViewCol(LocaleKeys.assignmentNumber.tr(), + list[index].aSSIGNMENTNUMBER.toString()), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.employeeName.tr(), + list[index].eMPLOYEENAME.toString()), + ItemDetailViewCol( + LocaleKeys.scheduleDate.tr(), + DateUtil.formatDateToDate( + DateUtil.convertStringToDate( + list[index].sCHEDULEDATE.toString()), + false)), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.shiftType.tr(), + list[index].sHTTYPEDESC.toString()), + ItemDetailViewCol( + LocaleKeys.shift.tr(), list[index].sHTNAME.toString()), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.breakText.tr(), + list[index].bREAKNAME.toString()), + ItemDetailViewCol(LocaleKeys.actualSwipeStart.tr(), + list[index].sHTACTUALSTARTTIME.toString()), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.actualSwipeEnd.tr(), + list[index].sHTACTUALENDTIME.toString()), + ItemDetailViewCol(LocaleKeys.approvedSwipeStart.tr(), + list[index].aPPROVEDSTARTTIME.toString()), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.approvedSwipeStartReason.tr(), + list[index].aPPROVEDSTARTREASON.toString()), + ItemDetailViewCol(LocaleKeys.approvedSwipeEnd.tr(), ""), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.approvedSwipeEndReason.tr(), + list[index].aPPROVEDENDREASONDESC.toString()), + Container(), + isItLast: true, + ), + ], + ).objectContainerView(), separatorBuilder: (BuildContext cxt, int index) => 1.height.paddingOnly(top: 8, bottom: 8), itemCount: list.length); @@ -316,27 +316,27 @@ class InfoFragment extends StatelessWidget { shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemBuilder: (BuildContext cxt, int index) => Column( - mainAxisSize: MainAxisSize.min, - children: [ - ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.employeeNumber.tr(), - list[index].eMPLOYEENUMBER.toString()), - ItemDetailViewCol(LocaleKeys.assignmentNumber.tr(), - list[index].aSSIGNMENTNUMBER.toString()), - ), - ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.employeeName.tr(), - list[index].eMPLOYEENAME.toString()), - ItemDetailViewCol( - LocaleKeys.scheduleDate.tr(), - DateUtil.formatDateToDate( - DateUtil.convertStringToDate( - list[index].sCHEDULEDATE.toString()), - false)), - isItLast: true, - ), - ], - ).objectContainerView(), + mainAxisSize: MainAxisSize.min, + children: [ + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.employeeNumber.tr(), + list[index].eMPLOYEENUMBER.toString()), + ItemDetailViewCol(LocaleKeys.assignmentNumber.tr(), + list[index].aSSIGNMENTNUMBER.toString()), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.employeeName.tr(), + list[index].eMPLOYEENAME.toString()), + ItemDetailViewCol( + LocaleKeys.scheduleDate.tr(), + DateUtil.formatDateToDate( + DateUtil.convertStringToDate( + list[index].sCHEDULEDATE.toString()), + false)), + isItLast: true, + ), + ], + ).objectContainerView(), separatorBuilder: (BuildContext cxt, int index) => 1.height.paddingOnly(top: 8, bottom: 8), itemCount: list.length); @@ -347,48 +347,48 @@ class InfoFragment extends StatelessWidget { shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemBuilder: (BuildContext cxt, int index) => Column( - mainAxisSize: MainAxisSize.min, - children: [ - ItemDetailGrid( - ItemDetailViewCol( - LocaleKeys.operatingUnit.tr(), - itemCreationHeader[index].oPERATINGUNIT?.toString() ?? - ""), - ItemDetailViewCol(LocaleKeys.category.tr(), - itemCreationHeader[index].cATEGORY?.toString() ?? ""), - ), - ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.requester.tr(), - itemCreationHeader[index].rEQUESTER?.toString() ?? ""), - ItemDetailViewCol(LocaleKeys.analyzedBy.tr(), - itemCreationHeader[index].aNALYZEDBY?.toString() ?? ""), - ), - ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.approvedDate.tr(), - itemCreationHeader[index].aPPROVEDDATE?.toString() ?? ""), - ItemDetailViewCol(LocaleKeys.itemType.tr(), - itemCreationHeader[index].iTEMTYPE?.toString() ?? ""), - ), - ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.relatedTo.tr(), - itemCreationHeader[index].rELATEDTO?.toString() ?? ""), - ItemDetailViewCol( - LocaleKeys.requestDate.tr(), - DateUtil.formatDateToDate( - DateUtil.convertStringToDate( - itemCreationHeader[index].rEQUESTDATE.toString()), - false)), - ), - ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.analyzedDate.tr(), - itemCreationHeader[index].aNALYZEDDATE?.toString() ?? ""), - ItemDetailViewCol( - LocaleKeys.urgent.tr(), - itemCreationHeader[index].uRGENTFLAGDISP?.toString() ?? - ""), - ), - ], - ).objectContainerView(), + mainAxisSize: MainAxisSize.min, + children: [ + ItemDetailGrid( + ItemDetailViewCol( + LocaleKeys.operatingUnit.tr(), + itemCreationHeader[index].oPERATINGUNIT?.toString() ?? + ""), + ItemDetailViewCol(LocaleKeys.category.tr(), + itemCreationHeader[index].cATEGORY?.toString() ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.requester.tr(), + itemCreationHeader[index].rEQUESTER?.toString() ?? ""), + ItemDetailViewCol(LocaleKeys.analyzedBy.tr(), + itemCreationHeader[index].aNALYZEDBY?.toString() ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.approvedDate.tr(), + itemCreationHeader[index].aPPROVEDDATE?.toString() ?? ""), + ItemDetailViewCol(LocaleKeys.itemType.tr(), + itemCreationHeader[index].iTEMTYPE?.toString() ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.relatedTo.tr(), + itemCreationHeader[index].rELATEDTO?.toString() ?? ""), + ItemDetailViewCol( + LocaleKeys.requestDate.tr(), + DateUtil.formatDateToDate( + DateUtil.convertStringToDate( + itemCreationHeader[index].rEQUESTDATE.toString()), + false)), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.analyzedDate.tr(), + itemCreationHeader[index].aNALYZEDDATE?.toString() ?? ""), + ItemDetailViewCol( + LocaleKeys.urgent.tr(), + itemCreationHeader[index].uRGENTFLAGDISP?.toString() ?? + ""), + ), + ], + ).objectContainerView(), separatorBuilder: (BuildContext cxt, int index) => 18.height, itemCount: itemCreationHeader.length); } @@ -401,7 +401,7 @@ class InfoFragment extends StatelessWidget { physics: const NeverScrollableScrollPhysics(), itemBuilder: (BuildContext cxt, int index) { List dataList = - list.isEmpty ? [] : (list[index].collectionNotification ?? []); + list.isEmpty ? [] : (list[index].collectionNotification ?? []); dataList = dataList .where((CollectionNotificationEit o) => o.displayFlag == "Y") .toList(); @@ -416,15 +416,15 @@ class InfoFragment extends StatelessWidget { physics: const NeverScrollableScrollPhysics(), itemBuilder: (BuildContext context, int index) => ItemDetailViewGridItem( - index, - dataList[index].segmentPrompt, - dataList[index].segmentValueDsp, - isNeedToShowEmptyDivider: (dataList.length == index + 1) - ? isOdd + index, + dataList[index].segmentPrompt, + dataList[index].segmentValueDsp, + isNeedToShowEmptyDivider: (dataList.length == index + 1) + ? isOdd ? true : false - : false, - ), + : false, + ), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, childAspectRatio: (itemWidth / itemHeight), @@ -453,8 +453,8 @@ class InfoFragment extends StatelessWidget { list[index].proposedPhoneNumber ?? "", isNeedToShowEmptyDivider: (list.length == index + 1) ? isOdd - ? true - : false + ? true + : false : false, ), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( @@ -490,8 +490,8 @@ class InfoFragment extends StatelessWidget { list[index].segmentValueDsp, isNeedToShowEmptyDivider: (list.length == index + 1) ? isOdd - ? true - : false + ? true + : false : false, ), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( @@ -518,7 +518,7 @@ class InfoFragment extends StatelessWidget { physics: const NeverScrollableScrollPhysics(), itemBuilder: (BuildContext cxt, int index) { List dataList = - list.isEmpty ? [] : (list[index].collectionNotification ?? []); + list.isEmpty ? [] : (list[index].collectionNotification ?? []); dataList = dataList .where((CollectionNotificationAbsence o) => o.dISPLAYFLAG == "Y") .toList(); @@ -534,31 +534,31 @@ class InfoFragment extends StatelessWidget { physics: const NeverScrollableScrollPhysics(), itemBuilder: (BuildContext context, int index) => ItemDetailViewGridItem( - index, - dataList[index].sEGMENTPROMPT, - dataList[index].sEGMENTVALUEDSP, - isNeedToShowEmptyDivider: (dataList.length == index + 1) - ? isOdd + index, + dataList[index].sEGMENTPROMPT, + dataList[index].sEGMENTVALUEDSP, + isNeedToShowEmptyDivider: (dataList.length == index + 1) + ? isOdd ? true : false - : false, - ), + : false, + ), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, childAspectRatio: (itemWidth / itemHeight), ), ).objectContainerView(); return ListView.separated( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemBuilder: (BuildContext cxt, int index) => - dataList[index].dISPLAYFLAG == "Y" - ? ItemDetailViewCol(dataList[index].sEGMENTPROMPT!, - dataList[index].sEGMENTVALUEDSP!) - : Container(), - separatorBuilder: (BuildContext cxt, int index) => - dataList[index].dISPLAYFLAG == "Y" ? 4.height : 0.height, - itemCount: dataList.length) + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (BuildContext cxt, int index) => + dataList[index].dISPLAYFLAG == "Y" + ? ItemDetailViewCol(dataList[index].sEGMENTPROMPT!, + dataList[index].sEGMENTVALUEDSP!) + : Container(), + separatorBuilder: (BuildContext cxt, int index) => + dataList[index].dISPLAYFLAG == "Y" ? 4.height : 0.height, + itemCount: dataList.length) .objectContainerView(); }, separatorBuilder: (BuildContext cxt, int index) => 12.height, @@ -572,9 +572,9 @@ class InfoFragment extends StatelessWidget { children: [ getPrNotificationBodyList.pINFORMATION != null ? getPrNotificationBodyList.pINFORMATION - .toString() - .toText14(color: MyColors.textMixColor) - .objectContainerView() + .toString() + .toText14(color: MyColors.textMixColor) + .objectContainerView() : Container(), 12.height, Column( @@ -625,11 +625,11 @@ class InfoFragment extends StatelessWidget { getAddressNotificationBodyList[index].sEGMENTPROMPT, getAddressNotificationBodyList[index].sEGMENTVALUEDSP, isNeedToShowEmptyDivider: - (getAddressNotificationBodyList.length == index + 1) - ? isOdd - ? true - : false - : false, + (getAddressNotificationBodyList.length == index + 1) + ? isOdd + ? true + : false + : false, ), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, @@ -658,11 +658,11 @@ class InfoFragment extends StatelessWidget { getterminationNotificationBodyList[index].sEGMENTPROMPT, getterminationNotificationBodyList[index].sEGMENTVALUEDSP, isNeedToShowEmptyDivider: - (getterminationNotificationBodyList.length == index + 1) - ? isOdd - ? true - : false - : false, + (getterminationNotificationBodyList.length == index + 1) + ? isOdd + ? true + : false + : false, ), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, @@ -702,11 +702,11 @@ class InfoFragment extends StatelessWidget { data.contactNotificationBody![index].segmentPrompt, data.contactNotificationBody![index].segmentValueDsp, isNeedToShowEmptyDivider: - (data.contactNotificationBody!.length == index + 1) - ? isOdd - ? true - : false - : false, + (data.contactNotificationBody!.length == index + 1) + ? isOdd + ? true + : false + : false, ), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, @@ -730,7 +730,7 @@ class InfoFragment extends StatelessWidget { GetPaymentNotificationBodyList? data) { return Column( children: [ - 12.height, + 12.height, if (data!.paymentDetailsList!.isNotEmpty) Column( children: [ @@ -739,54 +739,61 @@ class InfoFragment extends StatelessWidget { ItemDetailViewCol( LocaleKeys.requestNumber.tr(), data.paymentDetailsList![0].requestNumber ?? ""), ItemDetailViewCol( LocaleKeys.requesterEmpNum.tr(), - data.paymentDetailsList![0].requesterEmployeeName ?? ""), + data.paymentDetailsList![0].requesterEmployeeNumber ?? ""), ), ItemDetailGrid( ItemDetailViewCol( LocaleKeys.requestDate.tr(), - DateUtil.formatDateToDate( - DateUtil.convertStringToDate(data.paymentDetailsList![0].requestDate!), false) ?? ""), + DateUtil.formatDateToDate( + DateUtil.convertStringToDate(data.paymentDetailsList![0].requestDate!), false) ?? ""), ItemDetailViewCol( LocaleKeys.requesterEmpName.tr(), data.paymentDetailsList![0].requesterEmployeeName ?? ""), ), ItemDetailGrid( - ItemDetailViewCol( LocaleKeys.prepareEmpName.tr(), - data.paymentDetailsList![0].prepareEmployeeName ?? ""), + ItemDetailViewCol( LocaleKeys.prepareEmpNum.tr(), + data.paymentDetailsList![0].prepareEmployeeNumber ?? ""), ItemDetailViewCol( LocaleKeys.requesterPositionName.tr(), data.paymentDetailsList![0].requesterPositionName ?? ""), ), ItemDetailGrid( - ItemDetailViewCol( LocaleKeys.preparePositionName.tr(), - data.paymentDetailsList![0].preparePositionName ?? ""), + ItemDetailViewCol( LocaleKeys.prepareEmpName.tr(), + data.paymentDetailsList![0].prepareEmployeeName ?? ""), ItemDetailViewCol( LocaleKeys.requesterPayrollName.tr(), data.paymentDetailsList![0].requesterPayrollName ?? ""), ), + ItemDetailGrid( + ItemDetailViewCol( LocaleKeys.preparePositionName.tr(), + data.paymentDetailsList![0].preparePositionName ?? ""), + ItemDetailViewCol( LocaleKeys.requesterOperatingUnit.tr(), + data.paymentDetailsList![0].requesterOperatingUnits ?? "") + ), + ], ).objectContainerView(), if (data!.paymentDetailsList!.isNotEmpty) - Column( - children: [ - LocaleKeys.general.tr().toText14(color: MyColors.textMixColor), - ItemDetailGrid( - ItemDetailViewCol( - LocaleKeys.payingORGName.tr(), data.paymentDetailsList![0].payingOrganizationName ?? ""), - ItemDetailViewCol(LocaleKeys.requestAmount.tr(), - data.paymentDetailsList![0].requestAmount ?? ""), - ), - ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.paymentMethodName.tr(), - data.paymentDetailsList![0].paymentMethodName ?? ""), - ItemDetailViewCol( - LocaleKeys.currency.tr(), data.paymentDetailsList![0].currency ?? ""), - ), - ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.typeofPayment.tr(), - data.paymentDetailsList![0].typeOfPayment ?? ""), - ItemDetailViewCol( - LocaleKeys.paymentDetails.tr(), data.paymentDetailsList![0].paymentDetails ?? ""), - ), + Column( + children: [ + LocaleKeys.general.tr().toText14(color: MyColors.textMixColor), + ItemDetailGrid( + ItemDetailViewCol( + LocaleKeys.payingORGName.tr(), data.paymentDetailsList![0].payingOrganizationName ?? ""), + ItemDetailViewCol(LocaleKeys.requestAmount.tr(), + data.paymentDetailsList![0].requestAmount ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.paymentMethodName.tr(), + data.paymentDetailsList![0].paymentMethodName ?? ""), + ItemDetailViewCol( + LocaleKeys.currency.tr(), data.paymentDetailsList![0].currency ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.typeofPayment.tr(), + data.paymentDetailsList![0].typeOfPayment ?? ""), + ItemDetailViewCol( + LocaleKeys.paymentDetails.tr(), data.paymentDetailsList![0].paymentDetails ?? ""), + ), - ], - ).objectContainerView(), + ], + ).objectContainerView(), if (data!.beneficieryList!.isNotEmpty) Column( @@ -839,10 +846,65 @@ class InfoFragment extends StatelessWidget { ItemDetailGrid( ItemDetailViewCol(LocaleKeys.supplierNo.tr(), data.purchaseOrdersList![0].supplierNumber?? ""), - Container(), + Container(), ), ], ).objectContainerView(), + + if (data!.supplierInformationList!.isNotEmpty && data.supplierInformationList![0].supplierNumber !="") + Column( + children: [ + LocaleKeys.supplierInfo.tr().toText14(color: MyColors.textMixColor), + ItemDetailGrid( + ItemDetailViewCol( + LocaleKeys.supplierNo.tr(), data.supplierInformationList![0].supplierNumber ?? ""), + ItemDetailViewCol(LocaleKeys.supplierName.tr(), + data.supplierInformationList![0].supplierName.toString() ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.supplierAcNo.tr(), + data.supplierInformationList![0].supplierBankAccountNumber ?? ""), + ItemDetailViewCol( + LocaleKeys.supplierAcName.tr(), data.supplierInformationList![0].supplierBankAccountName ?? + "" ), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.supplierCRNo.tr(), + data.supplierInformationList![0].crNumber?? ""), + ItemDetailViewCol( LocaleKeys.supplierIBAN.tr(), data.supplierInformationList![0].supplierBankIban ?? + "" ), + ), + + ], + ).objectContainerView(), + // + if (data!.refundInvoiceList!.isNotEmpty && data.refundInvoiceList![0].patientNumber !="" ) + Column( + children: [ + LocaleKeys.patientRefundInvoice.tr().toText14(color: MyColors.textMixColor), + ItemDetailGrid( + ItemDetailViewCol( + LocaleKeys.patientNumber.tr(), data.refundInvoiceList![0].patientNumber?? ""), + ItemDetailViewCol(LocaleKeys.hospitalClinic.tr(), + data.refundInvoiceList![0].hospitalClinic.toString() ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.patientName.tr(), + data.refundInvoiceList![0].patientName ?? ""), + ItemDetailViewCol( + LocaleKeys.amount.tr(), data.refundInvoiceList![0].amount.toString() ?? + "" ), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.invoiceDate.tr(), + DateUtil.formatDateToDate( + DateUtil.convertStringToDate( data.refundInvoiceList![0].invoicedDate), false)?? ""), + ItemDetailViewCol( LocaleKeys.refundInvoice.tr(), data.refundInvoiceList![0].invoiceNumber ?? + "" ), + ), + + ], + ).objectContainerView(), ], ); } -- 2.30.2 From b06fb6345ad6979fc459b7ed56a698d869f6d692 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Tue, 12 Nov 2024 16:30:34 +0300 Subject: [PATCH 040/135] actions & attachment api response overlapping other request responses. fixed. --- lib/generated_plugin_registrant.dart | 4 +- lib/ui/work_list/worklist_detail_screen.dart | 297 +++++++------------ 2 files changed, 104 insertions(+), 197 deletions(-) diff --git a/lib/generated_plugin_registrant.dart b/lib/generated_plugin_registrant.dart index b59eec2..213926c 100644 --- a/lib/generated_plugin_registrant.dart +++ b/lib/generated_plugin_registrant.dart @@ -13,7 +13,7 @@ import 'package:firebase_core_web/firebase_core_web.dart'; import 'package:firebase_messaging_web/firebase_messaging_web.dart'; import 'package:fluttertoast/fluttertoast_web.dart'; import 'package:geolocator_web/geolocator_web.dart'; -import 'package:google_maps_flutter_web/google_maps_flutter_web.dart'; +// import 'package:google_maps_flutter_web/google_maps_flutter_web.dart'; import 'package:image_picker_for_web/image_picker_for_web.dart'; import 'package:just_audio_web/just_audio_web.dart'; // import 'package:record_web/record_web.dart'; @@ -32,7 +32,7 @@ void registerPlugins(Registrar registrar) { FirebaseMessagingWeb.registerWith(registrar); FluttertoastWebPlugin.registerWith(registrar); GeolocatorPlugin.registerWith(registrar); - GoogleMapsPlugin.registerWith(registrar); + // GoogleMapsPlugin.registerWith(registrar); ImagePickerPlugin.registerWith(registrar); JustAudioPlugin.registerWith(registrar); //RecordPluginWeb.registerWith(registrar); diff --git a/lib/ui/work_list/worklist_detail_screen.dart b/lib/ui/work_list/worklist_detail_screen.dart index 06e7501..ee595d1 100644 --- a/lib/ui/work_list/worklist_detail_screen.dart +++ b/lib/ui/work_list/worklist_detail_screen.dart @@ -23,6 +23,7 @@ import 'package:mohem_flutter_app/models/get_stamp_ms_notification_body_list_mod import 'package:mohem_flutter_app/models/get_stamp_ns_notification_body_list_model.dart'; import 'package:mohem_flutter_app/models/member_information_list_model.dart'; import 'package:mohem_flutter_app/models/notification_get_respond_attributes_list_model.dart'; +import 'package:mohem_flutter_app/models/termination/termination_notification_body.dart'; import 'package:mohem_flutter_app/models/worklist/GetRFCEmployeeList.dart'; import 'package:mohem_flutter_app/models/worklist/hr/eit_otification_body_model.dart'; import 'package:mohem_flutter_app/models/worklist/hr/get_address_notification_body_list.dart'; @@ -45,7 +46,6 @@ import 'package:mohem_flutter_app/widgets/bottom_sheet.dart'; import 'package:mohem_flutter_app/widgets/button/default_button.dart'; import 'package:mohem_flutter_app/widgets/dialogs/accept_reject_input_dialog.dart'; import 'package:mohem_flutter_app/widgets/dialogs/confirm_dialog.dart'; -import 'package:mohem_flutter_app/models/termination/termination_notification_body.dart'; class WorkListDetailScreen extends StatefulWidget { WorkListDetailScreen({Key? key}) : super(key: key); @@ -70,19 +70,16 @@ class _WorkListDetailScreenState extends State { List getStampMsNotifications = []; List getStampNsNotifications = []; List getMoNotificationBodyList = []; - List getNotificationRespondAttributes = - []; + List getNotificationRespondAttributes = []; NotificationGetRespondAttributesList? notificationNoteInput; List getRFCEmployeeList = []; //HR Details Screen Requests - List? - getEitCollectionNotificationBodyList = []; + List? getEitCollectionNotificationBodyList = []; List? getPhonesNotificationBodyList = []; List? getBasicDetNtfBodyList = []; - List? - getAbsenceCollectionNotificationBodyList = []; + List? getAbsenceCollectionNotificationBodyList = []; GetContactNotificationBodyList? getContactNotificationBodyList; List? getAddressNotificationBodyList = []; List? getTerminationNotificationBodyList = []; @@ -133,8 +130,7 @@ class _WorkListDetailScreenState extends State { getContactNotificationBodyList = null; getAddressNotificationBodyList!.clear(); getPaymentNotificationBodyList = null; - if (workListData!.iTEMTYPE == "HRSSA" || - workListData!.iTEMTYPE == "STAMP") { + if (workListData!.iTEMTYPE == "HRSSA" || workListData!.iTEMTYPE == "STAMP") { getUserInformation(); } @@ -191,8 +187,7 @@ class _WorkListDetailScreenState extends State { void getDataFromState() { if (workListData == null) { - workListData = AppState().workList![AppState() - .workListIndex!]; // ModalRoute.of(context)!.settings.arguments as WorkListResponseModel; + workListData = AppState().workList![AppState().workListIndex!]; // ModalRoute.of(context)!.settings.arguments as WorkListResponseModel; getData(); } } @@ -225,8 +220,7 @@ class _WorkListDetailScreenState extends State { Column( children: [ Container( - padding: const EdgeInsets.only( - left: 21, right: 21, top: 16, bottom: 16), + padding: const EdgeInsets.only(left: 21, right: 21, top: 16, bottom: 16), decoration: const BoxDecoration( borderRadius: BorderRadius.only( bottomLeft: Radius.circular(25), @@ -245,19 +239,13 @@ class _WorkListDetailScreenState extends State { child: Row( children: [ myTab(LocaleKeys.info.tr(), 0), - (workListData!.iTEMTYPE == "HRSSA" || - workListData!.iTEMTYPE == "STAMP") - ? myTab(LocaleKeys.details.tr(), 1) - : myTab(LocaleKeys.request.tr(), 1), + (workListData!.iTEMTYPE == "HRSSA" || workListData!.iTEMTYPE == "STAMP") ? myTab(LocaleKeys.details.tr(), 1) : myTab(LocaleKeys.request.tr(), 1), myTab(LocaleKeys.actions.tr(), 2), myTab(LocaleKeys.attachments.tr(), 3), ], ), ), - if ((workListData?.sUBJECT ?? "").isNotEmpty) - workListData!.sUBJECT! - .toText14() - .paddingOnly(top: 20, right: 21, left: 21), + if ((workListData?.sUBJECT ?? "").isNotEmpty) workListData!.sUBJECT!.toText14().paddingOnly(top: 20, right: 21, left: 21), PageView( controller: controller, onPageChanged: (int pageIndex) { @@ -269,38 +257,26 @@ class _WorkListDetailScreenState extends State { InfoFragment( poHeaderList: getPoNotificationBody?.pOHeader ?? [], workListData: workListData, - itemCreationHeader: - getItemCreationNtfBody?.itemCreationHeader ?? [], + itemCreationHeader: getItemCreationNtfBody?.itemCreationHeader ?? [], getStampMsNotifications: getStampMsNotifications, getStampNsNotifications: getStampNsNotifications, - getEitCollectionNotificationBodyList: - getEitCollectionNotificationBodyList, - getPhonesNotificationBodyList: - getPhonesNotificationBodyList, + getEitCollectionNotificationBodyList: getEitCollectionNotificationBodyList, + getPhonesNotificationBodyList: getPhonesNotificationBodyList, getBasicDetNtfBodyList: getBasicDetNtfBodyList, - getAddressNotificationBodyList: - getAddressNotificationBodyList, - getAbsenceCollectionNotificationBodyList: - getAbsenceCollectionNotificationBodyList, - getContactNotificationBodyList: - getContactNotificationBodyList, + getAddressNotificationBodyList: getAddressNotificationBodyList, + getAbsenceCollectionNotificationBodyList: getAbsenceCollectionNotificationBodyList, + getContactNotificationBodyList: getContactNotificationBodyList, getPrNotificationBodyList: getPrNotificationBody, - getTerminationNotificationBodyList: - getTerminationNotificationBodyList, - getPaymentNotificationBodyList: - getPaymentNotificationBodyList, + getTerminationNotificationBodyList: getTerminationNotificationBodyList, + getPaymentNotificationBodyList: getPaymentNotificationBodyList, ), - (workListData!.iTEMTYPE == "HRSSA" || - workListData!.iTEMTYPE == "STAMP" || workListData!.iTEMTYPE == "PAY_REQ") - ? DetailFragment( - workListData, memberInformationListModel) + (workListData!.iTEMTYPE == "HRSSA" || workListData!.iTEMTYPE == "STAMP" || workListData!.iTEMTYPE == "PAY_REQ") + ? DetailFragment(workListData, memberInformationListModel) : RequestFragment( moNotificationBodyList: getMoNotificationBodyList, poLinesList: getPoNotificationBody?.pOLines ?? [], - itemCreationLines: - getItemCreationNtfBody?.itemCreationLines ?? [], + itemCreationLines: getItemCreationNtfBody?.itemCreationLines ?? [], prLinesList: getPrNotificationBody?.pRLines ?? [], - ), isActionHistoryLoaded ? actionHistoryList.isEmpty @@ -320,13 +296,11 @@ class _WorkListDetailScreenState extends State { ).expanded, if (isApproveAvailable || isRejectAvailable || isCloseAvailable) Container( - padding: const EdgeInsets.only( - top: 14, bottom: 14, left: 21, right: 21), + padding: const EdgeInsets.only(top: 14, bottom: 14, left: 21, right: 21), decoration: const BoxDecoration( color: Colors.white, border: Border( - top: BorderSide( - color: MyColors.lightGreyEFColor, width: 1.0), + top: BorderSide(color: MyColors.lightGreyEFColor, width: 1.0), ), ), child: Row( @@ -335,29 +309,20 @@ class _WorkListDetailScreenState extends State { DefaultButton( LocaleKeys.reject.tr(), () => performAction(rejectAction), - colors: const [ - Color(0xffE47A7E), - Color(0xffDE6D71) - ], + colors: const [Color(0xffE47A7E), Color(0xffDE6D71)], ).expanded, if (isApproveAvailable && isRejectAvailable) 8.width, if (isApproveAvailable) DefaultButton( LocaleKeys.approve.tr(), () => performAction(approveAction), - colors: const [ - Color(0xff28C884), - Color(0xff1BB271) - ], + colors: const [Color(0xff28C884), Color(0xff1BB271)], ).expanded, if (isCloseAvailable) DefaultButton( LocaleKeys.ok.tr(), () => performAction("CLOSE"), - colors: const [ - Color(0xff32D892), - Color(0xff1AB170) - ], + colors: const [Color(0xff32D892), Color(0xff1AB170)], ).expanded, 8.width, Container( @@ -367,11 +332,7 @@ class _WorkListDetailScreenState extends State { shape: BoxShape.circle, color: MyColors.lightGreyE6Color, ), - child: Icon( - showFabOptions - ? Icons.more_vert_rounded - : Icons.more_horiz_rounded, - color: MyColors.darkIconColor), + child: Icon(showFabOptions ? Icons.more_vert_rounded : Icons.more_horiz_rounded, color: MyColors.darkIconColor), ).onPress(() { setState(() { showFabOptions = true; @@ -388,8 +349,7 @@ class _WorkListDetailScreenState extends State { opacity: showFabOptions ? 1 : 0, duration: const Duration(milliseconds: 250), child: Container( - padding: const EdgeInsets.only( - left: 21, right: 21, bottom: 75 - 12), + padding: const EdgeInsets.only(left: 21, right: 21, bottom: 75 - 12), width: double.infinity, height: double.infinity, color: Colors.white.withOpacity(.67), @@ -398,19 +358,15 @@ class _WorkListDetailScreenState extends State { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.end, children: [ - myFab(LocaleKeys.skip.tr(), "assets/images/skip.svg") - .onPress(() { - if (AppState().workList!.length - 1 > - AppState().workListIndex!) { + myFab(LocaleKeys.skip.tr(), "assets/images/skip.svg").onPress(() { + if (AppState().workList!.length - 1 > AppState().workListIndex!) { animationIndex = animationIndex + 1; - AppState().setWorkListIndex = - AppState().workListIndex! + 1; + AppState().setWorkListIndex = AppState().workListIndex! + 1; workListData = null; showFabOptions = false; tabIndex = 0; getDataFromState(); - } else if (AppState().workList!.length - 1 == - AppState().workListIndex!) { + } else if (AppState().workList!.length - 1 == AppState().workListIndex!) { Navigator.pop(context); } }), @@ -428,31 +384,25 @@ class _WorkListDetailScreenState extends State { ], ), ), - floatingActionButton: - (!isApproveAvailable && !isRejectAvailable && !isCloseAvailable) - ? Container( - height: 43, - width: 43, - decoration: const BoxDecoration( - shape: BoxShape.circle, - color: MyColors.lightGreyE6Color, - ), - child: Icon( - showFabOptions - ? Icons.more_vert_rounded - : Icons.more_horiz_rounded, - color: MyColors.darkIconColor), - ).onPress(() { - setState(() { - showFabOptions = true; - }); - }) - : null, + floatingActionButton: (!isApproveAvailable && !isRejectAvailable && !isCloseAvailable) + ? Container( + height: 43, + width: 43, + decoration: const BoxDecoration( + shape: BoxShape.circle, + color: MyColors.lightGreyE6Color, + ), + child: Icon(showFabOptions ? Icons.more_vert_rounded : Icons.more_horiz_rounded, color: MyColors.darkIconColor), + ).onPress(() { + setState(() { + showFabOptions = true; + }); + }) + : null, ); } - List viewApiButtonsList( - List notificationButtonsList) { + List viewApiButtonsList(List notificationButtonsList) { List fabs = []; for (int i = 0; i < notificationButtonsList.length; i++) { if (notificationButtonsList[i].bUTTONACTION! == "REJECTED" || @@ -466,9 +416,7 @@ class _WorkListDetailScreenState extends State { notificationButtonsList[i].bUTTONLABEL!, getActionImage(notificationButtonsList[i].bUTTONACTION!), isIconAsset: true, - ) - .paddingOnly(bottom: 12) - .onPress(() => handleFabAction(notificationButtonsList[i]))); + ).paddingOnly(bottom: 12).onPress(() => handleFabAction(notificationButtonsList[i]))); } return fabs; } @@ -547,8 +495,7 @@ class _WorkListDetailScreenState extends State { )); break; case "ANSWER_INFO": - performAction(notificationButton.bUTTONACTION!, - title: notificationButton.bUTTONLABEL); + performAction(notificationButton.bUTTONACTION!, title: notificationButton.bUTTONLABEL); break; case "RFC": getRFCEmployeeListFunc(); @@ -568,31 +515,21 @@ class _WorkListDetailScreenState extends State { callBackFunc: reloadWorkList, child: UpdateContinueSheet( workListData: workListData, - getEitCollectionNotificationBodyList: - getEitCollectionNotificationBodyList, - dynamicParams: DynamicListViewParams( - workListData!.sUBJECT!, workListData!.fUNCTIONNAME!, - isUpdate: true, - collectionNotificationList: - getEitCollectionNotificationBodyList![0] - .collectionNotification)), + getEitCollectionNotificationBodyList: getEitCollectionNotificationBodyList, + dynamicParams: DynamicListViewParams(workListData!.sUBJECT!, workListData!.fUNCTIONNAME!, + isUpdate: true, collectionNotificationList: getEitCollectionNotificationBodyList![0].collectionNotification)), ); break; case "CONTINUE_ACTION": showMyBottomSheet( context, - type:"CONTINUE_ACTION", + type: "CONTINUE_ACTION", callBackFunc: reloadWorkList, child: UpdateContinueSheet( workListData: workListData, - getEitCollectionNotificationBodyList: - getEitCollectionNotificationBodyList, - dynamicParams: DynamicListViewParams( - workListData!.sUBJECT!, workListData!.fUNCTIONNAME!, - isUpdate: true, - collectionNotificationList: - getEitCollectionNotificationBodyList![0] - .collectionNotification)), + getEitCollectionNotificationBodyList: getEitCollectionNotificationBodyList, + dynamicParams: DynamicListViewParams(workListData!.sUBJECT!, workListData!.fUNCTIONNAME!, + isUpdate: true, collectionNotificationList: getEitCollectionNotificationBodyList![0].collectionNotification)), ); break; case "APPROVE_AND_FORWARD": @@ -604,8 +541,7 @@ class _WorkListDetailScreenState extends State { notificationID: workListData!.nOTIFICATIONID, actionHistoryList: actionHistoryList, callBackFunc: reloadWorkList, - getNotificationRespondAttributes: - getNotificationRespondAttributes, + getNotificationRespondAttributes: getNotificationRespondAttributes, )); break; case "FORWARD": @@ -617,8 +553,7 @@ class _WorkListDetailScreenState extends State { notificationID: workListData!.nOTIFICATIONID, actionHistoryList: actionHistoryList, callBackFunc: reloadWorkList, - getNotificationRespondAttributes: - getNotificationRespondAttributes, + getNotificationRespondAttributes: getNotificationRespondAttributes, )); break; case "DEL": @@ -639,8 +574,7 @@ class _WorkListDetailScreenState extends State { void getRFCEmployeeListFunc() async { try { Utils.showLoading(context); - getRFCEmployeeList = await WorkListApiClient() - .getRFCEmployeeeList(workListData!.nOTIFICATIONID!); + getRFCEmployeeList = await WorkListApiClient().getRFCEmployeeeList(workListData!.nOTIFICATIONID!); Utils.hideLoading(context); actionHistoryList.last.sEQUENCE = getRFCEmployeeList[0].sEQ; showMyBottomSheet(context, @@ -660,8 +594,7 @@ class _WorkListDetailScreenState extends State { } } - Future performNetworkCall(BuildContext context, - {String? email, String? userId}) async { + Future performNetworkCall(BuildContext context, {String? email, String? userId}) async { showDialog( context: context, builder: (BuildContext cxt) => ConfirmDialog( @@ -671,12 +604,7 @@ class _WorkListDetailScreenState extends State { Navigator.pop(cxt); Utils.showLoading(context); try { - await WorkListApiClient().submitComment( - comment: "", - email: email, - userId: userId, - notificationId: workListData!.nOTIFICATIONID, - apiMode: "REJECT"); + await WorkListApiClient().submitComment(comment: "", email: email, userId: userId, notificationId: workListData!.nOTIFICATIONID, apiMode: "REJECT"); Utils.hideLoading(context); Navigator.pop(context, "delegate_reload"); } catch (ex) { @@ -694,9 +622,7 @@ class _WorkListDetailScreenState extends State { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ - title.toText12( - color: isSelected ? Colors.white : Colors.white.withOpacity(.74), - isCenter: true), + title.toText12(color: isSelected ? Colors.white : Colors.white.withOpacity(.74), isCenter: true), 4.height, Container( height: 8, @@ -764,10 +690,7 @@ class _WorkListDetailScreenState extends State { for (var element in getNotificationRespondAttributes!) { responseAttribute.add({ "ATTRIBUTE_NAME": element!.attributeName, - if (element!.attributeType == "number") - "ATTRIBUTE_NUMBER_VALUE": note - else if (element!.attributeType == "VARCHAR2") - "ATTRIBUTE_TEXT_VALUE": note + if (element!.attributeType == "number") "ATTRIBUTE_NUMBER_VALUE": note else if (element!.attributeType == "VARCHAR2") "ATTRIBUTE_TEXT_VALUE": note }); } @@ -780,11 +703,15 @@ class _WorkListDetailScreenState extends State { "RespondAttributeList": responseAttribute, }; - if (actionMode == "APPROVED" || actionMode == "APPROVE" || actionMode == "CLOSE" || actionMode == "ANSWER_INFO" || actionMode == "RFC" || actionMode == "TRY_APPROVE_AGAIN" || actionMode == "SEND_BACK_TO_PREPARER") { - + if (actionMode == "APPROVED" || + actionMode == "APPROVE" || + actionMode == "CLOSE" || + actionMode == "ANSWER_INFO" || + actionMode == "RFC" || + actionMode == "TRY_APPROVE_AGAIN" || + actionMode == "SEND_BACK_TO_PREPARER") { performNotificationAction(payload); - } else if (note.isNotEmpty && - (actionMode != "APPROVED" || actionMode != "APPROVE")) { + } else if (note.isNotEmpty && (actionMode != "APPROVED" || actionMode != "APPROVE")) { performNotificationAction(payload); } else { Utils.showToast(LocaleKeys.pleaseEnterComments.tr()); @@ -797,8 +724,7 @@ class _WorkListDetailScreenState extends State { void performNotificationAction(Map payload) async { try { Utils.showLoading(context); - GenericResponseModel model = - await WorkListApiClient().postNotificationActions(payload); + GenericResponseModel model = await WorkListApiClient().postNotificationActions(payload); Utils.hideLoading(context); Utils.showToast(LocaleKeys.yourChangeHasBeenSavedSuccessfully.tr()); animationIndex = animationIndex + 1; @@ -839,8 +765,7 @@ class _WorkListDetailScreenState extends State { if (apiCallCount == 0) Utils.showLoading(context); apiCallCount++; getEitCollectionNotificationBodyList!.clear(); - getEitCollectionNotificationBodyList = await WorkListApiClient() - .GetEitNotificationBody(workListData!.nOTIFICATIONID); + getEitCollectionNotificationBodyList = await WorkListApiClient().GetEitNotificationBody(workListData!.nOTIFICATIONID); apiCallCount--; if (apiCallCount == 0) { Utils.hideLoading(context); @@ -858,8 +783,7 @@ class _WorkListDetailScreenState extends State { if (apiCallCount == 0) Utils.showLoading(context); apiCallCount++; memberInformationListModel = null; - memberInformationListModel = await WorkListApiClient() - .getUserInformation(-999, workListData!.sELECTEDEMPLOYEENUMBER!); + memberInformationListModel = await WorkListApiClient().getUserInformation(-999, workListData!.sELECTEDEMPLOYEENUMBER!); apiCallCount--; if (apiCallCount == 0) { Utils.hideLoading(context); @@ -877,8 +801,7 @@ class _WorkListDetailScreenState extends State { if (apiCallCount == 0) Utils.showLoading(context); apiCallCount++; getPhonesNotificationBodyList!.clear(); - getPhonesNotificationBodyList = await WorkListApiClient() - .getPhonesNotificationBodyList(workListData!.nOTIFICATIONID); + getPhonesNotificationBodyList = await WorkListApiClient().getPhonesNotificationBodyList(workListData!.nOTIFICATIONID); apiCallCount--; if (apiCallCount == 0) { Utils.hideLoading(context); @@ -896,8 +819,7 @@ class _WorkListDetailScreenState extends State { if (apiCallCount == 0) Utils.showLoading(context); apiCallCount++; getBasicDetNtfBodyList!.clear(); - getBasicDetNtfBodyList = await WorkListApiClient() - .getBasicDetNtfBodyList(workListData!.nOTIFICATIONID); + getBasicDetNtfBodyList = await WorkListApiClient().getBasicDetNtfBodyList(workListData!.nOTIFICATIONID); apiCallCount--; if (apiCallCount == 0) { Utils.hideLoading(context); @@ -915,8 +837,7 @@ class _WorkListDetailScreenState extends State { if (apiCallCount == 0) Utils.showLoading(context); apiCallCount++; getAbsenceCollectionNotificationBodyList!.clear(); - getAbsenceCollectionNotificationBodyList = await WorkListApiClient() - .getAbsenceNotificationBody(workListData!.nOTIFICATIONID); + getAbsenceCollectionNotificationBodyList = await WorkListApiClient().getAbsenceNotificationBody(workListData!.nOTIFICATIONID); apiCallCount--; if (apiCallCount == 0) { Utils.hideLoading(context); @@ -933,8 +854,7 @@ class _WorkListDetailScreenState extends State { try { if (apiCallCount == 0) Utils.showLoading(context); apiCallCount++; - getContactNotificationBodyList = await WorkListApiClient() - .getContactNotificationBodyList(workListData!.nOTIFICATIONID); + getContactNotificationBodyList = await WorkListApiClient().getContactNotificationBodyList(workListData!.nOTIFICATIONID); apiCallCount--; if (apiCallCount == 0) { Utils.hideLoading(context); @@ -951,8 +871,7 @@ class _WorkListDetailScreenState extends State { try { if (apiCallCount == 0) Utils.showLoading(context); apiCallCount++; - getAddressNotificationBodyList = await WorkListApiClient() - .getAddressNotificationBodyList(workListData!.nOTIFICATIONID); + getAddressNotificationBodyList = await WorkListApiClient().getAddressNotificationBodyList(workListData!.nOTIFICATIONID); apiCallCount--; if (apiCallCount == 0) { Utils.hideLoading(context); @@ -968,8 +887,7 @@ class _WorkListDetailScreenState extends State { void getTerminationNotificationBody() async { try { if (apiCallCount == 0) apiCallCount++; - getTerminationNotificationBodyList = await WorkListApiClient() - .getTerminationNotificationBodyList(workListData!.nOTIFICATIONID); + getTerminationNotificationBodyList = await WorkListApiClient().getTerminationNotificationBodyList(workListData!.nOTIFICATIONID); Utils.hideLoading(context); apiCallCount--; if (apiCallCount == 0) { @@ -987,11 +905,9 @@ class _WorkListDetailScreenState extends State { if (apiCallCount == 0) Utils.showLoading(context); apiCallCount++; if (workListData!.rEQUESTTYPE == "STAMP_MS") { - getStampMsNotifications = await WorkListApiClient() - .getStampMsNotificationBody(workListData!.nOTIFICATIONID!, -999); + getStampMsNotifications = await WorkListApiClient().getStampMsNotificationBody(workListData!.nOTIFICATIONID!, -999); } else { - getStampNsNotifications = await WorkListApiClient() - .getStampNsNotificationBody(workListData!.nOTIFICATIONID!, -999); + getStampNsNotifications = await WorkListApiClient().getStampNsNotificationBody(workListData!.nOTIFICATIONID!, -999); } apiCallCount--; if (apiCallCount == 0) { @@ -1009,8 +925,7 @@ class _WorkListDetailScreenState extends State { try { if (apiCallCount == 0) Utils.showLoading(context); apiCallCount++; - getMoNotificationBodyList = await WorkListApiClient() - .getMoNotificationBody(workListData!.nOTIFICATIONID!, -999); + getMoNotificationBodyList = await WorkListApiClient().getMoNotificationBody(workListData!.nOTIFICATIONID!, -999); apiCallCount--; if (apiCallCount == 0) { Utils.hideLoading(context); @@ -1027,8 +942,7 @@ class _WorkListDetailScreenState extends State { try { if (apiCallCount == 0) Utils.showLoading(context); apiCallCount++; - getItemCreationNtfBody = await WorkListApiClient() - .getItemCreationNtfBody(workListData!.nOTIFICATIONID!, -999); + getItemCreationNtfBody = await WorkListApiClient().getItemCreationNtfBody(workListData!.nOTIFICATIONID!, -999); apiCallCount--; if (apiCallCount == 0) { Utils.hideLoading(context); @@ -1045,8 +959,7 @@ class _WorkListDetailScreenState extends State { try { if (apiCallCount == 0) Utils.showLoading(context); apiCallCount++; - getPoNotificationBody = await WorkListApiClient() - .getPoNotificationBody(workListData!.nOTIFICATIONID!, -999); + getPoNotificationBody = await WorkListApiClient().getPoNotificationBody(workListData!.nOTIFICATIONID!, -999); apiCallCount--; if (apiCallCount == 0) { Utils.hideLoading(context); @@ -1063,8 +976,7 @@ class _WorkListDetailScreenState extends State { try { if (apiCallCount == 0) Utils.showLoading(context); apiCallCount++; - getPrNotificationBody = await WorkListApiClient() - .getPRNotificationBody(workListData!.nOTIFICATIONID!, -999); + getPrNotificationBody = await WorkListApiClient().getPRNotificationBody(workListData!.nOTIFICATIONID!, -999); apiCallCount--; if (apiCallCount == 0) { Utils.hideLoading(context); @@ -1081,8 +993,7 @@ class _WorkListDetailScreenState extends State { try { if (apiCallCount == 0) Utils.showLoading(context); apiCallCount++; - getPaymentNotificationBodyList = await WorkListApiClient() - .getPaymentNotificationBody(workListData!.nOTIFICATIONID!, -999); + getPaymentNotificationBodyList = await WorkListApiClient().getPaymentNotificationBody(workListData!.nOTIFICATIONID!, -999); apiCallCount--; if (apiCallCount == 0) { Utils.hideLoading(context); @@ -1100,8 +1011,7 @@ class _WorkListDetailScreenState extends State { if (apiCallCount == 0) Utils.showLoading(context); apiCallCount++; getNotificationRespondAttributes.clear(); - getNotificationRespondAttributes = await WorkListApiClient() - .notificationGetRespondAttributes(workListData!.nOTIFICATIONID!); + getNotificationRespondAttributes = await WorkListApiClient().notificationGetRespondAttributes(workListData!.nOTIFICATIONID!); if (getNotificationRespondAttributes.isNotEmpty) { notificationNoteInput = getNotificationRespondAttributes.first; } @@ -1122,25 +1032,18 @@ class _WorkListDetailScreenState extends State { if (apiCallCount == 0) Utils.showLoading(context); apiCallCount++; notificationButtonsList.clear(); - notificationButtonsList = await WorkListApiClient() - .getNotificationButtons(workListData!.nOTIFICATIONID!); + notificationButtonsList = await WorkListApiClient().getNotificationButtons(workListData!.nOTIFICATIONID!); if (notificationButtonsList.isNotEmpty) { - isCloseAvailable = notificationButtonsList.any( - (GetNotificationButtonsList element) => - element.bUTTONACTION == "CLOSE"); - isApproveAvailable = - notificationButtonsList.any((GetNotificationButtonsList element) { - if (element.bUTTONACTION == "APPROVED" || - element.bUTTONACTION == "APPROVE") { + isCloseAvailable = notificationButtonsList.any((GetNotificationButtonsList element) => element.bUTTONACTION == "CLOSE"); + isApproveAvailable = notificationButtonsList.any((GetNotificationButtonsList element) { + if (element.bUTTONACTION == "APPROVED" || element.bUTTONACTION == "APPROVE") { approveAction = element.bUTTONACTION!; return true; } return false; }); - isRejectAvailable = - notificationButtonsList.any((GetNotificationButtonsList element) { - if (element.bUTTONACTION == "REJECTED" || - element.bUTTONACTION == "REJECT") { + isRejectAvailable = notificationButtonsList.any((GetNotificationButtonsList element) { + if (element.bUTTONACTION == "REJECTED" || element.bUTTONACTION == "REJECT") { rejectAction = element.bUTTONACTION!; return true; } @@ -1163,8 +1066,10 @@ class _WorkListDetailScreenState extends State { try { isActionHistoryLoaded = false; actionHistoryList.clear(); - actionHistoryList = await WorkListApiClient() - .getActionHistory(workListData!.nOTIFICATIONID!); + List _actionHistoryList = await WorkListApiClient().getActionHistory(workListData!.nOTIFICATIONID!); + if (!isActionHistoryLoaded) { + actionHistoryList = _actionHistoryList; + } setState(() { isActionHistoryLoaded = true; }); @@ -1177,8 +1082,10 @@ class _WorkListDetailScreenState extends State { try { isAttachmentLoaded = false; getAttachmentList.clear(); - getAttachmentList = await WorkListApiClient() - .getAttachments(workListData!.nOTIFICATIONID!); + List _getAttachmentList = await WorkListApiClient().getAttachments(workListData!.nOTIFICATIONID!); + if (!isAttachmentLoaded) { + getAttachmentList = _getAttachmentList; + } setState(() { isAttachmentLoaded = true; }); -- 2.30.2 From 5ecb4845a134f2c16f2cbe9e7676ecc76500e632 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Mon, 25 Nov 2024 10:23:28 +0300 Subject: [PATCH 041/135] po item history chart and scrollable list view added. --- assets/langs/ar-SA.json | 35 +- assets/langs/en-US.json | 35 +- lib/classes/consts.dart | 4 +- lib/generated/codegen_loader.g.dart | 2327 ++++++++++----------- lib/generated/locale_keys.g.dart | 84 +- lib/ui/work_list/item_history_screen.dart | 241 ++- pubspec.yaml | 1 + 7 files changed, 1458 insertions(+), 1269 deletions(-) diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 6370baf..12c1eb7 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -528,7 +528,7 @@ "noWinner": "حزين! لم يفز أحد اليوم.", "myTeam": "فريقي", "youCanPlayDemo": "لكن يمكنك لعب العرض", - "group" : "مجموعة", + "group": "مجموعة", "searchGroup": "مجموعة البحث", "connectHmgWifi": "قم بتوصيل HMG WIFI", "connectedHmgWifi": "اتصال HMG WIFI", @@ -545,19 +545,26 @@ "pleaseClickButtonToJoinMarathon": "الرجاء الضغط على الزر أدناه للانضمام إلى الماراثون", "youCannotJoinTheMarathon": "لا يمكنك الانضمام إلى الماراثون لأنك تجاوزت الحد الزمني", "open": "يفتح", - "requesterOperatingUnit":"وحدة تشغيل مقدم الطلب", - "prepareEmpNum":"إعداد رقم الموظف", - "supplierInfo" : "معلومات المورد", + "requesterOperatingUnit": "وحدة تشغيل مقدم الطلب", + "prepareEmpNum": "إعداد رقم الموظف", + "supplierInfo": "معلومات المورد", "supplierAcNo": "رقم حساب المورد", "supplierAcName": "اسم حساب المورد", - "supplierIBAN" : "رقم IBAN للمورد", - "supplierCRNo" :"رقم السجل التجاري", - "suppliedAcNo" : "رقم الحساب المقدم", - "patientRefundInvoice" : "فاتورة استرداد الأموال للمريض", - "patientNumber" : "رقم المريض", - "patientName" : "اسم المريض", - "invoiceDate" : "تاريخ الفاتورة", - "refundInvoice" :"فاتورة الاسترجاع", - "hospitalClinic" : "عيادة المستشفى" - + "supplierIBAN": "رقم IBAN للمورد", + "supplierCRNo": "رقم السجل التجاري", + "suppliedAcNo": "رقم الحساب المقدم", + "patientRefundInvoice": "فاتورة استرداد الأموال للمريض", + "patientNumber": "رقم المريض", + "patientName": "اسم المريض", + "invoiceDate": "تاريخ الفاتورة", + "refundInvoice": "فاتورة الاسترجاع", + "hospitalClinic": "عيادة المستشفى", + "graphicalAnalysis": "التحليل الرسومي", + "itemHistoryAnalysis": "تحليل تاريخ العنصر", + "pOno": "امر شراء #", + "oprUnit": "وحدة التشغيل", + "qtyOrdered": "الكمية المطلوبة", + "qtyReceived": "الكمية المستلمة", + "bonusQty": "كمية المكافأة", + "balQty": "كمية التوازن" } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 61bba1d..21e53de 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -564,19 +564,26 @@ "addAtLeastOneAttachment": "Please add at least one attachment.", "pleaseClickButtonToJoinMarathon": "Press the button below to join the Marathon.", "youCannotJoinTheMarathon": "You cannot join the Marathon because you have exceeded the time limit.", - "requesterOperatingUnit":"Requester Operating Unit", - "prepareEmpNum":"Prepare Employee Num", - "supplierInfo" : "Supplier Information", + "requesterOperatingUnit": "Requester Operating Unit", + "prepareEmpNum": "Prepare Employee Num", + "supplierInfo": "Supplier Information", "supplierAcNo": "Supplier Account No", - "supplierAcName":"Supplier Account Name", - "supplierIBAN" : "Supplier IBAN", - "supplierCRNo" : "CR Number", - "suppliedAcNo" : "Supplied Account No.", - "patientRefundInvoice" : "Patient Refund Invoice", - "patientNumber" : "Patient Number", - "patientName" : "Patient Name", - "invoiceDate" : "Invoice Date", - "refundInvoice" :"Refund Invoice", - "hospitalClinic" : "Hospital Clinic" - + "supplierAcName": "Supplier Account Name", + "supplierIBAN": "Supplier IBAN", + "supplierCRNo": "CR Number", + "suppliedAcNo": "Supplied Account No.", + "patientRefundInvoice": "Patient Refund Invoice", + "patientNumber": "Patient Number", + "patientName": "Patient Name", + "invoiceDate": "Invoice Date", + "refundInvoice": "Refund Invoice", + "hospitalClinic": "Hospital Clinic", + "graphicalAnalysis": "Graphical Analysis", + "itemHistoryAnalysis": "Item History Analysis", + "pOno": "P.O #", + "oprUnit": "Opr. Unit", + "qtyOrdered": "Qty. Ordered", + "qtyReceived": "Qty. Received", + "bonusQty": "Bonus Qty.", + "balQty": "Bal. Qty." } \ No newline at end of file diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 170762c..7103dfd 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -9,9 +9,9 @@ class ApiConsts { // static String baseUrl = "https://webservices.hmg.com"; // PreProd // static String baseUrl = "https://hmgwebservices.com"; // Live server - static String baseUrl = "https://mohemm.hmg.com"; // New Live server + // static String baseUrl = "https://mohemm.hmg.com"; // New Live server - // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver + static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.20.200.111:1010/"; // static String baseUrl = "https://webservices.hmg.com"; // PreProd diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index 357d6eb..aa3ed5c 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -1,1184 +1,1177 @@ // DO NOT EDIT. This is code generated via package:easy_localization/generate.dart -// ignore_for_file: prefer_single_quotes +// ignore_for_file: prefer_single_quotes, avoid_renaming_method_parameters import 'dart:ui'; import 'package:easy_localization/easy_localization.dart' show AssetLoader; -class CodegenLoader extends AssetLoader { +class CodegenLoader extends AssetLoader{ const CodegenLoader(); @override - Future> load(String fullPath, Locale locale) { + Future?> load(String path, Locale locale) { return Future.value(mapLocales[locale.toString()]); } - static const Map ar_SA = { - "mohemm": "Mohemm", - "english": "English", - "arabic": "عربي", - "login": "تسجيل الدخول", - "pleaseEnterLoginDetails": "الرجاء إدخال التفاصيل أدناه لتسجيل الدخول", - "username": "اسم المستخدم", - "password": "كلمة المرور", - "welcomeBack": "مرحبا بعودتك", - "wouldYouLikeToLoginWithCurrentUsername": "هل ترغب في تسجيل الدخول باسم المستخدم الحالي؟", - "lastLoginDetails": "تفاصيل تسجيل الدخول الأخير:", - "verificationType": "نوع التحقق:", - "pleaseVerify": "ارجوك تحقق", - "pleaseVerifyForBio": "الرجاء التحقق من تسجيل الدخول باستخدام أحد هذه الخيارات", - "verifyThroughFace": "تحقق من خلال الوجه", - "verifyThroughFingerprint": "تحقق من خلال بصمة الإصبع", - "verifyThroughSMS": "تحقق من خلال الرسائل القصيرة", - "verifyThroughWhatsapp": "تحقق من خلال Whatsapp", - "useAnotherAccount": "استخدم حسابا آخر", - "pleaseEnterTheVerificationCodeSentTo": "الرجاء إدخال رمز التحقق المرسل إلى ", - "theVerificationCodeWillExpireIn": "ستنتهي صلاحية رمز التحقق في ", - "goodMorning": "صباح الخير", - "markAttendance": "علامة الحضور", - "timeLeftToday": "الوقت المتبقي اليوم", - "checkIn": "تحقق في", - "workList": "قائمة العمل", - "leaveBalance": "رصيد الاجازات", - "missingSwipes": "تسجيل بصمة حضور", - "ticketBalance": "رصيد التذكرة", - "other": "آخر", - "services": "خدمات", - "viewAllServices": "عرض جميع الخدمات", - "monthlyAttendance": "الحضور الشهري", - "vacationRule": "قاعدة الاجازات", - "vacationType": "نوع الاجازة", - "startDateT": "تاريخ البدء", - "endDateT": "تاريخ الانتهاء", - "workFromHome": "العمل من المنزل", - "ticketRequest": "طلب تذكرة", - "viewAllOffers": "مشاهدة جميع العروض", - "offers": "عروض & ", - "discounts": "الخصومات", - "newString": "جديد", - "setTheNewPassword": "قم بتعيين كلمة المرور الجديدة", - "typeYourNewPasswordBelow": "اكتب كلمة المرور الجديدة أدناه", - "typeYourNewActiveDirectoryPasswordBelow": "اكتب كلمة مرور الدليل النشط الجديدة أدناه", - "confirmPassword": "تأكيد كلمة المرور", - "update": "تحديث", - "title": "عنوان", - "home": "الرئيسية", - "mySalary": "راتبي", - "createRequest": "إنشاء طلب", - "forgotPassword": "هل نسيت كلمة السر", - "employeeId": "هوية الموظف", - "loginCodeWillSentToMobileNumber": "الرجاء إدخال معرف الموظف الخاص بك ، وسيتم إرسال رمز تسجيل الدخول إلى رقم هاتفك المحمول", - "changePassword": "تغيير كلمة المرور", - "ok": "موافق", - "confirm": "تؤكد", - "passwordChangedSuccessfully": "تم تغيير الرقم السري بنجاح", - "itemsForSale": "سلع للبيع", - "attendanceDetails": "تفاصيل الحضور", - "order": "الطلبات", - "earlyOut": "الخروج مبكرا", - "shortage": "ساعات التقصير", - "excess": "فائض", - "lateIn": "القدوم المتاخر", - "approvedCheckOut": "اعتماد وقت الخروج", - "approvedCheckIn": "اعتماد وقت الدخول", - "actualCheckOut": "وقت الخروج", - "actualCheckIn": "وقت الدخول", - "present": "حضور", - "pres": "حضور", - "shiftTime": "وقت التناوب", - "absent": "غياب", - "attendance": "الحضور", - "scheduleDays": "ايام العمل", - "offDays": "ايام الراحه", - "nonAnalyzed": "لايوجد تحليل", - "shortageHour": "ساعات التقصير", - "stats": "الحاله", - "completed": "تم اكمال", - "msg": "Hello {} in the {} world ", - "msg_named": "{} are written in the {lang} language", - "clickMe": "Click me", - "doNotUseRecentPassword": "لا تستخدم كلمة مرور حديثة", - "atLeastOneLowercase": "حرف صغير واحد على الأقل", - "atLeastOneUppercase": "حرف كبير واحد على الأقل", - "atLeastOneNumeric": "رقم واحد على الأقل", - "minimum8Characters": "8 أحرف على الأقل", - "doNotAddRepeatingLetters": "لا تقم بإضافة أحرف متكررة", - "itShouldContainSpecialCharacter": "يجب لا يحتوي على أحرف خاصة", - "confirmPasswordMustMatch": "يجب أن يتطابق تأكيد كلمة المرور", - "sms": "رسالة قصيرة", - "fingerPrint": "بصمة", - "face": "التعرف على الوجه", - "whatsapp": "واتس اب", - "reject": "يرفض", - "approve": "يوافق", - "cancel": "إلغاء", - "requestedItems": "العناصر المطلوبة", - "request": "طلب", - "myRequest": "طلبي", - "actions": "أجراءات", - "delegate": "مندوب", - "request_info": "اطلب معلومات", - "attachments": "المرفقات", - "info": "معلومات", - "employeeNumber": "رقم الموظف", - "assignmentNumber": "رقم الواجب", - "employeeName": "اسم الموظف", - "scheduleDate": "تاريخ الجدول الزمني", - "shiftType": "نوع التحول", - "shift": "يحول", - "breakText": "استراحة", - "actualSwipeStart": "بدء التمرير الفعلي", - "actualSwipeEnd": "التمرير الفعلي للنهاية", - "approvedSwipeStart": "وافق انتقاد البدء", - "approvedSwipeStartReason": "تمت الموافقة على سبب بدء التمرير السريع", - "approvedSwipeEnd": "تمت الموافقة على تمرير النهاية", - "approvedSwipeEndReason": "الموافقة على سبب إنهاء التمرير", - "from": "من", - "to": "ل", - "sent": "أرسلت", - "closed": "مغلق", - "id": "هوية شخصية", - "responder": "المستجيب", - "jobTitle": "عنوان وظيفي", - "grade": "درجة", - "jobCategory": "تصنيف الوظيفة", - "category": "فئة", - "employeeEmailAddress": "عنوان البريد الإلكتروني للموظف", - "payrollBranch": "فرع الرواتب", - "yourChangeHasBeenSavedSuccessfully": "تم حفظ التغيير الخاص بك بنجاح", - "code": "شفرة", - "unit": "وحدة", - "quantity": "كمية", - "dateRequired": "التاريخ مطلوب", - "lineStatus": "حالة الخط", - "statusDate": "تاريخ الحالة", - "transactionType": "نوع المعاملة", - "operatingUnit": "وحدة التشغيل", - "organizationCode": "كود المنظمة", - "organization": "منظمة", - "fromSubInventory": "من الجرد الفرعي", - "fromLocator": "من محدد المواقع", - "toSubInventory": "إلى الجرد الفرعي", - "toLocator": "إلى محدد المواقع", - "shipToLocator": "شحن إلى محدد المواقع", - "itemHistory": "تاريخ العنصر", - "mfg": "مبدع", - "lineType": "نوع الخط", - "price": "السعر", - "lineAmount": "مبلغ الخط", - "lineDiscount": "خصم الخط٪", - "needByDate": "القادمة إلى الأمام", - "promisedDate": "التسجيل وعد", - "deliverToLocation": "تسليم إلى الموقع", - "requisitionNumber": "رقم الطلب", - "requester": "مقدم الطلب", - "quotationAnalysis": "تحليل الاقتباس", - "subject": "موضوعات", - "description": "وصف", - "supplier": "المورد", - "site": "موقع", - "buyer": "مشتر", - "preparer": "معد", - "creationDate": "تاريخ الإنشاء", - "shipToLocation": "الشحن الى الموقع", - "quotationNumber": "رقم الإقتباس", - "quotationDate": "تاريخ الاقتباس", - "paymentTerms": "شروط الدفع", - "currency": "عملة", - "grossAmount": "المبلغ الإجمالي", - "discountAmount": "مقدار الخصم", - "customDuty": "الرسوم الجمركية", - "shipHandle": "مقبض السفينة", - "otherCharges": "رسوم أخرى", - "totalPOAmountWithVAT": "إجمالي مبلغ الشراء مع ضريبة القيمة المضافة", - "totalPOAmountInWords": "إجمالي مبلغ أمر الشراء بالكلمات", - "requestNumber": "رقم الطلب", - "uom": "UOM", - "operatingCode": "كود التشغيل", - "poNumber": "PO عدد", - "revision": "مراجعة", - "quantityOrdered": "الكمية المطلوبة", - "quantityReceived": "الكمية المستلمة", - "bonusQuantity": "كمية المكافأة", - "purchasePrice": "سعر الشراء", - "discountPer": "خصم ٪", - "balanceQuantity": "كمية التوازن", - "netPrice": "السعر الصافي", - "closureStatus": "حالة الإغلاق", - "quotationNetPrice": "صافي سعر الاقتباس", - "quotationUOM": "اقتباس UOM", - "quotationQty": "اقتباس الكمية", - "itemCode": "رمز الصنف", - "vendorName": "اسم البائع", - "quotationMFGPartNumber": "رقم الجزء MFG الاقتباس", - "quotationDeliveryDate": "تاريخ تسليم عرض الأسعار", - "quotationBonusQuantity": "كمية مكافأة الاقتباس", - "quotationLineTotal": "مجموع خط الاقتباس", - "rfqUOM": "RFQ UOM", - "rfqQty": "RFQ الكمية", - "rfqNumber": "رقم RFQ", - "human": "بشري", - "resources": "موارد", - "details": "تفاصيل", - "noDataAvailable": "لا تتوافر بيانات", - "productName": "اسم المنتج", - "productDescription": "وصف المنتج", - "unitPrice": "سعر الوحده", - "manufacturerName": "اسم المصنع", - "manufacturerPartName": "اسم جزء الشركة المصنعة", - "supplierName": "اسم المورد", - "supplierContact": "الاتصال بالمورد", - "chargeToPatient": "المسؤول عن المريض", - "justification": "التبرير", - "itemDescription": "وصف السلعة", - "groupCode": "كود المجموعة", - "primaryUOM": "UOM الابتدائية", - "subgroupDescription": "وصف المجموعة الفرعية", - "subgroupCode": "رمز المجموعة الفرعية", - "groupDescription": "وصف المجموعة", - "templateName": "اسم القالب", - "itemCreationStatus": "حالة إنشاء العنصر", - "standardizationApprovalStatus": "حالة الموافقة على التقييس", - "standardizationApprovalRejectionReason": "سبب رفض الموافقة على التقييس", - "analyzedBy": "تحليل بواسطة", - "approvedDate": "تاريخ الموافقة", - "itemType": "نوع العنصر", - "relatedTo": "متعلق ب", - "requestDate": "تاريخ الطلب", - "analyzedDate": "تاريخ التحليل", - "urgent": "العاجلة", - "requestDetails": "طلب تفاصيل", - "approvalLevel": "مستوى الموافقة", - "requesterDetails": "تفاصيل مقدم الطلب", - "myAttendance": "حضوري", - "workOnBreak": "التعويض عن العمل اثناءالاستراحه", - "next": "التالي", - "apply": "يتقدم", - "mobile": "التليفون المحمول", - "completingYear": "نحن نقدر لك لاستكمال خدمة", - "year": "سنة", - "month": "شهر", - "day": "يوم", - "address": "العنوان", - "phoneNumber": "رقم الجوال", - "businessGroup": "مجموعة العمل", - "Payroll": "الراتب", - "civilIdentityNumber": "رقم الهويه", - "dateOfBirth": "تاريخ الميلاد", - "maritalStatus ": "الحالة الاجتماعية", - "fullName": "الأسم الكامل", - "remove": "حذف", - "submit": "ارسال", - "areYouSureYouWantToSubmit": "هل أنت متأكد أنك تريد أن تقدم؟", - "comments": "تعليقات", - "writeComment": "أكتب تعليقا", - "approversList": "قائمة الموافقين", - "yourRequestHasBeenSubmittedForApprovals": "تم تقديم طلبك للموافقات", - "monthlyPaySlip": "قسيمة الراتب الشهرية", - "particular": "خاص", - "earnings": "أرباح", - "deductions": "الخصومات", - "paymentMethodName": "اسم طريقة الدفع", - "bankName": "اسم البنك", - "branchCode": "رمز الفرع", - "accountNo": "رقم الحساب", - "summaryOfInformation": "ملخص المعلومات", - "totalPayAmount": "المبلغ الإجمالي للدفع", - "paymentInformation": "معلومات الدفع", - "performance": "تقييم الاداء", - "performanceEvaluation": "تقييم الأداء في", - "performanceEvaluationIn": "تقييم أدائك في", - "valuationIn": "تقييم الأداء في", - "amount": "مقدار", - "correctCurrentDatails": "تعديل او اكمال التفاصيل الحالية", - "selectType": " حدد نوع التغيير الذي تريد القيام به", - "enterNewInfo": " أدخل معلومات جديدة بسبب تغيير حقيقي في التفاصيل الحالية (على سبيل المثال بسبب تغيير في الحالة الاجتماعية", - "endDate": "تاريخ الانتهاء", - "removeThisMember": "هل انت متأكد تريد ازالة هذا العضو؟", - "wantUpdateThisMember ": "هل انت متأكد تريد تحديث بيانات هذا العضو؟", - "addNewFamilyMember": "اضافة عضو جديد", - "addRow": "اضافة صف جديد", - "pleaseSelect": "الرجاء اختيار", - "delete": "حذف", - "edit": "تعديل", - "add": "اضافه", - "myProfile": "معلوماتي", - "mowadhafhi": "موظفي", - "searchAnnouncements": "بحث الاعلانات", - "announcements": "اعلانات", - "swipeRequest": "طلب تسجيل حضور", - "serviceType": "نوع الخدمه", - "departmentName": "اسم القسم", - "selectDepartment": "اختر القسم", - "relatedSection": "قسم ذو صله", - "selectSection": "اختيار القسم", - "relatedTopic": "عنوان ذو صله", - "selectTopic": "اختر العنوان", - "supportingDocument": "ارفاق مستند", - "mowadhafhiRequest": "طلب موظفي", - "ticketReference": "مرجع التذكره", - "section": "القسم", - "topic": "العنوان", - "actionBy": "الرد بواسطة", - "pending": "معلق", - "pendingTransactions": "المعاملات المعلقه", - "selectRequestType": "الرجاء اختيار نوع الطلب", - "dateFrom": "من تاريخ", - "dateTo": "الى تاريخ", - "requestName": "اسم الطلب", - "createdFor": "انشاء لأجل", - "requestCreatedSuccessfully": "تم انشاء الطلب بنجاح", - "search": "بحث", - "wantToReject": "هل انت متأكد تريد الرفض", - "requestType": "نوع الطلب", - "employeeDigitalID": "هويةالموظف الرقمية", - "businessCard": "بطاقة العمل", - "viewBusinessCard": "عرض بطاقة العمل", - "logout": "تسجيل خروج", - "checkOut": "وقت الخروج", - "regular": "منتظم", - "mark": "علامة", - "selectMethodOfAttendance": "اختر طريقة تسجيل الحضور", - "comeNearHMGWifi": "HMG wifi من فضلك اقترب من", - "deliverNotificationToMeRegardless": "تسليم الإخطارات إلي بغض النظر عن أي قواعد عامة", - "close": "أغلق", - "respond": "يرد", - "vacationRuleAdded": "تمت إضافة قاعدة الإجازة", - "selectTypeT": "اختر صنف", - "notification": "تنبيه", - "selectNotification": "حدد إعلام", - "ifAllSelectedYouWillSkip": "* إذا تم تحديد الكل ، فستنتقل إلى الخطوة 3", - "applyForVacationRule": "التقدم بطلب للحصول على قانون الإجازة", - "step1": "الخطوة 1", - "step2": "الخطوة 2", - "step3": "الخطوه 3", - "message": "رسالة", - "writeAMessage": "اكتب رسالة", - "notificationReassign": "إعادة تعيين الإخطار", - "selectEmployee": "حدد الموظف", - "searchEmployeeForReplacement": "ابحث عن موظف بديل", - "searchForEmployee": "ابحث عن موظف", - "pleaseSpecifyEndTime": "الرجاء تحديد وقت الانتهاء", - "pleaseSelectNotificationReassign": "يرجى تحديد إعادة تعيين الإخطار", - "pleaseSelectEmployeeForReplacement": "الرجاء تحديد موظف للاستبدال", - "pleaseSelectAction": "الرجاء تحديد الإجراء", - "pleaseSelectDate": "الرجاء تحديد التاريخ", - "todayAttendance": "حضور اليوم", - "viewAttendance": "عرض الحضور", - "teamMembers": "اعضاءالفريق", - "profileDetails": "الملف الشخصي", - "noResultsFound": "لايوجد نتائج", - "searchBy": "بحث بواسطة", - "myTeamMembers": "اعضاء فريقي", - "save": "حفظ", - "TurnNotificationsFor": "تفعيل الاشعارات", - "worklistSettings": "اعدادات الاشعارات", - "absenceType": "نوع الغياب", - "absenceCategory": "فئة الغياب", - "days": "أيام", - "hours": "ساعات", - "approvalStatus": "حالة القبول", - "absenceStatus": "حالة الغياب", - "subordinateLeave": "إجازة التابعيين", - "numberDays": "عدد الأيام", - "poweredBy": "مشغل بواسطة", - "cloudSolutions": "حلول السحابة", - "selectTemplate": "حدد قالب", - "myPostedAds": "إعلاناتي المنشورة", - "browseCategories": "تصفح الفئات", - "searchItems": "عناصر البحث", - "offerAndDiscounts": "العروض والخصومات", - "offerValid": "العرض صالح", - "offerExpired": "انتهى العرض", - "whatAreYouOffering": "ما الذي تعرضه؟", - "selectCategory": "اختر الفئة", - "inProgress": "في تَقَدم", - "locked": "مقفل", - "addDetails": "أضف التفاصيل", - "reviewAndSell": "مراجعة وبيع", - "itemTitle": "عنوان البند", - "itemCondition": "حالة السلعة", - "used": "تستخدم", - "region": "منطقة", - "selectRegion": "اختر المنطقة", - "itemPrice": "سعر السلعة", - "itemPhotos": "صور البند", - "itemInfo": "معلومات العنصر", - "uploadAttachment": "تحميل المرفق", - "selectFromGalleryOrOpenCamera": "اختر من المعرض أو فتح الكاميرا", - "openCamera": "فتح\nالكاميرا", - "uploadFromGallery": "تحميل من\nملفات الجهاز", - "name": "الأسم", - "email": "ايميل", - "noHistoryAvailable": "لايوجد سجل بيانات سابقة ", - "purchaseRequisition": "طلب شراء", - "moveOrder": "طلب تغيير", - "humanResource": "الموارد البشريه", - "purchaseOrder": "امر شراء", - "ITGForms": "ITG نماذج", - "itemCreation": "أنشاء عنصر", - "stamp": "ختم", - "addFavoriteList": "هل تريد اضافة {name} لقائمة المفضله", - "feedbackUserExperience": "هذا للحصول على تعليقات حول تجربة المستخدم", - "rateUI": "كيف تريد أن تقيم", - "rateUI2": "ما مدى رضائك عن هذا التطبيق", - "submitSurvey": "ارسال الاستبيان", - "typeHere": "اكتب هنا", - "infoDetail": "تفاصيل المعلومات", - "amount_detail": "تفاصيل المبلغ", - "currentBalance": "الرصيد الحالي", - "currentLeaveBalance": "رصيد الاجازات الحالي", - "calculatedDays": "الايام المحسوبه", - "totalDays": "مجموع الأيام", - "usedBalance": "المستخدم", - "infants": "رضيع", - "child": "طفل", - "adult": "بالغ", - "updateMember": "هل انت متأكد تريد تحديث بيانات هذا العضو؟", - "fieldIsEmpty": "'{data}' الحقل فارغ. الرجاء التحديد", - "pleaseEnterComments": "الرجاء إدخال التعليقات", - "skip": "يتخطى", - "typeCurrentPasswordBelow": "اكتب كلمة المرور الحاليه", - "currentPassword": "كلمة المرور الحاليه", - "concurrentReports": "التقارير المتزامنه", - "EnterNewAddressMoved": "أدخل عنوان جديد إذا كنت قد انتقلت", - "CorrectAddress": "تصحيح أو تعديل هذا العنوان", - "SelectChangeWantToMake": " حدد نوع التغيير الذي تريد القيام به.", - "profile": { - "reset_password": {"label": "Reset Password", "username": "Username", "password": "password"}, - "profileCompletionPer": "استكمال الملف الشخصي", - "completeProfile": "الملف الشخصي الكامل", - "personalInformation": "معلومات شخصية", - "basicDetails": "تفاصيل أساسية", - "address": "العنوان", - "contactDetails": "بيانات التواصل", - "familyDetails": "تفاصيل عائلية", - "effectiveDate": "تاريخ النفاذ", - "country": "دولة" - }, - "clicked": { - "zero": "You clicked {} times!", - "one": "You clicked {} time!", - "two": "You clicked {} times!", - "few": "You clicked {} times!", - "many": "You clicked {} times!", - "other": "You clicked {} times!" + static const Map ar_SA = { + "mohemm": "Mohemm", + "english": "English", + "arabic": "عربي", + "login": "تسجيل الدخول", + "pleaseEnterLoginDetails": "الرجاء إدخال التفاصيل أدناه لتسجيل الدخول", + "username": "اسم المستخدم", + "password": "كلمة المرور", + "welcomeBack": "مرحبا بعودتك", + "wouldYouLikeToLoginWithCurrentUsername": "هل ترغب في تسجيل الدخول باسم المستخدم الحالي؟", + "lastLoginDetails": "تفاصيل تسجيل الدخول الأخير:", + "verificationType": "نوع التحقق:", + "pleaseVerify": "ارجوك تحقق", + "pleaseVerifyForBio": "الرجاء التحقق من تسجيل الدخول باستخدام أحد هذه الخيارات", + "verifyThroughFace": "تحقق من خلال الوجه", + "verifyThroughFingerprint": "تحقق من خلال بصمة الإصبع", + "verifyThroughSMS": "تحقق من خلال الرسائل القصيرة", + "verifyThroughWhatsapp": "تحقق من خلال Whatsapp", + "useAnotherAccount": "استخدم حسابا آخر", + "pleaseEnterTheVerificationCodeSentTo": "الرجاء إدخال رمز التحقق المرسل إلى ", + "theVerificationCodeWillExpireIn": "ستنتهي صلاحية رمز التحقق في ", + "goodMorning": "صباح الخير", + "markAttendance": "علامة الحضور", + "timeLeftToday": "الوقت المتبقي اليوم", + "checkIn": "تحقق في", + "workList": "قائمة العمل", + "leaveBalance": "رصيد الاجازات", + "missingSwipes": "تسجيل بصمة حضور", + "ticketBalance": "رصيد التذكرة", + "other": "آخر", + "services": "خدمات", + "viewAllServices": "عرض جميع الخدمات", + "monthlyAttendance": "الحضور الشهري", + "vacationRule": "قاعدة الاجازات", + "vacationType": "نوع الاجازة", + "startDateT": "تاريخ البدء", + "endDateT": "تاريخ الانتهاء", + "workFromHome": "العمل من المنزل", + "ticketRequest": "طلب تذكرة", + "viewAllOffers": "مشاهدة جميع العروض", + "offers": "عروض & ", + "discounts": "الخصومات", + "newString": "جديد", + "setTheNewPassword": "قم بتعيين كلمة المرور الجديدة", + "typeYourNewPasswordBelow": "اكتب كلمة المرور الجديدة أدناه", + "typeYourNewActiveDirectoryPasswordBelow": "اكتب كلمة مرور الدليل النشط الجديدة أدناه", + "confirmPassword": "تأكيد كلمة المرور", + "update": "تحديث", + "title": "عنوان", + "home": "الرئيسية", + "mySalary": "راتبي", + "createRequest": "إنشاء طلب", + "forgotPassword": "هل نسيت كلمة السر", + "employeeId": "هوية الموظف", + "loginCodeWillSentToMobileNumber": "الرجاء إدخال معرف الموظف الخاص بك ، وسيتم إرسال رمز تسجيل الدخول إلى رقم هاتفك المحمول", + "changePassword": "تغيير كلمة المرور", + "ok": "موافق", + "confirm": "تؤكد", + "passwordChangedSuccessfully": "تم تغيير الرقم السري بنجاح", + "itemsForSale": "سلع للبيع", + "attendanceDetails": "تفاصيل الحضور", + "order": "الطلبات", + "earlyOut": "الخروج مبكرا", + "shortage": "ساعات التقصير", + "excess": "فائض", + "lateIn": "القدوم المتاخر", + "approvedCheckOut": "اعتماد وقت الخروج", + "approvedCheckIn": "اعتماد وقت الدخول", + "actualCheckOut": "وقت الخروج", + "actualCheckIn": "وقت الدخول", + "present": "حضور", + "pres": "حضور", + "shiftTime": "وقت التناوب", + "absent": "غياب", + "attendance": "الحضور", + "scheduleDays": "ايام العمل", + "offDays": "ايام الراحه", + "nonAnalyzed": "لايوجد تحليل", + "shortageHour": "ساعات التقصير", + "stats": "الحاله", + "completed": "تم اكمال", + "msg": "Hello {} in the {} world ", + "msg_named": "{} are written in the {lang} language", + "clickMe": "Click me", + "doNotUseRecentPassword": "لا تستخدم كلمة مرور حديثة", + "atLeastOneLowercase": "حرف صغير واحد على الأقل", + "atLeastOneUppercase": "حرف كبير واحد على الأقل", + "atLeastOneNumeric": "رقم واحد على الأقل", + "minimum8Characters": "8 أحرف على الأقل", + "doNotAddRepeatingLetters": "لا تقم بإضافة أحرف متكررة", + "itShouldContainSpecialCharacter": "يجب لا يحتوي على أحرف خاصة", + "confirmPasswordMustMatch": "يجب أن يتطابق تأكيد كلمة المرور", + "sms": "رسالة قصيرة", + "fingerPrint": "بصمة", + "face": "التعرف على الوجه", + "whatsapp": "واتس اب", + "reject": "يرفض", + "approve": "يوافق", + "cancel": "إلغاء", + "generate": "يولد", + "requestedItems": "العناصر المطلوبة", + "request": "طلب", + "myRequest": "طلبي", + "actions": "أجراءات", + "delegate": "مندوب", + "request_info": "اطلب معلومات", + "attachments": "المرفقات", + "info": "معلومات", + "employeeNumber": "رقم الموظف", + "assignmentNumber": "رقم الواجب", + "employeeName": "اسم الموظف", + "scheduleDate": "تاريخ الجدول الزمني", + "shiftType": "نوع التحول", + "shift": "يحول", + "breakText": "استراحة", + "actualSwipeStart": "بدء التمرير الفعلي", + "actualSwipeEnd": "التمرير الفعلي للنهاية", + "approvedSwipeStart": "وافق انتقاد البدء", + "approvedSwipeStartReason": "تمت الموافقة على سبب بدء التمرير السريع", + "approvedSwipeEnd": "تمت الموافقة على تمرير النهاية", + "approvedSwipeEndReason": "الموافقة على سبب إنهاء التمرير", + "from": "من", + "to": "ل", + "sent": "أرسلت", + "closed": "مغلق", + "id": "هوية شخصية", + "responder": "المستجيب", + "jobTitle": "عنوان وظيفي", + "grade": "درجة", + "jobCategory": "تصنيف الوظيفة", + "category": "فئة", + "employeeEmailAddress": "عنوان البريد الإلكتروني للموظف", + "payrollBranch": "فرع الرواتب", + "yourChangeHasBeenSavedSuccessfully": "تم حفظ التغيير الخاص بك بنجاح", + "code": "شفرة", + "unit": "وحدة", + "quantity": "كمية", + "dateRequired": "التاريخ مطلوب", + "lineStatus": "حالة الخط", + "statusDate": "تاريخ الحالة", + "transactionType": "نوع المعاملة", + "operatingUnit": "وحدة التشغيل", + "organizationCode": "كود المنظمة", + "organization": "منظمة", + "fromSubInventory": "من الجرد الفرعي", + "fromLocator": "من محدد المواقع", + "toSubInventory": "إلى الجرد الفرعي", + "toLocator": "إلى محدد المواقع", + "shipToLocator": "شحن إلى محدد المواقع", + "itemHistory": "تاريخ العنصر", + "mfg": "مبدع", + "lineType": "نوع الخط", + "price": "السعر", + "lineAmount": "مبلغ الخط", + "lineDiscount": "خصم الخط٪", + "needByDate": "القادمة إلى الأمام", + "promisedDate": "التسجيل وعد", + "deliverToLocation": "تسليم إلى الموقع", + "requisitionNumber": "رقم الطلب", + "requester": "مقدم الطلب", + "quotationAnalysis": "تحليل الاقتباس", + "subject": "موضوعات", + "description": "وصف", + "supplier": "المورد", + "site": "موقع", + "buyer": "مشتر", + "preparer": "معد", + "creationDate": "تاريخ الإنشاء", + "shipToLocation": "الشحن الى الموقع", + "quotationNumber": "رقم الإقتباس", + "quotationDate": "تاريخ الاقتباس", + "paymentTerms": "شروط الدفع", + "currency": "عملة", + "grossAmount": "المبلغ الإجمالي", + "discountAmount": "مقدار الخصم", + "customDuty": "الرسوم الجمركية", + "shipHandle": "مقبض السفينة", + "otherCharges": "رسوم أخرى", + "totalPOAmountWithVAT": "إجمالي مبلغ الشراء مع ضريبة القيمة المضافة", + "totalPOAmountInWords": "إجمالي مبلغ أمر الشراء بالكلمات", + "requestNumber": "رقم الطلب", + "uom": "UOM", + "operatingCode": "كود التشغيل", + "poNumber": "PO عدد", + "revision": "مراجعة", + "quantityOrdered": "الكمية المطلوبة", + "quantityReceived": "الكمية المستلمة", + "bonusQuantity": "كمية المكافأة", + "purchasePrice": "سعر الشراء", + "discountPer": "خصم ٪", + "balanceQuantity": "كمية التوازن", + "netPrice": "السعر الصافي", + "closureStatus": "حالة الإغلاق", + "quotationNetPrice": "صافي سعر الاقتباس", + "quotationUOM": "اقتباس UOM", + "quotationQty": "اقتباس الكمية", + "itemCode": "رمز الصنف", + "vendorName": "اسم البائع", + "quotationMFGPartNumber": "رقم الجزء MFG الاقتباس", + "quotationDeliveryDate": "تاريخ تسليم عرض الأسعار", + "quotationBonusQuantity": "كمية مكافأة الاقتباس", + "quotationLineTotal": "مجموع خط الاقتباس", + "rfqUOM": "RFQ UOM", + "rfqQty": "RFQ الكمية", + "rfqNumber": "رقم RFQ", + "human": "بشري", + "resources": "موارد", + "details": "تفاصيل", + "noDataAvailable": "لا تتوافر بيانات", + "productName": "اسم المنتج", + "productDescription": "وصف المنتج", + "unitPrice": "سعر الوحده", + "manufacturerName": "اسم المصنع", + "manufacturerPartName": "اسم جزء الشركة المصنعة", + "supplierName": "اسم المورد", + "supplierContact": "الاتصال بالمورد", + "chargeToPatient": "المسؤول عن المريض", + "justification": "التبرير", + "itemDescription": "وصف السلعة", + "groupCode": "كود المجموعة", + "primaryUOM": "UOM الابتدائية", + "subgroupDescription": "وصف المجموعة الفرعية", + "subgroupCode": "رمز المجموعة الفرعية", + "groupDescription": "وصف المجموعة", + "templateName": "اسم القالب", + "itemCreationStatus": "حالة إنشاء العنصر", + "standardizationApprovalStatus": "حالة الموافقة على التقييس", + "standardizationApprovalRejectionReason": "سبب رفض الموافقة على التقييس", + "analyzedBy": "تحليل بواسطة", + "approvedDate": "تاريخ الموافقة", + "itemType": "نوع العنصر", + "relatedTo": "متعلق ب", + "requestDate": "تاريخ الطلب", + "analyzedDate": "تاريخ التحليل", + "urgent": "العاجلة", + "requestDetails": "طلب تفاصيل", + "approvalLevel": "مستوى الموافقة", + "requesterDetails": "تفاصيل مقدم الطلب", + "myAttendance": "حضوري", + "workOnBreak": "التعويض عن العمل اثناءالاستراحه", + "next": "التالي", + "apply": "يتقدم", + "mobile": "التليفون المحمول", + "completingYear": "نحن نقدر لك لاستكمال خدمة", + "year": "سنة", + "month": "شهر", + "day": "يوم", + "address": "العنوان", + "phoneNumber": "رقم الجوال", + "businessGroup": "مجموعة العمل", + "Payroll": "الراتب", + "civilIdentityNumber": "رقم الهويه", + "dateOfBirth": "تاريخ الميلاد", + "maritalStatus ": "الحالة الاجتماعية", + "fullName": "الأسم الكامل", + "remove": "حذف", + "submit": "ارسال", + "areYouSureYouWantToSubmit": "هل أنت متأكد أنك تريد أن تقدم؟", + "comments": "تعليقات", + "writeComment": "أكتب تعليقا", + "approversList": "قائمة الموافقين", + "yourRequestHasBeenSubmittedForApprovals": "تم تقديم طلبك للموافقات", + "monthlyPaySlip": "قسيمة الراتب الشهرية", + "particular": "خاص", + "earnings": "أرباح", + "deductions": "الخصومات", + "paymentMethodName": "اسم طريقة الدفع", + "bankName": "اسم البنك", + "branchCode": "رمز الفرع", + "accountNo": "رقم الحساب", + "summaryOfInformation": "ملخص المعلومات", + "totalPayAmount": "المبلغ الإجمالي للدفع", + "paymentInformation": "معلومات الدفع", + "performance": "تقييم الاداء", + "performanceEvaluation": "تقييم الأداء في", + "performanceEvaluationIn": "تقييم أدائك في", + "valuationIn": "تقييم الأداء في", + "amount": "مقدار", + "correctCurrentDatails": "تعديل او اكمال التفاصيل الحالية", + "selectType": " حدد نوع التغيير الذي تريد القيام به", + "enterNewInfo": " أدخل معلومات جديدة بسبب تغيير حقيقي في التفاصيل الحالية (على سبيل المثال بسبب تغيير في الحالة الاجتماعية", + "endDate": "تاريخ الانتهاء", + "removeThisMember": "هل انت متأكد تريد ازالة هذا العضو؟", + "wantUpdateThisMember ": "هل انت متأكد تريد تحديث بيانات هذا العضو؟", + "addNewFamilyMember": "اضافة عضو جديد", + "addRow": "اضافة صف جديد", + "pleaseSelect": "الرجاء اختيار", + "delete": "حذف", + "edit": "تعديل", + "add": "اضافه", + "myProfile": "معلوماتي", + "mowadhafhi": "موظفي", + "searchAnnouncements": "بحث الاعلانات", + "announcements": "اعلانات", + "swipeRequest": "طلب تسجيل حضور", + "serviceType": "نوع الخدمه", + "departmentName": "اسم القسم", + "selectDepartment": "اختر القسم", + "relatedSection": "قسم ذو صله", + "selectSection": "اختيار القسم", + "relatedTopic": "عنوان ذو صله", + "selectTopic": "اختر العنوان", + "supportingDocument": "ارفاق مستند", + "mowadhafhiRequest": "طلب موظفي", + "ticketReference": "مرجع التذكره", + "section": "القسم", + "topic": "العنوان", + "actionBy": "الرد بواسطة", + "pending": "معلق", + "pendingTransactions": "المعاملات المعلقه", + "selectRequestType": "الرجاء اختيار نوع الطلب", + "dateFrom": "من تاريخ", + "dateTo": "الى تاريخ", + "requestName": "اسم الطلب", + "createdFor": "انشاء لأجل", + "requestCreatedSuccessfully": "تم انشاء الطلب بنجاح", + "search": "بحث", + "wantToReject": "هل انت متأكد تريد الرفض", + "requestType": "نوع الطلب", + "employeeDigitalID": "هويةالموظف الرقمية", + "businessCard": "بطاقة العمل", + "viewBusinessCard": "عرض بطاقة العمل", + "logout": "تسجيل خروج", + "checkOut": "وقت الخروج", + "regular": "منتظم", + "mark": "علامة", + "selectMethodOfAttendance": "اختر طريقة تسجيل الحضور", + "comeNearHMGWifi": "HMG wifi من فضلك اقترب من", + "deliverNotificationToMeRegardless": "تسليم الإخطارات إلي بغض النظر عن أي قواعد عامة", + "close": "أغلق", + "respond": "يرد", + "vacationRuleAdded": "تمت إضافة قاعدة الإجازة", + "selectTypeT": "اختر صنف", + "notification": "تنبيه", + "selectNotification": "حدد إعلام", + "ifAllSelectedYouWillSkip": "* إذا تم تحديد الكل ، فستنتقل إلى الخطوة 3", + "applyForVacationRule": "التقدم بطلب للحصول على قانون الإجازة", + "step1": "الخطوة 1", + "step2": "الخطوة 2", + "step3": "الخطوه 3", + "message": "رسالة", + "writeAMessage": "اكتب رسالة", + "notificationReassign": "إعادة تعيين الإخطار", + "selectEmployee": "حدد الموظف", + "searchEmployeeForReplacement": "ابحث عن موظف بديل", + "searchForEmployee": "ابحث عن موظف", + "pleaseSpecifyEndTime": "الرجاء تحديد وقت الانتهاء", + "pleaseSelectNotificationReassign": "يرجى تحديد إعادة تعيين الإخطار", + "pleaseSelectEmployeeForReplacement": "الرجاء تحديد موظف للاستبدال", + "pleaseSelectAction": "الرجاء تحديد الإجراء", + "pleaseSelectDate": "الرجاء تحديد التاريخ", + "todayAttendance": "حضور اليوم", + "viewAttendance": "عرض الحضور", + "teamMembers": "اعضاءالفريق", + "profileDetails": "الملف الشخصي", + "noResultsFound": "لايوجد نتائج", + "searchBy": "بحث بواسطة", + "myTeamMembers": "اعضاء فريقي", + "save": "حفظ", + "TurnNotificationsFor": "تفعيل الاشعارات", + "worklistSettings": "اعدادات الاشعارات", + "absenceType": "نوع الغياب", + "absenceCategory": "فئة الغياب", + "days": "أيام", + "hours": "ساعات", + "approvalStatus": "حالة القبول", + "absenceStatus": "حالة الغياب", + "subordinateLeave": "إجازة التابعيين", + "numberDays": "عدد الأيام", + "poweredBy": "مشغل بواسطة", + "cloudSolutions": "حلول السحابة", + "selectTemplate": "حدد قالب", + "myPostedAds": "إعلاناتي المنشورة", + "browseCategories": "تصفح الفئات", + "searchItems": "عناصر البحث", + "offerAndDiscounts": "العروض والخصومات", + "offerValid": "العرض صالح", + "offerExpired": "انتهى العرض", + "whatAreYouOffering": "ما الذي تعرضه؟", + "selectCategory": "اختر الفئة", + "inProgress": "في تَقَدم", + "locked": "مقفل", + "addDetails": "أضف التفاصيل", + "reviewAndSell": "مراجعة وبيع", + "itemTitle": "عنوان البند", + "itemCondition": "حالة السلعة", + "used": "تستخدم", + "region": "منطقة", + "selectRegion": "اختر المنطقة", + "itemPrice": "سعر السلعة", + "itemPhotos": "صور البند", + "itemInfo": "معلومات العنصر", + "uploadAttachment": "تحميل المرفق", + "selectFromGalleryOrOpenCamera": "اختر من المعرض أو فتح الكاميرا", + "openCamera": "فتح\nالكاميرا", + "uploadFromGallery": "تحميل من\nملفات الجهاز", + "name": "الأسم", + "email": "ايميل", + "noHistoryAvailable": "لايوجد سجل بيانات سابقة ", + "purchaseRequisition": "طلب شراء", + "moveOrder": "طلب تغيير", + "humanResource": "الموارد البشريه", + "purchaseOrder": "امر شراء", + "ITGForms": "ITG نماذج", + "itemCreation": "أنشاء عنصر", + "stamp": "ختم", + "addFavoriteList": "هل تريد اضافة {name} لقائمة المفضله", + "feedbackUserExperience": "هذا للحصول على تعليقات حول تجربة المستخدم", + "rateUI": "كيف تريد أن تقيم", + "rateUI2": "ما مدى رضائك عن هذا التطبيق", + "submitSurvey": "ارسال الاستبيان", + "typeHere": "اكتب هنا", + "infoDetail": "تفاصيل المعلومات", + "amount_detail": "تفاصيل المبلغ", + "currentBalance": "الرصيد الحالي", + "currentLeaveBalance": "رصيد الاجازات الحالي", + "calculatedDays": "الايام المحسوبه", + "totalDays": "مجموع الأيام", + "usedBalance": "المستخدم", + "infants": "رضيع", + "child": "طفل", + "adult": "بالغ", + "updateMember": "هل انت متأكد تريد تحديث بيانات هذا العضو؟", + "fieldIsEmpty": "'{data}' الحقل فارغ. الرجاء التحديد", + "pleaseEnterComments": "الرجاء إدخال التعليقات", + "skip": "يتخطى", + "typeCurrentPasswordBelow": "اكتب كلمة المرور الحاليه", + "currentPassword": "كلمة المرور الحاليه", + "concurrentReports": "التقارير المتزامنه", + "EnterNewAddressMoved": "أدخل عنوان جديد إذا كنت قد انتقلت", + "CorrectAddress": "تصحيح أو تعديل هذا العنوان", + "SelectChangeWantToMake": " حدد نوع التغيير الذي تريد القيام به.", + "profile": { + "reset_password": { + "label": "Reset Password", + "username": "Username", + "password": "password" }, - "gender": { - "male": "Hi man ;) ", - "female": "Hello girl :)", - "with_arg": {"male": "Hi man ;) {}", "female": "Hello girl :) {}"} + "profileCompletionPer": "استكمال الملف الشخصي", + "completeProfile": "الملف الشخصي الكامل", + "personalInformation": "معلومات شخصية", + "basicDetails": "تفاصيل أساسية", + "address": "العنوان", + "contactDetails": "بيانات التواصل", + "familyDetails": "تفاصيل عائلية", + "effectiveDate": "تاريخ النفاذ", + "country": "دولة" + }, + "clicked": { + "zero": "You clicked {} times!", + "one": "You clicked {} time!", + "two": "You clicked {} times!", + "few": "You clicked {} times!", + "many": "You clicked {} times!", + "other": "You clicked {} times!" + }, + "gender": { + "male": "Hi man ;) ", + "female": "Hello girl :)", + "with_arg": { + "male": "Hi man ;) {}", + "female": "Hello girl :) {}" + } + }, + "reset_locale": "إعادة ضبط اللغة", + "chat": "دردشة", + "mychats": "دردشاتي", + "advancedSearch": "بحث متقدم", + "openNot": "التبليغات المفتوحة", + "fyi": "تبليغات للعلم", + "toDo": "تبليغات الأعمال", + "all": "كل التبليغات", + "meNot": "تبليغات صادرة مني", + "view": "عرض", + "fromUserName": "من", + "sentDate": "تاريخ الإرسال", + "itemTypeDisplayName": "اسم العرض", + "none": "بدون", + "createNewChat": "إنشاء محادثة جديدة", + "brainMarathon": "ماراثون الدماغ", + "contestTopicAbout": "سيكون موضوع المسابقة حول:", + "gameDate": "تاريخ اللعبة:", + "gameTime": "وقت اللعب:", + "joinMarathon": "انضم إلى ماراثون", + "joinDemoMarathon": "انضم إلى الماراثون التجريبي", + "demo": "تجريبي", + "minutes": "الدقائق", + "seconds": "ثواني", + "note": "ملحوظة:", + "demoMarathonNoteP1": "يمكنك لعب ماراثون العرض لتتعلم كيف يعمل. يمكنك الانضمام إلى ماراثون", + "demoMarathonNoteP2": "خمس دقائق", + "demoMarathonNoteP3": "قبل الوقت الفعلي.", + "sponsoredBy": "برعاية:", + "question": "سؤال", + "marathoners": "الماراثون", + "marathoner": "ماراثونر", + "prize": "جائزة:", + "winnerSelection": "اختيار الفائز", + "qualifiers": "تصفيات", + "qualifier": "المؤهل", + "getReadyForContest": "استعد للمسابقة القادمة:", + "winnerSelectedRandomly": "سيتم اختيار الفائز عشوائياً من بين التصفيات.", + "fingersCrossed": "تشابك الاصابع!!!", + "congrats": "مبروك !!!", + "allQuestionsCorrect": "لقد أجبت على جميع الأسئلة بشكل صحيح.", + "otp": "OTP", + "verification": "تَحَقّق", + "resend": "إعادة إرسال", + "codeExpire": "انتهت صلاحية رمز التحقق", + "typeheretoreply": "اكتب هنا للرد", + "favorite": "مفضلتي", + "searchfromchat": "البحث من الدردشة", + "yourAnswerCorrect": "إجابتك صحيحة", + "youMissedTheQuestion": "نفد منك الوقت. أنت خارج اللعبة. لكن يمكنك الاستمرار وكمشاهد.", + "wrongAnswer": "إجابتك غير صحيحة. أنت خارج اللعبة. لكن يمكنك الاستمرار وكمشاهد.", + "oops": "أوه!!!", + "winner": "الفائز", + "youWantToLeaveMarathon": "هل أنت متأكد أنك تريد العودة؟ سوف تخرج من المسابقة.", + "ourSponsor": "راعينا:", + "startingIn": "يبدأ في", + "youAreOutOfContest": "أنت خارج المسابقة.", + "winners": "الفائزين!!!", + "expireAfter": "تنتهي بعد", + "oneWeek": "أسبوع 1", + "twoWeek": "2 أسبوع", + "noUpcoming": "لا يوجد قادم", + "fakeLocation": ".لقد تتبعنا أنك تحاول استخدام موقع مزيف! يعتبر هذا مخالفة وقد تم إخطار الموارد البشرية", + "noWinner": "حزين! لم يفز أحد اليوم.", + "myTeam": "فريقي", + "youCanPlayDemo": "لكن يمكنك لعب العرض", + "group": "مجموعة", + "searchGroup": "مجموعة البحث", + "connectHmgWifi": "قم بتوصيل HMG WIFI", + "connectedHmgWifi": "اتصال HMG WIFI", + "itgForms": "نماذج (ITG)", + "resetAdPassword": "إعادة تعيين كلمة مرور AD", + "myDocuments": "مستنداتي", + "requiredDocuments": "المستندات المطلوبة", + "optionalDocuments": "المستندات الاختيارية", + "allDocuments": "كافة المستندات", + "expiredDocuments": "المستندات منتهية الصلاحية", + "missingDocuments": "مستندات مفقودة", + "uploadedDocuments": "المستندات التي تم تحميلها", + "addAtLeastOneAttachment": "الرجاء إضافة مرفق واحد على الأقل.", + "pleaseClickButtonToJoinMarathon": "الرجاء الضغط على الزر أدناه للانضمام إلى الماراثون", + "youCannotJoinTheMarathon": "لا يمكنك الانضمام إلى الماراثون لأنك تجاوزت الحد الزمني", + "open": "يفتح", + "requesterOperatingUnit": "وحدة تشغيل مقدم الطلب", + "prepareEmpNum": "إعداد رقم الموظف", + "supplierInfo": "معلومات المورد", + "supplierAcNo": "رقم حساب المورد", + "supplierAcName": "اسم حساب المورد", + "supplierIBAN": "رقم IBAN للمورد", + "supplierCRNo": "رقم السجل التجاري", + "suppliedAcNo": "رقم الحساب المقدم", + "patientRefundInvoice": "فاتورة استرداد الأموال للمريض", + "patientNumber": "رقم المريض", + "patientName": "اسم المريض", + "invoiceDate": "تاريخ الفاتورة", + "refundInvoice": "فاتورة الاسترجاع", + "hospitalClinic": "عيادة المستشفى", + "graphicalAnalysis": "التحليل الرسومي", + "itemHistoryAnalysis": "تحليل تاريخ العنصر", + "pOno": "امر شراء #", + "oprUnit": "وحدة التشغيل", + "qtyOrdered": "الكمية المطلوبة", + "qtyReceived": "الكمية المستلمة", + "bonusQty": "كمية المكافأة", + "balQty": "كمية التوازن" +}; +static const Map en_US = { + "mohemm": "Mohemm", + "english": "English", + "arabic": "عربي", + "login": "Login", + "pleaseEnterLoginDetails": "Please enter the detail below to login", + "username": "Username", + "password": "Password", + "welcomeBack": "Welcome back", + "wouldYouLikeToLoginWithCurrentUsername": "Would you like to login with current Username?", + "lastLoginDetails": "Last Login Details:", + "verificationType": "Verification Type:", + "pleaseVerify": "Please Verify", + "pleaseVerifyForBio": "Please verify login with one of the following options", + "verifyThroughFace": "Verify Through Face", + "verifyThroughFingerprint": "Verify Through Fingerprint", + "verifyThroughSMS": "Verify Through SMS", + "verifyThroughWhatsapp": "Verify Through Whatsapp", + "useAnotherAccount": "Use Another Account", + "pleaseEnterTheVerificationCodeSentTo": "Please enter the verification code sent to ", + "theVerificationCodeWillExpireIn": "The verification code will expire in ", + "goodMorning": "Good Morning", + "markAttendance": "Mark Attendance", + "timeLeftToday": "Time Left Today", + "checkIn": "Check In", + "workList": "Work List", + "leaveBalance": "Leave Balance", + "missingSwipes": "Missing Swipes", + "ticketBalance": "Ticket Balance", + "other": "Other", + "services": "Services", + "viewAllServices": "View All Services", + "monthlyAttendance": "Monthly Attendance", + "vacationRule": "Vacation Rule", + "vacationType": "Vacation Type", + "startDateT": "Start Date", + "endDateT": "End Date", + "workFromHome": "Work From Home", + "ticketRequest": "Ticket Request", + "viewAllOffers": "View All Offers", + "offers": "Offers & ", + "discounts": "Discounts", + "newString": "New", + "setTheNewPassword": "Set the new password", + "typeYourNewPasswordBelow": "Type your new password below", + "typeYourNewActiveDirectoryPasswordBelow": "Type new active directory password below", + "confirmPassword": "Confirm Password", + "update": "Update", + "title": "Title", + "home": "Home", + "mySalary": "My Salary", + "createRequest": "Create Request", + "forgotPassword": "Forgot Password", + "employeeId": "Employee ID", + "loginCodeWillSentToMobileNumber": "Please Enter your Employee ID, A login code will be sent to your mobile number", + "changePassword": "Change Password", + "ok": "OK", + "confirm": "Confirm", + "passwordChangedSuccessfully": "Password changed successfully", + "itemsForSale": "Items for Sale", + "attendanceDetails": "Attendance Details", + "order": "order", + "earlyOut": "Early Out", + "shortage": "Shortage", + "excess": "Excess", + "lateIn": "Late In", + "approvedCheckOut": "Approved Check Out", + "approvedCheckIn": "Approved Check In", + "actualCheckOut": "Actual Check Out", + "actualCheckIn": "Actual Check In", + "present": "PRESENT", + "pres": "present", + "shiftTime": "Shift Time", + "absent": "ABSENT", + "attendance": "Attendance", + "scheduleDays": "Schedule\nDays", + "offDays": "Off\nDays", + "nonAnalyzed": "Non\nAnalyzed", + "shortageHour": "Shortage\nHour", + "stats": "Stats", + "completed": "Completed", + "doNotUseRecentPassword": "Do not use recent password", + "atLeastOneLowercase": "At least one lowercase", + "atLeastOneUppercase": "At least one uppercase", + "atLeastOneNumeric": "At least one numeric", + "minimum8Characters": "Minimum 8 characters", + "doNotAddRepeatingLetters": "Do not add repeating letters", + "itShouldContainSpecialCharacter": "It should not contain special characters", + "confirmPasswordMustMatch": "Confirm password must match", + "sms": "SMS", + "fingerPrint": "Fingerprint", + "face": "Face", + "whatsapp": "Whatsapp", + "reject": "Reject", + "approve": "Approve", + "generate": "Generate", + "cancel": "Cancel", + "requestedItems": "Requested Items", + "request": "Request", + "myRequest": "My Request", + "actions": "Actions", + "delegate": "Delegate", + "request_info": "Request Info", + "attachments": "Attachments", + "info": "Info.", + "employeeNumber": "Employee Number", + "assignmentNumber": "Assignment Number", + "employeeName": "Employee Name", + "scheduleDate": "Schedule Date", + "shiftType": "Shift Type", + "shift": "Shift", + "breakText": "Break", + "actualSwipeStart": "Actual Swipe Start", + "actualSwipeEnd": "Actual Swipe End", + "approvedSwipeStart": "Approved Swipe Start", + "approvedSwipeStartReason": "Approved Swipe Start Reason", + "approvedSwipeEnd": "Approved Swipe End", + "approvedSwipeEndReason": "Approved Swipe End Reason", + "from": "From", + "to": "To", + "sent": "Sent", + "closed": "Closed", + "id": "ID", + "responder": "Responder", + "jobTitle": "Job Title", + "grade": "Grade", + "jobCategory": "Job Category", + "category": "Category", + "employeeEmailAddress": "Employee Email Address", + "payrollBranch": "Payroll Branch", + "yourChangeHasBeenSavedSuccessfully": "Your change has been saved successfully", + "code": "Code", + "unit": "Unit", + "quantity": "Quantity", + "dateRequired": "Date Required", + "lineStatus": "Line Status", + "statusDate": "Status Date", + "transactionType": "Transaction Type", + "operatingUnit": "Operating Unit", + "organizationCode": "Organization Code", + "organization": "Organization", + "fromSubInventory": "From Sub Inventory", + "fromLocator": "From Locator", + "toSubInventory": "To Sub Inventory", + "toLocator": "To Locator", + "shipToLocator": "Ship To Locator", + "itemHistory": "Item History", + "mfg": "MFG", + "lineType": "Line Type", + "price": "Price", + "lineAmount": "Line Amount", + "lineDiscount": "Line Discount %", + "needByDate": "Need By Date", + "promisedDate": "Promised Date", + "deliverToLocation": "Deliver To Location", + "requisitionNumber": "Requisition Number", + "requester": "Requester", + "subject": "Subject", + "quotationAnalysis": "Quotation Analysis", + "description": "Description", + "supplier": "Supplier", + "site": "Site", + "buyer": "Buyer", + "preparer": "Preparer", + "creationDate": "Creation Date", + "shipToLocation": "Ship To Location", + "quotationNumber": "Quotation Number", + "quotationDate": "Quotation Date", + "paymentTerms": "Payment Terms", + "currency": "Currency", + "grossAmount": "Gross Amount", + "discountAmount": "Discount Amount", + "customDuty": "Custom Duty", + "shipHandle": "Ship Handle", + "otherCharges": "Other Charges", + "totalPOAmountWithVAT": "Total PO Amount With VAT", + "totalPOAmountInWords": "Total PO Amount In Words", + "requestNumber": "Request Number", + "uom": "UOM", + "operatingCode": "Operating Code", + "poNumber": "PO Number", + "revision": "Revision", + "quantityOrdered": "Quantity Ordered", + "quantityReceived": "Quantity Received", + "bonusQuantity": "Bonus Quantity", + "purchasePrice": "Purchase Price", + "discountPer": "Discount %", + "balanceQuantity": "Balance Quantity", + "netPrice": "Net Price", + "closureStatus": "Closure Status", + "quotationNetPrice": "Quotation Net Price", + "quotationUOM": "Quotation UOM", + "quotationQty": "Quotation Qty", + "itemCode": "item Code", + "vendorName": "Vendor Name", + "quotationMFGPartNumber": "Quotation MFG Part Number", + "quotationDeliveryDate": "Quotation Delivery Date", + "quotationBonusQuantity": "Quotation Bonus Quantity", + "quotationLineTotal": "Quotation Line Total", + "rfqUOM": "RFQ UOM", + "rfqQty": "RFQ Qty", + "rfqNumber": "RFQ Number", + "msg": "Hello {} in the {} world ", + "msg_named": "{} are written in the {lang} language", + "clickMe": "Click me", + "human": "Human", + "resources": "Resources", + "details": "Details", + "noDataAvailable": "No Data Available", + "productName": "Product Name", + "productDescription": "Product Description", + "unitPrice": "Unit Price", + "manufacturerName": "Manufacturer Name", + "manufacturerPartName": "Manufacturer Part Name", + "supplierName": "Supplier Name", + "supplierContact": "Supplier Contact", + "chargeToPatient": "Charge To Patient", + "justification": "Justification", + "itemDescription": "Item Description", + "groupCode": "Group Code", + "primaryUOM": "Primary UOM", + "subgroupDescription": "Subgroup Description", + "subgroupCode": "Subgroup Code", + "groupDescription": "Group Description", + "templateName": "Template Name", + "itemCreationStatus": "Item Creation Status", + "standardizationApprovalStatus": "Standardization Approval Status", + "standardizationApprovalRejectionReason": "Standardization Approval Rejection Reason", + "analyzedBy": "Analyzed By", + "approvedDate": "Approved Date", + "itemType": "Item Type", + "relatedTo": "Related To", + "requestDate": "Request Date", + "analyzedDate": "Analyzed Date", + "urgent": "Urgent", + "requestDetails": "Request Details", + "approvalLevel": "Approval Level", + "requesterDetails": "Requester Details", + "myAttendance": "My Attendance", + "workOnBreak": "Work On Break", + "next": "Next", + "apply": "Apply", + "mobile": "Mobile", + "year": "Year", + "month": "Month", + "day": "Day", + "completingYear": "We appreciate you for completing the service of", + "address": "Address", + "phoneNumber": "Phone Number", + "businessGroup": "Business", + "Payroll": "Payroll", + "civilIdentityNumber": "Civil Identity Number", + "dateOfBirth": "Date of Birth", + "maritalStatus ": "Marital Status ", + "fullName": "Full Name", + "remove": "Remove", + "Attendance": "Attendance", + "submit": "Submit", + "areYouSureYouWantToSubmit": "Are you sure you want to submit?", + "comments": "Comments", + "writeComment": "Write a comment", + "approversList": "Approvers List", + "yourRequestHasBeenSubmittedForApprovals": "Your request has been submitted for approvals", + "monthlyPaySlip": "Monthly Pay Slip", + "particular": "Particular", + "earnings": "Earnings", + "deductions": "Deductions", + "paymentMethodName": "Payment Method Name", + "bankName": "Bank Name", + "branchCode": "Branch Code", + "accountNo": "Account No", + "summaryOfInformation": "Summary of Information", + "totalPayAmount": "Total Pay Amount", + "paymentInformation": "Payment Information", + "amount": "Amount", + "correctCurrentDatails": "correct or complete the current details", + "selectType": "Select the type of change you want to make", + "enterNewInfo": "Enter new Information because of a real change to the current details (e.g because of a change in marital status)", + "endDate": "*End Date", + "removeThisMember": "Are You Sure You Want to Remove this Member?", + "wantUpdateThisMember": "Are You Sure You Want to Update this Member?", + "addNewFamilyMember": "Add New Family Member", + "addRow": "Add new row", + "pleaseSelect": "Please Select *", + "delete": "delete", + "add": "Add", + "edit": "Edit", + "myProfile": "My Profile", + "mowadhafhi": "Mowadhafi", + "searchAnnouncements": "Search Announcements", + "announcements": "Announcements", + "swipeRequest": "Swipe Request", + "serviceType": "Service Type", + "departmentName": "Department Name", + "selectDepartment": "Select Department", + "relatedSection": "Related Section", + "selectSection": "Select Section", + "relatedTopic": "Related Topic", + "selectTopic": "Select Topic", + "supportingDocument": "Supporting Document", + "mowadhafhiRequest": "Mowadhafi Request", + "ticketReference": "Ticket Reference", + "section": "Section", + "topic": "Topic", + "actionBy": "Action By", + "pendingTransactions": "Pending Transactions", + "selectRequestType": "Please select request type", + "dateFrom": "Date From", + "dateTo": "Date To", + "requestName": "Request Name", + "createdFor": "Created For", + "requestType": "Request Type", + "requestCreatedSuccessfully": "Request created successfully", + "search": "Search", + "wantToReject": "Are you sure want to reject?", + "employeeDigitalID": "Employee Digital ID", + "businessCard": "Business Card", + "checkOut": "Check Out", + "regular": "Regular", + "mark": "Mark", + "performance": "Performance Evaluation", + "performanceEvaluationIn": "Your performance Evaluation in", + "valuationIn": "Performance Evaluation in", + "viewBusinessCard": "View Business Card", + "performanceEvaluation": "Performance Evaluation", + "logout": "Logout", + "selectMethodOfAttendance": "Select the method to mark the attendance", + "comeNearHMGWifi": "Please come near to HMG wifi", + "deliverNotificationToMeRegardless": "Deliver notifications to me regardless of any general rules", + "close": "Close", + "respond": "Respond", + "vacationRuleAdded": "Vacation rule added", + "selectTypeT": "Select Type", + "notification": "Notification", + "selectNotification": "Select Notification", + "ifAllSelectedYouWillSkip": "*If All is selected, you will skip to step 3", + "applyForVacationRule": "Apply for Vacation Rule", + "step1": "Step 1", + "step2": "Step 2", + "step3": "Step 3", + "message": "Message", + "writeAMessage": "Write a message", + "notificationReassign": "Notification Reassign", + "selectEmployee": "Select Employee", + "searchEmployeeForReplacement": "Search employee for replacement", + "searchForEmployee": "Search for Employee", + "pleaseSpecifyEndTime": "Please specify End Time", + "pleaseSelectNotificationReassign": "Please select notification reassign", + "pleaseSelectEmployeeForReplacement": "Please select employee for replacement", + "pleaseSelectAction": "Please select action", + "pleaseSelectDate": "Please select date", + "todayAttendance": "Today's Attendance", + "viewAttendance": "View Attendance", + "teamMembers": "Team Members", + "profileDetails": "Profile Details", + "noResultsFound": "No Results Found", + "searchBy": "Search by", + "myTeamMembers": "My Team Members", + "save": "Save", + "TurnNotificationsFor": "Turn on notifications for", + "worklistSettings": "Worklist Settings", + "absenceType": "Absence Type", + "absenceCategory": "Absence Category", + "days": "Days", + "hours": "Hours", + "approvalStatus": "Approval Status", + "absenceStatus": "Absence Status", + "poweredBy": "Powered By", + "cloudSolutions": "Cloud Solutions", + "subordinateLeave": "Subordinate Leave", + "numberDays": "Number of days", + "selectTemplate": "Select Template", + "myPostedAds": "My posted ads", + "browseCategories": "Browse Categories", + "searchItems": "Search Items", + "offerAndDiscounts": "Offer & Discounts", + "offerValid": "Offer Valid", + "offerExpired": "Offer Expired", + "whatAreYouOffering": "What are you offering?", + "selectCategory": "Select Category", + "inProgress": "InProgress", + "locked": "Locked", + "addDetails": "Add Details", + "reviewAndSell": "Review & Sell", + "itemTitle": "Item Title", + "itemCondition": "Item Condition", + "used": "Used", + "region": "Region", + "selectRegion": "Select Region", + "itemPrice": "Item Price", + "itemPhotos": "Item Photos", + "itemInfo": "Item Info", + "uploadAttachment": "Upload Attachment", + "selectFromGalleryOrOpenCamera": "Select from gallery or open camera", + "openCamera": "Open\nCamera", + "uploadFromGallery": "Upload from\nGallery", + "name": "Name", + "email": "Email", + "noHistoryAvailable": "No History Available", + "purchaseRequisition": "Purchase Requisition", + "moveOrder": "Move Order", + "humanResource": "Human Resource", + "purchaseOrder": "Purchase Order", + "ITGForms": "ITG Forms", + "itemCreation": "Item Creation", + "stamp": "Stamp", + "addFavoriteList": "Do you want to add {name} in your favorite list", + "feedbackUserExperience": "This is to get the feedback about the user experience", + "rateUI": "How would you like to rate", + "rateUI2": "How do you satisfied with this application", + "submitSurvey": "Submit Survey", + "typeHere": "Type here", + "infoDetail": "Info Detail", + "amount_detail": "Amount Detail", + "currentBalance": "Current Balance", + "currentLeaveBalance": "Current Leave Balance", + "calculatedDays": "Calculated Days", + "totalDays": "Total Days", + "usedBalance": "Used", + "infants": "Infants", + "child": "Child", + "adult": "Adult", + "updateMember": "Are You Sure You Want to Update this Member?", + "fieldIsEmpty": "'{data}' Field is empty. Please select", + "pleaseEnterComments": "Please enter comments", + "skip": "Skip", + "typeCurrentPasswordBelow": "Type Your Current password below", + "currentPassword": "Current password", + "concurrentReports": "Concurrent Reports", + "EnterNewAddressMoved": "Enter a new address if you have moved", + "CorrectAddress": "Correct or amend this address", + "SelectChangeWantToMake": "Select the type of change you want to make", + "profile": { + "reset_password": { + "label": "Reset Password", + "username": "Username", + "password": "password" }, - "reset_locale": "إعادة ضبط اللغة", - "chat": "دردشة", - "mychats": "دردشاتي", - "advancedSearch": "بحث متقدم", - "openNot": "التبليغات المفتوحة", - "fyi": "تبليغات للعلم", - "toDo": "تبليغات الأعمال", - "all": "كل التبليغات", - "meNot": "تبليغات صادرة مني", - "view": "عرض", - "fromUserName": "من", - "sentDate": "تاريخ الإرسال", - "itemTypeDisplayName": "اسم العرض", - "none": "بدون", - "createNewChat": "إنشاء محادثة جديدة", - "brainMarathon": "ماراثون الدماغ", - "contestTopicAbout": "سيكون موضوع المسابقة حول:", - "gameDate": "تاريخ اللعبة:", - "gameTime": "وقت اللعب:", - "joinMarathon": "انضم إلى ماراثون", - "joinDemoMarathon": "انضم إلى الماراثون التجريبي", - "demo": "تجريبي", - "minutes": "الدقائق", - "seconds": "ثواني", - "note": "ملحوظة:", - "demoMarathonNoteP1": "يمكنك لعب ماراثون العرض لتتعلم كيف يعمل. يمكنك الانضمام إلى ماراثون", - "demoMarathonNoteP2": "خمس دقائق", - "demoMarathonNoteP3": "قبل الوقت الفعلي.", - "sponsoredBy": "برعاية:", - "question": "سؤال", - "marathoners": "الماراثون", - "marathoner": "ماراثونر", - "prize": "جائزة:", - "winnerSelection": "اختيار الفائز", - "qualifiers": "تصفيات", - "qualifier": "المؤهل", - "getReadyForContest": "استعد للمسابقة القادمة:", - "winnerSelectedRandomly": "سيتم اختيار الفائز عشوائياً من بين التصفيات.", - "fingersCrossed": "تشابك الاصابع!!!", - "congrats": "مبروك !!!", - "allQuestionsCorrect": "لقد أجبت على جميع الأسئلة بشكل صحيح.", - "otp": "OTP", - "verification": "تَحَقّق", - "resend": "إعادة إرسال", - "codeExpire": "انتهت صلاحية رمز التحقق", - "typeheretoreply": "اكتب هنا للرد", - "favorite": "مفضلتي", - "searchfromchat": "البحث من الدردشة", - "yourAnswerCorrect": "إجابتك صحيحة", - "youMissedTheQuestion": "نفد منك الوقت. أنت خارج اللعبة. لكن يمكنك الاستمرار وكمشاهد.", - "wrongAnswer": "إجابتك غير صحيحة. أنت خارج اللعبة. لكن يمكنك الاستمرار وكمشاهد.", - "oops": "أوه!!!", - "winner": "الفائز", - "youWantToLeaveMarathon": "هل أنت متأكد أنك تريد العودة؟ سوف تخرج من المسابقة.", - "ourSponsor": "راعينا:", - "startingIn": "يبدأ في", - "youAreOutOfContest": "أنت خارج المسابقة.", - "winners": "الفائزين!!!", - "expireAfter": "تنتهي بعد", - "oneWeek": "أسبوع 1", - "twoWeek": "2 أسبوع", - "noUpcoming": "لا يوجد قادم", - "fakeLocation": ".لقد تتبعنا أنك تحاول استخدام موقع مزيف! يعتبر هذا مخالفة وقد تم إخطار الموارد البشرية", - "noWinner": "حزين! لم يفز أحد اليوم.", - "myTeam": "فريقي", - "youCanPlayDemo": "لكن يمكنك لعب العرض", - "group": "مجموعة", - "searchGroup": "مجموعة البحث", - "connectHmgWifi": "قم بتوصيل HMG WIFI", - "connectedHmgWifi": "اتصال HMG WIFI", - "itgForms": "نماذج (ITG)", - "resetAdPassword": "إعادة تعيين كلمة مرور AD", - "myDocuments": "مستنداتي", - "requiredDocuments": "المستندات المطلوبة", - "optionalDocuments": "المستندات الاختيارية", - "allDocuments": "كافة المستندات", - "expiredDocuments": "المستندات منتهية الصلاحية", - "missingDocuments": "مستندات مفقودة", - "uploadedDocuments": "المستندات التي تم تحميلها", - "youCannotJoinTheMarathon": "لا يمكنك الانضمام إلى الماراثون لأنك تجاوزت الحد الزمني", - "pleaseClickButtonToJoinMarathon": "الرجاء الضغط على الزر أدناه للانضمام إلى الماراثون", - "generate": "يولد", - "paymentRequest":"طلب الدفع", - "paymentDetails":"تفاصيل الدفع", - "requestNo":"رقم الطلب", - "requesterEmpNum":"رقم الموظف الذي قدم الطلب", - "requesterEmpName":"اسم الموظف مقدم الطلب", - "prepareEmpName":"إعداد اسم الموظف", - "requesterPositionName":"اسم الوظيفة لمقدم الطلب", - "preparePositionName":"إعداد اسم الوظيفة", - "requesterPayrollName":"اسم مقدم الطلب", - "payingORGName":"اسم المنظمة الدافعة", - "requestAmount":"مبلغ الطلب", - "typeofPayment":"نوع الدفع", - "beneficiaryDetails":"تفاصيل المستفيد", - "beneficiaryName":"اسم المستفيد", - "idIqama":"الهوية السعودية / الإقامة", - "beneficiaryBankName":"اسم البنك المستفيد", - "sadadNumber":"رقم سداد", - "beneficiaryIBAN":"رقم IBAN للمستفيد", - "purchaseOrders":"طلبات الشراء", - "approvalDate":"تاريخ الموافقة", - "pOAmount":"مبلغ الطلب", - "versionStatus":"حالة الإصدار", - "supplierNo":"رقم المورد", - "general":"عام", - "requesterOperatingUnit":"وحدة تشغيل مقدم الطلب", - "prepareEmpNum":"إعداد رقم الموظف", - - }; - static const Map en_US = { - "mohemm": "Mohemm", - "english": "English", - "arabic": "عربي", - "login": "Login", - "pleaseEnterLoginDetails": "Please enter the detail below to login", - "username": "Username", - "password": "Password", - "welcomeBack": "Welcome back", - "wouldYouLikeToLoginWithCurrentUsername": "Would you like to login with current Username?", - "lastLoginDetails": "Last Login Details:", - "verificationType": "Verification Type:", - "pleaseVerify": "Please Verify", - "pleaseVerifyForBio": "Please verify login with one of the following options", - "verifyThroughFace": "Verify Through Face", - "verifyThroughFingerprint": "Verify Through Fingerprint", - "verifyThroughSMS": "Verify Through SMS", - "verifyThroughWhatsapp": "Verify Through Whatsapp", - "useAnotherAccount": "Use Another Account", - "pleaseEnterTheVerificationCodeSentTo": "Please enter the verification code sent to ", - "theVerificationCodeWillExpireIn": "The verification code will expire in ", - "goodMorning": "Good Morning", - "markAttendance": "Mark Attendance", - "timeLeftToday": "Time Left Today", - "checkIn": "Check In", - "workList": "Work List", - "leaveBalance": "Leave Balance", - "missingSwipes": "Missing Swipes", - "ticketBalance": "Ticket Balance", - "other": "Other", - "services": "Services", - "viewAllServices": "View All Services", - "monthlyAttendance": "Monthly Attendance", - "vacationRule": "Vacation Rule", - "vacationType": "Vacation Type", - "startDateT": "Start Date", - "endDateT": "End Date", - "workFromHome": "Work From Home", - "ticketRequest": "Ticket Request", - "viewAllOffers": "View All Offers", - "offers": "Offers & ", - "discounts": "Discounts", - "newString": "New", - "setTheNewPassword": "Set the new password", - "typeYourNewPasswordBelow": "Type your new password below", - "typeYourNewActiveDirectoryPasswordBelow": "Type new active directory password below", - "confirmPassword": "Confirm Password", - "update": "Update", - "title": "Title", - "home": "Home", - "mySalary": "My Salary", - "createRequest": "Create Request", - "forgotPassword": "Forgot Password", - "employeeId": "Employee ID", - "loginCodeWillSentToMobileNumber": "Please Enter your Employee ID, A login code will be sent to your mobile number", - "changePassword": "Change Password", - "ok": "OK", - "confirm": "Confirm", - "passwordChangedSuccessfully": "Password changed successfully", - "itemsForSale": "Items for Sale", - "attendanceDetails": "Attendance Details", - "order": "order", - "earlyOut": "Early Out", - "shortage": "Shortage", - "excess": "Excess", - "lateIn": "Late In", - "approvedCheckOut": "Approved Check Out", - "approvedCheckIn": "Approved Check In", - "actualCheckOut": "Actual Check Out", - "actualCheckIn": "Actual Check In", - "present": "PRESENT", - "pres": "present", - "shiftTime": "Shift Time", - "absent": "ABSENT", - "attendance": "Attendance", - "scheduleDays": "Schedule\nDays", - "offDays": "Off\nDays", - "nonAnalyzed": "Non\nAnalyzed", - "shortageHour": "Shortage\nHour", - "stats": "Stats", - "completed": "Completed", - "doNotUseRecentPassword": "Do not use recent password", - "atLeastOneLowercase": "At least one lowercase", - "atLeastOneUppercase": "At least one uppercase", - "atLeastOneNumeric": "At least one numeric", - "minimum8Characters": "Minimum 8 characters", - "doNotAddRepeatingLetters": "Do not add repeating letters", - "itShouldContainSpecialCharacter": "It should not contain special character", - "confirmPasswordMustMatch": "Confirm password must match", - "sms": "SMS", - "fingerPrint": "Fingerprint", - "face": "Face", - "whatsapp": "Whatsapp", - "reject": "Reject", - "approve": "Approve", - "cancel": "Cancel", - "requestedItems": "Requested Items", - "request": "Request", - "myRequest": "My Request", - "actions": "Actions", - "delegate": "Delegate", - "request_info": "Request Info", - "attachments": "Attachments", - "info": "Info.", - "employeeNumber": "Employee Number", - "assignmentNumber": "Assignment Number", - "employeeName": "Employee Name", - "scheduleDate": "Schedule Date", - "shiftType": "Shift Type", - "shift": "Shift", - "breakText": "Break", - "actualSwipeStart": "Actual Swipe Start", - "actualSwipeEnd": "Actual Swipe End", - "approvedSwipeStart": "Approved Swipe Start", - "approvedSwipeStartReason": "Approved Swipe Start Reason", - "approvedSwipeEnd": "Approved Swipe End", - "approvedSwipeEndReason": "Approved Swipe End Reason", - "from": "From", - "to": "To", - "sent": "Sent", - "closed": "Closed", - "id": "ID", - "responder": "Responder", - "jobTitle": "Job Title", - "grade": "Grade", - "jobCategory": "Job Category", - "category": "Category", - "employeeEmailAddress": "Employee Email Address", - "payrollBranch": "Payroll Branch", - "yourChangeHasBeenSavedSuccessfully": "Your change has been saved successfully", - "code": "Code", - "unit": "Unit", - "quantity": "Quantity", - "dateRequired": "Date Required", - "lineStatus": "Line Status", - "statusDate": "Status Date", - "transactionType": "Transaction Type", - "operatingUnit": "Operating Unit", - "organizationCode": "Organization Code", - "organization": "Organization", - "fromSubInventory": "From Sub Inventory", - "fromLocator": "From Locator", - "toSubInventory": "To Sub Inventory", - "toLocator": "To Locator", - "shipToLocator": "Ship To Locator", - "itemHistory": "Item History", - "mfg": "MFG", - "lineType": "Line Type", - "price": "Price", - "lineAmount": "Line Amount", - "lineDiscount": "Line Discount %", - "needByDate": "Need By Date", - "promisedDate": "Promised Date", - "deliverToLocation": "Deliver To Location", - "requisitionNumber": "Requisition Number", - "requester": "Requester", - "subject": "Subject", - "quotationAnalysis": "Quotation Analysis", - "description": "Description", - "supplier": "Supplier", - "site": "Site", - "buyer": "Buyer", - "preparer": "Preparer", - "creationDate": "Creation Date", - "shipToLocation": "Ship To Location", - "quotationNumber": "Quotation Number", - "quotationDate": "Quotation Date", - "paymentTerms": "Payment Terms", - "currency": "Currency", - "grossAmount": "Gross Amount", - "discountAmount": "Discount Amount", - "customDuty": "Custom Duty", - "shipHandle": "Ship Handle", - "otherCharges": "Other Charges", - "totalPOAmountWithVAT": "Total PO Amount With VAT", - "totalPOAmountInWords": "Total PO Amount In Words", - "requestNumber": "Request Number", - "uom": "UOM", - "operatingCode": "Operating Code", - "poNumber": "PO Number", - "revision": "Revision", - "quantityOrdered": "Quantity Ordered", - "quantityReceived": "Quantity Received", - "bonusQuantity": "Bonus Quantity", - "purchasePrice": "Purchase Price", - "discountPer": "Discount %", - "balanceQuantity": "Balance Quantity", - "netPrice": "Net Price", - "closureStatus": "Closure Status", - "quotationNetPrice": "Quotation Net Price", - "quotationUOM": "Quotation UOM", - "quotationQty": "Quotation Qty", - "itemCode": "item Code", - "vendorName": "Vendor Name", - "quotationMFGPartNumber": "Quotation MFG Part Number", - "quotationDeliveryDate": "Quotation Delivery Date", - "quotationBonusQuantity": "Quotation Bonus Quantity", - "quotationLineTotal": "Quotation Line Total", - "rfqUOM": "RFQ UOM", - "rfqQty": "RFQ Qty", - "rfqNumber": "RFQ Number", - "msg": "Hello {} in the {} world ", - "msg_named": "{} are written in the {lang} language", - "clickMe": "Click me", - "human": "Human", - "resources": "Resources", - "details": "Details", - "noDataAvailable": "No Data Available", - "productName": "Product Name", - "productDescription": "Product Description", - "unitPrice": "Unit Price", - "manufacturerName": "Manufacturer Name", - "manufacturerPartName": "Manufacturer Part Name", - "supplierName": "Supplier Name", - "supplierContact": "Supplier Contact", - "chargeToPatient": "Charge To Patient", - "justification": "Justification", - "itemDescription": "Item Description", - "groupCode": "Group Code", - "primaryUOM": "Primary UOM", - "subgroupDescription": "Subgroup Description", - "subgroupCode": "Subgroup Code", - "groupDescription": "Group Description", - "templateName": "Template Name", - "itemCreationStatus": "Item Creation Status", - "standardizationApprovalStatus": "Standardization Approval Status", - "standardizationApprovalRejectionReason": "Standardization Approval Rejection Reason", - "analyzedBy": "Analyzed By", - "approvedDate": "Approved Date", - "itemType": "Item Type", - "relatedTo": "Related To", - "requestDate": "Request Date", - "analyzedDate": "Analyzed Date", - "urgent": "Urgent", - "requestDetails": "Request Details", - "approvalLevel": "Approval Level", - "requesterDetails": "Requester Details", - "myAttendance": "My Attendance", - "workOnBreak": "Work On Break", - "next": "Next", - "apply": "Apply", - "mobile": "Mobile", - "year": "Year", - "month": "Month", - "day": "Day", - "completingYear": "We appreciate you for completing the service of", + "profileCompletionPer": "Profile Completion", + "completeProfile": "Complete Profile", + "personalInformation": "Personal Information", + "basicDetails": "Basic Details", "address": "Address", - "phoneNumber": "Phone Number", - "businessGroup": "Business", - "Payroll": "Payroll", - "civilIdentityNumber": "Civil Identity Number", - "dateOfBirth": "Date of Birth", - "maritalStatus ": "Marital Status ", - "fullName": "Full Name", - "remove": "Remove", - "Attendance": "Attendance", - "submit": "Submit", - "areYouSureYouWantToSubmit": "Are you sure you want to submit?", - "comments": "Comments", - "writeComment": "Write a comment", - "approversList": "Approvers List", - "yourRequestHasBeenSubmittedForApprovals": "Your request has been submitted for approvals", - "monthlyPaySlip": "Monthly Pay Slip", - "particular": "Particular", - "earnings": "Earnings", - "deductions": "Deductions", - "paymentMethodName": "Payment Method Name", - "bankName": "Bank Name", - "branchCode": "Branch Code", - "accountNo": "Account No", - "summaryOfInformation": "Summary of Information", - "totalPayAmount": "Total Pay Amount", - "paymentInformation": "Payment Information", - "amount": "Amount", - "correctCurrentDatails": "correct or complete the current details", - "selectType": "Select the type of change you want to make", - "enterNewInfo": "Enter new Information because of a real change to the current details (e.g because of a change in marital status)", - "endDate": "*End Date", - "removeThisMember": "Are You Sure You Want to Remove this Member?", - "wantUpdateThisMember": "Are You Sure You Want to Update this Member?", - "addNewFamilyMember": "Add New Family Member", - "addRow": "Add new row", - "pleaseSelect": "Please Select *", - "delete": "delete", - "add": "Add", - "edit": "Edit", - "myProfile": "My Profile", - "mowadhafhi": "Mowadhafi", - "searchAnnouncements": "Search Announcements", - "announcements": "Announcements", - "swipeRequest": "Swipe Request", - "serviceType": "Service Type", - "departmentName": "Department Name", - "selectDepartment": "Select Department", - "relatedSection": "Related Section", - "selectSection": "Select Section", - "relatedTopic": "Related Topic", - "selectTopic": "Select Topic", - "supportingDocument": "Supporting Document", - "mowadhafhiRequest": "Mowadhafi Request", - "ticketReference": "Ticket Reference", - "section": "Section", - "topic": "Topic", - "actionBy": "Action By", - "pendingTransactions": "Pending Transactions", - "selectRequestType": "Please select request type", - "dateFrom": "Date From", - "dateTo": "Date To", - "requestName": "Request Name", - "createdFor": "Created For", - "requestType": "Request Type", - "requestCreatedSuccessfully": "Request created successfully", - "search": "Search", - "wantToReject": "Are you sure want to reject?", - "employeeDigitalID": "Employee Digital ID", - "businessCard": "Business Card", - "checkOut": "Check Out", - "regular": "Regular", - "mark": "Mark", - "performance": "Performance Evaluation", - "performanceEvaluationIn": "Your performance Evaluation in", - "valuationIn": "Performance Evaluation in", - "viewBusinessCard": "View Business Card", - "performanceEvaluation": "Performance Evaluation", - "logout": "Logout", - "selectMethodOfAttendance": "Select the method to mark the attendance", - "comeNearHMGWifi": "Please come near to HMG wifi", - "deliverNotificationToMeRegardless": "Deliver notifications to me regardless of any general rules", - "close": "Close", - "respond": "Respond", - "vacationRuleAdded": "Vacation rule added", - "selectTypeT": "Select Type", - "notification": "Notification", - "selectNotification": "Select Notification", - "ifAllSelectedYouWillSkip": "*If All is selected, you will skip to step 3", - "applyForVacationRule": "Apply for Vacation Rule", - "step1": "Step 1", - "step2": "Step 2", - "step3": "Step 3", - "message": "Message", - "writeAMessage": "Write a message", - "notificationReassign": "Notification Reassign", - "selectEmployee": "Select Employee", - "searchEmployeeForReplacement": "Search employee for replacement", - "searchForEmployee": "Search for Employee", - "pleaseSpecifyEndTime": "Please specify End Time", - "pleaseSelectNotificationReassign": "Please select notification reassign", - "pleaseSelectEmployeeForReplacement": "Please select employee for replacement", - "pleaseSelectAction": "Please select action", - "pleaseSelectDate": "Please select date", - "todayAttendance": "Today's Attendance", - "viewAttendance": "View Attendance", - "teamMembers": "Team Members", - "profileDetails": "Profile Details", - "noResultsFound": "No Results Found", - "searchBy": "Search by", - "myTeamMembers": "My Team Members", - "save": "Save", - "TurnNotificationsFor": "Turn on notifications for", - "worklistSettings": "Worklist Settings", - "absenceType": "Absence Type", - "absenceCategory": "Absence Category", - "days": "Days", - "hours": "Hours", - "approvalStatus": "Approval Status", - "absenceStatus": "Absence Status", - "poweredBy": "Powered By", - "cloudSolutions": "Cloud Solutions", - "subordinateLeave": "Subordinate Leave", - "numberDays": "Number of days", - "selectTemplate": "Select Template", - "myPostedAds": "My posted ads", - "browseCategories": "Browse Categories", - "searchItems": "Search Items", - "offerAndDiscounts": "Offer & Discounts", - "offerValid": "Offer Valid", - "offerExpired": "Offer Expired", - "whatAreYouOffering": "What are you offering?", - "selectCategory": "Select Category", - "inProgress": "InProgress", - "locked": "Locked", - "addDetails": "Add Details", - "reviewAndSell": "Review & Sell", - "itemTitle": "Item Title", - "itemCondition": "Item Condition", - "used": "Used", - "region": "Region", - "selectRegion": "Select Region", - "itemPrice": "Item Price", - "itemPhotos": "Item Photos", - "itemInfo": "Item Info", - "uploadAttachment": "Upload Attachment", - "selectFromGalleryOrOpenCamera": "Select from gallery or open camera", - "openCamera": "Open\nCamera", - "uploadFromGallery": "Upload from\nGallery", - "name": "Name", - "email": "Email", - "noHistoryAvailable": "No History Available", - "purchaseRequisition": "Purchase Requisition", - "moveOrder": "Move Order", - "humanResource": "Human Resource", - "purchaseOrder": "Purchase Order", - "ITGForms": "ITG Forms", - "itemCreation": "Item Creation", - "stamp": "Stamp", - "addFavoriteList": "Do you want to add {name} in your favorite list", - "feedbackUserExperience": "This is to get the feedback about the user experience", - "rateUI": "How would you like to rate", - "rateUI2": "How do you satisfied with this application", - "submitSurvey": "Submit Survey", - "typeHere": "Type here", - "infoDetail": "Info Detail", - "amount_detail": "Amount Detail", - "currentBalance": "Current Balance", - "currentLeaveBalance": "Current Leave Balance", - "calculatedDays": "Calculated Days", - "totalDays": "Total Days", - "usedBalance": "Used", - "infants": "Infants", - "child": "Child", - "adult": "Adult", - "updateMember": "Are You Sure You Want to Update this Member?", - "fieldIsEmpty": "'{data}' Field is empty. Please select", - "pleaseEnterComments": "Please enter comments", - "skip": "Skip", - "typeCurrentPasswordBelow": "Type Your Current password below", - "currentPassword": "Current password", - "concurrentReports": "Concurrent Reports", - "EnterNewAddressMoved": "Enter a new address if you have moved", - "CorrectAddress": "Correct or amend this address", - "SelectChangeWantToMake": "Select the type of change you want to make", - "profile": { - "reset_password": {"label": "Reset Password", "username": "Username", "password": "password"}, - "profileCompletionPer": "Profile Completion", - "completeProfile": "Complete Profile", - "personalInformation": "Personal Information", - "basicDetails": "Basic Details", - "address": "Address", - "contactDetails": "Contact Details", - "familyDetails": "Family Members", - "effectiveDate": "Effective Date", - "country": "Country" - }, - "clicked": { - "zero": "You clicked {} times!", - "one": "You clicked {} time!", - "two": "You clicked {} times!", - "few": "You clicked {} times!", - "many": "You clicked {} times!", - "other": "You clicked {} times!" - }, - "gender": { - "male": "Hi man ;) ", - "female": "Hello girl :)", - "with_arg": {"male": "Hi man ;) {}", "female": "Hello girl :) {}"} - }, - "reset_locale": "Reset Language", - "chat": "Chat", - "mychats": "My Chats", - "createNewChat": "Create New Chat", - "brainMarathon": "Brain Marathon", - "contestTopicAbout": "Contest Topic will be about:", - "gameDate": "Game Date:", - "gameTime": "Game Time:", - "joinMarathon": "Join Marathon", - "joinDemoMarathon": "Join Demo Marathon", - "demo": "Demo", - "minutes": "Minutes", - "seconds": "Seconds", - "note": "Note:", - "demoMarathonNoteP1": "You can play the demo Marathon to learn how it works. You can join the Marathon", - "demoMarathonNoteP2": "5 Minutes", - "demoMarathonNoteP3": "before the actual time.", - "sponsoredBy": "Sponsored By:", - "question": "Question", - "marathoners": "Marathoners", - "marathoner": "Marathoner", - "prize": "Prize:", - "advancedSearch": "Advanced Search", - "openNot": "Open Notifications", - "fyi": "FYI Notifications", - "toDo": "To Do Notifications", - "all": "All Notifications", - "meNot": "Notifications from Me", - "view": "View", - "fromUserName": "From User Name", - "sentDate": "Sent Date", - "itemTypeDisplayName": "Item Type Display Name", - "none": "None", - "winnerSelection": "Winner Selection", - "qualifiers": "Qualifiers", - "qualifier": "Qualifier", - "getReadyForContest": "Get Ready for the coming contest:", - "winnerSelectedRandomly": "The winner will be selected randomly among the qualifiers.", - "fingersCrossed": "Fingers Crossed!!!", - "congrats": "Congratulations!!!", - "otp": "OTP", - "verification": "Verification", - "resend": "Resend", - "codeExpire": "The verification code has been expired", - "allQuestionsCorrect": "You have answered all questions correct", - "typeheretoreply": "Type here to reply", - "favorite": "My Favorites", - "searchfromchat": "Search from chat", - "yourAnswerCorrect": "Your answer is correct", - "youMissedTheQuestion": "You ran out of time. You are out of the game. But you can continue as a viewer.", - "wrongAnswer": "Your answer is Incorrect. You are out of the game. But you can continue as a viewer.", - "oops": "Ooopsss!!!!", - "winner": "WINNER", - "youWantToLeaveMarathon": "Are you sure you want to go back? You will be out of the contest.", - "ourSponsor": "Our Sponsor:", - "startingIn": "Starting in", - "youAreOutOfContest": "You are out of the contest.", - "winners": "WINNERS!!!", - "expireAfter": "Expires After", - "oneWeek": "1 Week", - "twoWeek": "2 Week", - "noUpcoming": "There is no upcoming", - "fakeLocation": "We traced out that you try to use a fake location! This is considered a violation, and HR has been notified.", - "noWinner": "Sad! No one won today.", - "myTeam": "My Team", - "youCanPlayDemo": "But you can play demo", - "group": "Groups", - "searchGroup": "Search Group", - "connectHmgWifi": "Connect HMG WIFI", - "connectedHmgWifi": "Connected HMG WIFI", - "itgForms": "ITG Forms", - "resetAdPassword": "Reset AD Password", - "myDocuments": "My Documents", - "requiredDocuments": "Required Documents", - "optionalDocuments": "Optional Documents", - "allDocuments": "All\nDocuments", - "expiredDocuments": "Expired\nDocuments", - "missingDocuments": "Missing\nDocuments", - "uploadedDocuments": "Uploaded\nDocuments", - "manage": "Manage", - "members": "Members", - "areYouSureWantTodelete": "Are you sure want to delete?", - "groupMembers": "Group Members", - "manageGroup": "Manage Group", - "admin": "Admin", - "addUsers": "Add users to the group", - "editGroups": "Edit Group", - "groupNameshouldbe": "Group name should be minimum 10 character long", - "enterGroupName": "Please enter valid group Name", - "groupName": "Group Name", - "enterGroupNamePlease": "Please enter group name", - "audioCall": "Audio Call", - "videoCall": "Video Call", - "shareScreen": "Share Screen", - "searchByUserName": "Search By Username", - "userSearch": "User Search", - "userName": "User Name", - "userId": "UserID", - "pleaseClickButtonToJoinMarathon": "Press the button below to join the Marathon.", - "youCannotJoinTheMarathon": "You cannot join the Marathon because you have exceeded the time limit.", - "generate": "Generate", - "paymentRequest":"Pay Request", - "paymentDetails":"Payment Details", - "requestNo":"Request No", - "requesterEmpNum":"Requester Employee Num", - "requesterEmpName":"Requester Employee Name", - "prepareEmpName":"Prepare Employee Name", - "requesterPositionName":"Requester Position Name", - "preparePositionName":"Prepare Position Name", - "requesterPayrollName":"Requester Payroll Name", - "payingORGName":"Paying Organization Name", - "requestAmount":"Request Amount", - "typeofPayment":"Type of Payment", - "beneficiaryDetails":"Beneficiary Details", - "beneficiaryName":"Beneficiary Name", - "idIqama":"Saudi ID / Iqama", - "beneficiaryBankName":"Beneficiary Bank Name", - "sadadNumber":"Sadad Number", - "beneficiaryIBAN":"Beneficiary IBAN", - "purchaseOrders":"Purchase Orders", - "approvalDate":"Approval Date", - "pOAmount":"PO Amount", - "versionStatus":"Version Status", - "supplierNo":"Supplier No", - "general":"General", - "prepareEmpNum":"Prepare Employee Num", - "requesterOperatingUnit":"Requester Operating Unit", - "supplierInfo" : "Supplier Information", - "supplierNum": "Supplier Number", - "supplierAcNo": "Supplier Account Number", - "supplierAcName" : 'Supplier Account Name', - "supplierIBAN" : 'Supplier IBAN', - "supplierCRNo" : 'CR Number', - "suppliedAcNo" : 'Supplied Account No.', - "patientRefundInvoice" : 'Patient Refund Invoice', - "patientNumber" : 'Patient Number', - "patientName" : 'Patient Name', - "invoiceDate" : 'Invoice Date', - "refundInvoice" : 'Refund Invoice', - "hospitalClinic" : 'Hospital Clinic', - - - - }; - static const Map> mapLocales = {"ar_SA": ar_SA, "en_US": en_US}; + "contactDetails": "Contact Details", + "familyDetails": "Family Members", + "effectiveDate": "Effective Date", + "country": "Country" + }, + "clicked": { + "zero": "You clicked {} times!", + "one": "You clicked {} time!", + "two": "You clicked {} times!", + "few": "You clicked {} times!", + "many": "You clicked {} times!", + "other": "You clicked {} times!" + }, + "gender": { + "male": "Hi man ;) ", + "female": "Hello girl :)", + "with_arg": { + "male": "Hi man ;) {}", + "female": "Hello girl :) {}" + } + }, + "reset_locale": "Reset Language", + "chat": "Chat", + "mychats": "My Chats", + "createNewChat": "Create New Chat", + "brainMarathon": "Brain Marathon", + "contestTopicAbout": "Contest Topic will be about:", + "gameDate": "Game Date:", + "gameTime": "Game Time:", + "joinMarathon": "Join Marathon", + "joinDemoMarathon": "Join Demo Marathon", + "demo": "Demo", + "minutes": "Minutes", + "seconds": "Seconds", + "note": "Note:", + "demoMarathonNoteP1": "You can play the demo Marathon to learn how it works. You can join the Marathon", + "demoMarathonNoteP2": "5 Minutes", + "demoMarathonNoteP3": "before the actual time.", + "sponsoredBy": "Sponsored By:", + "question": "Question", + "marathoners": "Marathoners", + "marathoner": "Marathoner", + "prize": "Prize:", + "advancedSearch": "Advanced Search", + "openNot": "Open Notifications", + "fyi": "FYI Notifications", + "toDo": "To Do Notifications", + "all": "All Notifications", + "meNot": "Notifications from Me", + "view": "View", + "fromUserName": "From User Name", + "sentDate": "Sent Date", + "itemTypeDisplayName": "Item Type Display Name", + "none": "None", + "winnerSelection": "Winner Selection", + "qualifiers": "Qualifiers", + "qualifier": "Qualifier", + "getReadyForContest": "Get Ready for the coming contest:", + "winnerSelectedRandomly": "The winner will be selected randomly among the qualifiers.", + "fingersCrossed": "Fingers Crossed!!!", + "congrats": "Congratulations!!!", + "otp": "OTP", + "verification": "Verification", + "resend": "Resend", + "codeExpire": "The verification code has been expired", + "allQuestionsCorrect": "You have answered all questions correct", + "typeheretoreply": "Type here to reply", + "favorite": "My Favorites", + "searchfromchat": "Search from chat", + "yourAnswerCorrect": "Your answer is correct", + "youMissedTheQuestion": "You ran out of time. You are out of the game. But you can continue as a viewer.", + "wrongAnswer": "Your answer is Incorrect. You are out of the game. But you can continue as a viewer.", + "oops": "Ooopsss!!!!", + "winner": "WINNER", + "youWantToLeaveMarathon": "Are you sure you want to go back? You will be out of the contest.", + "ourSponsor": "Our Sponsor:", + "startingIn": "Starting in", + "youAreOutOfContest": "You are out of the contest.", + "winners": "WINNERS!!!", + "expireAfter": "Expires After", + "oneWeek": "1 Week", + "twoWeek": "2 Week", + "noUpcoming": "There is no upcoming", + "fakeLocation": "We traced out that you try to use a fake location! This is considered a violation, and HR has been notified.", + "noWinner": "Sad! No one won today.", + "myTeam": "My Team", + "youCanPlayDemo": "But you can play demo", + "group": "Groups", + "searchGroup": "Search Group", + "connectHmgWifi": "Connect HMG WIFI", + "connectedHmgWifi": "Connected HMG WIFI", + "itgForms": "ITG Forms", + "resetAdPassword": "Reset AD Password", + "myDocuments": "My Documents", + "requiredDocuments": "Required Documents", + "optionalDocuments": "Optional Documents", + "allDocuments": "All\nDocuments", + "expiredDocuments": "Expired\nDocuments", + "missingDocuments": "Missing\nDocuments", + "uploadedDocuments": "Uploaded\nDocuments", + "manage": "Manage", + "members": "Members", + "areYouSureWantTodelete": "Are you sure want to delete?", + "groupMembers": "Group Members", + "manageGroup": "Manage Group", + "admin": "Admin", + "addUsers": "Add users to the group", + "editGroups": "Edit Group", + "groupNameshouldbe": "Group name should be minimum 10 character long", + "enterGroupName": "Please enter valid group Name", + "groupName": "Group Name", + "enterGroupNamePlease": "Please enter group name", + "audioCall": "Audio Call", + "videoCall": "Video Call", + "shareScreen": "Share Screen", + "searchByUserName": "Search By Username", + "userSearch": "User Search", + "userName": "User Name", + "userId": "UserID", + "open": "open", + "addAtLeastOneAttachment": "Please add at least one attachment.", + "pleaseClickButtonToJoinMarathon": "Press the button below to join the Marathon.", + "youCannotJoinTheMarathon": "You cannot join the Marathon because you have exceeded the time limit.", + "requesterOperatingUnit": "Requester Operating Unit", + "prepareEmpNum": "Prepare Employee Num", + "supplierInfo": "Supplier Information", + "supplierAcNo": "Supplier Account No", + "supplierAcName": "Supplier Account Name", + "supplierIBAN": "Supplier IBAN", + "supplierCRNo": "CR Number", + "suppliedAcNo": "Supplied Account No.", + "patientRefundInvoice": "Patient Refund Invoice", + "patientNumber": "Patient Number", + "patientName": "Patient Name", + "invoiceDate": "Invoice Date", + "refundInvoice": "Refund Invoice", + "hospitalClinic": "Hospital Clinic", + "graphicalAnalysis": "Graphical Analysis", + "itemHistoryAnalysis": "Item History Analysis", + "pOno": "P.O #", + "oprUnit": "Opr. Unit", + "qtyOrdered": "Qty. Ordered", + "qtyReceived": "Qty. Received", + "bonusQty": "Bonus Qty.", + "balQty": "Bal. Qty." +}; +static const Map> mapLocales = {"ar_SA": ar_SA, "en_US": en_US}; } diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 9faea5a..c372a3a 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -98,6 +98,7 @@ abstract class LocaleKeys { static const reject = 'reject'; static const approve = 'approve'; static const cancel = 'cancel'; + static const generate = 'generate'; static const requestedItems = 'requestedItems'; static const request = 'request'; static const myRequest = 'myRequest'; @@ -403,7 +404,6 @@ abstract class LocaleKeys { static const purchaseOrder = 'purchaseOrder'; static const ITGForms = 'ITGForms'; static const itemCreation = 'itemCreation'; - static const paymentRequest = 'paymentRequest'; static const stamp = 'stamp'; static const addFavoriteList = 'addFavoriteList'; static const feedbackUserExperience = 'feedbackUserExperience'; @@ -527,67 +527,31 @@ abstract class LocaleKeys { static const expiredDocuments = 'expiredDocuments'; static const missingDocuments = 'missingDocuments'; static const uploadedDocuments = 'uploadedDocuments'; - - static const manage = 'manage'; - static const members = 'members'; - static const areYouSureWantTodelete = 'areYouSureWantTodelete'; - static const groupMembers = "groupMembers"; - static const manageGroup = "manageGroup"; - static const admin = "admin"; - static const addUsers ="addUsers"; - static const editGroups ="editGroups"; - static const groupNameshouldbe ="groupNameshouldbe"; - static const enterGroupName ="enterGroupName"; - static const groupName ="groupName"; - static const enterGroupNamePlease ="enterGroupNamePlease"; - static const audioCall = 'audioCall'; - static const videoCall ='videoCall'; - static const shareScreen ='shareScreen'; - static const searchByUserName ='searchByUserName'; - static const userSearch ='userSearch'; - static const userName ='userName'; - static const userId ='userId'; - static const addAtLeastOneAttachment ='addAtLeastOneAttachment'; - static const pleaseClickButtonToJoinMarathon ='pleaseClickButtonToJoinMarathon'; - static const youCannotJoinTheMarathon ='youCannotJoinTheMarathon'; - static const open ='open'; - static const generate = 'generate'; - static const paymentDetails ='paymentDetails'; - static const requestNo ='requestNo'; - static const requesterEmpNum ='requesterEmpNum'; - static const requesterEmpName ='requesterEmpName'; - static const prepareEmpName ='prepareEmpName'; - static const requesterPositionName ='requesterPositionName'; - static const preparePositionName ='preparePositionName'; - static const requesterPayrollName ='requesterPayrollName'; - static const payingORGName ='payingORGName'; - static const requestAmount ='requestAmount'; - static const typeofPayment ='typeofPayment'; - static const beneficiaryDetails ='beneficiaryDetails'; - static const beneficiaryName ='beneficiaryName'; - static const idIqama ='idIqama'; - static const beneficiaryBankName ='beneficiaryBankName'; - static const sadadNumber ='sadadNumber'; - static const beneficiaryIBAN ='beneficiaryIBAN'; - static const purchaseOrders ='purchaseOrders'; - static const pOAmount ='pOAmount'; - static const approvalDate ='approvalDate'; - static const versionStatus ='versionStatus'; - static const supplierNo ='supplierNo'; - static const general ="general"; + static const addAtLeastOneAttachment = 'addAtLeastOneAttachment'; + static const pleaseClickButtonToJoinMarathon = 'pleaseClickButtonToJoinMarathon'; + static const youCannotJoinTheMarathon = 'youCannotJoinTheMarathon'; + static const open = 'open'; + static const requesterOperatingUnit = 'requesterOperatingUnit'; + static const prepareEmpNum = 'prepareEmpNum'; static const supplierInfo = 'supplierInfo'; static const supplierAcNo = 'supplierAcNo'; static const supplierAcName = 'supplierAcName'; - static const supplierIBAN = 'Supplier IBAN'; - static const supplierCRNo = 'CR Number'; - static const suppliedAcNo = 'Supplied Account No.'; - static const patientRefundInvoice = "patientRefundInvoice"; - static const patientNumber = 'Patient Number'; - static const patientName = 'Patient Name'; - static const invoiceDate = 'Invoice Date'; - static const refundInvoice = 'Refund Invoice'; - static const hospitalClinic = 'Hospital Clinic'; - static const requesterOperatingUnit ='requesterOperatingUnit'; - static const prepareEmpNum ='prepareEmpNum'; + static const supplierIBAN = 'supplierIBAN'; + static const supplierCRNo = 'supplierCRNo'; + static const suppliedAcNo = 'suppliedAcNo'; + static const patientRefundInvoice = 'patientRefundInvoice'; + static const patientNumber = 'patientNumber'; + static const patientName = 'patientName'; + static const invoiceDate = 'invoiceDate'; + static const refundInvoice = 'refundInvoice'; + static const hospitalClinic = 'hospitalClinic'; + static const graphicalAnalysis = 'graphicalAnalysis'; + static const itemHistoryAnalysis = 'itemHistoryAnalysis'; + static const pOno = 'pOno'; + static const oprUnit = 'oprUnit'; + static const qtyOrdered = 'qtyOrdered'; + static const qtyReceived = 'qtyReceived'; + static const bonusQty = 'bonusQty'; + static const balQty = 'balQty'; } diff --git a/lib/ui/work_list/item_history_screen.dart b/lib/ui/work_list/item_history_screen.dart index 7490d38..71cea08 100644 --- a/lib/ui/work_list/item_history_screen.dart +++ b/lib/ui/work_list/item_history_screen.dart @@ -2,7 +2,8 @@ import 'dart:convert'; import 'dart:io'; import 'dart:typed_data'; -import 'package:easy_localization/src/public_ext.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:fl_chart/fl_chart.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:mohem_flutter_app/api/worklist/worklist_api_client.dart'; @@ -60,13 +61,21 @@ class _ItemHistoryScreenState extends State { int tabIndex = 0; PageController controller = PageController(); + final ScrollController _horizontalScrollController = ScrollController(); + final ScrollController _horizontalHeaderScrollController = ScrollController(); + @override void initState() { super.initState(); + _horizontalScrollController.addListener(() { + _horizontalHeaderScrollController.jumpTo(_horizontalScrollController.offset); + }); } @override void dispose() { + _horizontalScrollController.dispose(); + _horizontalHeaderScrollController.dispose(); super.dispose(); actionHistoryList.clear(); } @@ -129,23 +138,231 @@ class _ItemHistoryScreenState extends State { } } + TableRow rowChildren(GetPoItemHistoryList poData, int index) { + return TableRow( + decoration: BoxDecoration(color: index % 2 == 0 ? Colors.white : Colors.grey[100]), + children: [ + rowCell(poData.cREATIONDATE!, index), + rowCell(poData.pURCHASEPRICE!.toString(), index), + rowCell(poData.sUPPLIER!, index), + rowCell(poData.pONUMBER!.toString(), index), + rowCell(poData.oUNAME!, index), + rowCell(poData.rEVISIONNUM!.toString(), index), + rowCell(poData.bUYER!, index), + rowCell(poData.uOM!, index), + rowCell(poData.qUANTITYORDERED!.toString(), index), + rowCell(poData.qUANTITYRECEIVED!.toString(), index), + rowCell(poData.bONUSQUANTITY!.toString(), index), + rowCell(poData.dISCOUNTPERCENTAGE!.toString(), index), + rowCell(poData.bALANCEQUANTITY!.toString(), index), + rowCell(poData.nETPRICE!.toString(), index), + rowCell(poData.cLOSEDCODE!, index), + ], + ); + } + + Widget rowCell(String data, int index) { + return TableCell( + verticalAlignment: TableCellVerticalAlignment.middle, + child: Center( + child: Text( + data, + style: TextStyle(fontSize: 12, color: MyColors.normalTextColor, fontWeight: FontWeight.w500), + ), + + // data.toText12(color: MyColors.normalTextColor), + ).paddingAll(8)); + } + + Widget headerCell(String data) { + return Container( + padding: const EdgeInsets.only(top: 16, bottom: 16, left: 8, right: 8), + width: 120, + alignment: Alignment.center, + decoration: BoxDecoration(color: Colors.grey[300]), + child: data.toText14(color: MyColors.darkIconColor), + ); + } + + List gradientColors = [MyColors.gradiantEndColor, MyColors.gradiantEndColor]; + + LineChartData drawLineChart(List spots, List reversedList) { + return LineChartData( + lineTouchData: LineTouchData(enabled: true, touchTooltipData: LineTouchTooltipData(tooltipBgColor: Colors.grey[300])), + gridData: FlGridData( + show: true, + drawHorizontalLine: true, + drawVerticalLine: true, + verticalInterval: 1, + horizontalInterval: 1, + getDrawingVerticalLine: (value) { + return FlLine(color: Color(0xff37434d), strokeWidth: .3); + }, + getDrawingHorizontalLine: (value) { + return FlLine(color: Color(0xff37434d), strokeWidth: .3); + }, + ), + titlesData: FlTitlesData( + show: true, + bottomTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: true, + reservedSize: 30, + interval: 1, + getTitlesWidget: (double value, TitleMeta meta) { + return SideTitleWidget( + axisSide: meta.axisSide, + child: Text(reversedList[int.parse(meta.formattedValue)].cREATIONDATE!, style: TextStyle(fontSize: 10)), + ); + })), + leftTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: true, + reservedSize: 30, + interval: 1, + getTitlesWidget: (double value, TitleMeta meta) { + return SideTitleWidget( + axisSide: meta.axisSide, + child: Text(meta.formattedValue, style: TextStyle(fontSize: 10)), + ); + })), + topTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)), + rightTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: true, + reservedSize: 15, + getTitlesWidget: (double value, TitleMeta meta) { + return SideTitleWidget( + axisSide: meta.axisSide, + child: Text("", style: TextStyle(fontSize: 10)), + ); + })), + ), + borderData: FlBorderData(show: true, border: Border.all(color: const Color(0xff37434d))), + minX: 0, + maxX: poItemHistoryList.length.toDouble() - 1, + minY: poItemHistoryList.map((e) => e.pURCHASEPRICE!.toDouble()).reduce((curr, next) => curr < next ? curr : next) - 1, + maxY: poItemHistoryList.map((e) => e.pURCHASEPRICE!.toDouble()).reduce((curr, next) => curr > next ? curr : next) + 1, + lineBarsData: [ + LineChartBarData( + spots: spots, + isCurved: true, + gradient: LinearGradient( + colors: [ + ColorTween(begin: gradientColors[0], end: gradientColors[1]).lerp(0.2)!, + ColorTween(begin: gradientColors[0], end: gradientColors[1]).lerp(0.2)!, + ], + ), + barWidth: 2, + isStrokeCapRound: true, + dotData: FlDotData(show: true), + belowBarData: BarAreaData( + show: true, + gradient: LinearGradient( + colors: [ + ColorTween(begin: gradientColors[0], end: gradientColors[1]).lerp(0.2)!.withOpacity(0.1), + ColorTween(begin: gradientColors[0], end: gradientColors[1]).lerp(0.2)!.withOpacity(0.1), + ], + ), + ), + ), + ], + ); + } + @override Widget build(BuildContext context) { loadData(); + Widget? chartWidget; + + if (_screenParams!.isItemHistory && poItemHistoryList.isNotEmpty) { + try { + List reversedList = poItemHistoryList.reversed.toList(); + List dataPoints = List.generate( + reversedList.length, + (index) => FlSpot(index.toDouble(), reversedList[index].pURCHASEPRICE!.toDouble()), + ); + + double chartWidth = dataPoints.length * 70.0; + chartWidget = Column( + mainAxisSize: MainAxisSize.min, + children: [ + LocaleKeys.graphicalAnalysis.tr().toText14(color: MyColors.darkIconColor), + SizedBox( + height: 400, + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Container( + width: chartWidth, + padding: const EdgeInsets.all(16.0), + child: LineChart(drawLineChart(dataPoints, reversedList)), + ), + ), + ), + ], + ); + } catch (ex) {} + } + return Scaffold( appBar: AppBarWidget(context, title: _screenParams?.title ?? ""), backgroundColor: Colors.white, - body: ListView( - padding: _screenParams!.isPRInfo ? const EdgeInsets.all(0) : const EdgeInsets.all(21), - physics: const NeverScrollableScrollPhysics(), - children: [ - if (_screenParams!.isPRInfo) prLinesDataView(), - if (moItemHistoryList.isNotEmpty) loadMoItemHistoryData(), - if (poItemHistoryList.isNotEmpty) loadPoItemHistoryData(), - if (quotationAnalysisList.isNotEmpty) loadQuotationAnalysisData(), - if (moItemHistoryList.isEmpty && poItemHistoryList.isEmpty && quotationAnalysisList.isEmpty && !_screenParams!.isPRInfo) Utils.getNoDataWidget(context), - ], - ), + body: (_screenParams!.isItemHistory && poItemHistoryList.isNotEmpty) + ? Column( + children: [ + if (chartWidget != null) chartWidget, + if (poItemHistoryList.isNotEmpty) ...[ + LocaleKeys.itemHistoryAnalysis.tr().toText14(color: MyColors.darkIconColor), + 16.height, + SingleChildScrollView( + scrollDirection: Axis.horizontal, + physics: const NeverScrollableScrollPhysics(), + controller: _horizontalHeaderScrollController, + child: Row( + children: [ + headerCell(LocaleKeys.creationDate.tr()), + headerCell(LocaleKeys.purchasePrice.tr()), + headerCell(LocaleKeys.supplier.tr()), + headerCell(LocaleKeys.pOno.tr()), + headerCell(LocaleKeys.oprUnit.tr()), + headerCell(LocaleKeys.revision.tr()), + headerCell(LocaleKeys.buyer.tr()), + headerCell(LocaleKeys.uom.tr()), + headerCell(LocaleKeys.qtyOrdered.tr()), + headerCell(LocaleKeys.qtyReceived.tr()), + headerCell(LocaleKeys.bonusQty.tr()), + headerCell(LocaleKeys.discountPer.tr()), + headerCell(LocaleKeys.balQty.tr()), + headerCell(LocaleKeys.netPrice.tr()), + headerCell(LocaleKeys.closureStatus.tr()), + ], + ), + ), + SingleChildScrollView( + scrollDirection: Axis.vertical, + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + controller: _horizontalScrollController, + child: Table( + defaultColumnWidth: const FixedColumnWidth(120.0), + children: [for (int index = 0; index < poItemHistoryList.length; index++) rowChildren(poItemHistoryList[index], index)], + ), + ), + ).expanded, + ], + ], + ) + : ListView( + padding: _screenParams!.isPRInfo ? const EdgeInsets.all(0) : const EdgeInsets.all(21), + // physics: const NeverScrollableScrollPhysics(), + children: [ + if (_screenParams!.isPRInfo) prLinesDataView(), + if (moItemHistoryList.isNotEmpty) loadMoItemHistoryData(), + if (poItemHistoryList.isNotEmpty) loadPoItemHistoryData(), + if (quotationAnalysisList.isNotEmpty) loadQuotationAnalysisData(), + if (moItemHistoryList.isEmpty && poItemHistoryList.isEmpty && quotationAnalysisList.isEmpty && !_screenParams!.isPRInfo) Utils.getNoDataWidget(context), + ], + ), ); } diff --git a/pubspec.yaml b/pubspec.yaml index 2bcc749..687a3c0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -76,6 +76,7 @@ dependencies: flutter_rating_bar: ^4.0.1 auto_size_text: ^3.0.0 pull_to_refresh: ^2.0.0 + fl_chart: ^0.62.0 # lottie json animations lottie: any # Marathon Card Swipe -- 2.30.2 From 8e49df98a2a59c2aef9d05f020ec995e3ae6dcdb Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Mon, 25 Nov 2024 11:07:21 +0300 Subject: [PATCH 042/135] translation issue fixed. --- assets/langs/ar-SA.json | 52 +++++++++++++++++-- assets/langs/en-US.json | 27 +++++++++- lib/generated/codegen_loader.g.dart | 79 +++++++++++++++++++++++++++-- lib/generated/locale_keys.g.dart | 50 ++++++++++++++++-- 4 files changed, 195 insertions(+), 13 deletions(-) diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 12c1eb7..5220ae9 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -4,7 +4,10 @@ "arabic": "عربي", "login": "تسجيل الدخول", "pleaseEnterLoginDetails": "الرجاء إدخال التفاصيل أدناه لتسجيل الدخول", + "userId": "UserID", "username": "اسم المستخدم", + "userName": "اسم المستخدم", + "userSearch": "User Search", "password": "كلمة المرور", "welcomeBack": "مرحبا بعودتك", "wouldYouLikeToLoginWithCurrentUsername": "هل ترغب في تسجيل الدخول باسم المستخدم الحالي؟", @@ -97,7 +100,6 @@ "reject": "يرفض", "approve": "يوافق", "cancel": "إلغاء", - "generate": "يولد", "requestedItems": "العناصر المطلوبة", "request": "طلب", "myRequest": "طلبي", @@ -542,9 +544,34 @@ "missingDocuments": "مستندات مفقودة", "uploadedDocuments": "المستندات التي تم تحميلها", "addAtLeastOneAttachment": "الرجاء إضافة مرفق واحد على الأقل.", - "pleaseClickButtonToJoinMarathon": "الرجاء الضغط على الزر أدناه للانضمام إلى الماراثون", - "youCannotJoinTheMarathon": "لا يمكنك الانضمام إلى الماراثون لأنك تجاوزت الحد الزمني", "open": "يفتح", + "youCannotJoinTheMarathon": "لا يمكنك الانضمام إلى الماراثون لأنك تجاوزت الحد الزمني", + "pleaseClickButtonToJoinMarathon": "الرجاء الضغط على الزر أدناه للانضمام إلى الماراثون", + "generate": "يولد", + "paymentRequest": "طلب الدفع", + "paymentDetails": "تفاصيل الدفع", + "requestNo": "رقم الطلب", + "requesterEmpNum": "رقم الموظف الذي قدم الطلب", + "requesterEmpName": "اسم الموظف مقدم الطلب", + "prepareEmpName": "إعداد اسم الموظف", + "requesterPositionName": "اسم الوظيفة لمقدم الطلب", + "preparePositionName": "إعداد اسم الوظيفة", + "requesterPayrollName": "اسم مقدم الطلب", + "payingORGName": "اسم المنظمة الدافعة", + "requestAmount": "مبلغ الطلب", + "typeofPayment": "نوع الدفع", + "beneficiaryDetails": "تفاصيل المستفيد", + "beneficiaryName": "اسم المستفيد", + "idIqama": "الهوية السعودية / الإقامة", + "beneficiaryBankName": "اسم البنك المستفيد", + "sadadNumber": "رقم سداد", + "beneficiaryIBAN": "رقم IBAN للمستفيد", + "purchaseOrders": "طلبات الشراء", + "approvalDate": "تاريخ الموافقة", + "pOAmount": "مبلغ الطلب", + "versionStatus": "حالة الإصدار", + "supplierNo": "رقم المورد", + "general": "عام", "requesterOperatingUnit": "وحدة تشغيل مقدم الطلب", "prepareEmpNum": "إعداد رقم الموظف", "supplierInfo": "معلومات المورد", @@ -566,5 +593,22 @@ "qtyOrdered": "الكمية المطلوبة", "qtyReceived": "الكمية المستلمة", "bonusQty": "كمية المكافأة", - "balQty": "كمية التوازن" + "balQty": "كمية التوازن", + "videoCall": "مكالمة فيديو", + "addUsers": "إضافة مستخدمين إلى المجموعة", + "admin": "مشرف", + "areYouSureWantTodelete": "هل أنت متأكد أنك تريد الحذف؟", + "Attendance": "الحضور", + "audioCall": "مكالمة صوتية", + "editGroups": "تعديل المجموعة", + "enterGroupName": "يرجى إدخال اسم المجموعة الصحيح", + "enterGroupNamePlease": "يرجى إدخال اسم المجموعة", + "groupMembers": "أعضاء المجموعة", + "groupName": "اسم المجموعة", + "groupNameshouldbe": "يجب أن يتكون اسم المجموعة من 10 أحرف على الأقل", + "manage": "إدارة", + "manageGroup": "إدارة المجموعة", + "members": "الأعضاء", + "searchByUserName": "البحث بواسطة اسم المستخدم", + "shareScreen": "مشاركة الشاشة" } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 21e53de..7ea8af9 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -93,7 +93,6 @@ "whatsapp": "Whatsapp", "reject": "Reject", "approve": "Approve", - "generate": "Generate", "cancel": "Cancel", "requestedItems": "Requested Items", "request": "Request", @@ -303,6 +302,7 @@ "section": "Section", "topic": "Topic", "actionBy": "Action By", + "pending": "Pending", "pendingTransactions": "Pending Transactions", "selectRequestType": "Please select request type", "dateFrom": "Date From", @@ -565,6 +565,31 @@ "pleaseClickButtonToJoinMarathon": "Press the button below to join the Marathon.", "youCannotJoinTheMarathon": "You cannot join the Marathon because you have exceeded the time limit.", "requesterOperatingUnit": "Requester Operating Unit", + "generate": "Generate", + "paymentRequest": "Pay Request", + "paymentDetails": "Payment Details", + "requestNo": "Request No", + "requesterEmpNum": "Requester Employee Num", + "requesterEmpName": "Requester Employee Name", + "prepareEmpName": "Prepare Employee Name", + "requesterPositionName": "Requester Position Name", + "preparePositionName": "Prepare Position Name", + "requesterPayrollName": "Requester Payroll Name", + "payingORGName": "Paying Organization Name", + "requestAmount": "Request Amount", + "typeofPayment": "Type of Payment", + "beneficiaryDetails": "Beneficiary Details", + "beneficiaryName": "Beneficiary Name", + "idIqama": "Saudi ID / Iqama", + "beneficiaryBankName": "Beneficiary Bank Name", + "sadadNumber": "Sadad Number", + "beneficiaryIBAN": "Beneficiary IBAN", + "purchaseOrders": "Purchase Orders", + "approvalDate": "Approval Date", + "pOAmount": "PO Amount", + "versionStatus": "Version Status", + "supplierNo": "Supplier No", + "general": "General", "prepareEmpNum": "Prepare Employee Num", "supplierInfo": "Supplier Information", "supplierAcNo": "Supplier Account No", diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index aa3ed5c..36d809d 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -20,7 +20,10 @@ class CodegenLoader extends AssetLoader{ "arabic": "عربي", "login": "تسجيل الدخول", "pleaseEnterLoginDetails": "الرجاء إدخال التفاصيل أدناه لتسجيل الدخول", + "userId": "UserID", "username": "اسم المستخدم", + "userName": "اسم المستخدم", + "userSearch": "User Search", "password": "كلمة المرور", "welcomeBack": "مرحبا بعودتك", "wouldYouLikeToLoginWithCurrentUsername": "هل ترغب في تسجيل الدخول باسم المستخدم الحالي؟", @@ -113,7 +116,6 @@ class CodegenLoader extends AssetLoader{ "reject": "يرفض", "approve": "يوافق", "cancel": "إلغاء", - "generate": "يولد", "requestedItems": "العناصر المطلوبة", "request": "طلب", "myRequest": "طلبي", @@ -558,9 +560,34 @@ class CodegenLoader extends AssetLoader{ "missingDocuments": "مستندات مفقودة", "uploadedDocuments": "المستندات التي تم تحميلها", "addAtLeastOneAttachment": "الرجاء إضافة مرفق واحد على الأقل.", - "pleaseClickButtonToJoinMarathon": "الرجاء الضغط على الزر أدناه للانضمام إلى الماراثون", - "youCannotJoinTheMarathon": "لا يمكنك الانضمام إلى الماراثون لأنك تجاوزت الحد الزمني", "open": "يفتح", + "youCannotJoinTheMarathon": "لا يمكنك الانضمام إلى الماراثون لأنك تجاوزت الحد الزمني", + "pleaseClickButtonToJoinMarathon": "الرجاء الضغط على الزر أدناه للانضمام إلى الماراثون", + "generate": "يولد", + "paymentRequest": "طلب الدفع", + "paymentDetails": "تفاصيل الدفع", + "requestNo": "رقم الطلب", + "requesterEmpNum": "رقم الموظف الذي قدم الطلب", + "requesterEmpName": "اسم الموظف مقدم الطلب", + "prepareEmpName": "إعداد اسم الموظف", + "requesterPositionName": "اسم الوظيفة لمقدم الطلب", + "preparePositionName": "إعداد اسم الوظيفة", + "requesterPayrollName": "اسم مقدم الطلب", + "payingORGName": "اسم المنظمة الدافعة", + "requestAmount": "مبلغ الطلب", + "typeofPayment": "نوع الدفع", + "beneficiaryDetails": "تفاصيل المستفيد", + "beneficiaryName": "اسم المستفيد", + "idIqama": "الهوية السعودية / الإقامة", + "beneficiaryBankName": "اسم البنك المستفيد", + "sadadNumber": "رقم سداد", + "beneficiaryIBAN": "رقم IBAN للمستفيد", + "purchaseOrders": "طلبات الشراء", + "approvalDate": "تاريخ الموافقة", + "pOAmount": "مبلغ الطلب", + "versionStatus": "حالة الإصدار", + "supplierNo": "رقم المورد", + "general": "عام", "requesterOperatingUnit": "وحدة تشغيل مقدم الطلب", "prepareEmpNum": "إعداد رقم الموظف", "supplierInfo": "معلومات المورد", @@ -582,7 +609,24 @@ class CodegenLoader extends AssetLoader{ "qtyOrdered": "الكمية المطلوبة", "qtyReceived": "الكمية المستلمة", "bonusQty": "كمية المكافأة", - "balQty": "كمية التوازن" + "balQty": "كمية التوازن", + "videoCall": "مكالمة فيديو", + "addUsers": "إضافة مستخدمين إلى المجموعة", + "admin": "مشرف", + "areYouSureWantTodelete": "هل أنت متأكد أنك تريد الحذف؟", + "Attendance": "الحضور", + "audioCall": "مكالمة صوتية", + "editGroups": "تعديل المجموعة", + "enterGroupName": "يرجى إدخال اسم المجموعة الصحيح", + "enterGroupNamePlease": "يرجى إدخال اسم المجموعة", + "groupMembers": "أعضاء المجموعة", + "groupName": "اسم المجموعة", + "groupNameshouldbe": "يجب أن يتكون اسم المجموعة من 10 أحرف على الأقل", + "manage": "إدارة", + "manageGroup": "إدارة المجموعة", + "members": "الأعضاء", + "searchByUserName": "البحث بواسطة اسم المستخدم", + "shareScreen": "مشاركة الشاشة" }; static const Map en_US = { "mohemm": "Mohemm", @@ -679,7 +723,6 @@ static const Map en_US = { "whatsapp": "Whatsapp", "reject": "Reject", "approve": "Approve", - "generate": "Generate", "cancel": "Cancel", "requestedItems": "Requested Items", "request": "Request", @@ -889,6 +932,7 @@ static const Map en_US = { "section": "Section", "topic": "Topic", "actionBy": "Action By", + "pending": "Pending", "pendingTransactions": "Pending Transactions", "selectRequestType": "Please select request type", "dateFrom": "Date From", @@ -1151,6 +1195,31 @@ static const Map en_US = { "pleaseClickButtonToJoinMarathon": "Press the button below to join the Marathon.", "youCannotJoinTheMarathon": "You cannot join the Marathon because you have exceeded the time limit.", "requesterOperatingUnit": "Requester Operating Unit", + "generate": "Generate", + "paymentRequest": "Pay Request", + "paymentDetails": "Payment Details", + "requestNo": "Request No", + "requesterEmpNum": "Requester Employee Num", + "requesterEmpName": "Requester Employee Name", + "prepareEmpName": "Prepare Employee Name", + "requesterPositionName": "Requester Position Name", + "preparePositionName": "Prepare Position Name", + "requesterPayrollName": "Requester Payroll Name", + "payingORGName": "Paying Organization Name", + "requestAmount": "Request Amount", + "typeofPayment": "Type of Payment", + "beneficiaryDetails": "Beneficiary Details", + "beneficiaryName": "Beneficiary Name", + "idIqama": "Saudi ID / Iqama", + "beneficiaryBankName": "Beneficiary Bank Name", + "sadadNumber": "Sadad Number", + "beneficiaryIBAN": "Beneficiary IBAN", + "purchaseOrders": "Purchase Orders", + "approvalDate": "Approval Date", + "pOAmount": "PO Amount", + "versionStatus": "Version Status", + "supplierNo": "Supplier No", + "general": "General", "prepareEmpNum": "Prepare Employee Num", "supplierInfo": "Supplier Information", "supplierAcNo": "Supplier Account No", diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index c372a3a..851a5cd 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -6,7 +6,10 @@ abstract class LocaleKeys { static const arabic = 'arabic'; static const login = 'login'; static const pleaseEnterLoginDetails = 'pleaseEnterLoginDetails'; + static const userId = 'userId'; static const username = 'username'; + static const userName = 'userName'; + static const userSearch = 'userSearch'; static const password = 'password'; static const welcomeBack = 'welcomeBack'; static const wouldYouLikeToLoginWithCurrentUsername = 'wouldYouLikeToLoginWithCurrentUsername'; @@ -98,7 +101,6 @@ abstract class LocaleKeys { static const reject = 'reject'; static const approve = 'approve'; static const cancel = 'cancel'; - static const generate = 'generate'; static const requestedItems = 'requestedItems'; static const request = 'request'; static const myRequest = 'myRequest'; @@ -528,9 +530,34 @@ abstract class LocaleKeys { static const missingDocuments = 'missingDocuments'; static const uploadedDocuments = 'uploadedDocuments'; static const addAtLeastOneAttachment = 'addAtLeastOneAttachment'; - static const pleaseClickButtonToJoinMarathon = 'pleaseClickButtonToJoinMarathon'; - static const youCannotJoinTheMarathon = 'youCannotJoinTheMarathon'; static const open = 'open'; + static const youCannotJoinTheMarathon = 'youCannotJoinTheMarathon'; + static const pleaseClickButtonToJoinMarathon = 'pleaseClickButtonToJoinMarathon'; + static const generate = 'generate'; + static const paymentRequest = 'paymentRequest'; + static const paymentDetails = 'paymentDetails'; + static const requestNo = 'requestNo'; + static const requesterEmpNum = 'requesterEmpNum'; + static const requesterEmpName = 'requesterEmpName'; + static const prepareEmpName = 'prepareEmpName'; + static const requesterPositionName = 'requesterPositionName'; + static const preparePositionName = 'preparePositionName'; + static const requesterPayrollName = 'requesterPayrollName'; + static const payingORGName = 'payingORGName'; + static const requestAmount = 'requestAmount'; + static const typeofPayment = 'typeofPayment'; + static const beneficiaryDetails = 'beneficiaryDetails'; + static const beneficiaryName = 'beneficiaryName'; + static const idIqama = 'idIqama'; + static const beneficiaryBankName = 'beneficiaryBankName'; + static const sadadNumber = 'sadadNumber'; + static const beneficiaryIBAN = 'beneficiaryIBAN'; + static const purchaseOrders = 'purchaseOrders'; + static const approvalDate = 'approvalDate'; + static const pOAmount = 'pOAmount'; + static const versionStatus = 'versionStatus'; + static const supplierNo = 'supplierNo'; + static const general = 'general'; static const requesterOperatingUnit = 'requesterOperatingUnit'; static const prepareEmpNum = 'prepareEmpNum'; static const supplierInfo = 'supplierInfo'; @@ -553,5 +580,22 @@ abstract class LocaleKeys { static const qtyReceived = 'qtyReceived'; static const bonusQty = 'bonusQty'; static const balQty = 'balQty'; + static const videoCall = 'videoCall'; + static const addUsers = 'addUsers'; + static const admin = 'admin'; + static const areYouSureWantTodelete = 'areYouSureWantTodelete'; + static const Attendance = 'Attendance'; + static const audioCall = 'audioCall'; + static const editGroups = 'editGroups'; + static const enterGroupName = 'enterGroupName'; + static const enterGroupNamePlease = 'enterGroupNamePlease'; + static const groupMembers = 'groupMembers'; + static const groupName = 'groupName'; + static const groupNameshouldbe = 'groupNameshouldbe'; + static const manage = 'manage'; + static const manageGroup = 'manageGroup'; + static const members = 'members'; + static const searchByUserName = 'searchByUserName'; + static const shareScreen = 'shareScreen'; } -- 2.30.2 From d4e17e7f0d2f6026f7f44f056f30a4cfa7a43f5f Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Wed, 27 Nov 2024 16:07:34 +0300 Subject: [PATCH 043/135] dynamic form parent value added. (saudi council employee) --- lib/api/my_attendance_api_client.dart | 9 ++++-- lib/classes/consts.dart | 4 +-- .../dynamic_screens/dynamic_input_screen.dart | 29 +++++++++++++++---- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/lib/api/my_attendance_api_client.dart b/lib/api/my_attendance_api_client.dart index 78742a3..24cf6c0 100644 --- a/lib/api/my_attendance_api_client.dart +++ b/lib/api/my_attendance_api_client.dart @@ -40,14 +40,19 @@ class MyAttendanceApiClient { }, url, postParams); } - Future> getValueSetValues(String pSegmentName, String pDescFlexContextCode, String pDescFlexName, List> list, {String? empID, String? parentValue}) async { + Future> getValueSetValues(String pSegmentName, String pDescFlexContextCode, String pDescFlexName, List> list, + {String? empID, String? parentValue, bool hasParent = false}) async { String url = "${ApiConsts.erpRest}GET_VALUE_SET_VALUES"; Map postParams = { "P_SELECTED_RESP_ID": -999, "P_MENU_TYPE": "E", "P_PAGE_LIMIT": 1000, "P_PAGE_NUM": 1, - "P_PARENT_VALUE": empID != null ? parentValue : null, + "P_PARENT_VALUE": hasParent + ? parentValue + : empID != null + ? parentValue + : null, "P_SEGMENT_NAME": pSegmentName, "P_DESC_FLEX_CONTEXT_CODE": pDescFlexContextCode, "P_DESC_FLEX_NAME": pDescFlexName, diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 7103dfd..170762c 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -9,9 +9,9 @@ class ApiConsts { // static String baseUrl = "https://webservices.hmg.com"; // PreProd // static String baseUrl = "https://hmgwebservices.com"; // Live server - // static String baseUrl = "https://mohemm.hmg.com"; // New Live server + static String baseUrl = "https://mohemm.hmg.com"; // New Live server - static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver + // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.20.200.111:1010/"; // static String baseUrl = "https://webservices.hmg.com"; // PreProd diff --git a/lib/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart b/lib/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart index 4f67c62..ef88e11 100644 --- a/lib/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart +++ b/lib/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart @@ -97,7 +97,8 @@ class _DynamicInputScreenState extends State { SubmitEITTransactionList submitEITTransactionList = await MyAttendanceApiClient().submitEitTransaction(dESCFLEXCONTEXTCODE, dynamicParams!.dynamicId, values, empID: dynamicParams!.selectedEmp); Utils.hideLoading(context); await Navigator.pushNamed(context, AppRoutes.requestSubmitScreen, - arguments: RequestSubmitScreenParams(LocaleKeys.submit.tr(), submitEITTransactionList.pTRANSACTIONID!, submitEITTransactionList.pITEMKEY!, 'eit',isAttachmentMandatory: dynamicParams!.isAttachmentMandatory)); + arguments: RequestSubmitScreenParams(LocaleKeys.submit.tr(), submitEITTransactionList.pTRANSACTIONID!, submitEITTransactionList.pITEMKEY!, 'eit', + isAttachmentMandatory: dynamicParams!.isAttachmentMandatory)); if (!AppState().cancelRequestTrancsection) { return; } @@ -133,8 +134,27 @@ class _DynamicInputScreenState extends State { .toJson()) .toList(); + String? selectedEmp = dynamicParams!.selectedEmp; + bool hasParentId = false; + + if (segmentId.isNotEmpty && selectedEmp == null) { + for (var element in getEitDffStructureList!) { + try { + if (element.sEGMENTNAME == segmentId && selectedEmp == null) { + var selectedElement = element; + if (selectedElement.vALIDATIONTYPE == "Y" || selectedElement.vALIDATIONTYPE == "D") { + hasParentId = true; + break; + } + } + } catch (ex) { + print("err:$ex"); + } + } + } + List eServicesResponseModel = await MyAttendanceApiClient().getValueSetValues(segmentId, structureList.dESCFLEXCONTEXTCODE!, structureList.dESCFLEXNAME!, values, - empID: dynamicParams!.selectedEmp, parentValue: structureList.eSERVICESDV!.pVALUECOLUMNNAME); + empID: selectedEmp, parentValue: structureList.eSERVICESDV!.pVALUECOLUMNNAME, hasParent: hasParentId); List abc = genericResponseModel?.getEITDFFStructureList ?? []; getEitDffStructureList = abc; int index = getEitDffStructureList!.indexWhere((element) => element.sEGMENTNAME == segmentId); @@ -862,9 +882,8 @@ class _DynamicInputScreenState extends State { context: context, initialTime: time, builder: (cxt, child) { - return MediaQuery(data: MediaQuery.of(context).copyWith(alwaysUse24HourFormat: true), child: Localizations.override( - context: context, - locale: const Locale('en', 'US'),child: child ?? Container())); + return MediaQuery( + data: MediaQuery.of(context).copyWith(alwaysUse24HourFormat: true), child: Localizations.override(context: context, locale: const Locale('en', 'US'), child: child ?? Container())); }); if (picked != null && picked != time) { -- 2.30.2 From 0da0ffd43e7ea1328e2e622e77d892bfa2083ed2 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Wed, 27 Nov 2024 16:47:50 +0300 Subject: [PATCH 044/135] itg form attachment overlapping issue fixed. --- lib/ui/work_list/itg_detail_screen.dart | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/lib/ui/work_list/itg_detail_screen.dart b/lib/ui/work_list/itg_detail_screen.dart index 8cb7944..96139b4 100644 --- a/lib/ui/work_list/itg_detail_screen.dart +++ b/lib/ui/work_list/itg_detail_screen.dart @@ -642,16 +642,13 @@ class _ItgDetailScreenState extends State { void getItgRequestAttachments() async { try { - // Utils.showLoading(context); - itgFormAttachmentsList = + isAttachmentLoaded = false; + itgFormAttachmentsList.clear(); + List _itgFormAttachmentsList = (await WorkListApiClient().getITGFormAttachments(requestDetails!.requestType!, requestDetails!.iD, requestDetails!.itemID, AppState().memberInformationList?.eMPLOYEENUMBER ?? ""))!; - // allowedActionList = itgRequest?.allowedActions ?? []; - // if (allowedActionList.isNotEmpty) { - // isCloseAvailable = allowedActionList.any((element) => element.action == "CLOSE"); - // isApproveAvailable = itgRequest!.allowedActions!.any((element) => element.action == "Approve"); - // isRejectAvailable = itgRequest!.allowedActions!.any((element) => element.action == "Reject"); - // } - // Utils.hideLoading(context); + if (!isAttachmentLoaded) { + itgFormAttachmentsList = _itgFormAttachmentsList; + } setState(() { isAttachmentLoaded = true; }); -- 2.30.2 From b20e0a8c7bd3a6106651e26f0dad8db6a5d8a024 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Thu, 5 Dec 2024 13:42:04 +0300 Subject: [PATCH 045/135] updates --- assets/langs/ar-SA.json | 29 +++++++++++++----------- assets/langs/en-US.json | 27 +++++++++++----------- lib/widgets/item_detail_view_widget.dart | 3 ++- pubspec.yaml | 4 ++-- 4 files changed, 34 insertions(+), 29 deletions(-) diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 5220ae9..1eb7dde 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -100,6 +100,7 @@ "reject": "يرفض", "approve": "يوافق", "cancel": "إلغاء", + "generate": "يولد", "requestedItems": "العناصر المطلوبة", "request": "طلب", "myRequest": "طلبي", @@ -530,7 +531,7 @@ "noWinner": "حزين! لم يفز أحد اليوم.", "myTeam": "فريقي", "youCanPlayDemo": "لكن يمكنك لعب العرض", - "group": "مجموعة", + "group" : "مجموعة", "searchGroup": "مجموعة البحث", "connectHmgWifi": "قم بتوصيل HMG WIFI", "connectedHmgWifi": "اتصال HMG WIFI", @@ -544,6 +545,8 @@ "missingDocuments": "مستندات مفقودة", "uploadedDocuments": "المستندات التي تم تحميلها", "addAtLeastOneAttachment": "الرجاء إضافة مرفق واحد على الأقل.", + "pleaseClickButtonToJoinMarathon": "الرجاء الضغط على الزر أدناه للانضمام إلى الماراثون", + "youCannotJoinTheMarathon": "لا يمكنك الانضمام إلى الماراثون لأنك تجاوزت الحد الزمني", "open": "يفتح", "youCannotJoinTheMarathon": "لا يمكنك الانضمام إلى الماراثون لأنك تجاوزت الحد الزمني", "pleaseClickButtonToJoinMarathon": "الرجاء الضغط على الزر أدناه للانضمام إلى الماراثون", @@ -572,20 +575,20 @@ "versionStatus": "حالة الإصدار", "supplierNo": "رقم المورد", "general": "عام", - "requesterOperatingUnit": "وحدة تشغيل مقدم الطلب", - "prepareEmpNum": "إعداد رقم الموظف", - "supplierInfo": "معلومات المورد", + "requesterOperatingUnit":"وحدة تشغيل مقدم الطلب", + "prepareEmpNum":"إعداد رقم الموظف", + "supplierInfo" : "معلومات المورد", "supplierAcNo": "رقم حساب المورد", "supplierAcName": "اسم حساب المورد", - "supplierIBAN": "رقم IBAN للمورد", - "supplierCRNo": "رقم السجل التجاري", - "suppliedAcNo": "رقم الحساب المقدم", - "patientRefundInvoice": "فاتورة استرداد الأموال للمريض", - "patientNumber": "رقم المريض", - "patientName": "اسم المريض", - "invoiceDate": "تاريخ الفاتورة", - "refundInvoice": "فاتورة الاسترجاع", - "hospitalClinic": "عيادة المستشفى", + "supplierIBAN" : "رقم IBAN للمورد", + "supplierCRNo" :"رقم السجل التجاري", + "suppliedAcNo" : "رقم الحساب المقدم", + "patientRefundInvoice" : "فاتورة استرداد الأموال للمريض", + "patientNumber" : "رقم المريض", + "patientName" : "اسم المريض", + "invoiceDate" : "تاريخ الفاتورة", + "refundInvoice" :"فاتورة الاسترجاع", + "hospitalClinic" : "عيادة المستشفى", "graphicalAnalysis": "التحليل الرسومي", "itemHistoryAnalysis": "تحليل تاريخ العنصر", "pOno": "امر شراء #", diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 7ea8af9..03ae4d6 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -93,6 +93,7 @@ "whatsapp": "Whatsapp", "reject": "Reject", "approve": "Approve", + "generate": "Generate", "cancel": "Cancel", "requestedItems": "Requested Items", "request": "Request", @@ -564,7 +565,7 @@ "addAtLeastOneAttachment": "Please add at least one attachment.", "pleaseClickButtonToJoinMarathon": "Press the button below to join the Marathon.", "youCannotJoinTheMarathon": "You cannot join the Marathon because you have exceeded the time limit.", - "requesterOperatingUnit": "Requester Operating Unit", + "requesterOperatingUnit":"Requester Operating Unit", "generate": "Generate", "paymentRequest": "Pay Request", "paymentDetails": "Payment Details", @@ -590,19 +591,19 @@ "versionStatus": "Version Status", "supplierNo": "Supplier No", "general": "General", - "prepareEmpNum": "Prepare Employee Num", - "supplierInfo": "Supplier Information", + "prepareEmpNum":"Prepare Employee Num", + "supplierInfo" : "Supplier Information", "supplierAcNo": "Supplier Account No", - "supplierAcName": "Supplier Account Name", - "supplierIBAN": "Supplier IBAN", - "supplierCRNo": "CR Number", - "suppliedAcNo": "Supplied Account No.", - "patientRefundInvoice": "Patient Refund Invoice", - "patientNumber": "Patient Number", - "patientName": "Patient Name", - "invoiceDate": "Invoice Date", - "refundInvoice": "Refund Invoice", - "hospitalClinic": "Hospital Clinic", + "supplierAcName":"Supplier Account Name", + "supplierIBAN" : "Supplier IBAN", + "supplierCRNo" : "CR Number", + "suppliedAcNo" : "Supplied Account No.", + "patientRefundInvoice" : "Patient Refund Invoice", + "patientNumber" : "Patient Number", + "patientName" : "Patient Name", + "invoiceDate" : "Invoice Date", + "refundInvoice" :"Refund Invoice", + "hospitalClinic" : "Hospital Clinic", "graphicalAnalysis": "Graphical Analysis", "itemHistoryAnalysis": "Item History Analysis", "pOno": "P.O #", diff --git a/lib/widgets/item_detail_view_widget.dart b/lib/widgets/item_detail_view_widget.dart index 68b245a..f6797e8 100644 --- a/lib/widgets/item_detail_view_widget.dart +++ b/lib/widgets/item_detail_view_widget.dart @@ -86,7 +86,8 @@ class ItemDetailViewGridItem extends StatelessWidget { type != null ? type!.toLowerCase() == "table" ? getStringFromJSON(value!) - : Flexible(child: (value!.isEmpty ? "--" : value).toString().toText12Auto(color: MyColors.normalTextColor)) + // : Flexible(child: (value!.isEmpty ? "--" : value).toString().toText12Auto(color: MyColors.normalTextColor, maxLine: 5)) + : (value!.isEmpty ? "--" : value).toString().toText12Auto(color: MyColors.normalTextColor, maxLine: 6) : Container(), ], ), diff --git a/pubspec.yaml b/pubspec.yaml index 687a3c0..0265525 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html #version: 3.3.01+300040 -version: 3.7.96+1 +version: 3.7.98+1 environment: sdk: ">=2.16.0 <3.0.0" @@ -66,7 +66,7 @@ dependencies: month_picker_dialog_2: ^0.5.5 # open_file: ^3.2.1 open_filex: ^4.4.0 - wifi_iot: ^0.3.18 + wifi_iot: ^0.3.19+1 flutter_html: ^3.0.0-alpha.6 # flutter_barcode_scanner: ^2.0.0 qr_code_scanner: ^1.0.1 -- 2.30.2 From cdd56b2a5a2ae2d5fc422e85229a80ab0989874c Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Tue, 17 Dec 2024 16:40:25 +0300 Subject: [PATCH 046/135] Issue fixes & updates --- android/build.gradle | 2 +- .../leave_balance/leave_balance_screen.dart | 91 ++++++++++--------- lib/ui/login/login_screen.dart | 37 ++++---- lib/ui/work_list/itg_detail_screen.dart | 2 + .../worklist_fragments/actions_fragment.dart | 2 +- pubspec.yaml | 1 + 6 files changed, 74 insertions(+), 61 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 23ea6ba..abef75b 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.7.20' + ext.kotlin_version = '1.8.20' repositories { google() mavenCentral() diff --git a/lib/ui/leave_balance/leave_balance_screen.dart b/lib/ui/leave_balance/leave_balance_screen.dart index 9fb925c..447767f 100644 --- a/lib/ui/leave_balance/leave_balance_screen.dart +++ b/lib/ui/leave_balance/leave_balance_screen.dart @@ -64,47 +64,56 @@ class _LeaveBalanceState extends State { context, title: LocaleKeys.leaveBalance.tr(), ), - body: absenceTransList == null - ? const SizedBox() - : (absenceTransList!.isEmpty - ? Utils.getNoDataWidget(context).paddingOnly(top: 50) - : ListView( - physics: const BouncingScrollPhysics(), - padding: const EdgeInsets.all(21), - children: [ - BalancesDashboardWidget(LocaleKeys.currentLeaveBalance.tr(), true, selectedEmp: employeeId, showLoading: false), - 12.height, - ListView.separated( - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - padding: EdgeInsets.zero, - itemBuilder: (cxt, int index) => Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.startDateT.tr(), absenceTransList![index].sTARTDATE ?? ""), - ItemDetailViewCol(LocaleKeys.endDateT.tr(), absenceTransList![index].eNDDATE ?? ""), - ), - ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.absenceType.tr(), absenceTransList![index].aBSENCETYPE ?? ""), - ItemDetailViewCol(LocaleKeys.absenceCategory.tr(), absenceTransList![index].aBSENCECATEGORY ?? ""), - ), - ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.days.tr(), absenceTransList![index].aBSENCEDAYS?.toString() ?? ""), - ItemDetailViewCol(LocaleKeys.hours.tr(), absenceTransList![index].aBSENCEHOURS?.toString() ?? ""), - ), - ItemDetailGrid( - ItemDetailViewCol(LocaleKeys.approvalStatus.tr(), absenceTransList![index].aPPROVALSTATUS ?? ""), - ItemDetailViewCol(LocaleKeys.absenceStatus.tr(), absenceTransList![index].aBSENCESTATUS ?? ""), - isItLast: true, - ), - ], - ).objectContainerView(), - separatorBuilder: (cxt, index) => 12.height, - itemCount: absenceTransList!.length), - ], - )), + body: Column( + children: [ + Padding( + padding: const EdgeInsets.all(21.0), + child: BalancesDashboardWidget(LocaleKeys.currentLeaveBalance.tr(), true, selectedEmp: employeeId, showLoading: false), + ), + 12.height, + absenceTransList == null + ? const SizedBox() + : (absenceTransList!.isEmpty + ? Utils.getNoDataWidget(context).paddingOnly(top: 50) + : ListView( + physics: const BouncingScrollPhysics(), + padding: const EdgeInsets.all(21), + children: [ + // BalancesDashboardWidget(LocaleKeys.currentLeaveBalance.tr(), true, selectedEmp: employeeId, showLoading: false), + // 12.height, + ListView.separated( + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + padding: EdgeInsets.zero, + itemBuilder: (cxt, int index) => Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.startDateT.tr(), absenceTransList![index].sTARTDATE ?? ""), + ItemDetailViewCol(LocaleKeys.endDateT.tr(), absenceTransList![index].eNDDATE ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.absenceType.tr(), absenceTransList![index].aBSENCETYPE ?? ""), + ItemDetailViewCol(LocaleKeys.absenceCategory.tr(), absenceTransList![index].aBSENCECATEGORY ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.days.tr(), absenceTransList![index].aBSENCEDAYS?.toString() ?? ""), + ItemDetailViewCol(LocaleKeys.hours.tr(), absenceTransList![index].aBSENCEHOURS?.toString() ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.approvalStatus.tr(), absenceTransList![index].aPPROVALSTATUS ?? ""), + ItemDetailViewCol(LocaleKeys.absenceStatus.tr(), absenceTransList![index].aBSENCESTATUS ?? ""), + isItLast: true, + ), + ], + ).objectContainerView(), + separatorBuilder: (cxt, index) => 12.height, + itemCount: absenceTransList!.length), + ], + )), + ], + ), floatingActionButton: Container( height: 54, width: 54, diff --git a/lib/ui/login/login_screen.dart b/lib/ui/login/login_screen.dart index d4f1644..c71ae7f 100644 --- a/lib/ui/login/login_screen.dart +++ b/lib/ui/login/login_screen.dart @@ -30,6 +30,7 @@ import 'package:mohem_flutter_app/models/member_login_list_model.dart'; import 'package:mohem_flutter_app/models/privilege_list_model.dart'; import 'package:mohem_flutter_app/widgets/button/default_button.dart'; import 'package:mohem_flutter_app/widgets/input_widget.dart'; +import 'package:safe_device/safe_device.dart'; // import 'package:safe_device/safe_device.dart'; import 'package:wifi_iot/wifi_iot.dart'; @@ -70,26 +71,26 @@ class _LoginScreenState extends State { super.initState(); // hmsApiAvailability = HmsApiAvailability(); // checkFirebaseToken(); - // if (kReleaseMode) { - // checkDeviceSafety(); - // } + if (kReleaseMode) { + checkDeviceSafety(); + } } - // void checkDeviceSafety() async { - // try { - // isJailBroken = await SafeDevice.isJailBroken; - // isRealDevice = await SafeDevice.isRealDevice; - // if (Platform.isAndroid) { - // isOnExternalStorage = await SafeDevice.isOnExternalStorage; - // isDevelopmentModeEnable = await SafeDevice.isDevelopmentModeEnable; - // } - // if (isJailBroken || !isRealDevice || isOnExternalStorage || isDevelopmentModeEnable) { - // Navigator.pushNamedAndRemoveUntil(context, AppRoutes.unsafeDeviceScreen, (_) => false); - // } - // } catch (error) { - // print(error); - // } - // } + void checkDeviceSafety() async { + try { + isJailBroken = await SafeDevice.isJailBroken; + isRealDevice = await SafeDevice.isRealDevice; + if (Platform.isAndroid) { + isOnExternalStorage = await SafeDevice.isOnExternalStorage; + isDevelopmentModeEnable = await SafeDevice.isDevelopmentModeEnable; + } + if (isJailBroken || !isRealDevice || isOnExternalStorage || isDevelopmentModeEnable) { + Navigator.pushNamedAndRemoveUntil(context, AppRoutes.unsafeDeviceScreen, (_) => false); + } + } catch (error) { + print(error); + } + } @override void dispose() { diff --git a/lib/ui/work_list/itg_detail_screen.dart b/lib/ui/work_list/itg_detail_screen.dart index 96139b4..aaef95f 100644 --- a/lib/ui/work_list/itg_detail_screen.dart +++ b/lib/ui/work_list/itg_detail_screen.dart @@ -84,6 +84,7 @@ class _ItgDetailScreenState extends State { controller.jumpToPage(0); }); } catch (ex) { + setState(() {}); Utils.hideLoading(context); Utils.handleException(ex, context, null); } @@ -534,6 +535,7 @@ class _ItgDetailScreenState extends State { Utils.handleException(ex, context, null); } } + void performAnswerAction(String requestType, taskId, itemId, String employeeNumber, String comments) async { try { Utils.showLoading(context); diff --git a/lib/ui/work_list/worklist_fragments/actions_fragment.dart b/lib/ui/work_list/worklist_fragments/actions_fragment.dart index 41de635..29d5328 100644 --- a/lib/ui/work_list/worklist_fragments/actions_fragment.dart +++ b/lib/ui/work_list/worklist_fragments/actions_fragment.dart @@ -167,7 +167,7 @@ class ActionsFragment extends StatelessWidget { Duration duration = DateTime.now().difference(dateTimeFrom); return "Action duration: " + DateUtil.formatDuration(duration); } else { - if (actionHistoryList[index].nOTIFICATIONDATE!.isEmpty) { + if (actionHistoryList[index].nOTIFICATIONDATE!.isEmpty || actionHistoryList[index].aCTIONCODE! == "NO ACTION") { return ""; } else { DateTime dateTimeTo = DateUtil.convertSimpleStringDateToDate(actionHistoryList[index].nOTIFICATIONDATE!); diff --git a/pubspec.yaml b/pubspec.yaml index 0265525..a12c83a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -82,6 +82,7 @@ dependencies: # Marathon Card Swipe appinio_swiper: ^1.1.1 expandable: ^5.0.1 + safe_device: ^1.1.9 # networkImage cached_network_image: ^3.2.2 -- 2.30.2 From 2682158590bb8da716634c905f2d062546a7ae30 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Thu, 19 Dec 2024 12:58:10 +0300 Subject: [PATCH 047/135] ERM Channel Video changes --- lib/classes/consts.dart | 4 +- .../itg/its_add_screen_video_image.dart | 168 +++++++++++------- lib/widgets/my_video_progress_indicator.dart | 105 +++++++++++ 3 files changed, 214 insertions(+), 63 deletions(-) create mode 100644 lib/widgets/my_video_progress_indicator.dart diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 170762c..7103dfd 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -9,9 +9,9 @@ class ApiConsts { // static String baseUrl = "https://webservices.hmg.com"; // PreProd // static String baseUrl = "https://hmgwebservices.com"; // Live server - static String baseUrl = "https://mohemm.hmg.com"; // New Live server + // static String baseUrl = "https://mohemm.hmg.com"; // New Live server - // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver + static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.20.200.111:1010/"; // static String baseUrl = "https://webservices.hmg.com"; // PreProd 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 cf2d92b..2095650 100644 --- a/lib/ui/landing/itg/its_add_screen_video_image.dart +++ b/lib/ui/landing/itg/its_add_screen_video_image.dart @@ -12,6 +12,7 @@ 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:mohem_flutter_app/widgets/my_video_progress_indicator.dart'; import 'package:video_player/video_player.dart'; class ITGAdsScreen extends StatefulWidget { @@ -148,7 +149,35 @@ class _ITGAdsScreenState extends State { ? Lottie.asset(MyLottieConsts.audioPlaybackLottie) : AspectRatio( aspectRatio: _controller.value.aspectRatio, - child: VideoPlayer(_controller), + child: Stack( + alignment: Alignment.bottomCenter, + children: [ + VideoPlayer(_controller), + if (advertisementData?.isOptional ?? false) + Positioned( + top: 4, + right: 8, + child: Container( + padding: const EdgeInsets.only(left: 8, right: 8, top: 4, bottom: 4), + decoration: BoxDecoration( + color: Colors.white.withOpacity(0.5), + borderRadius: BorderRadius.circular(30)), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text(AppState().isArabic(context) ? "يتخطى" : "Skip"), + Icon(Icons.skip_next), + ], + ), + ).onPress(() { + Navigator.pop(context); + DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, "Skip").then((value) { + logger.d(value); + }); + }), + ), + ], + ), ), ), 30.height, @@ -159,70 +188,87 @@ class _ITGAdsScreenState extends State { textStyle: const TextStyle(color: Colors.white, fontSize: 16, letterSpacing: -0.48, fontWeight: FontWeight.bold), ), 50.height, - if (advertisementData?.isOptional ?? false) - DefaultButton(AppState().isArabic(context) ? "يتخطى" : "Skip", () async { - Navigator.pop(context); - DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, "Skip").then((value) { - logger.d(value); - }); - }).paddingOnly(left: 60.0, right: 60.0, top: 8, bottom: 8), + // if (advertisementData?.isOptional ?? false) + // DefaultButton(AppState().isArabic(context) ? "يتخطى" : "Skip", () async { + // Navigator.pop(context); + // DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, "Skip").then((value) { + // logger.d(value); + // }); + // }).paddingOnly(left: 60.0, right: 60.0, top: 8, bottom: 8), ValueListenableBuilder( valueListenable: hasTimerEnded, builder: (context, val, child) { - if (hasTimerEndedBool) { - return GridView.builder( - padding: EdgeInsets.zero, - itemCount: advertisementData?.actionButtonsColl!.length, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemBuilder: (context, index) { - String? btnText = AppState().isArabic(context) ? advertisementData?.actionButtonsColl![index].btnTextAr : advertisementData?.actionButtonsColl![index].btnTextEn; - return DefaultButton(btnText!, () async { - Navigator.pop(context); - DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, advertisementData?.actionButtonsColl![index].actionValue).then((value) { - logger.d(value); - }); - }).paddingOnly(left: 60.0, right: 60.0, top: 8, bottom: 8); - }, - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 1, - childAspectRatio: (7.0), + // if (hasTimerEndedBool) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + MyVideoProgressIndicator( + _controller, + allowScrubbing: false, + padding: EdgeInsets.only(left: 60, right: 60), + ), + GridView.builder( + padding: EdgeInsets.zero, + itemCount: advertisementData?.actionButtonsColl!.length, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (context, index) { + String? btnText = AppState().isArabic(context) ? advertisementData?.actionButtonsColl![index].btnTextAr : advertisementData?.actionButtonsColl![index].btnTextEn; + return DefaultButton( + btnText!, + hasTimerEndedBool + ? () async { + Navigator.pop(context); + DashboardApiClient() + .setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, advertisementData?.actionButtonsColl![index].actionValue) + .then((value) { + logger.d(value); + }); + } + : null) + .paddingOnly(left: 60.0, right: 60.0, top: 8, bottom: 8); + }, + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 1, + childAspectRatio: (7.0), + ), ), - ); - // 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(); - } + ], + ); + // 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, diff --git a/lib/widgets/my_video_progress_indicator.dart b/lib/widgets/my_video_progress_indicator.dart new file mode 100644 index 0000000..a6e9172 --- /dev/null +++ b/lib/widgets/my_video_progress_indicator.dart @@ -0,0 +1,105 @@ +import 'package:flutter/material.dart'; +import 'package:video_player/video_player.dart'; + +class MyVideoProgressIndicator extends StatefulWidget { + const MyVideoProgressIndicator( + this.controller, { + Key? key, + this.colors = const VideoProgressColors(), + required this.allowScrubbing, + this.padding = const EdgeInsets.only(top: 5.0), + }) : super(key: key); + + final VideoPlayerController controller; + + final VideoProgressColors colors; + + final bool allowScrubbing; + + final EdgeInsets padding; + + @override + State createState() => _VideoProgressIndicatorState(); +} + +class _VideoProgressIndicatorState extends State { + _VideoProgressIndicatorState() { + listener = () { + if (!mounted) { + return; + } + setState(() {}); + }; + } + + late VoidCallback listener; + + VideoPlayerController get controller => widget.controller; + + VideoProgressColors get colors => widget.colors; + + @override + void initState() { + super.initState(); + controller.addListener(listener); + } + + @override + void deactivate() { + controller.removeListener(listener); + super.deactivate(); + } + + @override + Widget build(BuildContext context) { + Widget progressIndicator; + if (controller.value.isInitialized) { + int duration = controller.value.duration.inMilliseconds; + int position = controller.value.position.inMilliseconds; + + int maxBuffering = 0; + for (DurationRange range in controller.value.buffered) { + int end = range.end.inMilliseconds; + if (end > maxBuffering) { + maxBuffering = end; + } + } + + progressIndicator = Stack( + fit: StackFit.passthrough, + children: [ + LinearProgressIndicator( + value: maxBuffering / duration, + valueColor: AlwaysStoppedAnimation(colors.bufferedColor), + backgroundColor: colors.backgroundColor, + minHeight: 8, + ), + LinearProgressIndicator( + value: position / duration, + valueColor: AlwaysStoppedAnimation(colors.playedColor), + backgroundColor: Colors.transparent, + minHeight: 8, + ), + ], + ); + } else { + progressIndicator = LinearProgressIndicator( + valueColor: AlwaysStoppedAnimation(colors.playedColor), + backgroundColor: colors.backgroundColor, + minHeight: 8, + ); + } + Widget paddedProgressIndicator = Padding( + padding: widget.padding, + child: progressIndicator, + ); + if (widget.allowScrubbing) { + return VideoScrubber( + controller: controller, + child: paddedProgressIndicator, + ); + } else { + return paddedProgressIndicator; + } + } +} -- 2.30.2 From 4eb3e6d52d80b9fb9ff5f38f30ee18f376947b16 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Thu, 19 Dec 2024 16:52:02 +0300 Subject: [PATCH 048/135] progress bar added on erm video. & skip button relocation. --- .../itg/its_add_screen_video_image.dart | 87 +++++---- lib/widgets/AnimatedProgressBar.dart | 176 ++++++++++++++++++ lib/widgets/button/default_button.dart | 17 +- lib/widgets/my_video_progress_indicator.dart | 73 +++++--- 4 files changed, 282 insertions(+), 71 deletions(-) create mode 100644 lib/widgets/AnimatedProgressBar.dart 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 2095650..db6ba3e 100644 --- a/lib/ui/landing/itg/its_add_screen_video_image.dart +++ b/lib/ui/landing/itg/its_add_screen_video_image.dart @@ -159,9 +159,7 @@ class _ITGAdsScreenState extends State { right: 8, child: Container( padding: const EdgeInsets.only(left: 8, right: 8, top: 4, bottom: 4), - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.5), - borderRadius: BorderRadius.circular(30)), + decoration: BoxDecoration(color: Colors.white.withOpacity(0.5), borderRadius: BorderRadius.circular(30)), child: Row( mainAxisSize: MainAxisSize.min, children: [ @@ -199,41 +197,56 @@ class _ITGAdsScreenState extends State { valueListenable: hasTimerEnded, builder: (context, val, child) { // if (hasTimerEndedBool) { - return Column( - mainAxisSize: MainAxisSize.min, - children: [ - MyVideoProgressIndicator( - _controller, - allowScrubbing: false, - padding: EdgeInsets.only(left: 60, right: 60), - ), - GridView.builder( - padding: EdgeInsets.zero, - itemCount: advertisementData?.actionButtonsColl!.length, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemBuilder: (context, index) { - String? btnText = AppState().isArabic(context) ? advertisementData?.actionButtonsColl![index].btnTextAr : advertisementData?.actionButtonsColl![index].btnTextEn; - return DefaultButton( - btnText!, - hasTimerEndedBool - ? () async { - Navigator.pop(context); - DashboardApiClient() - .setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, advertisementData?.actionButtonsColl![index].actionValue) - .then((value) { - logger.d(value); - }); - } - : null) - .paddingOnly(left: 60.0, right: 60.0, top: 8, bottom: 8); + return GridView.builder( + padding: EdgeInsets.zero, + itemCount: advertisementData?.actionButtonsColl!.length, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (context, index) { + String? btnText = AppState().isArabic(context) ? advertisementData?.actionButtonsColl![index].btnTextAr : advertisementData?.actionButtonsColl![index].btnTextEn; + + bool isAcknowledge = advertisementData?.actionButtonsColl![index].actionButtonId == 11; + if (isAcknowledge) { + return Stack( + alignment: Alignment.center, + children: [ + MyVideoProgressIndicator( + _controller, + allowScrubbing: false, + //padding: EdgeInsets.only(left: 60, right: 60), + ), + DefaultButton( + btnText!, + hasTimerEndedBool + ? () async { + Navigator.pop(context); + DashboardApiClient() + .setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, advertisementData?.actionButtonsColl![index].actionValue) + .then((value) { + logger.d(value); + }); + } + : null, + disabledColor: Colors.transparent, + textColor: !hasTimerEndedBool ? Colors.white.withOpacity(.5) : Colors.white, + ).paddingOnly(left: 60.0, right: 60.0, top: 8, bottom: 8), + ], + ); + } + return DefaultButton( + btnText!, + () async { + Navigator.pop(context); + DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, advertisementData?.actionButtonsColl![index].actionValue).then((value) { + logger.d(value); + }); }, - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 1, - childAspectRatio: (7.0), - ), - ), - ], + ).paddingOnly(left: 60.0, right: 60.0, top: 8, bottom: 8); + }, + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 1, + childAspectRatio: (7.0), + ), ); // Row( // mainAxisAlignment: MainAxisAlignment.center, diff --git a/lib/widgets/AnimatedProgressBar.dart b/lib/widgets/AnimatedProgressBar.dart new file mode 100644 index 0000000..c0bf3d1 --- /dev/null +++ b/lib/widgets/AnimatedProgressBar.dart @@ -0,0 +1,176 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +/// Animated progress bar. Behaves like implicitly animated widget. +/// Check basic implicit animated Flutter widgets like [AnimatedContainer] +/// It animates [value] changes. +/// Requires [duration] to set filling duration timer +/// [onEnd] callback to trigger additional actions (e.g. another animation) +/// at the end of the current animation +/// [color] or [gradient] to fill the progress bar. Only one parameter is allowed. +/// Optional [backgroundColor], defaults to transparent +/// Optional [width] defaults to 200.0 +/// Optional [height] defaults to 10.0 +/// Optional [curve] defaults to [Curves.linear] +class AnimatedProgressBar extends ImplicitlyAnimatedWidget { + const AnimatedProgressBar({ + key, + required duration, + required this.value, + this.width = 200.0, + this.height = 10.0, + this.color, + this.gradient, + this.backgroundColor = Colors.transparent, + curve = Curves.linear, + onEnd, + }) : super(key: key, duration: duration, curve: curve, onEnd: onEnd); + + ///progress bar width + final double width; + + ///progress bar height + final double height; + + ///current progress value + final double? value; + + ///progress bar gradient parameter + final Gradient? gradient; + + ///progress bar color parameter + final Color? color; + + ///progress bar color parameter + final Color backgroundColor; + + @override + AnimatedWidgetBaseState createState() => _AnimatedBarState(); +} + +class _AnimatedBarState extends AnimatedWidgetBaseState { + Tween? _progressValue; + + @override + void forEachTween(TweenVisitor visitor) { + _progressValue = visitor(_progressValue, widget.value, (value) => Tween(begin: value)) as Tween?; + } + + @override + Widget build(BuildContext context) { + return ProgressBar( + value: _progressValue?.evaluate(animation), + width: widget.width, + height: widget.height, + gradient: widget.gradient, + color: widget.color, + backgroundColor: widget.backgroundColor, + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder description) { + super.debugFillProperties(description); + description.add(DiagnosticsProperty('progressValue', _progressValue, showName: false, defaultValue: null)); + } +} + +class ProgressBar extends StatelessWidget { + const ProgressBar({ + Key? key, + required this.value, + this.width = 200.0, + this.height = 10.0, + this.color, + this.backgroundColor = Colors.transparent, + this.gradient, + }) : assert( + gradient == null || color == null, + 'Cannot provide both a color and a gradient', + ), + assert( + gradient != null || color != null, + 'Need to provide color or gradient', + ), + super(key: key); + + ///progress bar width + final double width; + + ///progress bar height + final double height; + + ///current progress value + final double? value; + + ///progress bar gradient parameter + final Gradient? gradient; + + ///progress bar color parameter + final Color? color; + + ///progress bar color parameter + final Color backgroundColor; + + @override + Widget build(BuildContext context) { + return CustomPaint( + size: Size(width, height), + foregroundPainter: ProgressPainter( + value: value!, + color: color, + gradient: gradient, + ), + painter: BackgroundPainter( + backgroundColor: backgroundColor, + ), + ); + } +} + +class BackgroundPainter extends CustomPainter { + const BackgroundPainter({required this.backgroundColor}); + + ///progress bar backgroundColor + final Color backgroundColor; + + @override + void paint(Canvas canvas, Size size) { + Paint paint = Paint()..color = backgroundColor; + canvas.drawRRect(RRect.fromRectAndRadius(Offset.zero & size, Radius.circular(6)), paint); + } + + @override + bool shouldRepaint(covariant BackgroundPainter oldDelegate) => false; +} + +class ProgressPainter extends CustomPainter { + const ProgressPainter({required this.value, this.gradient, this.color}); + + ///current progress bar value + final double value; + + ///progress bar gradient infill + final Gradient? gradient; + + ///progress bar gradient color + final Color? color; + + @override + void paint(Canvas canvas, Size size) { + Paint paint = Paint(); + if (gradient != null) { + paint.shader = gradient?.createShader(Offset.zero & size); + } + if (color != null) { + paint.color = color!; + } + canvas.clipRRect(RRect.fromRectAndRadius(Offset.zero & size, Radius.circular(6))); + canvas.drawRRect(RRect.fromRectAndRadius(Rect.fromLTRB(0, 0, size.width * value, size.height), Radius.circular(6)), paint); + } + + @override + bool shouldRepaint(covariant ProgressPainter oldDelegate) { + return value != oldDelegate.value; + } +} diff --git a/lib/widgets/button/default_button.dart b/lib/widgets/button/default_button.dart index 338a13d..ba15fad 100644 --- a/lib/widgets/button/default_button.dart +++ b/lib/widgets/button/default_button.dart @@ -47,28 +47,21 @@ class DefaultButton extends StatelessWidget { decoration: BoxDecoration( borderRadius: BorderRadius.circular(6.0), gradient: onPress == null - ? const LinearGradient( + ? LinearGradient( colors: [ - Color(0xffEAEAEA), - Color(0xffEAEAEA), + disabledColor ?? Color(0xffEAEAEA), + disabledColor ?? Color(0xffEAEAEA), ], ) : color == MyColors.yellowColorII ? const LinearGradient( - colors: [ - MyColors.yellowColorII, - MyColors.yellowColorII, - ], + colors: [MyColors.yellowColorII, MyColors.yellowColorII], ) : LinearGradient( transform: const GradientRotation(.83), begin: Alignment.topRight, end: Alignment.bottomLeft, - colors: colors ?? - [ - MyColors.gradiantEndColor, - MyColors.gradiantStartColor, - ], + colors: colors ?? [MyColors.gradiantEndColor, MyColors.gradiantStartColor], ), ), child: Row( diff --git a/lib/widgets/my_video_progress_indicator.dart b/lib/widgets/my_video_progress_indicator.dart index a6e9172..3593115 100644 --- a/lib/widgets/my_video_progress_indicator.dart +++ b/lib/widgets/my_video_progress_indicator.dart @@ -1,4 +1,6 @@ import 'package:flutter/material.dart'; +import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/widgets/AnimatedProgressBar.dart'; import 'package:video_player/video_player.dart'; class MyVideoProgressIndicator extends StatefulWidget { @@ -68,36 +70,63 @@ class _VideoProgressIndicatorState extends State { progressIndicator = Stack( fit: StackFit.passthrough, children: [ - LinearProgressIndicator( - value: maxBuffering / duration, - valueColor: AlwaysStoppedAnimation(colors.bufferedColor), - backgroundColor: colors.backgroundColor, - minHeight: 8, - ), - LinearProgressIndicator( + // LinearProgressIndicator( + // value: maxBuffering / duration, + // valueColor: AlwaysStoppedAnimation(colors.bufferedColor), + // backgroundColor: colors.backgroundColor, + // minHeight: 8, + // ), + // LinearProgressIndicator( + // value: position / duration, + // valueColor: AlwaysStoppedAnimation(colors.playedColor), + // backgroundColor: Colors.transparent, + // minHeight: 8, + // ), + + AnimatedProgressBar( value: position / duration, - valueColor: AlwaysStoppedAnimation(colors.playedColor), - backgroundColor: Colors.transparent, - minHeight: 8, + duration: const Duration(seconds: 2), + height: 43, + width: MediaQuery.of(context).size.width - 120, + gradient: const LinearGradient( + transform: GradientRotation(.83), + begin: Alignment.topRight, + end: Alignment.bottomLeft, + colors: [ + MyColors.gradiantEndColor, + MyColors.gradiantStartColor, + ], + ), + backgroundColor: Colors.grey.withOpacity(0.6), ), ], ); } else { - progressIndicator = LinearProgressIndicator( - valueColor: AlwaysStoppedAnimation(colors.playedColor), - backgroundColor: colors.backgroundColor, - minHeight: 8, + // progressIndicator = LinearProgressIndicator( + // valueColor: AlwaysStoppedAnimation(colors.playedColor), + // backgroundColor: colors.backgroundColor, + // minHeight: 8, + // ); + progressIndicator = AnimatedProgressBar( + value: 1, + duration: const Duration(seconds: 2), + height: 43, + width: MediaQuery.of(context).size.width - 120, + gradient: const LinearGradient( + transform: GradientRotation(.83), + begin: Alignment.topRight, + end: Alignment.bottomLeft, + colors: [ + MyColors.gradiantEndColor, + MyColors.gradiantStartColor, + ], + ), + backgroundColor: Colors.grey.withOpacity(0.6), ); } - Widget paddedProgressIndicator = Padding( - padding: widget.padding, - child: progressIndicator, - ); + Widget paddedProgressIndicator = Padding(padding: widget.padding, child: progressIndicator); if (widget.allowScrubbing) { - return VideoScrubber( - controller: controller, - child: paddedProgressIndicator, - ); + return VideoScrubber(controller: controller, child: paddedProgressIndicator); } else { return paddedProgressIndicator; } -- 2.30.2 From 5d0091fe5b2311c0d721428fca758a7a072f4236 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Sun, 22 Dec 2024 12:33:48 +0300 Subject: [PATCH 049/135] Unsafe device check implemented --- lib/app_state/app_state.dart | 2 +- lib/classes/consts.dart | 4 ++-- lib/ui/login/login_screen.dart | 2 ++ lib/ui/unsafe_device_screen.dart | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/app_state/app_state.dart b/lib/app_state/app_state.dart index 7b22836..aea9251 100644 --- a/lib/app_state/app_state.dart +++ b/lib/app_state/app_state.dart @@ -90,7 +90,7 @@ class AppState { String get getHuaweiPushToken => _huaweiPushToken; - final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 8.2, mobileType: Platform.isAndroid ? "android" : "ios"); + final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 8.3, mobileType: Platform.isAndroid ? "android" : "ios"); void setPostParamsInitConfig() { diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 7103dfd..170762c 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -9,9 +9,9 @@ class ApiConsts { // static String baseUrl = "https://webservices.hmg.com"; // PreProd // static String baseUrl = "https://hmgwebservices.com"; // Live server - // static String baseUrl = "https://mohemm.hmg.com"; // New Live server + static String baseUrl = "https://mohemm.hmg.com"; // New Live server - static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver + // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.20.200.111:1010/"; // static String baseUrl = "https://webservices.hmg.com"; // PreProd diff --git a/lib/ui/login/login_screen.dart b/lib/ui/login/login_screen.dart index c71ae7f..3a35222 100644 --- a/lib/ui/login/login_screen.dart +++ b/lib/ui/login/login_screen.dart @@ -8,6 +8,7 @@ import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; + // import 'package:huawei_hmsavailability/huawei_hmsavailability.dart'; import 'package:mohem_flutter_app/api/login_api_client.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; @@ -31,6 +32,7 @@ import 'package:mohem_flutter_app/models/privilege_list_model.dart'; import 'package:mohem_flutter_app/widgets/button/default_button.dart'; import 'package:mohem_flutter_app/widgets/input_widget.dart'; import 'package:safe_device/safe_device.dart'; + // import 'package:safe_device/safe_device.dart'; import 'package:wifi_iot/wifi_iot.dart'; diff --git a/lib/ui/unsafe_device_screen.dart b/lib/ui/unsafe_device_screen.dart index dca8748..c8e1243 100644 --- a/lib/ui/unsafe_device_screen.dart +++ b/lib/ui/unsafe_device_screen.dart @@ -32,7 +32,7 @@ class _UnsafeDeviceScreenState extends State { 50.height, "Sorry".toText24(isBold: true), 21.height, - "You are using Mohemm app on an unsafe device. To be able to use the app with all it's features, Please make sure that the below points are considered: " + "You are using MoheM app on an unsafe device. To be able to use the app with all it's features, Please make sure that the below points are considered: " .toText14(isCenter: true) .paddingOnly(left: 20.0, right: 20.0), 48.height, -- 2.30.2 From c1503cc23602930a2e8d66c54900967b3c386742 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Sun, 22 Dec 2024 15:55:20 +0300 Subject: [PATCH 050/135] updates & fixes --- lib/classes/consts.dart | 2 +- .../itg/its_add_screen_video_image.dart | 13 ++++++------ lib/ui/login/verify_last_login_screen.dart | 21 +++++++------------ 3 files changed, 15 insertions(+), 21 deletions(-) diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 170762c..5e6a6ca 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -7,7 +7,7 @@ class ApiConsts { // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.201.204.101:2024"; // static String baseUrl = "https://webservices.hmg.com"; // PreProd - // static String baseUrl = "https://hmgwebservices.com"; // Live server + // static String baseUrl = "https://hmgwebservices.com"; // Live server static String baseUrl = "https://mohemm.hmg.com"; // New Live server 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 db6ba3e..6e1358c 100644 --- a/lib/ui/landing/itg/its_add_screen_video_image.dart +++ b/lib/ui/landing/itg/its_add_screen_video_image.dart @@ -197,7 +197,7 @@ class _ITGAdsScreenState extends State { valueListenable: hasTimerEnded, builder: (context, val, child) { // if (hasTimerEndedBool) { - return GridView.builder( + return ListView.builder( padding: EdgeInsets.zero, itemCount: advertisementData?.actionButtonsColl!.length, shrinkWrap: true, @@ -205,7 +205,8 @@ class _ITGAdsScreenState extends State { itemBuilder: (context, index) { String? btnText = AppState().isArabic(context) ? advertisementData?.actionButtonsColl![index].btnTextAr : advertisementData?.actionButtonsColl![index].btnTextEn; - bool isAcknowledge = advertisementData?.actionButtonsColl![index].actionButtonId == 11; + // bool isAcknowledge = advertisementData?.actionButtonsColl![index].actionButtonId == 11; + bool isAcknowledge = advertisementData?.actionButtonsColl![index].actionButtonId == 17; if (isAcknowledge) { return Stack( alignment: Alignment.center, @@ -243,10 +244,10 @@ class _ITGAdsScreenState extends State { }, ).paddingOnly(left: 60.0, right: 60.0, top: 8, bottom: 8); }, - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 1, - childAspectRatio: (7.0), - ), + // gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + // crossAxisCount: 1, + // childAspectRatio: (7.0), + // ), ); // Row( // mainAxisAlignment: MainAxisAlignment.center, diff --git a/lib/ui/login/verify_last_login_screen.dart b/lib/ui/login/verify_last_login_screen.dart index d6d041d..13c9b0c 100644 --- a/lib/ui/login/verify_last_login_screen.dart +++ b/lib/ui/login/verify_last_login_screen.dart @@ -57,14 +57,10 @@ class _VerifyLastLoginScreenState extends State { @override Widget build(BuildContext context) { - if(ModalRoute.of(context)!.settings.arguments != null) { - mobileLoginInfoListModel ??= ModalRoute - .of(context)! - .settings - .arguments as GetMobileLoginInfoListModel; + if (ModalRoute.of(context)!.settings.arguments != null) { + mobileLoginInfoListModel ??= ModalRoute.of(context)!.settings.arguments as GetMobileLoginInfoListModel; // String empName = AppState().isArabic(context) ? AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEAr! : AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEEn!; String empName = mobileLoginInfoListModel!.employeeName!; - } return Scaffold( @@ -140,7 +136,7 @@ class _VerifyLastLoginScreenState extends State { LocaleKeys.pleaseVerify.tr().toText16(), if (isNeedVerifyWithFaceIDAndBiometrics) LocaleKeys.pleaseVerifyForBio.tr().toText12(), GridView( - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2, crossAxisSpacing: 13, mainAxisSpacing: 9), + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: MediaQuery.of(context).size.width > 400 ? 3 : 2, crossAxisSpacing: 8.5, mainAxisSpacing: 9), physics: const NeverScrollableScrollPhysics(), padding: const EdgeInsets.only(top: 9), shrinkWrap: true, @@ -295,7 +291,7 @@ class _VerifyLastLoginScreenState extends State { width: 38, color: isDisable ? MyColors.darkTextColor.withOpacity(0.7) : null, ), - _title.toText16(height: 20/16) + _title.toText16(height: 20 / 16) ], ), ), @@ -397,12 +393,10 @@ class _VerifyLastLoginScreenState extends State { Utils.hideLoading(context); Utils.handleException(ex, context, null); dynamic errorCode = ex; - if(errorCode.error.errorStatusCode ==699){ - Future.delayed(const Duration(seconds: 2), () - { + if (errorCode.error.errorStatusCode == 699) { + Future.delayed(const Duration(seconds: 2), () { Navigator.pop(context); - Navigator.pushNamedAndRemoveUntil( - context, AppRoutes.login, (Route route) => false); + Navigator.pushNamedAndRemoveUntil(context, AppRoutes.login, (Route route) => false); }); } } @@ -419,5 +413,4 @@ class _VerifyLastLoginScreenState extends State { // // isLoading = isTrue; // }); // } - } -- 2.30.2 From 9f89f7530d78f3386f07965a0a82b286df05bd69 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Mon, 23 Dec 2024 12:41:55 +0300 Subject: [PATCH 051/135] Update to stores VersionID 8.5 --- lib/ui/login/verify_last_login_screen.dart | 2 +- pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ui/login/verify_last_login_screen.dart b/lib/ui/login/verify_last_login_screen.dart index 13c9b0c..8604baf 100644 --- a/lib/ui/login/verify_last_login_screen.dart +++ b/lib/ui/login/verify_last_login_screen.dart @@ -136,7 +136,7 @@ class _VerifyLastLoginScreenState extends State { LocaleKeys.pleaseVerify.tr().toText16(), if (isNeedVerifyWithFaceIDAndBiometrics) LocaleKeys.pleaseVerifyForBio.tr().toText12(), GridView( - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: MediaQuery.of(context).size.width > 400 ? 3 : 2, crossAxisSpacing: 8.5, mainAxisSpacing: 9), + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2, crossAxisSpacing: 13, mainAxisSpacing: 9), physics: const NeverScrollableScrollPhysics(), padding: const EdgeInsets.only(top: 9), shrinkWrap: true, diff --git a/pubspec.yaml b/pubspec.yaml index a12c83a..9740e7d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html #version: 3.3.01+300040 -version: 3.7.98+1 +version: 3.7.98+3 environment: sdk: ">=2.16.0 <3.0.0" -- 2.30.2 From 3e19508c5e4a0b2245ed18b38ddbca2cac3aada2 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Wed, 25 Dec 2024 10:28:48 +0300 Subject: [PATCH 052/135] child education assistance added. --- lib/api/my_attendance_api_client.dart | 45 ++++++++++++++ lib/classes/consts.dart | 4 +- lib/config/routes.dart | 8 +-- lib/models/generic_response_model.dart | 42 +++++++++---- .../get_eit_transaction_list_model.dart | 60 +++++++++++++------ .../dynamic_screens/dynamic_input_screen.dart | 29 +++++++-- .../dynamic_listview_screen.dart | 19 ++++-- .../services_menu_list_screen.dart | 2 + .../child_education_assistance.dart | 58 ++++++++++++++++++ 9 files changed, 220 insertions(+), 47 deletions(-) create mode 100644 lib/ui/screens/child_education/child_education_assistance.dart diff --git a/lib/api/my_attendance_api_client.dart b/lib/api/my_attendance_api_client.dart index 24cf6c0..74e9855 100644 --- a/lib/api/my_attendance_api_client.dart +++ b/lib/api/my_attendance_api_client.dart @@ -29,6 +29,21 @@ class MyAttendanceApiClient { }, url, postParams); } + Future?> getCeiTransaction(String pFunctionName, int? relationID) async { + String url = "${ApiConsts.erpRest}GET_CEI_TRANSACTIONS"; + Map postParams = {"P_PAGE_LIMIT": 50, "P_PAGE_NUM": 1, "P_FUNCTION_NAME": pFunctionName}; + postParams.addAll(AppState().postParamsJson); + if (relationID != null) postParams["P_CONTACT_RELATIONSHIP_ID"] = relationID; + return await ApiClient().postJsonForObject((json) { + GenericResponseModel? responseData = GenericResponseModel.fromJson(json); + if (responseData.getCEITransactionList?.isNotEmpty ?? false) { + return responseData.getCEITransactionList!.map((e) => GetEITTransactionList(collectionTransaction: e.collectionTransaction)).toList(); + } else { + return []; + } + }, url, postParams); + } + Future getEitDffStructure(String pFunctionName, String? empID) async { String url = "${ApiConsts.erpRest}GET_EIT_DFF_STRUCTURE"; Map postParams = {"P_SELECTED_RESP_ID": -999, "P_MENU_TYPE": "E", "P_FUNCTION_NAME": pFunctionName}; @@ -40,6 +55,17 @@ class MyAttendanceApiClient { }, url, postParams); } + Future getCEIDffStructure(String pFunctionName, String? empID) async { + String url = "${ApiConsts.erpRest}GET_CEI_DFF_STRUCTURE"; + Map postParams = {"P_FUNCTION_NAME": pFunctionName}; + postParams.addAll(AppState().postParamsJson); + if (empID != null) postParams["P_SELECTED_EMPLOYEE_NUMBER"] = empID; + return await ApiClient().postJsonForObject((json) { + GenericResponseModel? responseData = GenericResponseModel.fromJson(json); + return responseData; + }, url, postParams); + } + Future> getValueSetValues(String pSegmentName, String pDescFlexContextCode, String pDescFlexName, List> list, {String? empID, String? parentValue, bool hasParent = false}) async { String url = "${ApiConsts.erpRest}GET_VALUE_SET_VALUES"; @@ -102,6 +128,25 @@ class MyAttendanceApiClient { }, url, postParams); } + Future submitCEITransaction(String pDescFlexContextCode, String pFunctionName, List> list, {String? empID, int? pContactRelationID}) async { + String url = "${ApiConsts.erpRest}SUBMIT_CEI_TRANSACTION"; + Map postParams = { + "P_SELECTED_RESP_ID": -999, + "P_MENU_TYPE": "E", + "P_DESC_FLEX_CONTEXT_CODE": pDescFlexContextCode, + "P_CONTACT_RELATIONSHIP_ID": pContactRelationID, + "P_FUNCTION_NAME": pFunctionName, + "EITTransactionTBL": list, + "EITTransactionTBLModel": list, + }; + postParams.addAll(AppState().postParamsJson); + if (empID != null) postParams["P_SELECTED_EMPLOYEE_NUMBER"] = empID; + return await ApiClient().postJsonForObject((json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.submitEITTransactionList!; //ESERVICESDV.fromJson(responseData.getDefaultValueList!.toJson()); + }, url, postParams); + } + Future submitEitTransaction(String pDescFlexContextCode, String pFunctionName, List> list, {String? empID}) async { String url = "${ApiConsts.erpRest}SUBMIT_EIT_TRANSACTION"; Map postParams = { diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 5e6a6ca..6442b88 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -9,9 +9,9 @@ class ApiConsts { // static String baseUrl = "https://webservices.hmg.com"; // PreProd // static String baseUrl = "https://hmgwebservices.com"; // Live server - static String baseUrl = "https://mohemm.hmg.com"; // New Live server + // static String baseUrl = "https://mohemm.hmg.com"; // New Live server - // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver + static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.20.200.111:1010/"; // static String baseUrl = "https://webservices.hmg.com"; // PreProd diff --git a/lib/config/routes.dart b/lib/config/routes.dart index 33559e2..6afc095 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:mohem_flutter_app/models/my_documents/employee_documents_list_model.dart'; import 'package:mohem_flutter_app/ui/app_update_screen.dart'; import 'package:mohem_flutter_app/ui/attendance/add_vacation_rule_screen.dart'; import 'package:mohem_flutter_app/ui/attendance/monthly_attendance_screen.dart'; @@ -33,7 +32,6 @@ import 'package:mohem_flutter_app/ui/misc/request_submit_screen.dart'; import 'package:mohem_flutter_app/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart'; import 'package:mohem_flutter_app/ui/my_attendance/dynamic_screens/dynamic_listview_screen.dart'; import 'package:mohem_flutter_app/ui/my_attendance/services_menu_list_screen.dart'; - // import 'package:mohem_flutter_app/ui/my_attendance/my_attendance_screen.dart'; import 'package:mohem_flutter_app/ui/my_team/create_request.dart'; import 'package:mohem_flutter_app/ui/my_team/employee_details.dart'; @@ -55,7 +53,7 @@ import 'package:mohem_flutter_app/ui/profile/personal_info.dart'; import 'package:mohem_flutter_app/ui/profile/profile_screen.dart'; import 'package:mohem_flutter_app/ui/screens/announcements/announcement_details.dart'; import 'package:mohem_flutter_app/ui/screens/announcements/announcements.dart'; - +import 'package:mohem_flutter_app/ui/screens/child_education/child_education_assistance.dart'; // import 'package:mohem_flutter_app/ui/my_attendance/work_from_home_screen.dart'; import 'package:mohem_flutter_app/ui/screens/eit/add_eit.dart'; import 'package:mohem_flutter_app/ui/screens/items_for_sale/add_new_item_for_sale.dart'; @@ -64,7 +62,6 @@ import 'package:mohem_flutter_app/ui/screens/items_for_sale/items_for_sale_home. import 'package:mohem_flutter_app/ui/screens/mowadhafhi/mowadhafhi_home.dart'; import 'package:mohem_flutter_app/ui/screens/mowadhafhi/mowadhafhi_hr_request.dart'; import 'package:mohem_flutter_app/ui/screens/mowadhafhi/request_details.dart'; -import 'package:mohem_flutter_app/ui/screens/my_documents/my_document_detail_screen.dart'; import 'package:mohem_flutter_app/ui/screens/my_documents/my_documents_screen.dart'; import 'package:mohem_flutter_app/ui/screens/my_requests/my_requests.dart'; import 'package:mohem_flutter_app/ui/screens/my_requests/new_request.dart'; @@ -198,6 +195,7 @@ class AppRoutes { static const String manageGroup = "/manageGroup"; static const String groupMembers = "/groupmembers"; static const String groupChatDetailed = "/groupChatDetailed"; + //Marathon static const String marathonIntroScreen = "/marathonIntroScreen"; static const String marathonScreen = "/marathonScreen"; @@ -208,6 +206,7 @@ class AppRoutes { static const String unsafeDeviceScreen = "/unsafeDeviceScreen"; static const String appUpdateScreen = "/appUpdateScreen"; + static const String childEducation = "/childEducation"; static final Map routes = { login: (BuildContext context) => LoginScreen(), @@ -325,5 +324,6 @@ class AppRoutes { unsafeDeviceScreen: (BuildContext context) => const UnsafeDeviceScreen(), appUpdateScreen: (BuildContext context) => const AppUpdateScreen(), + childEducation: (BuildContext context) => ChildEducationAssistance(), }; } diff --git a/lib/models/generic_response_model.dart b/lib/models/generic_response_model.dart index e9daeb4..4175e7f 100644 --- a/lib/models/generic_response_model.dart +++ b/lib/models/generic_response_model.dart @@ -185,8 +185,8 @@ class GenericResponseModel { List? getBasicDetDffStructureList; List? getBasicDetNtfBodyList; List? getCEICollectionNotificationBodyList; - List? getCEIDFFStructureList; - List? getCEITransactionList; + List? getCEIDFFStructureList; + List? getCEITransactionList; List? getCcpTransactionsList; List? getContactColsStructureList; @@ -226,6 +226,7 @@ class GenericResponseModel { List? getOrganizationsSalariesList; List? getPaymentInformationList; List? getPayslipList; + // List? getPendingReqDetailsList; // List? getPendingReqFunctionsList; List? getPerformanceAppraisalList; @@ -503,7 +504,7 @@ class GenericResponseModel { this.getPoItemHistoryList, this.getPoNotificationBodyList, this.getPrNotificationBodyList, - this.getPaymentNotificationBodyList, + this.getPaymentNotificationBodyList, this.getPRInformationList, this.getQuotationAnalysisList, this.getRFCEmployeeListList, @@ -700,7 +701,7 @@ class GenericResponseModel { cancelHRTransactionLIst = json['CancelHRTransactionLIst'] != null ? new CancelHRTransactionLIst.fromJson(json['CancelHRTransactionLIst']) : null; if (json['GetTermNotificationBodyList'] != null) { - getTermNotificationBodyList = []; + getTermNotificationBodyList = []; json['GetTermNotificationBodyList'].forEach((v) { getTermNotificationBodyList!.add(TerminationNotificationBody.fromJson(v)); }); @@ -845,8 +846,21 @@ class GenericResponseModel { } getCEICollectionNotificationBodyList = json['GetCEICollectionNotificationBodyList']; - getCEIDFFStructureList = json['GetCEIDFFStructureList']; - getCEITransactionList = json['GetCEITransactionList']; + + if (json['GetCEIDFFStructureList'] != null) { + getCEIDFFStructureList = []; + json['GetCEIDFFStructureList'].forEach((v) { + getCEIDFFStructureList!.add(GetEITDFFStructureList.fromJson(v)); + }); + } + + if (json['GetCEITransactionList'] != null) { + getCEITransactionList = []; + json['GetCEITransactionList'].forEach((v) { + getCEITransactionList!.add(GetCEITransactionList.fromJson(v)); + }); + } + getCcpTransactionsList = json['GetCcpTransactionsList']; getContactNotificationBodyList = json["GetContactNotificationBodyList"] == null ? null : GetContactNotificationBodyList.fromJson(json["GetContactNotificationBodyList"]); if (json['GetContactColsStructureList'] != null) { @@ -1028,7 +1042,6 @@ class GenericResponseModel { getPrNotificationBodyList = json['GetPrNotificationBodyList'] != null ? GetPrNotificationBodyList.fromJson(json['GetPrNotificationBodyList']) : null; getPaymentNotificationBodyList = json['Pay_ReqNotificationBody'] != null ? GetPaymentNotificationBodyList.fromJson(json['Pay_ReqNotificationBody']) : null; - getPRInformationList = json['PR_Information_List'] != null ? GetPRInformationList.fromJson(json['PR_Information_List']) : null; if (json['GetQuotationAnalysisList'] != null) { getQuotationAnalysisList = []; @@ -1106,8 +1119,6 @@ class GenericResponseModel { }); } - - if (json['GetTimeCardSummaryList'] != null) { getTimeCardSummaryList = []; json['GetTimeCardSummaryList'].forEach((v) { @@ -1544,8 +1555,15 @@ class GenericResponseModel { } data['GetCEICollectionNotificationBodyList'] = this.getCEICollectionNotificationBodyList; - data['GetCEIDFFStructureList'] = this.getCEIDFFStructureList; - data['GetCEITransactionList'] = this.getCEITransactionList; + + + if (this.getCEIDFFStructureList != null) { + data['GetCEIDFFStructureList'] = this.getCEIDFFStructureList!.map((v) => v.toJson()).toList(); + } + + if (this.getCEITransactionList != null) { + data['GetCEITransactionList'] = this.getCEITransactionList!.map((v) => v.toJson()).toList(); + } data['GetCcpTransactionsList'] = this.getCcpTransactionsList; if (this.getContactDetailsList != null) { data['GetContactDetailsList'] = this.getContactDetailsList!.map((v) => v.toJson()).toList(); @@ -1628,7 +1646,7 @@ class GenericResponseModel { data['GetNotificationReassignModeList'] = getNotificationReassignModeList!.map((v) => v.toJson()).toList(); } - if(getTermNotificationBodyList !=null){ + if (getTermNotificationBodyList != null) { data['GetTermNotificationBodyList'] = getTermNotificationBodyList!.map((v) => v.toJson()).toList(); } data['GetObjectValuesList'] = this.getObjectValuesList; diff --git a/lib/models/get_eit_transaction_list_model.dart b/lib/models/get_eit_transaction_list_model.dart index d8c39c9..c459bbd 100644 --- a/lib/models/get_eit_transaction_list_model.dart +++ b/lib/models/get_eit_transaction_list_model.dart @@ -15,8 +15,30 @@ class GetEITTransactionList { Map toJson() { Map data = new Map(); if (this.collectionTransaction != null) { - data['Collection_Transaction'] = - this.collectionTransaction!.map((v) => v.toJson()).toList(); + data['Collection_Transaction'] = this.collectionTransaction!.map((v) => v.toJson()).toList(); + } + return data; + } +} + +class GetCEITransactionList { + List? collectionTransaction; + + GetCEITransactionList({this.collectionTransaction}); + + GetCEITransactionList.fromJson(Map json) { + if (json['Collection_Transaction'] != null) { + collectionTransaction = []; + json['Collection_Transaction'].forEach((v) { + collectionTransaction!.add(new CollectionTransaction.fromJson(v)); + }); + } + } + + Map toJson() { + Map data = new Map(); + if (this.collectionTransaction != null) { + data['Collection_Transaction'] = this.collectionTransaction!.map((v) => v.toJson()).toList(); } return data; } @@ -43,22 +65,22 @@ class CollectionTransaction { CollectionTransaction( {this.aPPLICATIONCOLUMNNAME, - this.dATATYPE, - this.dATEVALUE, - this.dESCFLEXCONTEXTCODE, - this.dESCFLEXNAME, - this.dISPLAYFLAG, - this.fROMROWNUM, - this.nOOFROWS, - this.nUMBERVALUE, - this.rOWNUM, - this.sEGMENTNAME, - this.sEGMENTPROMPT, - this.sEGMENTSEQNUM, - this.sEGMENTVALUEDSP, - this.tOROWNUM, - this.tRANSACTIONNUMBER, - this.vARCHAR2VALUE}); + this.dATATYPE, + this.dATEVALUE, + this.dESCFLEXCONTEXTCODE, + this.dESCFLEXNAME, + this.dISPLAYFLAG, + this.fROMROWNUM, + this.nOOFROWS, + this.nUMBERVALUE, + this.rOWNUM, + this.sEGMENTNAME, + this.sEGMENTPROMPT, + this.sEGMENTSEQNUM, + this.sEGMENTVALUEDSP, + this.tOROWNUM, + this.tRANSACTIONNUMBER, + this.vARCHAR2VALUE}); CollectionTransaction.fromJson(Map json) { aPPLICATIONCOLUMNNAME = json['APPLICATION_COLUMN_NAME']; @@ -101,4 +123,4 @@ class CollectionTransaction { data['VARCHAR2_VALUE'] = this.vARCHAR2VALUE; return data; } -} \ No newline at end of file +} diff --git a/lib/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart b/lib/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart index ef88e11..73f05bc 100644 --- a/lib/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart +++ b/lib/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart @@ -46,10 +46,17 @@ class _DynamicInputScreenState extends State { void getTransactionsStructure() async { try { Utils.showLoading(context); - genericResponseModel = await MyAttendanceApiClient().getEitDffStructure(dynamicParams!.dynamicId, dynamicParams!.selectedEmp); + if (dynamicParams?.pContactRelationshipId == null) { + genericResponseModel = await MyAttendanceApiClient().getEitDffStructure(dynamicParams!.dynamicId, dynamicParams!.selectedEmp); + getEitDffStructureList = genericResponseModel?.getEITDFFStructureList ?? []; + } else { + genericResponseModel = await MyAttendanceApiClient().getCEIDffStructure(dynamicParams!.dynamicId, null); + getEitDffStructureList = genericResponseModel?.getCEIDFFStructureList ?? []; + } + dESCFLEXCONTEXTCODE = genericResponseModel!.pDESCFLEXCONTEXTCODE ?? ""; descFlexConTextTitle = genericResponseModel!.pDESCFLEXCONTEXTNAME ?? ""; - getEitDffStructureList = genericResponseModel?.getEITDFFStructureList ?? []; + // getEitDffStructureList = genericResponseModel?.getEITDFFStructureList ?? []; //getEitDffStructureList = getEitDffStructureList!.where((element) => element.dISPLAYFLAG != "N").toList(); Utils.hideLoading(context); setState(() {}); @@ -90,11 +97,21 @@ class _DynamicInputScreenState extends State { }).toList(); values.add(ValidateEitTransactionModel(dATEVALUE: null, nAME: "PEI_ACTION", nUMBERVALUE: null, tRANSACTIONNUMBER: 1, vARCHAR2VALUE: "NEW_ROW").toJson()); - values.add(ValidateEitTransactionModel(dATEVALUE: null, nAME: "PEI_EXTRA_INFO_ID", nUMBERVALUE: -1, tRANSACTIONNUMBER: 1, vARCHAR2VALUE: null).toJson()); - values.add(ValidateEitTransactionModel(dATEVALUE: null, nAME: "PEI_OBJECT_VERSION_NUMBER", nUMBERVALUE: 0, tRANSACTIONNUMBER: 1, vARCHAR2VALUE: null).toJson()); - genericResponseModel = await MyAttendanceApiClient().validateEitTransaction(dESCFLEXCONTEXTCODE, dynamicParams!.dynamicId, values, empID: dynamicParams!.selectedEmp); - SubmitEITTransactionList submitEITTransactionList = await MyAttendanceApiClient().submitEitTransaction(dESCFLEXCONTEXTCODE, dynamicParams!.dynamicId, values, empID: dynamicParams!.selectedEmp); + if (dynamicParams!.pContactRelationshipId == null) { + values.add(ValidateEitTransactionModel(dATEVALUE: null, nAME: "PEI_EXTRA_INFO_ID", nUMBERVALUE: -1, tRANSACTIONNUMBER: 1, vARCHAR2VALUE: null).toJson()); + values.add(ValidateEitTransactionModel(dATEVALUE: null, nAME: "PEI_OBJECT_VERSION_NUMBER", nUMBERVALUE: 0, tRANSACTIONNUMBER: 1, vARCHAR2VALUE: null).toJson()); + } else { + values.add(ValidateEitTransactionModel(dATEVALUE: null, nAME: "CONTACT_EXTRA_INFO_ID", nUMBERVALUE: -1, tRANSACTIONNUMBER: 1, vARCHAR2VALUE: null).toJson()); + values.add(ValidateEitTransactionModel(dATEVALUE: null, nAME: "CEI_OBJECT_VERSION_NUMBER", nUMBERVALUE: 0, tRANSACTIONNUMBER: 1, vARCHAR2VALUE: null).toJson()); + } + SubmitEITTransactionList submitEITTransactionList; + if (dynamicParams!.pContactRelationshipId == null) { + genericResponseModel = await MyAttendanceApiClient().validateEitTransaction(dESCFLEXCONTEXTCODE, dynamicParams!.dynamicId, values, empID: dynamicParams!.selectedEmp); + submitEITTransactionList = await MyAttendanceApiClient().submitEitTransaction(dESCFLEXCONTEXTCODE, dynamicParams!.dynamicId, values, empID: dynamicParams!.selectedEmp); + } else { + submitEITTransactionList = await MyAttendanceApiClient().submitCEITransaction(dESCFLEXCONTEXTCODE, dynamicParams!.dynamicId, values, pContactRelationID: dynamicParams!.pContactRelationshipId); + } Utils.hideLoading(context); await Navigator.pushNamed(context, AppRoutes.requestSubmitScreen, arguments: RequestSubmitScreenParams(LocaleKeys.submit.tr(), submitEITTransactionList.pTRANSACTIONID!, submitEITTransactionList.pITEMKEY!, 'eit', diff --git a/lib/ui/my_attendance/dynamic_screens/dynamic_listview_screen.dart b/lib/ui/my_attendance/dynamic_screens/dynamic_listview_screen.dart index 94a201f..54b250d 100644 --- a/lib/ui/my_attendance/dynamic_screens/dynamic_listview_screen.dart +++ b/lib/ui/my_attendance/dynamic_screens/dynamic_listview_screen.dart @@ -24,11 +24,13 @@ class DynamicListViewParams { List? collectionNotificationList; final String? selectedEmp; + final int? pContactRelationshipId; DynamicListViewParams( this.title, this.dynamicId, { this.selectedEmp, + this.pContactRelationshipId, this.uRL = 'GET_EIT_DFF_STRUCTURE', this.requestID = '', this.colsURL = '', @@ -59,10 +61,14 @@ class _DynamicListViewScreenState extends State { super.initState(); } - void getTransactions() async { + void getTransactions({bool isCei = false}) async { try { Utils.showLoading(context); - getEITTransactionList = await MyAttendanceApiClient().getEitTransaction(dynamicParams!.dynamicId, dynamicParams!.selectedEmp); + if (isCei) { + getEITTransactionList = await MyAttendanceApiClient().getCeiTransaction(dynamicParams!.dynamicId, dynamicParams!.pContactRelationshipId); + } else { + getEITTransactionList = await MyAttendanceApiClient().getEitTransaction(dynamicParams!.dynamicId, dynamicParams!.selectedEmp); + } getEITTransactionList?.forEach((element) { element.collectionTransaction = element.collectionTransaction?.where((elemen) => elemen.dISPLAYFLAG == "Y").toList() ?? []; }); @@ -97,8 +103,13 @@ class _DynamicListViewScreenState extends State { Widget build(BuildContext context) { if (dynamicParams == null) { dynamicParams = ModalRoute.of(context)!.settings.arguments as DynamicListViewParams; - isTicketRequest = dynamicParams!.dynamicId == "HMG_TKT_NEW_EIT_SS"; - getTransactions(); + if (dynamicParams?.pContactRelationshipId == null) { + isTicketRequest = dynamicParams!.dynamicId == "HMG_TKT_NEW_EIT_SS"; + getTransactions(); + } else { + isTicketRequest = false; + getTransactions(isCei: true); + } } Widget dataWidget = ListView( physics: const BouncingScrollPhysics(), diff --git a/lib/ui/my_attendance/services_menu_list_screen.dart b/lib/ui/my_attendance/services_menu_list_screen.dart index 44aac6a..a074cad 100644 --- a/lib/ui/my_attendance/services_menu_list_screen.dart +++ b/lib/ui/my_attendance/services_menu_list_screen.dart @@ -64,6 +64,8 @@ class ServicesMenuListScreen extends StatelessWidget { if (servicesMenuData.list[index].requestType == "EIT") { Navigator.pushNamed(context, AppRoutes.dynamicScreen, arguments: DynamicListViewParams(servicesMenuData.list[index].prompt!, servicesMenuData.list[index].functionName!, selectedEmp: servicesMenuData.selectedEmp)); + } else if (servicesMenuData.list[index].requestType == "CEI") { + Navigator.pushNamed(context, AppRoutes.childEducation, arguments: servicesMenuData.list[index]); } else { if (servicesMenuData.list[index].requestType == "TERMINATION") { Navigator.pushNamed(context, AppRoutes.endEmploymentScreen, diff --git a/lib/ui/screens/child_education/child_education_assistance.dart b/lib/ui/screens/child_education/child_education_assistance.dart new file mode 100644 index 0000000..283dab3 --- /dev/null +++ b/lib/ui/screens/child_education/child_education_assistance.dart @@ -0,0 +1,58 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:mohem_flutter_app/api/profile_api_client.dart'; +import 'package:mohem_flutter_app/classes/colors.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/dashboard/menu_entries.dart'; +import 'package:mohem_flutter_app/models/get_employee_contacts.model.dart'; +import 'package:mohem_flutter_app/ui/my_attendance/dynamic_screens/dynamic_listview_screen.dart'; +import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; + +class ChildEducationAssistance extends StatelessWidget { + ChildEducationAssistance({Key? key}) : super(key: key); + + GetMenuEntriesList? menuEntry; + + @override + Widget build(BuildContext context) { + menuEntry ??= ModalRoute.of(context)!.settings.arguments as GetMenuEntriesList; + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBarWidget(context, title: menuEntry!.prompt!), + body: FutureBuilder( + future: ProfileApiClient().getEmployeeContacts(), + builder: (BuildContext cxt, AsyncSnapshot> snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const Center(child: CircularProgressIndicator()); + } else if (snapshot.hasData) { + List empContactList = snapshot.data!; + return ListView.separated( + padding: const EdgeInsets.all(21), + separatorBuilder: (BuildContext cxt, int index) => 12.height, + itemCount: empContactList.length, + itemBuilder: (BuildContext context, int index) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + "${empContactList[index].cONTACTNAME}".toText16(color: MyColors.grey3AColor), + "${LocaleKeys.dateOfBirth.tr()}: ${empContactList[index].dATEOFBIRTH?.split(" ").first ?? ""}".toText14(color: MyColors.grey3AColor, weight: FontWeight.w400), + "${empContactList[index].rELATIONSHIP}".toText11(color: MyColors.textMixColor), + ], + ).objectContainerView(disablePadding: false, center: false).onPress(() { + Navigator.pushNamed(context, AppRoutes.dynamicScreen, + arguments: DynamicListViewParams(empContactList[index].cONTACTNAME!, menuEntry!.functionName!, pContactRelationshipId: empContactList[index].cONTACTRELATIONSHIPID)); + }); + }); + } else { + return LocaleKeys.noDataAvailable.tr().toText16().center; + } + }, + ), + ); + } +} -- 2.30.2 From e20d6eca3f27fc958618de582b3bb39b8204b8a8 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Mon, 30 Dec 2024 10:43:24 +0300 Subject: [PATCH 053/135] Safe device issue fixed --- lib/ui/login/login_screen.dart | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/lib/ui/login/login_screen.dart b/lib/ui/login/login_screen.dart index 3a35222..2aa2da3 100644 --- a/lib/ui/login/login_screen.dart +++ b/lib/ui/login/login_screen.dart @@ -59,8 +59,7 @@ class _LoginScreenState extends State { bool? isAppOpenBySystem; bool isJailBroken = false; - bool isRealDevice = false; - bool isOnExternalStorage = false; + bool isRealDevice = true; bool isDevelopmentModeEnable = false; BasicMemberInformationModel? _basicMemberInformation; @@ -78,16 +77,20 @@ class _LoginScreenState extends State { } } - void checkDeviceSafety() async { + void checkDeviceSafety() { try { - isJailBroken = await SafeDevice.isJailBroken; - isRealDevice = await SafeDevice.isRealDevice; + SafeDevice.isJailBroken.then((bool value) { + isJailBroken = value; + }); + SafeDevice.isRealDevice.then((value) { + isRealDevice = value; + }); + if (Platform.isAndroid) { - isOnExternalStorage = await SafeDevice.isOnExternalStorage; - isDevelopmentModeEnable = await SafeDevice.isDevelopmentModeEnable; - } - if (isJailBroken || !isRealDevice || isOnExternalStorage || isDevelopmentModeEnable) { - Navigator.pushNamedAndRemoveUntil(context, AppRoutes.unsafeDeviceScreen, (_) => false); + // isOnExternalStorage = await SafeDevice.isOnExternalStorage; + SafeDevice.isDevelopmentModeEnable.then((value) { + isDevelopmentModeEnable = value; + }); } } catch (error) { print(error); @@ -123,7 +126,14 @@ class _LoginScreenState extends State { firebaseToken = ""; } AppNotifications().init(firebaseToken, context); - checkLoginInfo(); + + if (isJailBroken || !isRealDevice || isDevelopmentModeEnable) { + Utils.hideLoading(context); + Navigator.pushNamedAndRemoveUntil(context, AppRoutes.unsafeDeviceScreen, (_) => false); + } else { + checkLoginInfo(); + } + await FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(true); } // }); @@ -201,6 +211,8 @@ class _LoginScreenState extends State { } Utils.saveStringFromPrefs(SharedPrefsConsts.password, password.text); } catch (ex) { + print(ex); + print(ex.toString()); Utils.hideLoading(context); Utils.handleException(ex, context, (msg) { Utils.confirmDialog( -- 2.30.2 From 9362859013be51abae21fe160a2cec8b8980199f Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Tue, 31 Dec 2024 17:20:22 +0300 Subject: [PATCH 054/135] CEI notification body added. --- lib/api/my_attendance_api_client.dart | 2 +- lib/api/worklist/worklist_api_client.dart | 14 +++++++++++++ lib/models/generic_response_model.dart | 16 ++++++++------ lib/ui/work_list/worklist_detail_screen.dart | 22 +++++++++++++++++++- 4 files changed, 46 insertions(+), 8 deletions(-) diff --git a/lib/api/my_attendance_api_client.dart b/lib/api/my_attendance_api_client.dart index 74e9855..37bf9e8 100644 --- a/lib/api/my_attendance_api_client.dart +++ b/lib/api/my_attendance_api_client.dart @@ -143,7 +143,7 @@ class MyAttendanceApiClient { if (empID != null) postParams["P_SELECTED_EMPLOYEE_NUMBER"] = empID; return await ApiClient().postJsonForObject((json) { GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.submitEITTransactionList!; //ESERVICESDV.fromJson(responseData.getDefaultValueList!.toJson()); + return responseData.submitCEITransactionList!; //ESERVICESDV.fromJson(responseData.getDefaultValueList!.toJson()); }, url, postParams); } diff --git a/lib/api/worklist/worklist_api_client.dart b/lib/api/worklist/worklist_api_client.dart index e08d30b..9667961 100644 --- a/lib/api/worklist/worklist_api_client.dart +++ b/lib/api/worklist/worklist_api_client.dart @@ -534,6 +534,20 @@ class WorkListApiClient { }, url, postParams); } + Future?> GetCeiNotificationBody(int? notificationId) async { + String url = "${ApiConsts.erpRest}GET_CEI_NOTIFICATION_BODY"; + Map postParams = { + "P_NOTIFICATION_ID": notificationId, + "P_PAGE_LIMIT": 100, + "P_PAGE_NUM": 1, + }; + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject((json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getCEICollectionNotificationBodyList; + }, url, postParams); + } + Future?> getPhonesNotificationBodyList(int? notificationId) async { String url = "${ApiConsts.erpRest}GET_PHONES_NOTIFICATION_BODY"; Map postParams = { diff --git a/lib/models/generic_response_model.dart b/lib/models/generic_response_model.dart index 4175e7f..e87c3e0 100644 --- a/lib/models/generic_response_model.dart +++ b/lib/models/generic_response_model.dart @@ -184,7 +184,7 @@ class GenericResponseModel { List? getBasicDetColsStructureList; List? getBasicDetDffStructureList; List? getBasicDetNtfBodyList; - List? getCEICollectionNotificationBodyList; + List? getCEICollectionNotificationBodyList; List? getCEIDFFStructureList; List? getCEITransactionList; List? getCcpTransactionsList; @@ -356,7 +356,7 @@ class GenericResponseModel { StartTermApprovalProcessList? startTermApprovalProcessList; SubmitAddressTransaction? submitAddressTransactionList; SubmitBasicDetailsTransactionList? submitBasicDetTransactionList; - String? submitCEITransactionList; + SubmitEITTransactionList? submitCEITransactionList; SubmitCcpTransactionList? submitCcpTransactionList; SubmitContactTransactionList? submitContactTransactionList; SubmitEITTransactionList? submitEITTransactionList; @@ -845,7 +845,9 @@ class GenericResponseModel { }); } - getCEICollectionNotificationBodyList = json['GetCEICollectionNotificationBodyList']; + getCEICollectionNotificationBodyList = json["GetCEICollectionNotificationBodyList"] == null + ? null + : List.from(json["GetCEICollectionNotificationBodyList"].map((x) => GetEitCollectionNotificationBodyList.fromJson(x))); if (json['GetCEIDFFStructureList'] != null) { getCEIDFFStructureList = []; @@ -1378,7 +1380,7 @@ class GenericResponseModel { submitAddressTransactionList = json['SubmitAddressTransactionList'] != null ? SubmitAddressTransaction.fromJson(json['SubmitAddressTransactionList']) : null; submitBasicDetTransactionList = json['SubmitBasicDetTransactionList'] != null ? SubmitBasicDetailsTransactionList.fromJson(json['SubmitBasicDetTransactionList']) : null; - submitCEITransactionList = json['SubmitCEITransactionList']; + submitCEITransactionList = json['SubmitCEITransactionList'] != null ? SubmitEITTransactionList.fromJson(json['SubmitCEITransactionList']) : null; submitCcpTransactionList = json['SubmitCcpTransactionList'] != null ? new SubmitCcpTransactionList.fromJson(json['SubmitCcpTransactionList']) : null; submitContactTransactionList = json['SubmitContactTransactionList'] != null ? SubmitContactTransactionList.fromJson(json['SubmitContactTransactionList']) : null; submitEITTransactionList = json['SubmitEITTransactionList'] != null ? SubmitEITTransactionList.fromJson(json['SubmitEITTransactionList']) : null; @@ -1553,10 +1555,8 @@ class GenericResponseModel { if (this.getBasicDetNtfBodyList != null) { data['GetBasicDetNtfBodyList'] = this.getBasicDetNtfBodyList!.map((v) => v.toJson()).toList(); } - data['GetCEICollectionNotificationBodyList'] = this.getCEICollectionNotificationBodyList; - if (this.getCEIDFFStructureList != null) { data['GetCEIDFFStructureList'] = this.getCEIDFFStructureList!.map((v) => v.toJson()).toList(); } @@ -1855,6 +1855,10 @@ class GenericResponseModel { } data['SubmitCEITransactionList'] = this.submitCEITransactionList; + + if (this.submitCEITransactionList != null) { + data['SubmitCEITransactionList'] = this.submitCEITransactionList!.toJson(); + } if (this.submitCcpTransactionList != null) { data['SubmitCcpTransactionList'] = this.submitCcpTransactionList!.toJson(); } diff --git a/lib/ui/work_list/worklist_detail_screen.dart b/lib/ui/work_list/worklist_detail_screen.dart index ee595d1..69c669f 100644 --- a/lib/ui/work_list/worklist_detail_screen.dart +++ b/lib/ui/work_list/worklist_detail_screen.dart @@ -142,7 +142,9 @@ class _WorkListDetailScreenState extends State { if (workListData!.iTEMTYPE == "HRSSA") { if (workListData!.rEQUESTTYPE == "EIT") { getEitNotificationBody(); - } else if (workListData!.rEQUESTTYPE == "PHONE_NUMBERS") { + } else if (workListData!.rEQUESTTYPE == "CEI") { + getCEINotificationBody(); + }else if (workListData!.rEQUESTTYPE == "PHONE_NUMBERS") { getPhonesNotificationBody(); } else if (workListData!.rEQUESTTYPE == "BASIC_DETAILS") { getBasicDetNtfBody(); @@ -760,6 +762,24 @@ class _WorkListDetailScreenState extends State { } } + void getCEINotificationBody() async { + try { + if (apiCallCount == 0) Utils.showLoading(context); + apiCallCount++; + getEitCollectionNotificationBodyList!.clear(); + getEitCollectionNotificationBodyList = await WorkListApiClient().GetCeiNotificationBody(workListData!.nOTIFICATIONID); + apiCallCount--; + if (apiCallCount == 0) { + Utils.hideLoading(context); + setState(() {}); + } + } catch (ex) { + apiCallCount--; + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + } + } + void getEitNotificationBody() async { try { if (apiCallCount == 0) Utils.showLoading(context); -- 2.30.2 From c35074576a8c2c4d04b21a0cc9cee39b9697bf20 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Thu, 30 Jan 2025 11:41:44 +0300 Subject: [PATCH 055/135] offer and discount, do not show if api have issue. --- lib/classes/consts.dart | 6 +- lib/provider/dashboard_provider_model.dart | 4 +- lib/ui/landing/dashboard_screen.dart | 188 +++++++++++---------- 3 files changed, 102 insertions(+), 96 deletions(-) diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 6442b88..fea9b75 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -9,9 +9,9 @@ class ApiConsts { // static String baseUrl = "https://webservices.hmg.com"; // PreProd // static String baseUrl = "https://hmgwebservices.com"; // Live server - // static String baseUrl = "https://mohemm.hmg.com"; // New Live server - - static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver + static String baseUrl = "https://mohemm.hmg.com"; // New Live server + // + // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.20.200.111:1010/"; // static String baseUrl = "https://webservices.hmg.com"; // PreProd diff --git a/lib/provider/dashboard_provider_model.dart b/lib/provider/dashboard_provider_model.dart index 0e18544..e3f6511 100644 --- a/lib/provider/dashboard_provider_model.dart +++ b/lib/provider/dashboard_provider_model.dart @@ -253,8 +253,10 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { notifyListeners(); } catch (ex) { // Utils.hideLoading(context); + getOffersList=[]; + isOffersLoading = false; notifyListeners(); - Utils.handleException(ex, context, null); + // Utils.handleException(ex, context, null); } } diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index 333d271..4448ad1 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -3,7 +3,6 @@ import 'dart:io'; import 'dart:ui' as ui; import 'package:easy_localization/easy_localization.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_countdown_timer/flutter_countdown_timer.dart'; import 'package:flutter_svg/flutter_svg.dart'; @@ -421,103 +420,108 @@ class _DashboardScreenState extends State with WidgetsBindingOb ), ], ).paddingOnly(left: 21, right: 21, top: 7, bottom: 21), - Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - LocaleKeys.offers.tr().toText12(), - Row( - children: [ - LocaleKeys.discounts.tr().toText24(isBold: true), - 6.width, - Container( - padding: const EdgeInsets.only(left: 8, right: 8), - decoration: BoxDecoration( - color: MyColors.yellowColor, - borderRadius: BorderRadius.circular(10), - ), - child: LocaleKeys.newString.tr().toText10(isBold: true)), - ], - ), - ], + Consumer(builder: (BuildContext context, DashboardProviderModel model, Widget? child) { + if (!model.isOffersLoading && model.getOffersList.isEmpty) { + return const SizedBox(); + } + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + LocaleKeys.offers.tr().toText12(), + Row( + children: [ + LocaleKeys.discounts.tr().toText24(isBold: true), + 6.width, + Container( + padding: const EdgeInsets.only(left: 8, right: 8), + decoration: BoxDecoration( + color: MyColors.yellowColor, + borderRadius: BorderRadius.circular(10), + ), + child: LocaleKeys.newString.tr().toText10(isBold: true)), + ], + ), + ], + ), ), - ), - LocaleKeys.viewAllOffers.tr().toText12(isUnderLine: true).onPress(() { - Navigator.pushNamed(context, AppRoutes.offersAndDiscounts); - }) - ], - ).paddingOnly(left: 21, right: 21), - Consumer( - builder: (BuildContext context, DashboardProviderModel model, Widget? child) { - return SizedBox( - height: 103 + 33, - child: ListView.separated( - shrinkWrap: true, - physics: const BouncingScrollPhysics(), - padding: const EdgeInsets.only(left: 21, right: 21, top: 13), - scrollDirection: Axis.horizontal, - itemBuilder: (BuildContext cxt, int index) { - return model.isOffersLoading - ? const OffersShimmerWidget() - : InkWell( - onTap: () { - navigateToDetails(data.getOffersList[index]); - }, - child: SizedBox( - width: 73, - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Container( - width: 73, - height: 73, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: const BorderRadius.all( - Radius.circular(100), - ), - border: Border.all(color: MyColors.lightGreyE3Color, width: 1), - ), - child: ClipRRect( - borderRadius: const BorderRadius.all( - Radius.circular(50), + LocaleKeys.viewAllOffers.tr().toText12(isUnderLine: true).onPress(() { + Navigator.pushNamed(context, AppRoutes.offersAndDiscounts); + }) + ], + ).paddingOnly(left: 21, right: 21), + Consumer( + builder: (BuildContext context, DashboardProviderModel model, Widget? child) { + return SizedBox( + height: 103 + 33, + child: ListView.separated( + shrinkWrap: true, + physics: const BouncingScrollPhysics(), + padding: const EdgeInsets.only(left: 21, right: 21, top: 13), + scrollDirection: Axis.horizontal, + itemBuilder: (BuildContext cxt, int index) { + return model.isOffersLoading + ? const OffersShimmerWidget() + : InkWell( + onTap: () { + navigateToDetails(data.getOffersList[index]); + }, + child: SizedBox( + width: 73, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + width: 73, + height: 73, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: const BorderRadius.all( + Radius.circular(100), + ), + border: Border.all(color: MyColors.lightGreyE3Color, width: 1), ), - child: Hero( - tag: "ItemImage" + data.getOffersList[index].offersDiscountId.toString()!, - transitionOnUserGestures: true, - child: Image.network( - data.getOffersList[index].logo ?? "", - fit: BoxFit.contain, + child: ClipRRect( + borderRadius: const BorderRadius.all( + Radius.circular(50), + ), + child: Hero( + tag: "ItemImage" + data.getOffersList[index].offersDiscountId.toString()!, + transitionOnUserGestures: true, + child: Image.network( + data.getOffersList[index].logo ?? "", + fit: BoxFit.contain, + ), ), ), ), - ), - 4.height, - Expanded( - child: AppState().isArabic(context) - ? data.getOffersList[index].titleAr!.toText12(isCenter: true, maxLine: 1) - : data.getOffersList[index].titleEn!.toText12(isCenter: true, maxLine: 1), - ), - ], + 4.height, + Expanded( + child: AppState().isArabic(context) + ? data.getOffersList[index].titleAr!.toText12(isCenter: true, maxLine: 1) + : data.getOffersList[index].titleEn!.toText12(isCenter: true, maxLine: 1), + ), + ], + ), ), - ), - ); - }, - separatorBuilder: (BuildContext cxt, int index) => 8.width, - itemCount: 9), - ); - }, - ), - ], - ), + ); + }, + separatorBuilder: (BuildContext cxt, int index) => 8.width, + itemCount: 9), + ); + }, + ), + ], + ); + }), Container( width: double.infinity, padding: const EdgeInsets.only(top: 31), -- 2.30.2 From a33da491f96cb2e709abc8b15f81334a902ee93e Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Thu, 30 Jan 2025 15:14:05 +0300 Subject: [PATCH 056/135] description format section seperated in itg forms --- .../request_detail_fragment.dart | 94 ++++++++++++------- lib/widgets/item_detail_view_widget.dart | 8 +- 2 files changed, 64 insertions(+), 38 deletions(-) diff --git a/lib/ui/work_list/itg_fragments/request_detail_fragment.dart b/lib/ui/work_list/itg_fragments/request_detail_fragment.dart index 83f574f..ba67ba4 100644 --- a/lib/ui/work_list/itg_fragments/request_detail_fragment.dart +++ b/lib/ui/work_list/itg_fragments/request_detail_fragment.dart @@ -69,46 +69,70 @@ class RequestDetailFragment extends StatelessWidget { ); } - Widget detailView(List fields) { + Widget detailView(List fieldsF) { + List fields = List.from(fieldsF); + bool isOdd = false; if (fields.length % 2 != 0) { isOdd = true; fields.add(new Fields()); } - return GridView.builder( - itemCount: fields.length, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemBuilder: (context, index) { - if (fields[index].value == null) { - return ItemDetailViewGridItem( - index, - fields[index].title, - fields[index].multipleValue?.join(", ") ?? "", - isNeedToShowEmptyDivider: (fields.length == index + 1) - ? isOdd - ? true - : false - : false, - type: fields[index].type, - ); - } - return ItemDetailViewGridItem( - index, - fields[index].title, - fields[index].value ?? "", - isNeedToShowEmptyDivider: (fields.length == index + 1) - ? isOdd - ? true - : false - : false, - type: fields[index].type, - ); - }, - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, - childAspectRatio: (itemWidth / itemHeight), - ), + + int descriptionFormatIndex = fields.indexWhere((element) => element.title == "Description Format" || element.title == "Description Format"); // todo add arabic in future + Widget? descriptionFormatView; + if (descriptionFormatIndex >= 0) { + Fields descriptionFormat = fields[descriptionFormatIndex]; + fields.removeAt(descriptionFormatIndex); + + descriptionFormatView = ItemDetailViewGridItem( + 2, + descriptionFormat.title, + descriptionFormat.value == null ? (descriptionFormat.multipleValue?.join(", ") ?? "") : descriptionFormat.value ?? "", + type: descriptionFormat.type, + maxLine: 0, + ); + } + + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + GridView.builder( + itemCount: fields.length, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (context, index) { + if (fields[index].value == null) { + return ItemDetailViewGridItem( + index, + fields[index].title, + fields[index].multipleValue?.join(", ") ?? "", + isNeedToShowEmptyDivider: (fields.length == index + 1) + ? isOdd + ? true + : false + : false, + type: fields[index].type, + ); + } + return ItemDetailViewGridItem( + index, + fields[index].title, + fields[index].value ?? "", + isNeedToShowEmptyDivider: (fields.length == index + 1) + ? isOdd + ? true + : false + : false, + type: fields[index].type, + ); + }, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + childAspectRatio: (itemWidth / itemHeight), + ), + ), + if (descriptionFormatView != null) descriptionFormatView, + ], ).objectContainerView(); return ListView.separated( shrinkWrap: true, diff --git a/lib/widgets/item_detail_view_widget.dart b/lib/widgets/item_detail_view_widget.dart index f6797e8..a98b066 100644 --- a/lib/widgets/item_detail_view_widget.dart +++ b/lib/widgets/item_detail_view_widget.dart @@ -52,8 +52,9 @@ class ItemDetailViewGridItem extends StatelessWidget { final String? value; final String? type; final bool isNeedToShowEmptyDivider; + final int maxLine; - ItemDetailViewGridItem(this.index, this.title, this.value, {Key? key, this.isNeedToShowEmptyDivider = false, this.type = ""}) : super(key: key); + ItemDetailViewGridItem(this.index, this.title, this.value, {Key? key, this.isNeedToShowEmptyDivider = false, this.type = "", this.maxLine = 6}) : super(key: key); @override Widget build(BuildContext context) { @@ -76,10 +77,11 @@ class ItemDetailViewGridItem extends StatelessWidget { ), ), child: isNeedToShowEmptyDivider - ? Container() + ? SizedBox() : Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, children: [ title != null ? Flexible(child: "$title:".toText12Auto(isBold: true, color: const Color(0xff2BB8A6))) : Container(), 4.width, @@ -87,7 +89,7 @@ class ItemDetailViewGridItem extends StatelessWidget { ? type!.toLowerCase() == "table" ? getStringFromJSON(value!) // : Flexible(child: (value!.isEmpty ? "--" : value).toString().toText12Auto(color: MyColors.normalTextColor, maxLine: 5)) - : (value!.isEmpty ? "--" : value).toString().toText12Auto(color: MyColors.normalTextColor, maxLine: 6) + : (value!.isEmpty ? "--" : value).toString().toText12Auto(color: MyColors.normalTextColor, maxLine: maxLine) : Container(), ], ), -- 2.30.2 From 6e3fc55fde6d49b465e28209dbf653d72f49e4b4 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Tue, 4 Feb 2025 11:06:03 +0300 Subject: [PATCH 057/135] event activity added - cont --- lib/api/dashboard_api_client.dart | 10 + lib/classes/consts.dart | 4 +- lib/classes/date_uitl.dart | 2 +- lib/models/dashboard/event_activity.dart | 77 +++ lib/models/generic_response_model.dart | 5 + lib/provider/dashboard_provider_model.dart | 28 +- lib/ui/landing/dashboard_screen.dart | 11 + lib/ui/landing/event_activity_banner.dart | 578 +++++++++++++++++++ lib/widgets/glowy_borders/glowy_borders.dart | 150 +++++ 9 files changed, 859 insertions(+), 6 deletions(-) create mode 100644 lib/models/dashboard/event_activity.dart create mode 100644 lib/ui/landing/event_activity_banner.dart create mode 100644 lib/widgets/glowy_borders/glowy_borders.dart diff --git a/lib/api/dashboard_api_client.dart b/lib/api/dashboard_api_client.dart index bc0fece..89e7d48 100644 --- a/lib/api/dashboard_api_client.dart +++ b/lib/api/dashboard_api_client.dart @@ -105,6 +105,16 @@ class DashboardApiClient { }, url, postParams); } + Future getEventActivity() async { + String url = "${ApiConsts.erpRest}Get_EventActivity"; + Map postParams = {"P_SELECTED_RESP_ID": -999, "P_MENU_TYPE": "E"}; + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject((json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData; + }, url, postParams); + } + //Mark Attendance Future markAttendance({String lat = "0", String? long = "0", required int pointType, String nfcValue = "", bool isGpsRequired = false, String QRValue = "", String payrollCode = ""}) async { String url = "${ApiConsts.swpRest}AuthenticateAndSwipeUserSupportNFC"; diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index fea9b75..c2772b8 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -9,9 +9,9 @@ class ApiConsts { // static String baseUrl = "https://webservices.hmg.com"; // PreProd // static String baseUrl = "https://hmgwebservices.com"; // Live server - static String baseUrl = "https://mohemm.hmg.com"; // New Live server + // static String baseUrl = "https://mohemm.hmg.com"; // New Live server // - // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver + static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.20.200.111:1010/"; // static String baseUrl = "https://webservices.hmg.com"; // PreProd diff --git a/lib/classes/date_uitl.dart b/lib/classes/date_uitl.dart index e27843c..53b6525 100644 --- a/lib/classes/date_uitl.dart +++ b/lib/classes/date_uitl.dart @@ -7,7 +7,7 @@ class DateUtil { /// static DateTime convertStringToDateMarathon(String date) { - // /Date(1585774800000+0300)/ + // return DateTime(2025, 2, 5); if (date != null) { const start = "/Date("; const end = "+0300)"; diff --git a/lib/models/dashboard/event_activity.dart b/lib/models/dashboard/event_activity.dart new file mode 100644 index 0000000..e7e821c --- /dev/null +++ b/lib/models/dashboard/event_activity.dart @@ -0,0 +1,77 @@ +class EventActivityList { + EventActivityList({ + required this.id, + required this.titleEn, + required this.titleAr, + required this.shortDescEn, + required this.shortDescAr, + required this.longDescEn, + required this.longDescAr, + required this.url, + required this.startOn, + required this.endOn, + required this.channel, + required this.isActive, + required this.createdBy, + required this.createdOn, + required this.modifiedBy, + required this.modifiedOn, + }); + + final int? id; + final String? titleEn; + final String? titleAr; + final String? shortDescEn; + final String? shortDescAr; + final String? longDescEn; + final String? longDescAr; + final String? url; + final String? startOn; + final String? endOn; + final int? channel; + final bool? isActive; + final int? createdBy; + final String? createdOn; + final String? modifiedBy; + final String? modifiedOn; + + factory EventActivityList.fromJson(Map json) { + return EventActivityList( + id: json["ID"], + titleEn: json["TitleEn"], + titleAr: json["TitleAr"], + shortDescEn: json["ShortDescEn"], + shortDescAr: json["ShortDescAr"], + longDescEn: json["LongDescEn"], + longDescAr: json["LongDescAr"], + url: json["URL"], + startOn: json["StartOn"], + endOn: json["EndOn"], + channel: json["Channel"], + isActive: json["IsActive"], + createdBy: json["CreatedBy"], + createdOn: json["CreatedOn"], + modifiedBy: json["ModifiedBy"], + modifiedOn: json["ModifiedOn"], + ); + } + + Map toJson() => { + "ID": id, + "TitleEn": titleEn, + "TitleAr": titleAr, + "ShortDescEn": shortDescEn, + "ShortDescAr": shortDescAr, + "LongDescEn": longDescEn, + "LongDescAr": longDescAr, + "URL": url, + "StartOn": startOn, + "EndOn": endOn, + "Channel": channel, + "IsActive": isActive, + "CreatedBy": createdBy, + "CreatedOn": createdOn, + "ModifiedBy": modifiedBy, + "ModifiedOn": modifiedOn, + }; +} diff --git a/lib/models/generic_response_model.dart b/lib/models/generic_response_model.dart index e87c3e0..ba48836 100644 --- a/lib/models/generic_response_model.dart +++ b/lib/models/generic_response_model.dart @@ -1,6 +1,7 @@ import 'package:mohem_flutter_app/models/add_att_success_list_model.dart'; import 'package:mohem_flutter_app/models/add_attachment_list_model.dart'; import 'package:mohem_flutter_app/models/basic_member_information_model.dart'; +import 'package:mohem_flutter_app/models/dashboard/event_activity.dart'; import 'package:mohem_flutter_app/models/dashboard/get_accrual_balances_list_model.dart'; import 'package:mohem_flutter_app/models/dashboard/get_attendance_tracking_list_model.dart'; import 'package:mohem_flutter_app/models/dashboard/get_open_missing_swipes_list_model.dart'; @@ -214,6 +215,7 @@ class GenericResponseModel { List? getItemTypesList; List? getLookupValuesList; List? getMenuEntriesList; + List? getEventActivityList; List? getMoItemHistoryList; List? getMoNotificationBodyList; List? getNotificationButtonsList; @@ -487,6 +489,7 @@ class GenericResponseModel { this.getItemTypesList, this.getLookupValuesList, this.getMenuEntriesList, + this.getEventActivityList, this.getMoItemHistoryList, this.getMoNotificationBodyList, this.getNotificationButtonsList, @@ -974,6 +977,7 @@ class GenericResponseModel { getItemTypesList = json['GetItemTypesList']; getLookupValuesList = json['GetLookupValuesList']; getMenuEntriesList = json["GetMenuEntriesList"] == null ? null : List.from(json["GetMenuEntriesList"].map((x) => GetMenuEntriesList.fromJson(x))); + getEventActivityList = json["EventActivityList"] == null ? null : List.from(json["EventActivityList"].map((x) => EventActivityList.fromJson(x))); if (json['GetMoItemHistoryList'] != null) { getMoItemHistoryList = []; json['GetMoItemHistoryList'].forEach((v) { @@ -1630,6 +1634,7 @@ class GenericResponseModel { data['GetItemTypesList'] = this.getItemTypesList; data['GetLookupValuesList'] = this.getLookupValuesList; data['GetMenuEntriesList'] = this.getMenuEntriesList; + data['EventActivityList'] = this.getEventActivityList; if (this.getMoItemHistoryList != null) { data['GetMoItemHistoryList'] = this.getMoItemHistoryList!.map((v) => v.toJson()).toList(); } diff --git a/lib/provider/dashboard_provider_model.dart b/lib/provider/dashboard_provider_model.dart index e3f6511..9b57133 100644 --- a/lib/provider/dashboard_provider_model.dart +++ b/lib/provider/dashboard_provider_model.dart @@ -9,6 +9,7 @@ import 'package:mohem_flutter_app/config/routes.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; import 'package:mohem_flutter_app/main.dart'; import 'package:mohem_flutter_app/models/dashboard/drawer_menu_item_model.dart'; +import 'package:mohem_flutter_app/models/dashboard/event_activity.dart'; import 'package:mohem_flutter_app/models/dashboard/get_accrual_balances_list_model.dart'; import 'package:mohem_flutter_app/models/dashboard/get_attendance_tracking_list_model.dart'; import 'package:mohem_flutter_app/models/dashboard/get_open_notifications_list.dart'; @@ -20,7 +21,6 @@ import 'package:mohem_flutter_app/models/dashboard/mohemm_itg_pending_task_respo import 'package:mohem_flutter_app/models/generic_response_model.dart'; import 'package:mohem_flutter_app/models/itg/itg_response_model.dart'; import 'package:mohem_flutter_app/models/offers_and_discounts/get_offers_list.dart'; -import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart'; import 'package:mohem_flutter_app/widgets/dialogs/confirm_dialog.dart'; /// Mix-in [DiagnosticableTreeMixin] to have access to [debugFillProperties] for the devtool @@ -50,9 +50,12 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { //Menu Entries bool isServicesMenusLoading = true; + bool isEventLoadingLoading = true; List? homeMenus; List? getMenuEntriesList; + EventActivityList? eventActivity; + //Offers And Discounts bool isOffersLoading = true; List getOffersList = []; @@ -99,6 +102,7 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { ticketBalance = 0; isServicesMenusLoading = true; + isEventLoadingLoading = true; homeMenus = null; getMenuEntriesList = null; isOffersLoading = true; @@ -253,10 +257,28 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { notifyListeners(); } catch (ex) { // Utils.hideLoading(context); - getOffersList=[]; + getOffersList = []; isOffersLoading = false; notifyListeners(); - // Utils.handleException(ex, context, null); + // Utils.handleException(ex, context, null); + } + } + + void fetchEventActivity() async { + try { + GenericResponseModel? genericResponseModel = await DashboardApiClient().getEventActivity(); + List eventList = (genericResponseModel!.getEventActivityList ?? []); + if (eventList.isNotEmpty) { + eventActivity = eventList.first; + } + + isEventLoadingLoading = false; + notifyListeners(); + } catch (ex) { + logger.wtf(ex); + isEventLoadingLoading = false; + notifyListeners(); + Utils.handleException(ex, null, null); } } diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index 4448ad1..67e748c 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -21,6 +21,7 @@ import 'package:mohem_flutter_app/models/offers_and_discounts/get_offers_list.da import 'package:mohem_flutter_app/models/privilege_list_model.dart'; import 'package:mohem_flutter_app/provider/chat_provider_model.dart'; import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; +import 'package:mohem_flutter_app/ui/landing/event_activity_banner.dart'; import 'package:mohem_flutter_app/ui/landing/widget/app_drawer.dart'; import 'package:mohem_flutter_app/ui/landing/widget/menus_widget.dart'; import 'package:mohem_flutter_app/ui/landing/widget/services_widget.dart'; @@ -149,6 +150,7 @@ class _DashboardScreenState extends State with WidgetsBindingOb data.fetchMissingSwipe(context); data.fetchLeaveTicketBalance(context, DateTime.now()); data.fetchMenuEntries(); + data.fetchEventActivity(); data.getCategoryOffersListAPI(context); marathonProvider.getMarathonDetailsFromApi(); marathonProvider.getMarathonTutorial(); @@ -420,6 +422,7 @@ class _DashboardScreenState extends State with WidgetsBindingOb ), ], ).paddingOnly(left: 21, right: 21, top: 7, bottom: 21), + eventActivityWidget(context), Consumer(builder: (BuildContext context, DashboardProviderModel model, Widget? child) { if (!model.isOffersLoading && model.getOffersList.isEmpty) { return const SizedBox(); @@ -706,6 +709,14 @@ class _DashboardScreenState extends State with WidgetsBindingOb ); } + Widget eventActivityWidget(BuildContext context) { + return (context.watch().isEventLoadingLoading) + ? const MarathonBannerShimmer().paddingOnly(left: 21, right: 21, bottom: 21, top: 0) + : context.watch().eventActivity == null + ? const SizedBox() + : const EventActivityBanner().paddingOnly(left: 21, right: 21, bottom: 21, top: 0); + } + void navigateToDetails(OffersListModel offersListModelObj) { List getOffersDetailList = []; getOffersDetailList.clear(); diff --git a/lib/ui/landing/event_activity_banner.dart b/lib/ui/landing/event_activity_banner.dart new file mode 100644 index 0000000..83c58dd --- /dev/null +++ b/lib/ui/landing/event_activity_banner.dart @@ -0,0 +1,578 @@ +import 'dart:math' as math; + +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.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/date_uitl.dart'; +import 'package:mohem_flutter_app/classes/decorations_helper.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/main.dart'; +import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; +import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart'; +import 'package:mohem_flutter_app/ui/marathon/widgets/countdown_timer_main_screen.dart'; +import 'package:mohem_flutter_app/widgets/glowy_borders/glowy_borders.dart'; +import 'package:provider/provider.dart'; + +// It is used to pass a dummy time to test Marathon +int dummyTime = DateTime.now().millisecondsSinceEpoch + 8690; + +class EventActivityBanner extends StatelessWidget { + const EventActivityBanner({Key? key}) : super(key: key); + + // Widget getUnPrivilegedMarathon(BuildContext context) { + // return Container( + // decoration: MyDecorations.shadowDecoration, + // height: isTablet ? MediaQuery.of(context).size.height * 0.17 : MediaQuery.of(context).size.height * 0.11, + // clipBehavior: Clip.antiAlias, + // child: Stack( + // children: [ + // Transform( + // alignment: Alignment.center, + // transform: Matrix4.rotationY( + // AppState().isArabic(context) ? math.pi : 0, + // ), + // child: SvgPicture.asset( + // "assets/images/marathon_banner_bg.svg", + // fit: BoxFit.fill, + // width: double.infinity, + // ), + // ), + // AppState().isArabic(context) + // ? Positioned( + // right: -15, + // top: -10, + // child: Transform.rotate( + // angle: 10, + // child: Container( + // width: isTablet ? 70 : 65, + // height: isTablet ? 40 : 32, + // color: MyColors.darkDigitColor, + // ), + // ), + // ) + // : Positioned( + // left: -20, + // top: -10, + // child: Transform.rotate( + // angle: 15, + // child: Container( + // width: isTablet ? 70 : 65, + // height: isTablet ? 40 : 32, + // color: MyColors.darkDigitColor, + // ), + // ), + // ), + // SizedBox( + // width: double.infinity, + // height: double.infinity, + // child: Row( + // children: [ + // const Expanded( + // flex: 3, + // child: SizedBox( + // width: double.infinity, + // height: double.infinity, + // ), + // ), + // Expanded( + // flex: AppState().isArabic(context) ? 4 : 5, + // child: SizedBox( + // width: double.infinity, + // height: double.infinity, + // child: Row( + // mainAxisAlignment: MainAxisAlignment.start, + // children: [ + // Column( + // mainAxisAlignment: MainAxisAlignment.center, + // crossAxisAlignment: CrossAxisAlignment.start, + // mainAxisSize: MainAxisSize.min, + // children: [ + // AppState().isArabic(context) ? 0.height : 5.height, + // Text( + // LocaleKeys.getReadyForContest.tr(), + // style: TextStyle( + // fontSize: isTablet ? 20 : 11, + // fontStyle: FontStyle.italic, + // fontWeight: FontWeight.w600, + // color: MyColors.white.withOpacity(0.83), + // letterSpacing: -0.4, + // ), + // ), + // Text( + // LocaleKeys.brainMarathon.tr(), + // style: TextStyle( + // fontStyle: FontStyle.italic, + // fontSize: isTablet ? 30 : 19, + // fontWeight: FontWeight.bold, + // color: MyColors.white.withOpacity(0.83), + // height: 32 / 22, + // ), + // ), + // ], + // ).paddingOnly( + // left: AppState().isArabic(context) ? 12 : 3, + // right: AppState().isArabic(context) ? 3 : 12, + // ) + // ], + // ), + // ), + // ), + // ], + // ), + // ), + // AppState().isArabic(context) + // ? Align( + // alignment: Alignment.topRight, + // child: SizedBox( + // height: isTablet ? 30 : 20, + // width: isTablet ? 45 : 35, + // child: Transform.rotate( + // angle: math.pi / 4.5, + // child: Text( + // LocaleKeys.brainMarathon.tr(), + // textAlign: TextAlign.center, + // maxLines: 2, + // style: TextStyle( + // color: MyColors.white, + // fontWeight: FontWeight.bold, + // fontSize: isTablet ? 8 : 6, + // height: 1.2, + // ), + // ), + // ), + // ), + // ).paddingOnly(top: 5) + // : Align( + // alignment: Alignment.topLeft, + // child: SizedBox( + // height: isTablet ? 30 : 20, + // width: isTablet ? 45 : 35, + // child: Transform.rotate( + // angle: -math.pi / 4.5, + // child: Text( + // LocaleKeys.brainMarathon.tr(), + // textAlign: TextAlign.center, + // maxLines: 2, + // style: TextStyle( + // color: MyColors.kWhiteColor, + // fontWeight: FontWeight.bold, + // fontSize: isTablet ? 8 : 6, + // height: 1.2, + // ), + // ), + // ), + // ), + // ).paddingOnly(top: 5), + // Container( + // height: double.infinity, + // width: double.infinity, + // color: Colors.black.withOpacity(0.6), + // child: const Icon( + // Icons.lock_rounded, + // color: MyColors.lightGreyIconColor, + // ), + // ), + // ], + // ), + // ); + // } + + Widget getNoUpcomingMarathonWidget(BuildContext context) { + return Container( + decoration: MyDecorations.shadowDecoration, + height: isTablet ? MediaQuery.of(context).size.height * 0.17 : MediaQuery.of(context).size.height * 0.11, + clipBehavior: Clip.antiAlias, + child: Stack( + children: [ + Transform( + alignment: Alignment.center, + transform: Matrix4.rotationY( + AppState().isArabic(context) ? math.pi : 0, + ), + child: SvgPicture.asset( + "assets/images/marathon_banner_bg.svg", + fit: BoxFit.fill, + width: double.infinity, + ), + ), + AppState().isArabic(context) + ? Positioned( + right: -15, + top: -10, + child: Transform.rotate( + angle: 10, + child: Container( + width: isTablet ? 70 : 65, + height: isTablet ? 40 : 32, + color: MyColors.darkDigitColor, + ), + ), + ) + : Positioned( + left: -20, + top: -10, + child: Transform.rotate( + angle: 15, + child: Container( + width: isTablet ? 70 : 65, + height: isTablet ? 40 : 32, + color: MyColors.darkDigitColor, + ), + ), + ), + SizedBox( + width: double.infinity, + height: double.infinity, + child: Row( + children: [ + const Expanded( + flex: 3, + child: SizedBox( + width: double.infinity, + height: double.infinity, + ), + ), + Expanded( + flex: AppState().isArabic(context) ? 4 : 5, + child: SizedBox( + width: double.infinity, + height: double.infinity, + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + AppState().isArabic(context) ? 0.height : 5.height, + Text( + LocaleKeys.noUpcoming.tr(), + style: TextStyle( + fontSize: isTablet ? 20 : 11, + fontStyle: FontStyle.italic, + fontWeight: FontWeight.w600, + color: MyColors.white.withOpacity(0.83), + letterSpacing: -0.4, + ), + ), + Text( + LocaleKeys.brainMarathon.tr(), + style: TextStyle( + fontStyle: FontStyle.italic, + fontSize: isTablet ? 30 : 19, + fontWeight: FontWeight.bold, + color: MyColors.white.withOpacity(0.83), + height: 32 / 22, + ), + ), + Text( + LocaleKeys.youCanPlayDemo.tr(), + style: TextStyle( + fontSize: isTablet ? 20 : 11, + fontStyle: FontStyle.italic, + fontWeight: FontWeight.w600, + color: MyColors.white.withOpacity(0.83), + letterSpacing: -0.4, + ), + ), + ], + ).paddingOnly( + left: AppState().isArabic(context) ? 12 : 3, + right: AppState().isArabic(context) ? 3 : 12, + ) + ], + ), + ), + ), + ], + ), + ), + AppState().isArabic(context) + ? Align( + alignment: Alignment.topRight, + child: SizedBox( + height: isTablet ? 30 : 20, + width: isTablet ? 45 : 35, + child: Transform.rotate( + angle: math.pi / 4.5, + child: Text( + LocaleKeys.brainMarathon.tr(), + textAlign: TextAlign.center, + maxLines: 2, + style: TextStyle( + color: MyColors.white, + fontWeight: FontWeight.bold, + fontSize: isTablet ? 8 : 6, + height: 1.2, + ), + ), + ), + ), + ).paddingOnly(top: 5) + : Align( + alignment: Alignment.topLeft, + child: SizedBox( + height: isTablet ? 30 : 20, + width: isTablet ? 45 : 35, + child: Transform.rotate( + angle: -math.pi / 4.5, + child: Text( + LocaleKeys.brainMarathon.tr(), + textAlign: TextAlign.center, + maxLines: 2, + style: TextStyle( + color: MyColors.kWhiteColor, + fontWeight: FontWeight.bold, + fontSize: isTablet ? 8 : 6, + height: 1.2, + ), + ), + ), + ), + ).paddingOnly(top: 5), + ], + ), + ).onPress(() { + Navigator.pushNamed(context, AppRoutes.marathonIntroScreen); + }); + } + + @override + Widget build(BuildContext context) { + DashboardProviderModel dashboardProvider = context.read(); + + return Container( + // decoration: BoxDecoration( + // color: MyColors.kWhiteColor, + // borderRadius: BorderRadius.circular(8), + // boxShadow: [ + // BoxShadow( + // color: const Color(0xff000000).withOpacity(.05), + // blurRadius: 26, + // offset: const Offset(0, -3), + // ), + // ], + // ), + height: isTablet ? MediaQuery.of(context).size.height * 0.17 : MediaQuery.of(context).size.height * 0.11, + child: AnimatedGradientBorder( + borderSize: 3, + stretchAlongAxis: true, + animationTime: 2, + stretchAxis: Axis.vertical, + gradientColors: const [ + Color(0xff0E5A64), + Color(0xff0E5A64), + Color(0xff0E5A64), + Color(0xff91C481), + ], + borderRadius: BorderRadius.circular(10), + child: Container( + decoration: BoxDecoration( + color: const Color(0xff0E5A64), + borderRadius: BorderRadius.circular(8), + ), + // height: isTablet ? MediaQuery.of(context).size.height * 0.17 : MediaQuery.of(context).size.height * 0.11, + + child: Stack( + children: [ + // Transform( + // alignment: Alignment.center, + // transform: Matrix4.rotationY( + // AppState().isArabic(context) ? math.pi : 0, + // ), + // child: SvgPicture.asset( + // "assets/images/marathon_banner_bg.svg", + // fit: BoxFit.fill, + // width: double.infinity, + // ), + // ), + // AppState().isArabic(context) + // ? Positioned( + // right: -15, + // top: -10, + // child: Transform.rotate( + // angle: 10, + // child: Container( + // width: isTablet ? 70 : 65, + // height: isTablet ? 40 : 32, + // color: MyColors.darkDigitColor, + // ), + // ), + // ) + // : Positioned( + // left: -20, + // top: -10, + // child: Transform.rotate( + // angle: 15, + // child: Container( + // width: isTablet ? 70 : 65, + // height: isTablet ? 40 : 32, + // color: MyColors.darkDigitColor, + // ), + // ), + // ), + SizedBox( + width: double.infinity, + height: double.infinity, + child: Row( + children: [ + const Expanded( + flex: 3, + child: SizedBox( + width: double.infinity, + height: double.infinity, + ), + ), + Expanded( + flex: AppState().isArabic(context) ? 4 : 5, + child: SizedBox( + width: double.infinity, + height: double.infinity, + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + AppState().isArabic(context) ? 0.height : 5.height, + Text( + LocaleKeys.getReadyForContest.tr(), + style: TextStyle( + fontSize: isTablet ? 20 : 11, + fontStyle: FontStyle.italic, + fontWeight: FontWeight.w600, + color: MyColors.white.withOpacity(0.83), + letterSpacing: -0.4, + ), + ), + Flexible( + child: Text( + displayLocalizedContent( + isPhoneLangArabic: AppState().isArabic(context), + selectedLanguage: 3, + englishContent: dashboardProvider.eventActivity?.titleEn ?? "", + arabicContent: dashboardProvider.eventActivity?.titleAr ?? "", + ), + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontStyle: FontStyle.italic, + fontSize: isTablet ? 30 : 19, + fontWeight: FontWeight.bold, + color: MyColors.white.withOpacity(0.83), + height: 32 / 22, + ), + ), + ), + isTablet ? 10.height : 3.height, + CountdownTimerForMainScreen( + timeToMarathon: DateUtil.convertStringToDateMarathon(dashboardProvider.eventActivity!.startOn!).millisecondsSinceEpoch, + provider: context.read(), + ), + ], + ).paddingOnly( + left: AppState().isArabic(context) ? 12 : 3, + right: AppState().isArabic(context) ? 3 : 12, + ) + ], + ), + ), + ), + ], + ), + ), + // AppState().isArabic(context) + // ? Align( + // alignment: Alignment.topRight, + // child: SizedBox( + // height: isTablet ? 30 : 20, + // width: isTablet ? 45 : 35, + // child: Transform.rotate( + // angle: math.pi / 4.5, + // child: Text( + // LocaleKeys.brainMarathon.tr(), + // textAlign: TextAlign.center, + // maxLines: 2, + // style: TextStyle( + // color: MyColors.white, + // fontWeight: FontWeight.bold, + // fontSize: isTablet ? 8 : 6, + // height: 1.2, + // ), + // ), + // ), + // ), + // ).paddingOnly(top: 5) + // : Align( + // alignment: Alignment.topLeft, + // child: SizedBox( + // height: isTablet ? 30 : 20, + // width: isTablet ? 45 : 35, + // child: Transform.rotate( + // angle: -math.pi / 4.5, + // child: Text( + // LocaleKeys.brainMarathon.tr(), + // textAlign: TextAlign.center, + // maxLines: 2, + // style: TextStyle( + // color: MyColors.kWhiteColor, + // fontWeight: FontWeight.bold, + // fontSize: isTablet ? 8 : 6, + // height: 1.2, + // ), + // ), + // ), + // ), + // ).paddingOnly(top: 5), + !AppState().isArabic(context) + ? Positioned( + right: 0, + bottom: 0, + child: RotatedBox( + quarterTurns: 4, + child: SvgPicture.asset("assets/images/arrow_next.svg", color: MyColors.whiteColor), + ).paddingAll(isTablet ? 20 : 15), + ) + : Positioned( + bottom: 0, + left: 0, + child: RotatedBox( + quarterTurns: 2, + child: SvgPicture.asset("assets/images/arrow_next.svg", color: MyColors.whiteColor), + ).paddingAll(isTablet ? 20 : 15), + ), + ], + ).onPress(() async { + // int remainingTimeInMinutes = DateTime.parse(dashboardProvider.eventActivity!.startOn!).difference(DateTime.now()).inMinutes; + // if (remainingTimeInMinutes > 5 && dashboardProvider.eventActivity.sponsors != null && provider.marathonDetailModel.sponsors!.isNotEmpty) { + // Utils.showLoading(context); + // try { + // await provider.initializeVideoPlayer().then((_) { + // Utils.hideLoading(context); + // provider.startTimerForSponsorVideo(); + // Navigator.pushNamed(context, AppRoutes.marathonSponsorVideoScreen); + // }); + // } catch (e) { + // if (kDebugMode) { + // log("Error in VideoPlayer: ${e.toString()}"); + // } + // Utils.hideLoading(context); + // Navigator.pushNamed(context, AppRoutes.marathonIntroScreen); + // } + // } else { + // Navigator.pushNamed(context, AppRoutes.marathonIntroScreen); + // } + // provider.updateLanguageAsPerMarathon(context, provider.isUpComingMarathon ? provider.marathonDetailModel : provider.demoMarathonDetailModel); + })), + ), + ); + } +} diff --git a/lib/widgets/glowy_borders/glowy_borders.dart b/lib/widgets/glowy_borders/glowy_borders.dart new file mode 100644 index 0000000..ffdc31b --- /dev/null +++ b/lib/widgets/glowy_borders/glowy_borders.dart @@ -0,0 +1,150 @@ +library glowy_borderspertino.dart; + +import 'dart:math' as math; + +import 'package:flutter/cupertino.dart'; +import 'package:mohem_flutter_app/classes/colors.dart'; + +class AnimatedGradientBorder extends StatefulWidget { + const AnimatedGradientBorder( + {Key? key, + required this.child, + required this.gradientColors, + required this.borderRadius, + this.animationTime, + this.borderSize, + this.animationProgress, + this.stretchAlongAxis = false, + this.stretchAxis = Axis.horizontal}); + + final Widget child; + final double? borderSize; + final List gradientColors; + final BorderRadiusGeometry borderRadius; + final int? animationTime; + final double? animationProgress; + final bool stretchAlongAxis; + final Axis stretchAxis; + + @override + State createState() => AnimatedGradientState(); +} + +class AnimatedGradientState extends State with SingleTickerProviderStateMixin { + late AnimationController _controller; + late Animation _angleAnimation; + + @override + void initState() { + super.initState(); + _controller = AnimationController(vsync: this, duration: Duration(seconds: widget.animationTime ?? 2)); + _controller.addListener(() => setState(() {})); + _angleAnimation = Tween(begin: 0.1, end: 2 * math.pi).animate(_controller); + if (widget.animationProgress != null) { + _controller.forward(); + } else { + _controller.repeat(); + } + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + void didUpdateWidget(covariant AnimatedGradientBorder oldWidget) { + super.didUpdateWidget(oldWidget); + double? animateTo = widget.animationProgress; + if (animateTo != null) { + _controller.animateTo(animateTo); + } else { + _controller.repeat(); + } + } + + @override + Widget build(BuildContext context) { + double? negativeMargin = -1.0 * (widget.borderSize ?? 0); + return Container( + padding: EdgeInsets.all(widget.borderSize ?? 0), + clipBehavior: Clip.hardEdge, + decoration: BoxDecoration( + color: MyColors.kWhiteColor, + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: const Color(0xff000000).withOpacity(.05), + blurRadius: 26, + offset: const Offset(0, -3), + ), + ], + ), + child: Stack(alignment: Alignment.center, clipBehavior: Clip.none, children: [ + Positioned( + top: negativeMargin, + left: negativeMargin, + right: negativeMargin, + bottom: negativeMargin, + child: AnimatedGradientContainer( + gradientColors: widget.gradientColors, + borderRadius: widget.borderRadius, + gradientAngle: _angleAnimation.value, + )), + widget.child, + // BackdropFilter( + // filter: ImageFilter.blur(sigmaX: widget.glowSize ?? 0, sigmaY: widget.glowSize ?? 0), + // child: Stack( + // alignment: Alignment.center, + // clipBehavior: Clip.none, + // children: [ + // Positioned( + // top: negativeMargin, + // right: negativeMargin, + // left: negativeMargin, + // bottom: negativeMargin, + // child: AnimatedGradientContainer( + // gradientColors: widget.gradientColors, + // borderRadius: widget.borderRadius, + // gradientAngle: _angleAnimation.value, + // )), + // if (widget.stretchAlongAxis) + // SizedBox( + // width: widget.stretchAxis == Axis.horizontal ? double.infinity : null, + // height: widget.stretchAxis == Axis.vertical ? double.infinity : null, + // child: widget.child, + // ) + // else + // widget.child, + // ], + // ), + // ), + ]), + ); + } +} + +class AnimatedGradientContainer extends StatelessWidget { + const AnimatedGradientContainer({Key? key, required this.gradientColors, required this.gradientAngle, required this.borderRadius}); + + final List gradientColors; + final double gradientAngle; + final BorderRadiusGeometry borderRadius; + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + borderRadius: borderRadius, + gradient: SweepGradient( + colors: [...gradientColors, ...gradientColors.reversed], stops: _generateColorStops([...gradientColors, ...gradientColors.reversed]), transform: GradientRotation(gradientAngle)))); + } + + List _generateColorStops(List colors) { + return colors.asMap().entries.map((entry) { + double percentageStop = entry.key / colors.length; + return percentageStop; + }).toList(); + } +} -- 2.30.2 From 75ba1283d3066aa14b1ae28d333021e8f13e4089 Mon Sep 17 00:00:00 2001 From: sultan khan Date: Wed, 5 Feb 2025 10:39:03 +0300 Subject: [PATCH 058/135] event activity page added. --- assets/langs/ar-SA.json | 4 +- assets/langs/en-US.json | 4 +- lib/config/routes.dart | 4 + lib/generated/codegen_loader.g.dart | 8 +- lib/generated/locale_keys.g.dart | 3 +- lib/models/dashboard/event_activity.dart | 11 +- lib/ui/landing/dashboard_screen.dart | 6 +- lib/ui/landing/event_activity_banner.dart | 340 ++++-------------- .../widgets/countdown_timer_main_screen.dart | 18 +- .../event_activity/activity_event_card.dart | 112 ++++++ .../event_activity/activity_footer.dart | 39 ++ .../event_activity/event_activity.dart | 49 +++ 12 files changed, 303 insertions(+), 295 deletions(-) create mode 100644 lib/ui/screens/event_activity/activity_event_card.dart create mode 100644 lib/ui/screens/event_activity/activity_footer.dart create mode 100644 lib/ui/screens/event_activity/event_activity.dart diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 1eb7dde..c4c5f20 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -613,5 +613,7 @@ "manageGroup": "إدارة المجموعة", "members": "الأعضاء", "searchByUserName": "البحث بواسطة اسم المستخدم", - "shareScreen": "مشاركة الشاشة" + "shareScreen": "مشاركة الشاشة", + "start":"يبدأ", + "about":"عن" } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 03ae4d6..559b9c9 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -611,5 +611,7 @@ "qtyOrdered": "Qty. Ordered", "qtyReceived": "Qty. Received", "bonusQty": "Bonus Qty.", - "balQty": "Bal. Qty." + "balQty": "Bal. Qty.", + "start":"Start", + "about":"About" } \ No newline at end of file diff --git a/lib/config/routes.dart b/lib/config/routes.dart index 6afc095..4653880 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -56,6 +56,7 @@ import 'package:mohem_flutter_app/ui/screens/announcements/announcements.dart'; import 'package:mohem_flutter_app/ui/screens/child_education/child_education_assistance.dart'; // import 'package:mohem_flutter_app/ui/my_attendance/work_from_home_screen.dart'; import 'package:mohem_flutter_app/ui/screens/eit/add_eit.dart'; +import 'package:mohem_flutter_app/ui/screens/event_activity/event_activity.dart'; import 'package:mohem_flutter_app/ui/screens/items_for_sale/add_new_item_for_sale.dart'; import 'package:mohem_flutter_app/ui/screens/items_for_sale/item_for_sale_detail.dart'; import 'package:mohem_flutter_app/ui/screens/items_for_sale/items_for_sale_home.dart'; @@ -208,6 +209,8 @@ class AppRoutes { static const String appUpdateScreen = "/appUpdateScreen"; static const String childEducation = "/childEducation"; + static const String activityScreen = "/activityScreen"; + static final Map routes = { login: (BuildContext context) => LoginScreen(), verifyLogin: (BuildContext context) => VerifyLoginScreen(), @@ -325,5 +328,6 @@ class AppRoutes { unsafeDeviceScreen: (BuildContext context) => const UnsafeDeviceScreen(), appUpdateScreen: (BuildContext context) => const AppUpdateScreen(), childEducation: (BuildContext context) => ChildEducationAssistance(), + activityScreen:(BuildContext context) => const EventActivityScreen() }; } diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index 36d809d..0e2cfbf 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -626,7 +626,9 @@ class CodegenLoader extends AssetLoader{ "manageGroup": "إدارة المجموعة", "members": "الأعضاء", "searchByUserName": "البحث بواسطة اسم المستخدم", - "shareScreen": "مشاركة الشاشة" + "shareScreen": "مشاركة الشاشة", + "start":"يبدأ", + "about":"عن" }; static const Map en_US = { "mohemm": "Mohemm", @@ -1240,7 +1242,9 @@ static const Map en_US = { "qtyOrdered": "Qty. Ordered", "qtyReceived": "Qty. Received", "bonusQty": "Bonus Qty.", - "balQty": "Bal. Qty." + "balQty": "Bal. Qty.", + "start":"Start", + "about":"About" }; static const Map> mapLocales = {"ar_SA": ar_SA, "en_US": en_US}; } diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 851a5cd..f8bc858 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -597,5 +597,6 @@ abstract class LocaleKeys { static const members = 'members'; static const searchByUserName = 'searchByUserName'; static const shareScreen = 'shareScreen'; - + static const start = 'start'; + static const about ='about'; } diff --git a/lib/models/dashboard/event_activity.dart b/lib/models/dashboard/event_activity.dart index e7e821c..4b523d7 100644 --- a/lib/models/dashboard/event_activity.dart +++ b/lib/models/dashboard/event_activity.dart @@ -1,4 +1,4 @@ -class EventActivityList { + class EventActivityList { EventActivityList({ required this.id, required this.titleEn, @@ -16,6 +16,8 @@ class EventActivityList { required this.createdOn, required this.modifiedBy, required this.modifiedOn, + required this.shortImageURL, + required this.detailImageURL }); final int? id; @@ -34,7 +36,8 @@ class EventActivityList { final String? createdOn; final String? modifiedBy; final String? modifiedOn; - + final String? shortImageURL; + final String? detailImageURL; factory EventActivityList.fromJson(Map json) { return EventActivityList( id: json["ID"], @@ -53,6 +56,8 @@ class EventActivityList { createdOn: json["CreatedOn"], modifiedBy: json["ModifiedBy"], modifiedOn: json["ModifiedOn"], + shortImageURL: json["ShortImageURL"], + detailImageURL: json["DetailImageURL"] ); } @@ -73,5 +78,7 @@ class EventActivityList { "CreatedOn": createdOn, "ModifiedBy": modifiedBy, "ModifiedOn": modifiedOn, + "DetailImageURL": detailImageURL, + "ShortImageURL" : shortImageURL }; } diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index 67e748c..4640c25 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -712,9 +712,9 @@ class _DashboardScreenState extends State with WidgetsBindingOb Widget eventActivityWidget(BuildContext context) { return (context.watch().isEventLoadingLoading) ? const MarathonBannerShimmer().paddingOnly(left: 21, right: 21, bottom: 21, top: 0) - : context.watch().eventActivity == null - ? const SizedBox() - : const EventActivityBanner().paddingOnly(left: 21, right: 21, bottom: 21, top: 0); + : (context.watch().eventActivity != null && context.watch().eventActivity!.isActive ==true) + ? const EventActivityBanner().paddingOnly(left: 21, right: 21, bottom: 21, top: 0) + : const SizedBox(); } void navigateToDetails(OffersListModel offersListModelObj) { diff --git a/lib/ui/landing/event_activity_banner.dart b/lib/ui/landing/event_activity_banner.dart index 83c58dd..47c8158 100644 --- a/lib/ui/landing/event_activity_banner.dart +++ b/lib/ui/landing/event_activity_banner.dart @@ -19,170 +19,11 @@ import 'package:mohem_flutter_app/ui/marathon/widgets/countdown_timer_main_scree import 'package:mohem_flutter_app/widgets/glowy_borders/glowy_borders.dart'; import 'package:provider/provider.dart'; -// It is used to pass a dummy time to test Marathon int dummyTime = DateTime.now().millisecondsSinceEpoch + 8690; class EventActivityBanner extends StatelessWidget { const EventActivityBanner({Key? key}) : super(key: key); - // Widget getUnPrivilegedMarathon(BuildContext context) { - // return Container( - // decoration: MyDecorations.shadowDecoration, - // height: isTablet ? MediaQuery.of(context).size.height * 0.17 : MediaQuery.of(context).size.height * 0.11, - // clipBehavior: Clip.antiAlias, - // child: Stack( - // children: [ - // Transform( - // alignment: Alignment.center, - // transform: Matrix4.rotationY( - // AppState().isArabic(context) ? math.pi : 0, - // ), - // child: SvgPicture.asset( - // "assets/images/marathon_banner_bg.svg", - // fit: BoxFit.fill, - // width: double.infinity, - // ), - // ), - // AppState().isArabic(context) - // ? Positioned( - // right: -15, - // top: -10, - // child: Transform.rotate( - // angle: 10, - // child: Container( - // width: isTablet ? 70 : 65, - // height: isTablet ? 40 : 32, - // color: MyColors.darkDigitColor, - // ), - // ), - // ) - // : Positioned( - // left: -20, - // top: -10, - // child: Transform.rotate( - // angle: 15, - // child: Container( - // width: isTablet ? 70 : 65, - // height: isTablet ? 40 : 32, - // color: MyColors.darkDigitColor, - // ), - // ), - // ), - // SizedBox( - // width: double.infinity, - // height: double.infinity, - // child: Row( - // children: [ - // const Expanded( - // flex: 3, - // child: SizedBox( - // width: double.infinity, - // height: double.infinity, - // ), - // ), - // Expanded( - // flex: AppState().isArabic(context) ? 4 : 5, - // child: SizedBox( - // width: double.infinity, - // height: double.infinity, - // child: Row( - // mainAxisAlignment: MainAxisAlignment.start, - // children: [ - // Column( - // mainAxisAlignment: MainAxisAlignment.center, - // crossAxisAlignment: CrossAxisAlignment.start, - // mainAxisSize: MainAxisSize.min, - // children: [ - // AppState().isArabic(context) ? 0.height : 5.height, - // Text( - // LocaleKeys.getReadyForContest.tr(), - // style: TextStyle( - // fontSize: isTablet ? 20 : 11, - // fontStyle: FontStyle.italic, - // fontWeight: FontWeight.w600, - // color: MyColors.white.withOpacity(0.83), - // letterSpacing: -0.4, - // ), - // ), - // Text( - // LocaleKeys.brainMarathon.tr(), - // style: TextStyle( - // fontStyle: FontStyle.italic, - // fontSize: isTablet ? 30 : 19, - // fontWeight: FontWeight.bold, - // color: MyColors.white.withOpacity(0.83), - // height: 32 / 22, - // ), - // ), - // ], - // ).paddingOnly( - // left: AppState().isArabic(context) ? 12 : 3, - // right: AppState().isArabic(context) ? 3 : 12, - // ) - // ], - // ), - // ), - // ), - // ], - // ), - // ), - // AppState().isArabic(context) - // ? Align( - // alignment: Alignment.topRight, - // child: SizedBox( - // height: isTablet ? 30 : 20, - // width: isTablet ? 45 : 35, - // child: Transform.rotate( - // angle: math.pi / 4.5, - // child: Text( - // LocaleKeys.brainMarathon.tr(), - // textAlign: TextAlign.center, - // maxLines: 2, - // style: TextStyle( - // color: MyColors.white, - // fontWeight: FontWeight.bold, - // fontSize: isTablet ? 8 : 6, - // height: 1.2, - // ), - // ), - // ), - // ), - // ).paddingOnly(top: 5) - // : Align( - // alignment: Alignment.topLeft, - // child: SizedBox( - // height: isTablet ? 30 : 20, - // width: isTablet ? 45 : 35, - // child: Transform.rotate( - // angle: -math.pi / 4.5, - // child: Text( - // LocaleKeys.brainMarathon.tr(), - // textAlign: TextAlign.center, - // maxLines: 2, - // style: TextStyle( - // color: MyColors.kWhiteColor, - // fontWeight: FontWeight.bold, - // fontSize: isTablet ? 8 : 6, - // height: 1.2, - // ), - // ), - // ), - // ), - // ).paddingOnly(top: 5), - // Container( - // height: double.infinity, - // width: double.infinity, - // color: Colors.black.withOpacity(0.6), - // child: const Icon( - // Icons.lock_rounded, - // color: MyColors.lightGreyIconColor, - // ), - // ), - // ], - // ), - // ); - // } - Widget getNoUpcomingMarathonWidget(BuildContext context) { return Container( decoration: MyDecorations.shadowDecoration, @@ -348,7 +189,7 @@ class EventActivityBanner extends StatelessWidget { Widget build(BuildContext context) { DashboardProviderModel dashboardProvider = context.read(); - return Container( + return SizedBox( // decoration: BoxDecoration( // color: MyColors.kWhiteColor, // borderRadius: BorderRadius.circular(8), @@ -384,52 +225,46 @@ class EventActivityBanner extends StatelessWidget { children: [ // Transform( // alignment: Alignment.center, - // transform: Matrix4.rotationY( - // AppState().isArabic(context) ? math.pi : 0, - // ), - // child: SvgPicture.asset( - // "assets/images/marathon_banner_bg.svg", - // fit: BoxFit.fill, - // width: double.infinity, - // ), - // ), - // AppState().isArabic(context) - // ? Positioned( - // right: -15, - // top: -10, - // child: Transform.rotate( - // angle: 10, - // child: Container( - // width: isTablet ? 70 : 65, - // height: isTablet ? 40 : 32, - // color: MyColors.darkDigitColor, - // ), - // ), - // ) - // : Positioned( - // left: -20, - // top: -10, - // child: Transform.rotate( - // angle: 15, - // child: Container( - // width: isTablet ? 70 : 65, - // height: isTablet ? 40 : 32, - // color: MyColors.darkDigitColor, - // ), - // ), - // ), + // // transform: Matrix4.rotationY( + // // AppState().isArabic(context) ? math.pi : 0, + // // ), + // child: + // + + AppState().isArabic(context) + ? Positioned( + left: -15, + top: -10, + child: Transform.rotate( + angle: 10, + child: SizedBox( + child: SvgPicture.asset( + "assets/images/light_bulb.svg"), + ), + ), + ) + : Positioned( + right: 0, + top: 10, + child: Opacity( + opacity: .5, + child: SvgPicture.asset( + "assets/images/light_bulb.svg", + ), + )), + SizedBox( width: double.infinity, height: double.infinity, child: Row( children: [ - const Expanded( - flex: 3, - child: SizedBox( - width: double.infinity, - height: double.infinity, - ), - ), + Expanded( + flex: 3, + child: Image.network( + dashboardProvider.eventActivity?.shortImageURL ?? + "", + fit: BoxFit.cover, + )), Expanded( flex: AppState().isArabic(context) ? 4 : 5, child: SizedBox( @@ -444,16 +279,7 @@ class EventActivityBanner extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ AppState().isArabic(context) ? 0.height : 5.height, - Text( - LocaleKeys.getReadyForContest.tr(), - style: TextStyle( - fontSize: isTablet ? 20 : 11, - fontStyle: FontStyle.italic, - fontWeight: FontWeight.w600, - color: MyColors.white.withOpacity(0.83), - letterSpacing: -0.4, - ), - ), + Flexible( child: Text( displayLocalizedContent( @@ -465,17 +291,33 @@ class EventActivityBanner extends StatelessWidget { overflow: TextOverflow.ellipsis, style: TextStyle( fontStyle: FontStyle.italic, - fontSize: isTablet ? 30 : 19, + fontSize: isTablet ? 25 : 16, fontWeight: FontWeight.bold, - color: MyColors.white.withOpacity(0.83), - height: 32 / 22, + color: MyColors.white, + height: 32 / 24, ), ), + ), Text( + displayLocalizedContent( + isPhoneLangArabic: AppState().isArabic(context), + selectedLanguage: 3, + englishContent: dashboardProvider.eventActivity?.shortDescEn ?? "", + arabicContent: dashboardProvider.eventActivity?.shortDescAr ?? "", + ), + style: TextStyle( + fontSize: isTablet ? 20 : 11, + fontStyle: FontStyle.italic, + fontWeight: FontWeight.w600, + color: MyColors.white, + letterSpacing: -0.5, + ), ), - isTablet ? 10.height : 3.height, + + isTablet ? 15.height : 10.height, CountdownTimerForMainScreen( timeToMarathon: DateUtil.convertStringToDateMarathon(dashboardProvider.eventActivity!.startOn!).millisecondsSinceEpoch, provider: context.read(), + isEvent: true, ), ], ).paddingOnly( @@ -489,49 +331,7 @@ class EventActivityBanner extends StatelessWidget { ], ), ), - // AppState().isArabic(context) - // ? Align( - // alignment: Alignment.topRight, - // child: SizedBox( - // height: isTablet ? 30 : 20, - // width: isTablet ? 45 : 35, - // child: Transform.rotate( - // angle: math.pi / 4.5, - // child: Text( - // LocaleKeys.brainMarathon.tr(), - // textAlign: TextAlign.center, - // maxLines: 2, - // style: TextStyle( - // color: MyColors.white, - // fontWeight: FontWeight.bold, - // fontSize: isTablet ? 8 : 6, - // height: 1.2, - // ), - // ), - // ), - // ), - // ).paddingOnly(top: 5) - // : Align( - // alignment: Alignment.topLeft, - // child: SizedBox( - // height: isTablet ? 30 : 20, - // width: isTablet ? 45 : 35, - // child: Transform.rotate( - // angle: -math.pi / 4.5, - // child: Text( - // LocaleKeys.brainMarathon.tr(), - // textAlign: TextAlign.center, - // maxLines: 2, - // style: TextStyle( - // color: MyColors.kWhiteColor, - // fontWeight: FontWeight.bold, - // fontSize: isTablet ? 8 : 6, - // height: 1.2, - // ), - // ), - // ), - // ), - // ).paddingOnly(top: 5), + !AppState().isArabic(context) ? Positioned( right: 0, @@ -551,25 +351,11 @@ class EventActivityBanner extends StatelessWidget { ), ], ).onPress(() async { - // int remainingTimeInMinutes = DateTime.parse(dashboardProvider.eventActivity!.startOn!).difference(DateTime.now()).inMinutes; - // if (remainingTimeInMinutes > 5 && dashboardProvider.eventActivity.sponsors != null && provider.marathonDetailModel.sponsors!.isNotEmpty) { - // Utils.showLoading(context); - // try { - // await provider.initializeVideoPlayer().then((_) { - // Utils.hideLoading(context); - // provider.startTimerForSponsorVideo(); - // Navigator.pushNamed(context, AppRoutes.marathonSponsorVideoScreen); - // }); - // } catch (e) { - // if (kDebugMode) { - // log("Error in VideoPlayer: ${e.toString()}"); - // } - // Utils.hideLoading(context); - // Navigator.pushNamed(context, AppRoutes.marathonIntroScreen); - // } - // } else { - // Navigator.pushNamed(context, AppRoutes.marathonIntroScreen); - // } + int remainingTimeInMinutes = DateUtil.convertStringToDateMarathon(dashboardProvider.eventActivity!.startOn!).difference(DateTime.now()).inMinutes; + if (remainingTimeInMinutes < 0) { + Navigator.pushNamed(context, AppRoutes.activityScreen); + + } // provider.updateLanguageAsPerMarathon(context, provider.isUpComingMarathon ? provider.marathonDetailModel : provider.demoMarathonDetailModel); })), ), diff --git a/lib/ui/marathon/widgets/countdown_timer_main_screen.dart b/lib/ui/marathon/widgets/countdown_timer_main_screen.dart index ef828da..e9818c2 100644 --- a/lib/ui/marathon/widgets/countdown_timer_main_screen.dart +++ b/lib/ui/marathon/widgets/countdown_timer_main_screen.dart @@ -13,19 +13,15 @@ import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart'; class CountdownTimerForMainScreen extends StatelessWidget { final int timeToMarathon; final MarathonProvider provider; - + final bool isEvent; CountdownTimerForMainScreen({ Key? key, required this.provider, required this.timeToMarathon, + this.isEvent =false, }) : super(key: key); - final TextStyle styleTextHome = TextStyle( - color: MyColors.white.withOpacity(0.45), - fontStyle: FontStyle.italic, - fontWeight: FontWeight.w800, - letterSpacing: -0.4, - ); + final TextStyle styleDigitHome = TextStyle( height: 22 / 27, @@ -75,7 +71,13 @@ class CountdownTimerForMainScreen extends StatelessWidget { text, minFontSize: 7, maxFontSize: 8, - style: styleTextHome, + style: TextStyle( + color: isEvent ? MyColors.white : MyColors.white.withOpacity(0.45), + fontStyle: FontStyle.italic, + fontWeight: FontWeight.w800, + letterSpacing: -0.4, + ), + ); } diff --git a/lib/ui/screens/event_activity/activity_event_card.dart b/lib/ui/screens/event_activity/activity_event_card.dart new file mode 100644 index 0000000..5c02971 --- /dev/null +++ b/lib/ui/screens/event_activity/activity_event_card.dart @@ -0,0 +1,112 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.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/consts.dart'; +import 'package:mohem_flutter_app/classes/decorations_helper.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/main.dart'; +import 'package:mohem_flutter_app/models/marathon/marathon_model.dart'; +import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; +import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart'; +import 'package:provider/provider.dart'; +import 'package:shimmer/shimmer.dart'; + +class ActivityEventDetailsCard extends StatelessWidget { + final DashboardProviderModel model; + + const ActivityEventDetailsCard({Key? key, required this.model}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + width: double.infinity, + decoration: MyDecorations.shadowDecoration, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + CachedNetworkImage( + imageUrl: model.eventActivity!.detailImageURL!, + placeholder: (BuildContext context, String url) => const LinearProgressIndicator( + value: 0.7, + minHeight: 200, + valueColor: AlwaysStoppedAnimation(Colors.white), + backgroundColor: Color(0xff196D73), + ).toShimmer(), + fit: BoxFit.cover,width: double.infinity , + ), + + ], + ), + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 20,), + Text( + displayLocalizedContent( + isPhoneLangArabic: AppState().isArabic(context), + selectedLanguage: 3, + englishContent: model.eventActivity?.titleEn ?? "", + arabicContent: model.eventActivity?.titleAr ?? "", + ), + style: TextStyle( + fontStyle: FontStyle.italic, + fontSize: isTablet ? 30 : 20, + fontWeight: FontWeight.bold, + color:const Color(0xff3C3838), + // height: 42 / 30, + ), + + ).paddingOnly(left: 10, right: 10, bottom: 2), + + Row(children:[ + SvgPicture.asset("assets/images/highlight.svg"), + Text( + displayLocalizedContent( + isPhoneLangArabic: AppState().isArabic(context), + selectedLanguage: 3, + englishContent: model.eventActivity?.shortDescEn ?? "", + arabicContent: model.eventActivity?.shortDescAr ?? "", + ), + style: TextStyle( + fontStyle: FontStyle.italic, + fontSize: isTablet ? 20 : 14, + fontWeight: FontWeight.bold, + color:const Color(0xff2BB8A8), + // height: 32 / 24, + ), + + ).paddingOnly(left: 10, right: 10) + ]).paddingOnly(bottom: 25), + + LocaleKeys.about.tr().toText16(color: const Color(0xff3C3838)).paddingOnly(bottom: 5), + Text( + displayLocalizedContent( + isPhoneLangArabic: AppState().isArabic(context), + selectedLanguage: 3, + englishContent: model.eventActivity?.longDescEn ?? "", + arabicContent: model.eventActivity?.longDescAr ?? "", + ), + style: TextStyle( + fontStyle: FontStyle.italic, + fontSize: isTablet ? 18 : 12, + fontWeight: FontWeight.bold, + color:const Color(0xff3C3838), + // height: 32 / 24, + ), + + ).paddingOnly(bottom: 10) + ], + ) + ]); + } +} diff --git a/lib/ui/screens/event_activity/activity_footer.dart b/lib/ui/screens/event_activity/activity_footer.dart new file mode 100644 index 0000000..a5fcd81 --- /dev/null +++ b/lib/ui/screens/event_activity/activity_footer.dart @@ -0,0 +1,39 @@ +// ignore_for_file: always_specify_types + +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:mohem_flutter_app/app_state/app_state.dart'; +import 'package:mohem_flutter_app/classes/colors.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/main.dart'; +import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; +import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart'; +import 'package:mohem_flutter_app/widgets/button/default_button.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class ActivityEventFooter extends StatelessWidget { + final DashboardProviderModel provider; + + const ActivityEventFooter({ + Key? key, + required this.provider, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Column(children: [ + DefaultButton( + LocaleKeys.start.tr(), + () => launchUrl(Uri.parse(provider.eventActivity!.url!)), + color: MyColors.greenColor, + ).insideContainer, + + ]); + + } + + +} diff --git a/lib/ui/screens/event_activity/event_activity.dart b/lib/ui/screens/event_activity/event_activity.dart new file mode 100644 index 0000000..f523eb6 --- /dev/null +++ b/lib/ui/screens/event_activity/event_activity.dart @@ -0,0 +1,49 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:mohem_flutter_app/extensions/int_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/provider/dashboard_provider_model.dart'; +import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart'; +import 'package:mohem_flutter_app/ui/marathon/widgets/marathon_details_card.dart'; +import 'package:mohem_flutter_app/ui/marathon/widgets/marathon_footer.dart'; +import 'package:mohem_flutter_app/ui/marathon/widgets/marathon_timer_card.dart'; +import 'package:mohem_flutter_app/ui/screens/event_activity/activity_event_card.dart'; +import 'package:mohem_flutter_app/ui/screens/event_activity/activity_footer.dart'; +import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; +import 'package:provider/provider.dart'; + +class EventActivityScreen extends StatelessWidget { + const EventActivityScreen({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + DashboardProviderModel provider = context.read(); + return Scaffold( + appBar: AppBarWidget( + context, + title: LocaleKeys.details.tr(), + onHomeTapped: () { + Navigator.pop(context); + + }, + onBackTapped: () { + Navigator.pop(context); + }, + ), + body: Column( + children: [ + ListView( + padding: const EdgeInsets.all(21), + children: [ + ActivityEventDetailsCard(model: provider), + 20.height, + ], + ).expanded, + 1.divider, + ActivityEventFooter(provider: provider), + ], + ), + ); + } +} -- 2.30.2 From 822a99a2918ae5b573080f305272c04843023bc7 Mon Sep 17 00:00:00 2001 From: sultan khan Date: Wed, 5 Feb 2025 17:38:14 +0300 Subject: [PATCH 059/135] countdown updated. --- lib/ui/landing/event_activity_banner.dart | 6 +- .../event_activity/activity_footer.dart | 63 +++++++++++++++++-- 2 files changed, 62 insertions(+), 7 deletions(-) diff --git a/lib/ui/landing/event_activity_banner.dart b/lib/ui/landing/event_activity_banner.dart index 47c8158..2e9315f 100644 --- a/lib/ui/landing/event_activity_banner.dart +++ b/lib/ui/landing/event_activity_banner.dart @@ -351,11 +351,11 @@ class EventActivityBanner extends StatelessWidget { ), ], ).onPress(() async { - int remainingTimeInMinutes = DateUtil.convertStringToDateMarathon(dashboardProvider.eventActivity!.startOn!).difference(DateTime.now()).inMinutes; - if (remainingTimeInMinutes < 0) { + // int remainingTimeInMinutes = DateUtil.convertStringToDateMarathon(dashboardProvider.eventActivity!.startOn!).difference(DateTime.now()).inMinutes; + // if (remainingTimeInMinutes < 0) { Navigator.pushNamed(context, AppRoutes.activityScreen); - } + //} // provider.updateLanguageAsPerMarathon(context, provider.isUpComingMarathon ? provider.marathonDetailModel : provider.demoMarathonDetailModel); })), ), diff --git a/lib/ui/screens/event_activity/activity_footer.dart b/lib/ui/screens/event_activity/activity_footer.dart index a5fcd81..8db2175 100644 --- a/lib/ui/screens/event_activity/activity_footer.dart +++ b/lib/ui/screens/event_activity/activity_footer.dart @@ -2,8 +2,10 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_countdown_timer/flutter_countdown_timer.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/date_uitl.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'; @@ -11,7 +13,9 @@ import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; import 'package:mohem_flutter_app/main.dart'; import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart'; +import 'package:mohem_flutter_app/ui/marathon/widgets/countdown_timer_main_screen.dart'; import 'package:mohem_flutter_app/widgets/button/default_button.dart'; +import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher.dart'; class ActivityEventFooter extends StatelessWidget { @@ -24,12 +28,63 @@ class ActivityEventFooter extends StatelessWidget { @override Widget build(BuildContext context) { + + int remainingTime = DateTime.now().millisecondsSinceEpoch + DateUtil.convertStringToDateMarathon(provider.eventActivity!.startOn!).difference(DateTime.now()).inMilliseconds; + return Column(children: [ - DefaultButton( + CountdownTimer( + endTime: remainingTime, + widgetBuilder: (context, time) { + if (time == null) { + return DefaultButton( + LocaleKeys.start.tr(), + () => launchUrl(Uri.parse(provider.eventActivity!.url!)), + color: MyColors.greenColor, + ).insideContainer; + } + return Container( + height: 58, + padding: const EdgeInsets.only( + top: 15, bottom: 15, right: 30, left: 30), + margin: const EdgeInsets.only(top: 5, bottom: 5), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(6.0), + gradient: + const LinearGradient( + transform: GradientRotation(.83), + begin: Alignment.topRight, + end: Alignment.bottomLeft, + colors: [ + MyColors.gradiantEndColor, + MyColors.gradiantStartColor + ], + ), + ), + child: CountdownTimerForMainScreen( + timeToMarathon: DateUtil + .convertStringToDateMarathon(provider.eventActivity!.startOn!) + .millisecondsSinceEpoch, + provider: context.read(), + isEvent: true, + )); + + }, + onEnd: (){ + + }, + endWidget: DefaultButton( LocaleKeys.start.tr(), - () => launchUrl(Uri.parse(provider.eventActivity!.url!)), - color: MyColors.greenColor, - ).insideContainer, + () => launchUrl(Uri.parse(provider.eventActivity!.url!)), + color: MyColors.greenColor, + ).insideContainer, + + ) + // if (remainingTimeInMinutes < 0) + // + // else + // + // + // , ]); -- 2.30.2 From 29334a9ef01dbde505ca7f04b3e4cd0f8969acff Mon Sep 17 00:00:00 2001 From: sultan khan Date: Thu, 6 Feb 2025 10:38:15 +0300 Subject: [PATCH 060/135] leave balance page fix. --- lib/ui/leave_balance/leave_balance_screen.dart | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/ui/leave_balance/leave_balance_screen.dart b/lib/ui/leave_balance/leave_balance_screen.dart index 447767f..85354f9 100644 --- a/lib/ui/leave_balance/leave_balance_screen.dart +++ b/lib/ui/leave_balance/leave_balance_screen.dart @@ -64,7 +64,7 @@ class _LeaveBalanceState extends State { context, title: LocaleKeys.leaveBalance.tr(), ), - body: Column( + body:SingleChildScrollView(child:Column( children: [ Padding( padding: const EdgeInsets.all(21.0), @@ -76,8 +76,10 @@ class _LeaveBalanceState extends State { : (absenceTransList!.isEmpty ? Utils.getNoDataWidget(context).paddingOnly(top: 50) : ListView( - physics: const BouncingScrollPhysics(), + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), padding: const EdgeInsets.all(21), + children: [ // BalancesDashboardWidget(LocaleKeys.currentLeaveBalance.tr(), true, selectedEmp: employeeId, showLoading: false), // 12.height, @@ -113,7 +115,7 @@ class _LeaveBalanceState extends State { ], )), ], - ), + )), floatingActionButton: Container( height: 54, width: 54, -- 2.30.2 From 6e15336cc48b8f0fcc3c391e8b51afb322ad6cc4 Mon Sep 17 00:00:00 2001 From: sultan khan Date: Thu, 6 Feb 2025 11:22:30 +0300 Subject: [PATCH 061/135] image changes. --- lib/ui/landing/event_activity_banner.dart | 5 ++++- lib/ui/screens/event_activity/activity_event_card.dart | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/ui/landing/event_activity_banner.dart b/lib/ui/landing/event_activity_banner.dart index 2e9315f..511b0fe 100644 --- a/lib/ui/landing/event_activity_banner.dart +++ b/lib/ui/landing/event_activity_banner.dart @@ -25,6 +25,7 @@ class EventActivityBanner extends StatelessWidget { const EventActivityBanner({Key? key}) : super(key: key); Widget getNoUpcomingMarathonWidget(BuildContext context) { + ; return Container( decoration: MyDecorations.shadowDecoration, height: isTablet ? MediaQuery.of(context).size.height * 0.17 : MediaQuery.of(context).size.height * 0.11, @@ -258,13 +259,15 @@ class EventActivityBanner extends StatelessWidget { height: double.infinity, child: Row( children: [ + Expanded( flex: 3, child: Image.network( dashboardProvider.eventActivity?.shortImageURL ?? "", fit: BoxFit.cover, - )), + key: UniqueKey() + ).paddingAll(5)), Expanded( flex: AppState().isArabic(context) ? 4 : 5, child: SizedBox( diff --git a/lib/ui/screens/event_activity/activity_event_card.dart b/lib/ui/screens/event_activity/activity_event_card.dart index 5c02971..56450b5 100644 --- a/lib/ui/screens/event_activity/activity_event_card.dart +++ b/lib/ui/screens/event_activity/activity_event_card.dart @@ -35,13 +35,16 @@ class ActivityEventDetailsCard extends StatelessWidget { children: [ CachedNetworkImage( imageUrl: model.eventActivity!.detailImageURL!, + height: 200, placeholder: (BuildContext context, String url) => const LinearProgressIndicator( value: 0.7, minHeight: 200, + valueColor: AlwaysStoppedAnimation(Colors.white), backgroundColor: Color(0xff196D73), ).toShimmer(), - fit: BoxFit.cover,width: double.infinity , + fit: BoxFit.contain,width: double.infinity , + cacheKey: UniqueKey().toString(), ), ], -- 2.30.2 From 5adc2bc64fe5b1a0c2202bc3b363fb2ab22a79fd Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Thu, 6 Feb 2025 11:23:58 +0300 Subject: [PATCH 062/135] updates --- lib/app_state/app_state.dart | 2 +- lib/ui/login/login_screen.dart | 8 ++++---- lib/ui/unsafe_device_screen.dart | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/app_state/app_state.dart b/lib/app_state/app_state.dart index aea9251..7269cd5 100644 --- a/lib/app_state/app_state.dart +++ b/lib/app_state/app_state.dart @@ -90,7 +90,7 @@ class AppState { String get getHuaweiPushToken => _huaweiPushToken; - final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 8.3, mobileType: Platform.isAndroid ? "android" : "ios"); + final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 8.6, mobileType: Platform.isAndroid ? "android" : "ios"); void setPostParamsInitConfig() { diff --git a/lib/ui/login/login_screen.dart b/lib/ui/login/login_screen.dart index 2aa2da3..13d8853 100644 --- a/lib/ui/login/login_screen.dart +++ b/lib/ui/login/login_screen.dart @@ -88,9 +88,9 @@ class _LoginScreenState extends State { if (Platform.isAndroid) { // isOnExternalStorage = await SafeDevice.isOnExternalStorage; - SafeDevice.isDevelopmentModeEnable.then((value) { - isDevelopmentModeEnable = value; - }); + // SafeDevice.isDevelopmentModeEnable.then((value) { + // isDevelopmentModeEnable = value; + // }); } } catch (error) { print(error); @@ -127,7 +127,7 @@ class _LoginScreenState extends State { } AppNotifications().init(firebaseToken, context); - if (isJailBroken || !isRealDevice || isDevelopmentModeEnable) { + if (isJailBroken || !isRealDevice) { Utils.hideLoading(context); Navigator.pushNamedAndRemoveUntil(context, AppRoutes.unsafeDeviceScreen, (_) => false); } else { diff --git a/lib/ui/unsafe_device_screen.dart b/lib/ui/unsafe_device_screen.dart index c8e1243..dcfe820 100644 --- a/lib/ui/unsafe_device_screen.dart +++ b/lib/ui/unsafe_device_screen.dart @@ -37,10 +37,10 @@ class _UnsafeDeviceScreenState extends State { .paddingOnly(left: 20.0, right: 20.0), 48.height, passwordConstraintsUI("The device is not jailbroken or rooted.", true).paddingOnly(left: 24.0, right: 5.0), - 8.height, - passwordConstraintsUI("The app is not installed on external storage.", true).paddingOnly(left: 24.0, right: 5.0), - 8.height, - passwordConstraintsUI("Development mode is disabled.", true).paddingOnly(left: 24.0, right: 5.0), + // 8.height, + // passwordConstraintsUI("The app is not installed on external storage.", true).paddingOnly(left: 24.0, right: 5.0), + // 8.height, + // passwordConstraintsUI("Development mode is disabled.", true).paddingOnly(left: 24.0, right: 5.0), 21.height, DefaultButton(LocaleKeys.ok.tr(), () async { if (Platform.isAndroid) { -- 2.30.2 From 92a16381aa38f854d699a3efe0c67ae8065aed50 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Thu, 6 Feb 2025 12:13:01 +0300 Subject: [PATCH 063/135] Update to stores VersionID 8.6 --- lib/classes/consts.dart | 4 ++-- pubspec.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index c2772b8..fea9b75 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -9,9 +9,9 @@ class ApiConsts { // static String baseUrl = "https://webservices.hmg.com"; // PreProd // static String baseUrl = "https://hmgwebservices.com"; // Live server - // static String baseUrl = "https://mohemm.hmg.com"; // New Live server + static String baseUrl = "https://mohemm.hmg.com"; // New Live server // - static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver + // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.20.200.111:1010/"; // static String baseUrl = "https://webservices.hmg.com"; // PreProd diff --git a/pubspec.yaml b/pubspec.yaml index 9740e7d..e23c069 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html #version: 3.3.01+300040 -version: 3.7.98+3 +version: 3.7.992+1 environment: sdk: ">=2.16.0 <3.0.0" -- 2.30.2 From 5db63e571a5bb696e333d0761c05a681f64b0108 Mon Sep 17 00:00:00 2001 From: "taha.alam" Date: Sun, 9 Feb 2025 15:13:53 +0300 Subject: [PATCH 064/135] WD: flutter upgraded to 3.27.4 --- assets/images/biometrics.svg | 33 ++++++++ lib/classes/notifications.dart | 2 +- lib/dialogs/otp_dialog.dart | 4 +- lib/theme/app_theme.dart | 75 +++++++++++++++---- .../attendance/monthly_attendance_screen.dart | 4 +- lib/ui/chat/chat_home_screen.dart | 2 + lib/ui/login/verify_last_login_screen.dart | 17 +++-- lib/ui/login/verify_login_screen.dart | 38 +++++++++- lib/ui/my_team/view_attendance.dart | 4 +- lib/ui/profile/delete_family_member.dart | 4 +- .../offers_and_discounts_details.dart | 2 +- lib/ui/work_list/item_history_screen.dart | 8 +- lib/widgets/app_bar_widget.dart | 2 + lib/widgets/image_picker.dart | 2 +- lib/widgets/nfc/nfc_reader_sheet.dart | 9 ++- pubspec.yaml | 22 +++--- 16 files changed, 175 insertions(+), 53 deletions(-) create mode 100644 assets/images/biometrics.svg diff --git a/assets/images/biometrics.svg b/assets/images/biometrics.svg new file mode 100644 index 0000000..5d61575 --- /dev/null +++ b/assets/images/biometrics.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/classes/notifications.dart b/lib/classes/notifications.dart index 8f432d7..00b732e 100644 --- a/lib/classes/notifications.dart +++ b/lib/classes/notifications.dart @@ -35,7 +35,7 @@ class AppNotifications { await flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation()?.requestPermissions(alert: true, badge: true, sound: true); } else if (Platform.isAndroid) { AndroidFlutterLocalNotificationsPlugin? androidImplementation = flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation(); - bool? granted = await androidImplementation?.requestPermission(); + bool? granted = await androidImplementation?.requestNotificationsPermission(); if (granted == false) { if (kDebugMode) { print("-------------------- Permission Granted ------------------------"); diff --git a/lib/dialogs/otp_dialog.dart b/lib/dialogs/otp_dialog.dart index 9f7c82e..7265d97 100644 --- a/lib/dialogs/otp_dialog.dart +++ b/lib/dialogs/otp_dialog.dart @@ -202,11 +202,11 @@ class OtpDialog { ), errorBorder: OutlineInputBorder( borderRadius: const BorderRadius.all(Radius.circular(10.0)), - borderSide: BorderSide(color: Theme.of(context).errorColor), + borderSide: BorderSide(color: Theme.of(context).colorScheme.error), ), focusedErrorBorder: OutlineInputBorder( borderRadius: const BorderRadius.all(Radius.circular(10.0)), - borderSide: BorderSide(color: Theme.of(context).errorColor), + borderSide: BorderSide(color: Theme.of(context).colorScheme.error), ), ); } diff --git a/lib/theme/app_theme.dart b/lib/theme/app_theme.dart index 586c3aa..b1a5570 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'; @@ -15,36 +16,84 @@ class AppTheme { }, ), hintColor: Colors.grey[400], - colorScheme: ColorScheme.fromSwatch(accentColor: MyColors.backgroundColor), + colorScheme: ColorScheme.fromSwatch( + accentColor: MyColors.backgroundColor, + errorColor: const Color.fromRGBO(235, 80, 60, 1.0), + ), disabledColor: Colors.grey[300], - errorColor: const Color.fromRGBO(235, 80, 60, 1.0), scaffoldBackgroundColor: MyColors.backgroundColor, textSelectionTheme: const TextSelectionThemeData(cursorColor: Colors.grey, selectionColor: Color.fromRGBO(80, 100, 253, 0.5), selectionHandleColor: Colors.grey), canvasColor: Colors.white, - backgroundColor: const Color.fromRGBO(255, 255, 255, 1), highlightColor: Colors.grey[100]!.withOpacity(0.4), splashColor: Colors.transparent, primaryColor: primaryColor, primaryColorDark: primaryColor, - buttonColor: Colors.black, - toggleableActiveColor: secondaryColor, + buttonTheme: ButtonThemeData( + buttonColor: Colors.black, + ), + switchTheme: SwitchThemeData( + thumbColor: MaterialStateProperty.resolveWith( + (Set states) { + if (states.contains(MaterialState.disabled)) { + return null; + } + if (states.contains(MaterialState.selected)) { + return secondaryColor; + } + return null; + }), + trackColor: MaterialStateProperty.resolveWith( + (Set states) { + if (states.contains(MaterialState.disabled)) { + return null; + } + if (states.contains(MaterialState.selected)) { + return secondaryColor; + } + return null; + }), + ), + radioTheme: RadioThemeData( + fillColor: MaterialStateProperty.resolveWith( + (Set states) { + if (states.contains(MaterialState.disabled)) { + return null; + } + if (states.contains(MaterialState.selected)) { + return secondaryColor; + } + return null; + }), + ), + checkboxTheme: CheckboxThemeData( + fillColor: MaterialStateProperty.resolveWith( + (Set states) { + if (states.contains(MaterialState.disabled)) { + return null; + } + if (states.contains(MaterialState.selected)) { + return secondaryColor; + } + return null; + }), + ), indicatorColor: secondaryColor, bottomSheetTheme: const BottomSheetThemeData( backgroundColor: Color(0xFFE0E0E0), ), - primaryTextTheme: const TextTheme( - bodyText2: TextStyle(color: Colors.white), - ), iconTheme: const IconThemeData(color: MyColors.darkIconColor), textTheme: const TextTheme( - bodyText1: TextStyle(color: Colors.black, letterSpacing: 0.6), - headline1: TextStyle(color: Colors.white, letterSpacing: 0.6), - headline2: TextStyle(color: Colors.white, letterSpacing: 0.6), + bodyMedium: TextStyle(color: Colors.black, letterSpacing: 0.6), + headlineSmall: TextStyle(color: Colors.white, letterSpacing: 0.6), + headlineMedium: TextStyle(color: Colors.white, letterSpacing: 0.6), ), floatingActionButtonTheme: const FloatingActionButtonThemeData(highlightElevation: 2, disabledElevation: 0, elevation: 2), - appBarTheme: AppBarTheme( + + appBarTheme: AppBarTheme( + systemOverlayStyle: const SystemUiOverlayStyle( + statusBarBrightness: Brightness.light, + ), color: const Color(0xff515A5D), - brightness: 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 65f101b..cb1e784 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,6 @@ class _MonthlyAttendanceScreenState extends State { initialDate: formattedDate, firstDate: DateTime(searchYear - 2), lastDate: DateTime.now(), - confirmText: Text(LocaleKeys.confirm.tr()), - cancelText: Text(LocaleKeys.cancel.tr()), ).then((selectedDate) { if (selectedDate != null) { searchMonth = getMonth(selectedDate.month); diff --git a/lib/ui/chat/chat_home_screen.dart b/lib/ui/chat/chat_home_screen.dart index 04d7c2e..2f392f3 100644 --- a/lib/ui/chat/chat_home_screen.dart +++ b/lib/ui/chat/chat_home_screen.dart @@ -214,6 +214,8 @@ class _ChatHomeScreenState extends State { }, ), floatingActionButton: FloatingActionButton( + backgroundColor: Colors.transparent, + elevation: 0, child: Container( width: 60, height: 60, diff --git a/lib/ui/login/verify_last_login_screen.dart b/lib/ui/login/verify_last_login_screen.dart index 8604baf..9970206 100644 --- a/lib/ui/login/verify_last_login_screen.dart +++ b/lib/ui/login/verify_last_login_screen.dart @@ -4,8 +4,9 @@ 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:local_auth_android/local_auth_android.dart'; +import 'package:local_auth_darwin/local_auth_darwin.dart'; import 'package:mohem_flutter_app/api/login_api_client.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; @@ -69,7 +70,7 @@ class _VerifyLastLoginScreenState extends State { automaticallyImplyLeading: false, title: (mobileLoginInfoListModel?.businessCardPrivilege ?? false) ? LocaleKeys.viewBusinessCard.tr().toText12(color: MyColors.textMixColor, isUnderLine: true).onPress(() { - showMDialog(context, child: BusinessCardDialog()); + showMDialog(context, child: const BusinessCardDialog()); }) : Container(), actions: [ @@ -93,7 +94,7 @@ class _VerifyLastLoginScreenState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ LocaleKeys.welcomeBack.tr().toText12(), - mobileLoginInfoListModel!.employeeName!.toText24(isBold: true), + mobileLoginInfoListModel?.employeeName?.toText24(isBold: true) ?? const SizedBox.shrink(), 10.height, LocaleKeys.wouldYouLikeToLoginWithCurrentUsername.tr().toText16(), Container( @@ -126,7 +127,7 @@ class _VerifyLastLoginScreenState extends State { children: [ LocaleKeys.verificationType.tr().toText10(color: MyColors.grey57Color), getVerificationType(mobileLoginInfoListModel!.loginType!).toText12(), - Expanded(child: SizedBox()), + const Expanded(child: SizedBox()), DateUtil.formatDateToTime(DateUtil.convertStringToDate(mobileLoginInfoListModel!.editedOn!)).toText12(), ], ) @@ -225,7 +226,10 @@ class _VerifyLastLoginScreenState 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', + options: const AuthenticationOptions( + useErrorDialogs: true, stickyAuth: true, biometricOnly: true, + ),authMessages: [iosStrings,const AndroidAuthMessages(),]); } on PlatformException catch (e) { print(e); Utils.hideLoading(context); @@ -235,7 +239,8 @@ class _VerifyLastLoginScreenState extends State { } Widget _loginOptionButton(String _title, String _icon, int _flag, int? _loginIndex) { - bool isDisable = ((_flag == 3 && !checkBiometricIsAvailable(BiometricType.face)) || (_flag == 4 && !checkBiometricIsAvailable(BiometricType.fingerprint))); + bool isDisable = (_flag == 3 && !checkBiometricIsAvailable(BiometricType.face) || + _flag == 4 && !checkBiometricIsAvailable(BiometricType.fingerprint) && _flag == 4 && !checkBiometricIsAvailable(BiometricType.strong)); return InkWell( onTap: isDisable ? null diff --git a/lib/ui/login/verify_login_screen.dart b/lib/ui/login/verify_login_screen.dart index ac3c454..ea8439e 100644 --- a/lib/ui/login/verify_login_screen.dart +++ b/lib/ui/login/verify_login_screen.dart @@ -4,8 +4,9 @@ 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:local_auth_darwin/local_auth_darwin.dart'; +import 'package:local_auth_android/local_auth_android.dart'; import 'package:mohem_flutter_app/api/login_api_client.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; @@ -90,6 +91,7 @@ class _VerifyLoginScreenState extends State { Future _getAvailableBiometrics() async { try { _availableBioMetricType = await auth.getAvailableBiometrics(); + print("the available biometric are ${_availableBioMetricType.length}"); } on PlatformException catch (e) { // AppToast.showErrorToast(message: e.message); print(e); @@ -516,7 +518,14 @@ 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', + options: const AuthenticationOptions( + useErrorDialogs: true, + stickyAuth: true, + biometricOnly: true, + ), + authMessages: [iosStrings, const AndroidAuthMessages()]); } on PlatformException catch (e) { print(e); Utils.hideLoading(context); @@ -526,7 +535,25 @@ class _VerifyLoginScreenState extends State { } Widget _loginOptionButton(String _title, String _icon, int _flag, int? _loginIndex) { - bool isDisable = ((_flag == 3 && !checkBiometricIsAvailable(BiometricType.face)) || (_flag == 4 && !checkBiometricIsAvailable(BiometricType.fingerprint))); + bool isDisable = (_flag == 3 && !checkBiometricIsAvailable(BiometricType.face) || + _flag == 4 && !checkBiometricIsAvailable(BiometricType.fingerprint) && _flag == 4 && !checkBiometricIsAvailable(BiometricType.strong)); + // bool isDisable = false; + // switch (_flag) { + // case 3: + // isDisable = !(checkBiometricIsAvailable(BiometricType.face) || + // checkBiometricIsAvailable(BiometricType.weak)); + // break; + // case 4: + // isDisable = !(checkBiometricIsAvailable(BiometricType.fingerprint) || + // checkBiometricIsAvailable(BiometricType.strong)); + // break; + // } + // // bool isDisable = ((_flag == 3 && + // // (!checkBiometricIsAvailable(BiometricType.face) || + // // !checkBiometricIsAvailable(BiometricType.weak))) || + // // (_flag == 4 && + // // (!checkBiometricIsAvailable(BiometricType.fingerprint) || + // // !checkBiometricIsAvailable(BiometricType.strong)))); return InkWell( onTap: isDisable ? null @@ -596,8 +623,13 @@ class _VerifyLoginScreenState extends State { bool checkBiometricIsAvailable(BiometricType biometricType) { bool isAvailable = false; + print("the given biometric is $biometricType"); + for (int i = 0; i < _availableBioMetricType.length; i++) { + print("the current biometric is ${_availableBioMetricType[i]}"); + if (biometricType == _availableBioMetricType[i]) { + print("the data is available $biometricType"); isAvailable = true; break; } diff --git a/lib/ui/my_team/view_attendance.dart b/lib/ui/my_team/view_attendance.dart index a45f35c..96e673d 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,6 @@ class _ViewAttendanceState extends State { initialDate: formattedDate, firstDate: DateTime(searchYear - 2), lastDate: DateTime.now(), - confirmText: Text(LocaleKeys.confirm.tr()), - cancelText: Text(LocaleKeys.cancel.tr()), ).then( (selectedDate) { if (selectedDate != null) { diff --git a/lib/ui/profile/delete_family_member.dart b/lib/ui/profile/delete_family_member.dart index 3b73512..f478b53 100644 --- a/lib/ui/profile/delete_family_member.dart +++ b/lib/ui/profile/delete_family_member.dart @@ -115,8 +115,8 @@ class _DeleteFamilyMemberState extends State { padding: EdgeInsets.only(left: 50, right: 50), child: TextButton( style: TextButton.styleFrom( - primary: MyColors.white, - onSurface: MyColors.white, + foregroundColor: MyColors.white, + surfaceTintColor: MyColors.white, backgroundColor: MyColors.gradiantEndColor, ), onPressed: () { diff --git a/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart b/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart index b4cb242..30a9fa2 100644 --- a/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart +++ b/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart @@ -76,7 +76,7 @@ class _OffersAndDiscountsDetailsState extends State { : getOffersList[0].titleEn!.toText22(isBold: true, color: const Color(0xff2B353E)).center, Html( data: AppState().isArabic(context) ? getOffersList[0].descriptionAr! : getOffersList[0].descriptionEn ?? "", - onLinkTap: (String? url, RenderContext context, Map attributes, _) { + onLinkTap: (String? url, Map attributes, _) { launchUrl(Uri.parse(url!)); }, ), diff --git a/lib/ui/work_list/item_history_screen.dart b/lib/ui/work_list/item_history_screen.dart index 71cea08..92516e8 100644 --- a/lib/ui/work_list/item_history_screen.dart +++ b/lib/ui/work_list/item_history_screen.dart @@ -188,7 +188,7 @@ class _ItemHistoryScreenState extends State { LineChartData drawLineChart(List spots, List reversedList) { return LineChartData( - lineTouchData: LineTouchData(enabled: true, touchTooltipData: LineTouchTooltipData(tooltipBgColor: Colors.grey[300])), + lineTouchData: LineTouchData(enabled: true, touchTooltipData: LineTouchTooltipData()), gridData: FlGridData( show: true, drawHorizontalLine: true, @@ -211,7 +211,7 @@ class _ItemHistoryScreenState extends State { interval: 1, getTitlesWidget: (double value, TitleMeta meta) { return SideTitleWidget( - axisSide: meta.axisSide, + meta: meta, child: Text(reversedList[int.parse(meta.formattedValue)].cREATIONDATE!, style: TextStyle(fontSize: 10)), ); })), @@ -222,7 +222,7 @@ class _ItemHistoryScreenState extends State { interval: 1, getTitlesWidget: (double value, TitleMeta meta) { return SideTitleWidget( - axisSide: meta.axisSide, + meta: meta, child: Text(meta.formattedValue, style: TextStyle(fontSize: 10)), ); })), @@ -233,7 +233,7 @@ class _ItemHistoryScreenState extends State { reservedSize: 15, getTitlesWidget: (double value, TitleMeta meta) { return SideTitleWidget( - axisSide: meta.axisSide, + meta: meta, child: Text("", style: TextStyle(fontSize: 10)), ); })), diff --git a/lib/widgets/app_bar_widget.dart b/lib/widgets/app_bar_widget.dart index 6f9898e..744b7eb 100644 --- a/lib/widgets/app_bar_widget.dart +++ b/lib/widgets/app_bar_widget.dart @@ -15,6 +15,8 @@ AppBar AppBarWidget(BuildContext context, void Function()? onBackTapped}) { return AppBar( leadingWidth: 0, + + automaticallyImplyLeading: false, title: Row( children: [ GestureDetector( diff --git a/lib/widgets/image_picker.dart b/lib/widgets/image_picker.dart index 943d68e..f808d6e 100644 --- a/lib/widgets/image_picker.dart +++ b/lib/widgets/image_picker.dart @@ -159,7 +159,7 @@ class _BottomSheet extends StatelessWidget { Widget build(BuildContext context) { return Container( padding: const EdgeInsets.symmetric(vertical: 12.0), - decoration: BoxDecoration(color: Theme.of(context).backgroundColor, borderRadius: const BorderRadius.only(topLeft: Radius.circular(16.0), topRight: Radius.circular(16.0))), + decoration: BoxDecoration(color: Theme.of(context).scaffoldBackgroundColor, borderRadius: const BorderRadius.only(topLeft: Radius.circular(16.0), topRight: Radius.circular(16.0))), child: SafeArea( top: false, child: Column( diff --git a/lib/widgets/nfc/nfc_reader_sheet.dart b/lib/widgets/nfc/nfc_reader_sheet.dart index b7b97a7..0ecc5e8 100644 --- a/lib/widgets/nfc/nfc_reader_sheet.dart +++ b/lib/widgets/nfc/nfc_reader_sheet.dart @@ -78,9 +78,11 @@ class _NfcLayoutState extends State { } Widget scanNfc() { - return Container( - key: ValueKey(1), + return SizedBox( + width: MediaQuery.sizeOf(context).width, child: Column( + key: ValueKey(1), + mainAxisSize: MainAxisSize.min, children: [ SizedBox( @@ -138,8 +140,9 @@ class _NfcLayoutState extends State { Widget doneNfc() { return Container( - key: ValueKey(2), + width: MediaQuery.sizeOf(context).width, child: Column( + key: ValueKey(2), mainAxisSize: MainAxisSize.min, children: [ SizedBox( diff --git a/pubspec.yaml b/pubspec.yaml index 9740e7d..08a6251 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -20,7 +20,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 3.7.98+3 environment: - sdk: ">=2.16.0 <3.0.0" + sdk: ">=2.16.0 <3.7.0" # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions @@ -40,13 +40,13 @@ dependencies: injector: ^2.0.0 provider: ^6.0.1 easy_localization: ^3.0.0 - http: ^0.13.4 + http: ^1.3.0 permission_handler: ^10.2.0 flutter_svg: any sizer: ^2.0.15 - local_auth: ^1.1.9 + local_auth: ^2.3.0 fluttertoast: ^8.0.8 - syncfusion_flutter_calendar: ^19.4.48 + syncfusion_flutter_calendar: ^28.2.4 # flutter_calendar_carousel: ^2.1.0 pie_chart: ^5.1.0 shared_preferences: ^2.0.12 @@ -60,12 +60,12 @@ dependencies: # android_id: ^0.1.3+1 platform_device_id: ^1.0.1 image_picker: ^0.8.5+3 - file_picker: 5.2.5 + file_picker: ^8.3.1 geolocator: ^9.0.2 - month_year_picker: ^0.2.0+1 - month_picker_dialog_2: ^0.5.5 + month_year_picker: ^0.4.0+1 + month_picker_dialog: ^6.0.3 # open_file: ^3.2.1 - open_filex: ^4.4.0 + open_filex: ^4.6.0 wifi_iot: ^0.3.19+1 flutter_html: ^3.0.0-alpha.6 # flutter_barcode_scanner: ^2.0.0 @@ -76,7 +76,7 @@ dependencies: flutter_rating_bar: ^4.0.1 auto_size_text: ^3.0.0 pull_to_refresh: ^2.0.0 - fl_chart: ^0.62.0 + fl_chart: ^0.70.2 # lottie json animations lottie: any # Marathon Card Swipe @@ -93,7 +93,7 @@ dependencies: swipe_to: ^1.0.2 flutter_webrtc: ^0.9.17 camera: ^0.10.3 - flutter_local_notifications: ^10.0.0 + flutter_local_notifications: ^18.0.1 #firebase_analytics: any #Chat Voice Message Recoding & Play @@ -116,7 +116,7 @@ dependencies: firebase_crashlytics: ^2.9.0 #Items for sale Image Carousel Slider - carousel_slider: ^4.2.1 + carousel_slider: ^5.0.0 #Huawei Specified # store_checker: ^1.1.0 -- 2.30.2 From 7c3f6a508f7acc3619801db200a281bc68964154 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Tue, 25 Feb 2025 10:41:52 +0300 Subject: [PATCH 065/135] updates & fixes --- lib/classes/date_uitl.dart | 8 ++-- .../approval_level_fragment.dart | 39 ++++++++++++++++--- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/lib/classes/date_uitl.dart b/lib/classes/date_uitl.dart index 53b6525..8714b40 100644 --- a/lib/classes/date_uitl.dart +++ b/lib/classes/date_uitl.dart @@ -38,12 +38,12 @@ class DateUtil { return DateTime.now(); } - static DateTime convertSimpleStringDateToDate(String date) { + static DateTime convertSimpleStringDateToDate(String date, {bool isITG = false}) { // print(date.toUpperCase()); - return getDateTimeFromString(date.split(" ")[0], date.toUpperCase().split(" ")[1] + " " + date.toUpperCase().split(" ")[2]); + return getDateTimeFromString(date.split(" ")[0], date.toUpperCase().split(" ")[1] + " " + date.toUpperCase().split(" ")[2], isITG: isITG); } - static DateTime getDateTimeFromString(String date, String time) { + static DateTime getDateTimeFromString(String date, String time, {bool isITG = false}) { var hours = num.parse(time.split(":")[0]); var mins = time.split(":")[1]; var secs = time.split(":")[2].split(" ")[0]; @@ -60,7 +60,7 @@ class DateUtil { } } date = date + " $hours:$mins:$secs"; - DateTime returnDate = DateFormat("MM/dd/yyyy HH:mm:ss", "en_US").parse(date); + DateTime returnDate = isITG ? DateFormat("dd/MM/yyyy HH:mm:ss", "en_US").parse(date) : DateFormat("MM/dd/yyyy HH:mm:ss", "en_US").parse(date); return returnDate; } diff --git a/lib/ui/work_list/itg_fragments/approval_level_fragment.dart b/lib/ui/work_list/itg_fragments/approval_level_fragment.dart index 09e44d4..e617511 100644 --- a/lib/ui/work_list/itg_fragments/approval_level_fragment.dart +++ b/lib/ui/work_list/itg_fragments/approval_level_fragment.dart @@ -2,6 +2,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.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/date_uitl.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'; @@ -28,7 +29,7 @@ class ApprovalLevelfragment extends StatelessWidget { itemCount: wFHistory.length, padding: const EdgeInsets.all(21), itemBuilder: (context, index) { - return showItem(context, wFHistory[index]); + return showItem(context, wFHistory[index], index); }, separatorBuilder: (BuildContext context, int index) { return 12.height; @@ -37,7 +38,7 @@ class ApprovalLevelfragment extends StatelessWidget { ); } - Widget showItem(BuildContext context, WFHistory history) { + Widget showItem(BuildContext context, WFHistory history, int index) { return Container( width: double.infinity, decoration: BoxDecoration( @@ -89,7 +90,9 @@ class ApprovalLevelfragment extends StatelessWidget { 8.width, if (history.date!.isNotEmpty) history.date!.toText12(color: MyColors.lightTextColor), ], - ) + ), + 10.height, + getActionDuration(index).toText11(maxLine: 1, color: const Color(0xff1FA269)) ], ), ) @@ -143,8 +146,34 @@ class ApprovalLevelfragment extends StatelessWidget { ); } + String getActionDuration(int index) { + if (wFHistory[index].action!.toLowerCase() == "submit" || wFHistory[index].action!.toLowerCase() == "submitted") { + return ""; + // DateTime dateTimeFrom = DateUtil.convertSimpleStringDateToDate(wFHistory[index].date!); + // Duration duration = DateTime.now().difference(dateTimeFrom); + // return "Action duration: " + DateUtil.formatDuration(duration); + } + else if (wFHistory[index].employeeID == AppState().memberInformationList?.eMPLOYEENUMBER) { + // if (wFHistory[index + 1].date!.isEmpty) { + // return ""; + // } + DateTime dateTimeFrom = DateUtil.convertSimpleStringDateToDate(wFHistory[index + 1].date!, isITG: true); + Duration duration = DateTime.now().difference(dateTimeFrom); + return "Action duration: " + DateUtil.formatDuration(duration); + } else { + if (wFHistory[index].date!.isEmpty || wFHistory[index].action!.toLowerCase() == "NO ACTION") { + return ""; + } else { + DateTime dateTimeTo = DateUtil.convertSimpleStringDateToDate(wFHistory[index].date!); + DateTime dateTimeFrom = DateUtil.convertSimpleStringDateToDate(wFHistory[index + 1].date!); + Duration duration = dateTimeTo.difference(dateTimeFrom); + return "Action duration: " + DateUtil.formatDuration(duration); + } + } + } + Color getStatusColor(String code) { - if (code.toLowerCase() == "submit") { + if (code.toLowerCase() == "submit" || code.toLowerCase() == "submitted") { return MyColors.grey3AColor; } else if (code.toLowerCase() == "pending") { return MyColors.yellowColor; @@ -152,7 +181,7 @@ class ApprovalLevelfragment extends StatelessWidget { return MyColors.redColor; } else if (code.toLowerCase() == "approved" || code.toLowerCase() == "auto-approve" || code.toLowerCase() == "auto-approved" || code.toLowerCase() == "doable" || code.toLowerCase() == "answer") { return MyColors.greenColor; - } else if (code.toLowerCase() == "requested information" || code.toLowerCase() == "assign" || code.toLowerCase() == "reassign") { + } else if (code.toLowerCase() == "requested information" || code.toLowerCase() == "request information" || code.toLowerCase() == "assign" || code.toLowerCase() == "reassign") { return MyColors.orange; } else { return MyColors.whiteColor; -- 2.30.2 From be46dcb9b1c1a0f0753093d03de70d6507c0e755 Mon Sep 17 00:00:00 2001 From: sultan khan Date: Thu, 6 Mar 2025 16:15:49 +0300 Subject: [PATCH 066/135] employee search work in progress --- android/build.gradle | 3 +- android/gradle.properties | 1 + .../gradle/wrapper/gradle-wrapper.properties | 4 +- ios/Flutter/AppFrameworkInfo.plist | 2 +- ios/Runner.xcodeproj/project.pbxproj | 3 +- .../xcshareddata/xcschemes/Runner.xcscheme | 2 +- ios/Runner/AppDelegate.swift | 2 +- .../get_eit_dff_structure_list_model.dart | 8 +- .../dynamic_screens/dynamic_input_screen.dart | 82 +++++++++++-------- pubspec.yaml | 2 +- 10 files changed, 63 insertions(+), 46 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index abef75b..2c90dbd 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.8.20' + ext.kotlin_version = '1.9.10' repositories { google() mavenCentral() @@ -11,6 +11,7 @@ buildscript { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath 'com.google.gms:google-services:4.3.8' classpath 'com.huawei.agconnect:agcp:1.8.0.300' + classpath "com.android.tools:r8:8.2.33" } } diff --git a/android/gradle.properties b/android/gradle.properties index 2260f45..56359bf 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,3 +1,4 @@ org.gradle.jvmargs=-Xmx1836M android.useAndroidX=true android.enableJetifier=true +org.gradle.java.home=/Users/user/Library/Java/JavaVirtualMachines/jbr-17.0.12/Contents/Home/ \ No newline at end of file diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 2f8758c..1e830b7 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Fri Jun 23 08:50:38 CEST 2017 +#Thu Mar 06 11:40:30 AST 2025 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip \ No newline at end of file diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist index 9625e10..7c56964 100644 --- a/ios/Flutter/AppFrameworkInfo.plist +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 11.0 + 12.0 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 1eb87d0..32f5090 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -160,7 +160,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { @@ -232,6 +232,7 @@ files = ( ); inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); name = "Thin Binary"; outputPaths = ( diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index c87d15a..5e31d3d 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ json) { aLPHANUMERICALLOWEDFLAG = json['ALPHANUMERIC_ALLOWED_FLAG']; @@ -148,6 +150,7 @@ class GetEITDFFStructureList { uSEDFLAG = json['USED_FLAG']; vALIDATIONTYPE = json['VALIDATION_TYPE']; vALIDATIONTYPEDSP = json['VALIDATION_TYPE_DSP']; + vSSRCHFLAG = json['VS_SRCH_FLAG']; } Map toJson() { @@ -203,6 +206,7 @@ class GetEITDFFStructureList { data['USED_FLAG'] = this.uSEDFLAG; data['VALIDATION_TYPE'] = this.vALIDATIONTYPE; data['VALIDATION_TYPE_DSP'] = this.vALIDATIONTYPEDSP; + data['VS_SRCH_FLAG'] =this.vSSRCHFLAG; return data; } diff --git a/lib/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart b/lib/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart index 73f05bc..f5cae16 100644 --- a/lib/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart +++ b/lib/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart @@ -684,42 +684,52 @@ class _DynamicInputScreenState extends State { ).paddingOnly(bottom: 12); } } else { - return PopupMenuButton( - child: DynamicTextFieldWidget( - (model.sEGMENTPROMPT ?? "") + (model.rEQUIREDFLAG == "Y" ? "*" : ""), - model.eSERVICESDV?.pVALUECOLUMNNAME ?? "", - isEnable: false, - isPopup: true, - isInputTypeNum: true, - isReadOnly: model.rEADONLY == "Y", - ).paddingOnly(bottom: 12), - itemBuilder: (_) => >[ - if (model.rEADONLY != "Y") - for (int i = 0; i < model.eSERVICESVS!.length; i++) - PopupMenuItem( - value: i, - child: Column( - children: [ - Text(model.eSERVICESVS![i].vALUECOLUMNNAME!), - const PopupMenuDivider(), - ], - )), - ], - onSelected: (int popipIndex) async { - ESERVICESDV eservicesdv = ESERVICESDV( - pIDCOLUMNNAME: model.eSERVICESVS![popipIndex].iDCOLUMNNAME, - pRETURNMSG: "null", - pRETURNSTATUS: "null", //getEitDffStructureList![popipIndex].dEFAULTVALUE, - pVALUECOLUMNNAME: model.eSERVICESVS![popipIndex].vALUECOLUMNNAME); - getEitDffStructureList![index].eSERVICESDV = eservicesdv; - setState(() {}); - if (model.cHILDSEGMENTSVSSplited?.isNotEmpty ?? false) { - await calGetValueSetValues(model); - } - if (model.cHILDSEGMENTSDVSplited?.isNotEmpty ?? false) { - await getDefaultValues(model); - } - }); + //condition need to be added here. + if(model.vSSRCHFLAG =='Y'){ + + + }else { + return PopupMenuButton( + child: DynamicTextFieldWidget( + (model.sEGMENTPROMPT ?? "") + + (model.rEQUIREDFLAG == "Y" ? "*" : ""), + model.eSERVICESDV?.pVALUECOLUMNNAME ?? "", + isEnable: false, + isPopup: true, + isInputTypeNum: true, + isReadOnly: model.rEADONLY == "Y", + ).paddingOnly(bottom: 12), + itemBuilder: (_) => + >[ + if (model.rEADONLY != "Y") + for (int i = 0; i < model.eSERVICESVS!.length; i++) + PopupMenuItem( + value: i, + child: Column( + children: [ + Text(model.eSERVICESVS![i].vALUECOLUMNNAME!), + const PopupMenuDivider(), + ], + )), + ], + onSelected: (int popipIndex) async { + ESERVICESDV eservicesdv = ESERVICESDV( + pIDCOLUMNNAME: model.eSERVICESVS![popipIndex].iDCOLUMNNAME, + pRETURNMSG: "null", + pRETURNSTATUS: "null", + //getEitDffStructureList![popipIndex].dEFAULTVALUE, + pVALUECOLUMNNAME: model.eSERVICESVS![popipIndex] + .vALUECOLUMNNAME); + getEitDffStructureList![index].eSERVICESDV = eservicesdv; + setState(() {}); + if (model.cHILDSEGMENTSVSSplited?.isNotEmpty ?? false) { + await calGetValueSetValues(model); + } + if (model.cHILDSEGMENTSDVSplited?.isNotEmpty ?? false) { + await getDefaultValues(model); + } + }); + } } } else { return const SizedBox(); diff --git a/pubspec.yaml b/pubspec.yaml index 08a6251..13708ea 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -91,7 +91,7 @@ dependencies: signalr_netcore: ^1.3.3 logging: ^1.0.1 swipe_to: ^1.0.2 - flutter_webrtc: ^0.9.17 + flutter_webrtc: ^0.12.11 camera: ^0.10.3 flutter_local_notifications: ^18.0.1 #firebase_analytics: any -- 2.30.2 From c26b2d9a5f5fbe728c3b9c7878c9714a5b6e3ca8 Mon Sep 17 00:00:00 2001 From: sultan khan Date: Fri, 7 Mar 2025 18:30:19 +0300 Subject: [PATCH 067/135] search employee inprogress --- android/app/src/debug/AndroidManifest.xml | 2 +- android/app/src/main/AndroidManifest.xml | 2 +- android/gradle.properties | 2 +- ios/Runner.xcodeproj/project.pbxproj | 21 ++++ lib/api/dashboard_api_client.dart | 1 + lib/api/my_attendance_api_client.dart | 26 ++++- .../get_set_values_request_model.dart | 8 +- .../get_eit_dff_structure_list_model.dart | 6 +- lib/provider/chat_provider_model.dart | 2 +- lib/ui/chat/common.dart | 4 +- .../dynamic_screens/dynamic_input_screen.dart | 109 +++++++++++++++++- lib/ui/termination/end_employement.dart | 42 ++++++- .../search_employee_bottom_sheet.dart | 23 +++- lib/widgets/location/Location.dart | 2 +- 14 files changed, 229 insertions(+), 21 deletions(-) diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml index 50ab38d..11decc3 100644 --- a/android/app/src/debug/AndroidManifest.xml +++ b/android/app/src/debug/AndroidManifest.xml @@ -1,5 +1,5 @@ + package="hmg.cloudSolutions.mohem"> diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index d018fec..8edb0f0 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,6 +1,6 @@ + package="hmg.cloudSolutions.mohem"> diff --git a/android/gradle.properties b/android/gradle.properties index 56359bf..54e1a43 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,4 +1,4 @@ -org.gradle.jvmargs=-Xmx1836M +org.gradle.jvmargs=-Xmx2048M android.useAndroidX=true android.enableJetifier=true org.gradle.java.home=/Users/user/Library/Java/JavaVirtualMachines/jbr-17.0.12/Contents/Home/ \ No newline at end of file diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 32f5090..97a5b37 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -144,6 +144,7 @@ 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, C4CFBC4C5CAC00182015ACD5 /* [CP] Embed Pods Frameworks */, + EF29CE25BB57F5AA48CE1136 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -273,6 +274,23 @@ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; + EF29CE25BB57F5AA48CE1136 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -363,6 +381,7 @@ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; @@ -501,6 +520,7 @@ baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; @@ -531,6 +551,7 @@ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; diff --git a/lib/api/dashboard_api_client.dart b/lib/api/dashboard_api_client.dart index 89e7d48..ad6696a 100644 --- a/lib/api/dashboard_api_client.dart +++ b/lib/api/dashboard_api_client.dart @@ -13,6 +13,7 @@ import 'package:mohem_flutter_app/models/generic_response_model.dart'; import 'package:mohem_flutter_app/models/itg/itg_main_response.dart'; import 'package:mohem_flutter_app/models/itg/itg_response_model.dart'; import 'package:platform_device_id/platform_device_id.dart'; +// import 'package:platform_device_id/platform_device_id.dart'; import 'package:uuid/uuid.dart'; class DashboardApiClient { diff --git a/lib/api/my_attendance_api_client.dart b/lib/api/my_attendance_api_client.dart index 37bf9e8..3978c2d 100644 --- a/lib/api/my_attendance_api_client.dart +++ b/lib/api/my_attendance_api_client.dart @@ -91,7 +91,31 @@ class MyAttendanceApiClient { return responseData.getValueSetValuesList ?? []; }, url, postParams); } - + Future> getValueSetValuesSearch(String pSegmentName, String pDescFlexContextCode, String pDescFlexName, List> list, + {String? empID, String? parentValue, bool hasParent = false}) async { + String url = "${ApiConsts.erpRest}GET_VALUE_SET_VALUES_SRCH"; + Map postParams = { + "P_SELECTED_RESP_ID": -999, + "P_MENU_TYPE": "E", + "P_PAGE_LIMIT": 1000, + "P_PAGE_NUM": 1, + "P_PARENT_VALUE": hasParent + ? parentValue + : empID != null + ? parentValue + : null, + "P_SEGMENT_NAME": pSegmentName, + "P_DESC_FLEX_CONTEXT_CODE": pDescFlexContextCode, + "P_DESC_FLEX_NAME": pDescFlexName, + "GetValueSetValuesTBL": list, + }; + postParams.addAll(AppState().postParamsJson); + if (empID != null) postParams["P_SELECTED_EMPLOYEE_NUMBER"] = empID; + return await ApiClient().postJsonForObject((json) { + GenericResponseModel? responseData = GenericResponseModel.fromJson(json); + return responseData.getValueSetValuesList ?? []; + }, url, postParams); + } Future getDefaultValue(String pSegmentName, String pDescFlexContextCode, String pDescFlexName, List> list, {String? empID}) async { String url = "${ApiConsts.erpRest}GET_DEFAULT_VALUE"; Map postParams = { diff --git a/lib/models/dyanmic_forms/get_set_values_request_model.dart b/lib/models/dyanmic_forms/get_set_values_request_model.dart index 07c840a..9f1c52c 100644 --- a/lib/models/dyanmic_forms/get_set_values_request_model.dart +++ b/lib/models/dyanmic_forms/get_set_values_request_model.dart @@ -4,13 +4,15 @@ class GetSetValuesRequestModel { String? dESCRIPTION; String? iDCOLUMNNAME; String? fLEXVALUESETNAME; - + String? pSRCHVALUECOLUMNNAME; GetSetValuesRequestModel( {this.sEGMENTNAME, this.vALUECOLUMNNAME, this.dESCRIPTION, this.iDCOLUMNNAME, - this.fLEXVALUESETNAME}); + this.fLEXVALUESETNAME, + this.pSRCHVALUECOLUMNNAME, + }); GetSetValuesRequestModel.fromJson(Map json) { sEGMENTNAME = json['SEGMENT_NAME']; @@ -18,6 +20,7 @@ class GetSetValuesRequestModel { dESCRIPTION = json['DESCRIPTION']; iDCOLUMNNAME = json['ID_COLUMN_NAME']; fLEXVALUESETNAME = json['FLEX_VALUE_SET_NAME']; + pSRCHVALUECOLUMNNAME = json['P_SRCH_VALUE_COLUMN_NAME']; } Map toJson() { @@ -27,6 +30,7 @@ class GetSetValuesRequestModel { data['DESCRIPTION'] = this.dESCRIPTION; data['ID_COLUMN_NAME'] = this.iDCOLUMNNAME; data['FLEX_VALUE_SET_NAME'] = this.fLEXVALUESETNAME; + data['P_SRCH_VALUE_COLUMN_NAME'] =this.pSRCHVALUECOLUMNNAME; return data; } } diff --git a/lib/models/get_eit_dff_structure_list_model.dart b/lib/models/get_eit_dff_structure_list_model.dart index 05a1535..59736d3 100644 --- a/lib/models/get_eit_dff_structure_list_model.dart +++ b/lib/models/get_eit_dff_structure_list_model.dart @@ -218,14 +218,15 @@ class ESERVICESDV { dynamic pRETURNMSG; String? pRETURNSTATUS; dynamic pVALUECOLUMNNAME; - - ESERVICESDV({this.pIDCOLUMNNAME, this.pRETURNMSG, this.pRETURNSTATUS, this.pVALUECOLUMNNAME}); + dynamic pSRCHVALUECOLUMNNAME; + ESERVICESDV({this.pIDCOLUMNNAME, this.pRETURNMSG, this.pRETURNSTATUS, this.pVALUECOLUMNNAME, this.pSRCHVALUECOLUMNNAME}); ESERVICESDV.fromJson(Map json) { pIDCOLUMNNAME = json['P_ID_COLUMN_NAME']; pRETURNMSG = json['P_RETURN_MSG']; pRETURNSTATUS = json['P_RETURN_STATUS']; pVALUECOLUMNNAME = json['P_VALUE_COLUMN_NAME']; + pSRCHVALUECOLUMNNAME = json['P_SRCH_VALUE_COLUMN_NAME']; } Map toJson() { @@ -234,6 +235,7 @@ class ESERVICESDV { data['P_RETURN_MSG'] = pRETURNMSG; data['P_RETURN_STATUS'] = pRETURNSTATUS; data['P_VALUE_COLUMN_NAME'] = pVALUECOLUMNNAME; + data['P_SRCH_VALUE_COLUMN_NAME'] =pSRCHVALUECOLUMNNAME; return data; } } diff --git a/lib/provider/chat_provider_model.dart b/lib/provider/chat_provider_model.dart index 380278d..474fb51 100644 --- a/lib/provider/chat_provider_model.dart +++ b/lib/provider/chat_provider_model.dart @@ -1685,7 +1685,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { File file = File(path!); file.readAsBytesSync(); path = file.path; - await playerController.preparePlayer(file.path, 1.0); + await playerController.preparePlayer(file.path, 1.0); _timer?.cancel(); notifyListeners(); } diff --git a/lib/ui/chat/common.dart b/lib/ui/chat/common.dart index e0cb4d0..daaeca9 100644 --- a/lib/ui/chat/common.dart +++ b/lib/ui/chat/common.dart @@ -170,7 +170,7 @@ class WaveBubble extends StatelessWidget { padding: EdgeInsets.zero, margin: EdgeInsets.zero, enableSeekGesture: true, - density: 1, + // density: 1, playerWaveStyle: const PlayerWaveStyle( fixedWaveColor: Colors.white, liveWaveColor: MyColors.greenColor, @@ -178,7 +178,7 @@ class WaveBubble extends StatelessWidget { showBottom: true, waveCap: StrokeCap.round, seekLineThickness: 2, - visualizerHeight: 4, + // visualizerHeight: 4, backgroundColor: Colors.transparent, ), ), diff --git a/lib/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart b/lib/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart index f5cae16..00453b2 100644 --- a/lib/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart +++ b/lib/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart @@ -21,6 +21,8 @@ import 'package:mohem_flutter_app/models/submit_eit_transaction_list_model.dart' import 'package:mohem_flutter_app/ui/misc/request_submit_screen.dart'; import 'package:mohem_flutter_app/ui/my_attendance/dynamic_screens/dynamic_listview_screen.dart'; import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; +import 'package:mohem_flutter_app/widgets/bottom_sheet.dart'; +import 'package:mohem_flutter_app/widgets/bottom_sheets/search_employee_bottom_sheet.dart'; import 'package:mohem_flutter_app/widgets/button/default_button.dart'; import 'package:mohem_flutter_app/widgets/dynamic_forms/dynamic_textfield_widget.dart'; @@ -37,7 +39,7 @@ class _DynamicInputScreenState extends State { GenericResponseModel? genericResponseModel; List? getEitDffStructureList; DynamicListViewParams? dynamicParams; - + String? selectedReplacementEmployee; @override void initState() { super.initState(); @@ -686,7 +688,51 @@ class _DynamicInputScreenState extends State { } else { //condition need to be added here. if(model.vSSRCHFLAG =='Y'){ + return DynamicTextFieldWidget( + LocaleKeys.selectEmployee.tr(), + "", + // selectedReplacementEmployee == null ? LocaleKeys.searchForEmployee + // .tr() : selectedReplacementEmployee!.employeeDisplayName ?? "", + isEnable: false, + onTap: () { + showMyBottomSheet( + context, + + callBackFunc: () {}, + child: SearchEmployeeBottomSheet( + title: LocaleKeys.searchForEmployee.tr(), + apiMode: LocaleKeys.delegate.tr(), + fromDynamicScreen: true, + fromChat: false, + onSelectEmployee: (_selectedEmployee) { + // Navigator.pop(context); + // selectedReplacementEmployee = _selectedEmployee; + ESERVICESDV eservicesdv = ESERVICESDV( + pIDCOLUMNNAME:_selectedEmployee.userName, + pRETURNMSG: "null", + pRETURNSTATUS: "null", //getEitDffStructureList![popipIndex].dEFAULTVALUE, + pVALUECOLUMNNAME:_selectedEmployee.employeeDisplayName); + getEitDffStructureList![index].eSERVICESDV = eservicesdv; + + setState(() {}); + }, + onSearchClick: (String empID) async{ + ESERVICESDV eservicesdv = + ESERVICESDV(pSRCHVALUECOLUMNNAME: empID, pRETURNMSG: "null", pRETURNSTATUS: "null", pVALUECOLUMNNAME: ""); + getEitDffStructureList![index].eSERVICESDV = eservicesdv; + setState(() {}); + if (model.cHILDSEGMENTSVSSplited?.isNotEmpty ?? false) { + await calGetValueSetValuesSearch(model, empID); + } + if (model.cHILDSEGMENTSDVSplited?.isNotEmpty ?? false) { + await getDefaultValues(model); + } + }, + ), + ); + }, + ); }else { return PopupMenuButton( @@ -924,4 +970,65 @@ class _DynamicInputScreenState extends State { } return time; } + Future calGetValueSetValuesSearch(GetEITDFFStructureList structureList,String userID, {bool showLoading = true}) async { + try { + if (showLoading) Utils.showLoading(context); + for (int i = 0; i < (structureList.cHILDSEGMENTSVSSplited?.length ?? 0); i++) { + List> values = []; + String segmentId = structureList.cHILDSEGMENTSVSSplited![i]; + + if (dESCFLEXCONTEXTCODE.isEmpty) dESCFLEXCONTEXTCODE = structureList.dESCFLEXCONTEXTCODE!; + List filteredList = getEitDffStructureList?.where((element) => element.cHILDSEGMENTSVSSplited!.contains(segmentId)).toList() ?? []; + + if (filteredList.isEmpty && structureList.cHILDSEGMENTSVSSplited!.isNotEmpty) { + segmentId = structureList.cHILDSEGMENTSVSSplited![0]; + filteredList = getEitDffStructureList?.where((element) => element.cHILDSEGMENTSVSSplited!.contains(segmentId)).toList() ?? []; + } + values = filteredList + .map((e) => GetSetValuesRequestModel( + sEGMENTNAME: e.sEGMENTNAME, vALUECOLUMNNAME: e.eSERVICESDV!.pVALUECOLUMNNAME, dESCRIPTION: "", iDCOLUMNNAME: e.eSERVICESDV!.pIDCOLUMNNAME, fLEXVALUESETNAME: e.fLEXVALUESETNAME, pSRCHVALUECOLUMNNAME: userID ) + .toJson()) + .toList(); + + String? selectedEmp = dynamicParams!.selectedEmp; + bool hasParentId = false; + + if (segmentId.isNotEmpty && selectedEmp == null) { + for (var element in getEitDffStructureList!) { + try { + if (element.sEGMENTNAME == segmentId && selectedEmp == null) { + var selectedElement = element; + if (selectedElement.vALIDATIONTYPE == "Y" || selectedElement.vALIDATIONTYPE == "D") { + hasParentId = true; + break; + } + } + } catch (ex) { + print("err:$ex"); + } + } + } + + List eServicesResponseModel = await MyAttendanceApiClient().getValueSetValuesSearch(segmentId, structureList.dESCFLEXCONTEXTCODE!, structureList.dESCFLEXNAME!, values, + empID: selectedEmp, parentValue: structureList.eSERVICESDV!.pVALUECOLUMNNAME, hasParent: hasParentId); + List abc = genericResponseModel?.getEITDFFStructureList ?? []; + getEitDffStructureList = abc; + int index = getEitDffStructureList!.indexWhere((element) => element.sEGMENTNAME == segmentId); + getEitDffStructureList![index].eSERVICESVS!.clear(); + getEitDffStructureList![index].eSERVICESDV = ESERVICESDV(); + if (eServicesResponseModel.isNotEmpty) getEitDffStructureList![index].eSERVICESVS!.addAll(eServicesResponseModel); + // getEitDffStructureList = genericResponseModel?.getEITDFFStructureList ?? []; + //getEitDffStructureList = getEitDffStructureList!.where((element) => element.dISPLAYFLAG != "N").toList(); + } + if (showLoading) { + await Future.delayed(const Duration(seconds: 1)); + Utils.hideLoading(context); + } + + setState(() {}); + } catch (ex) { + if (showLoading) Utils.hideLoading(context); + Utils.handleException(ex, context, null); + } + } } diff --git a/lib/ui/termination/end_employement.dart b/lib/ui/termination/end_employement.dart index 8837806..18ae916 100644 --- a/lib/ui/termination/end_employement.dart +++ b/lib/ui/termination/end_employement.dart @@ -18,9 +18,12 @@ import 'package:mohem_flutter_app/models/get_eit_dff_structure_list_model.dart' import 'package:mohem_flutter_app/models/submit_term_transaction_list_model.dart'; import 'package:mohem_flutter_app/models/termination/get_term_cols_structure_list_model.dart'; import 'package:mohem_flutter_app/models/termination/get_term_dff_structure_list_model.dart'; +import 'package:mohem_flutter_app/models/worklist/replacement_list_model.dart'; import 'package:mohem_flutter_app/ui/misc/request_submit_screen.dart'; import 'package:mohem_flutter_app/ui/my_attendance/dynamic_screens/dynamic_listview_screen.dart'; import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; +import 'package:mohem_flutter_app/widgets/bottom_sheet.dart'; +import 'package:mohem_flutter_app/widgets/bottom_sheets/search_employee_bottom_sheet.dart'; import 'package:mohem_flutter_app/widgets/button/default_button.dart'; import 'package:mohem_flutter_app/widgets/dynamic_forms/dynamic_textfield_widget.dart'; @@ -37,7 +40,7 @@ class _EndEmploymentScreenState extends State { List? termColsList; List? termDffList; DynamicListViewParams? dynamicParams; - + ReplacementList? selectedReplacementEmployee; @override void initState() { super.initState(); @@ -413,9 +416,40 @@ class _EndEmploymentScreenState extends State { await calGetValueSetValues(model); } }, - ).paddingOnly(bottom: 12); + ); } } else { + if(model.sEGMENTNAME =='REPLACEMENT_PERSON') { + return DynamicTextFieldWidget( + LocaleKeys.selectEmployee.tr(), + selectedReplacementEmployee == null ? LocaleKeys.searchForEmployee + .tr() : selectedReplacementEmployee!.employeeDisplayName ?? "", + isEnable: false, + onTap: () { + showMyBottomSheet( + context, + callBackFunc: () {}, + child: SearchEmployeeBottomSheet( + title: LocaleKeys.searchForEmployee.tr(), + apiMode: LocaleKeys.delegate.tr(), + fromChat: false, + onSelectEmployee: (_selectedEmployee) { + // Navigator.pop(context); + selectedReplacementEmployee = _selectedEmployee; + ESERVICESDV eservicesdv = ESERVICESDV( + pIDCOLUMNNAME:_selectedEmployee.userName, + pRETURNMSG: "null", + pRETURNSTATUS: "null", //getEitDffStructureList![popipIndex].dEFAULTVALUE, + pVALUECOLUMNNAME:_selectedEmployee.employeeDisplayName); + termDffList![index].eSERVICESDV = eservicesdv; + + setState(() {}); + }, + ), + ); + }, + ); + }else{ return PopupMenuButton( child: DynamicTextFieldWidget( (model.sEGMENTPROMPT ?? "") + (model.rEQUIREDFLAG == "Y" ? "*" : ""), @@ -436,11 +470,13 @@ class _EndEmploymentScreenState extends State { pRETURNSTATUS: "null", //getEitDffStructureList![popipIndex].dEFAULTVALUE, pVALUECOLUMNNAME: model.eSERVICESVS![popipIndex].vALUECOLUMNNAME); termDffList![index].eSERVICESDV = eservicesdv; + print(eservicesdv); setState(() {}); if (model.cHILDSEGMENTSVSSplited?.isNotEmpty ?? false) { await calGetValueSetValues(model); } }); + } } } else { return const SizedBox(); @@ -455,7 +491,7 @@ class _EndEmploymentScreenState extends State { isPopup: true, isInputTypeNum: true, isReadOnly: model.rEADONLY == "Y", - ).paddingOnly(bottom: 12), + ), itemBuilder: (_) => >[ if (model.rEADONLY != "Y") for (int i = 0; i < model.eSERVICESVS!.length; i++) PopupMenuItem(value: i, child: Text(model.eSERVICESVS![i].vALUECOLUMNNAME!)), diff --git a/lib/widgets/bottom_sheets/search_employee_bottom_sheet.dart b/lib/widgets/bottom_sheets/search_employee_bottom_sheet.dart index d810457..f2f362a 100644 --- a/lib/widgets/bottom_sheets/search_employee_bottom_sheet.dart +++ b/lib/widgets/bottom_sheets/search_employee_bottom_sheet.dart @@ -30,8 +30,9 @@ class SearchEmployeeBottomSheet extends StatefulWidget { String title, apiMode; List? actionHistoryList; Function(ReplacementList) onSelectEmployee; + Function(String)? onSearchClick; bool fromChat; - + bool? fromDynamicScreen; SearchEmployeeBottomSheet({ required this.title, required this.apiMode, @@ -39,6 +40,8 @@ class SearchEmployeeBottomSheet extends StatefulWidget { this.actionHistoryList, required this.onSelectEmployee, required this.fromChat, + this.fromDynamicScreen =false, + this.onSearchClick, }); @override @@ -152,7 +155,12 @@ class _SearchEmployeeBottomSheetState extends State { 21.height, "Search".toText16(), 11.height, - Row( + widget.fromDynamicScreen! ? Row( + children: [ + radioOption( "UserId" , 0, _selectedSearchIndex), + + ], + ) : Row( children: [ radioOption(widget.fromChat ? "UserId" : "Name", 0, _selectedSearchIndex), radioOption("User Name", 1, _selectedSearchIndex), @@ -164,7 +172,7 @@ class _SearchEmployeeBottomSheetState extends State { children: [ DynamicTextFieldWidget( "Search", - "Search By Username", + widget.fromDynamicScreen! ? "Search By UserID" : "Search By Username", inputAction: TextInputAction.done, suffixIconData: Icons.search, onChange: (text) { @@ -175,8 +183,13 @@ class _SearchEmployeeBottomSheetState extends State { IconButton( constraints: const BoxConstraints(), onPressed: () async { - await SystemChannels.textInput.invokeMethod('TextInput.hide'); - widget.fromChat ? fetchChatUser() : fetchUserByInput(); + if(widget.onSearchClick !=null){ + widget.onSearchClick!(searchText); + }else { + await SystemChannels.textInput.invokeMethod( + 'TextInput.hide'); + widget.fromChat ? fetchChatUser() : fetchUserByInput(); + } }, icon: const Icon(Icons.search), ) diff --git a/lib/widgets/location/Location.dart b/lib/widgets/location/Location.dart index 47babca..23ad0cc 100644 --- a/lib/widgets/location/Location.dart +++ b/lib/widgets/location/Location.dart @@ -44,7 +44,7 @@ class Location { AppPermissions.location((granted) { if (granted) { - Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.medium, timeLimit: const Duration(seconds: 5)).then((value) { + Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.lowest, timeLimit: const Duration(seconds: 10)).then((value) { done(value); }).catchError((err) { errorCallBack(); -- 2.30.2 From 54aa6108566415f06284545d761d037ef24b9580 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Mon, 17 Mar 2025 15:46:17 +0300 Subject: [PATCH 068/135] long text field changed to separate field. --- .../request_detail_fragment.dart | 42 ++++++++++++------- lib/widgets/item_detail_view_widget.dart | 5 ++- 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/lib/ui/work_list/itg_fragments/request_detail_fragment.dart b/lib/ui/work_list/itg_fragments/request_detail_fragment.dart index ba67ba4..d4d7e07 100644 --- a/lib/ui/work_list/itg_fragments/request_detail_fragment.dart +++ b/lib/ui/work_list/itg_fragments/request_detail_fragment.dart @@ -40,6 +40,7 @@ class RequestDetailFragment extends StatelessWidget { ? LocaleKeys.noDataAvailable.tr().toText16().center : ListView( shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), children: uiList, ), ), @@ -73,26 +74,29 @@ class RequestDetailFragment extends StatelessWidget { List fields = List.from(fieldsF); bool isOdd = false; + + List longValueFields = []; + + longValueFields = fields + .where((Fields element) => (element.value?.length ?? 0) > 120) + .toList() + .map((Fields descriptionFormat) => ItemDetailViewGridItem( + 2, + descriptionFormat.title, + descriptionFormat.value == null ? (descriptionFormat.multipleValue?.join(", ") ?? "") : descriptionFormat.value ?? "", + type: descriptionFormat.type, + showSpaceAfterLine: true, + maxLine: 0, + )) + .toList(); + + fields.removeWhere((element) => (element.value?.length ?? 0) > 120); + if (fields.length % 2 != 0) { isOdd = true; fields.add(new Fields()); } - int descriptionFormatIndex = fields.indexWhere((element) => element.title == "Description Format" || element.title == "Description Format"); // todo add arabic in future - Widget? descriptionFormatView; - if (descriptionFormatIndex >= 0) { - Fields descriptionFormat = fields[descriptionFormatIndex]; - fields.removeAt(descriptionFormatIndex); - - descriptionFormatView = ItemDetailViewGridItem( - 2, - descriptionFormat.title, - descriptionFormat.value == null ? (descriptionFormat.multipleValue?.join(", ") ?? "") : descriptionFormat.value ?? "", - type: descriptionFormat.type, - maxLine: 0, - ); - } - return Column( mainAxisSize: MainAxisSize.min, children: [ @@ -131,7 +135,13 @@ class RequestDetailFragment extends StatelessWidget { childAspectRatio: (itemWidth / itemHeight), ), ), - if (descriptionFormatView != null) descriptionFormatView, + ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + padding: EdgeInsets.zero, + itemBuilder: (cxt, index) => longValueFields[index], + separatorBuilder: (cxt, index) => 16.height, + itemCount: longValueFields.length), ], ).objectContainerView(); return ListView.separated( diff --git a/lib/widgets/item_detail_view_widget.dart b/lib/widgets/item_detail_view_widget.dart index a98b066..64bbd01 100644 --- a/lib/widgets/item_detail_view_widget.dart +++ b/lib/widgets/item_detail_view_widget.dart @@ -53,8 +53,9 @@ class ItemDetailViewGridItem extends StatelessWidget { final String? type; final bool isNeedToShowEmptyDivider; final int maxLine; + final bool showSpaceAfterLine; - ItemDetailViewGridItem(this.index, this.title, this.value, {Key? key, this.isNeedToShowEmptyDivider = false, this.type = "", this.maxLine = 6}) : super(key: key); + ItemDetailViewGridItem(this.index, this.title, this.value, {Key? key, this.isNeedToShowEmptyDivider = false, this.showSpaceAfterLine = false, this.type = "", this.maxLine = 6}) : super(key: key); @override Widget build(BuildContext context) { @@ -92,7 +93,7 @@ class ItemDetailViewGridItem extends StatelessWidget { : (value!.isEmpty ? "--" : value).toString().toText12Auto(color: MyColors.normalTextColor, maxLine: maxLine) : Container(), ], - ), + ).paddingOnly(top: showSpaceAfterLine ? 16 : 0), ); } } -- 2.30.2 From 72c178382f62ea85029d5bedf3db88c8cc16752d Mon Sep 17 00:00:00 2001 From: Aamir Muhammad Date: Thu, 1 May 2025 21:22:52 +0300 Subject: [PATCH 069/135] time sheet changes --- assets/icons/itg/alert.svg | 3 + assets/icons/itg/calendar-remove.svg | 4 + assets/icons/itg/calendar.svg | 8 + assets/icons/itg/coming-soon.svg | 3 + assets/icons/itg/finger-print-remove.svg | 10 + assets/icons/itg/knight-shield.svg | 3 + assets/icons/itg/money-not-found.svg | 4 + assets/icons/itg/stethoscope.svg | 3 + assets/icons/itg/time-quarter-pass.svg | 15 + assets/icons/itg/time-quarter.svg | 7 + lib/api/dashboard_api_client.dart | 215 +++-- lib/api/worklist/worklist_api_client.dart | 882 ++++++++++-------- lib/classes/consts.dart | 8 +- lib/main.dart | 54 +- lib/models/itg/itg_summary_data.dart | 101 ++ lib/provider/dashboard_provider_model.dart | 15 +- lib/ui/login/verify_last_login_screen.dart | 206 ++-- lib/ui/work_list/itg_detail_screen.dart | 266 +++--- .../request_detail_fragment.dart | 151 +-- lib/ui/work_list/work_list_screen.dart | 373 ++++---- lib/widgets/otp_widget.dart | 22 +- pubspec.yaml | 3 +- 22 files changed, 1228 insertions(+), 1128 deletions(-) create mode 100644 assets/icons/itg/alert.svg create mode 100644 assets/icons/itg/calendar-remove.svg create mode 100644 assets/icons/itg/calendar.svg create mode 100644 assets/icons/itg/coming-soon.svg create mode 100644 assets/icons/itg/finger-print-remove.svg create mode 100644 assets/icons/itg/knight-shield.svg create mode 100644 assets/icons/itg/money-not-found.svg create mode 100644 assets/icons/itg/stethoscope.svg create mode 100644 assets/icons/itg/time-quarter-pass.svg create mode 100644 assets/icons/itg/time-quarter.svg create mode 100644 lib/models/itg/itg_summary_data.dart diff --git a/assets/icons/itg/alert.svg b/assets/icons/itg/alert.svg new file mode 100644 index 0000000..6f0f0ca --- /dev/null +++ b/assets/icons/itg/alert.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/itg/calendar-remove.svg b/assets/icons/itg/calendar-remove.svg new file mode 100644 index 0000000..965a40c --- /dev/null +++ b/assets/icons/itg/calendar-remove.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/icons/itg/calendar.svg b/assets/icons/itg/calendar.svg new file mode 100644 index 0000000..2ac497c --- /dev/null +++ b/assets/icons/itg/calendar.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/assets/icons/itg/coming-soon.svg b/assets/icons/itg/coming-soon.svg new file mode 100644 index 0000000..52d5ffc --- /dev/null +++ b/assets/icons/itg/coming-soon.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/itg/finger-print-remove.svg b/assets/icons/itg/finger-print-remove.svg new file mode 100644 index 0000000..bc6fe65 --- /dev/null +++ b/assets/icons/itg/finger-print-remove.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/assets/icons/itg/knight-shield.svg b/assets/icons/itg/knight-shield.svg new file mode 100644 index 0000000..e0bf799 --- /dev/null +++ b/assets/icons/itg/knight-shield.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/itg/money-not-found.svg b/assets/icons/itg/money-not-found.svg new file mode 100644 index 0000000..01121a6 --- /dev/null +++ b/assets/icons/itg/money-not-found.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/icons/itg/stethoscope.svg b/assets/icons/itg/stethoscope.svg new file mode 100644 index 0000000..31c4638 --- /dev/null +++ b/assets/icons/itg/stethoscope.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/itg/time-quarter-pass.svg b/assets/icons/itg/time-quarter-pass.svg new file mode 100644 index 0000000..5a8a758 --- /dev/null +++ b/assets/icons/itg/time-quarter-pass.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/assets/icons/itg/time-quarter.svg b/assets/icons/itg/time-quarter.svg new file mode 100644 index 0000000..7eaf056 --- /dev/null +++ b/assets/icons/itg/time-quarter.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/lib/api/dashboard_api_client.dart b/lib/api/dashboard_api_client.dart index ad6696a..145b039 100644 --- a/lib/api/dashboard_api_client.dart +++ b/lib/api/dashboard_api_client.dart @@ -13,6 +13,7 @@ import 'package:mohem_flutter_app/models/generic_response_model.dart'; import 'package:mohem_flutter_app/models/itg/itg_main_response.dart'; import 'package:mohem_flutter_app/models/itg/itg_response_model.dart'; import 'package:platform_device_id/platform_device_id.dart'; + // import 'package:platform_device_id/platform_device_id.dart'; import 'package:uuid/uuid.dart'; @@ -27,40 +28,56 @@ class DashboardApiClient { String url = "${ApiConsts.erpRest}GET_Attendance_Tracking"; Map postParams = {}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.getAttendanceTrackingList; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getAttendanceTrackingList; + }, + url, + postParams, + ); } Future getOpenNotifications() async { String url = "${ApiConsts.erpRest}GET_OPEN_NOTIFICATIONS"; Map postParams = {}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData; + }, + url, + postParams, + ); } Future getCOCNotifications() async { String url = "${ApiConsts.cocRest}Mohemm_ITG_ReviewerAdmin_Pending_Tasks"; Map postParams = {"Date": DateUtil.getISODateFormat(DateTime.now()), "EmployeeNumber": AppState().memberInformationList?.eMPLOYEENUMBER}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData; + }, + url, + postParams, + ); } Future getItgFormsPendingTask() async { String url = "${ApiConsts.cocRest}ITGFormsPendingTasks"; Map postParams = {}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - ItgFormsModel responseData = ItgFormsModel.fromJson(json); - return responseData; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + ItgFormsModel responseData = ItgFormsModel.fromJson(json); + return responseData; + }, + url, + postParams, + ); } Future> getAccrualBalances(String effectiveDate, {String? empID}) async { @@ -68,20 +85,28 @@ class DashboardApiClient { Map postParams = {"P_EFFECTIVE_DATE": effectiveDate}; postParams.addAll(AppState().postParamsJson); if (empID != null) postParams["P_SELECTED_EMPLOYEE_NUMBER"] = empID; - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.getAccrualBalancesList ?? []; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getAccrualBalancesList ?? []; + }, + url, + postParams, + ); } Future getOpenMissingSwipes() async { String url = "${ApiConsts.erpRest}GET_OPEN_MISSING_SWIPES"; Map postParams = {}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData; + }, + url, + postParams, + ); } //Menus List @@ -89,10 +114,14 @@ class DashboardApiClient { String url = "${ApiConsts.erpRest}GET_MENU"; Map postParams = {}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.listMenu ?? []; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.listMenu ?? []; + }, + url, + postParams, + ); } //GET_MENU_ENTRIES @@ -100,24 +129,40 @@ class DashboardApiClient { String url = "${ApiConsts.erpRest}GET_MENU_ENTRIES"; Map postParams = {"P_SELECTED_RESP_ID": -999, "P_MENU_TYPE": "E"}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData; + }, + url, + postParams, + ); } Future getEventActivity() async { String url = "${ApiConsts.erpRest}Get_EventActivity"; Map postParams = {"P_SELECTED_RESP_ID": -999, "P_MENU_TYPE": "E"}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData; + }, + url, + postParams, + ); } //Mark Attendance - Future markAttendance({String lat = "0", String? long = "0", required int pointType, String nfcValue = "", bool isGpsRequired = false, String QRValue = "", String payrollCode = ""}) async { + Future markAttendance({ + String lat = "0", + String? long = "0", + required int pointType, + String nfcValue = "", + bool isGpsRequired = false, + String QRValue = "", + String payrollCode = "", + }) async { String url = "${ApiConsts.swpRest}AuthenticateAndSwipeUserSupportNFC"; var uuid = Uuid(); // Generate a v4 (random) id @@ -132,13 +177,17 @@ class DashboardApiClient { "NFCValue": nfcValue, "WifiValue": pointType == 3 ? "100" : "", "IsGpsRequired": isGpsRequired, - "PayrollCodeStr": AppState().postParamsObject?.payrollCodeStr.toString() ?? "" + "PayrollCodeStr": AppState().postParamsObject?.payrollCodeStr.toString() ?? "", }; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData; + }, + url, + postParams, + ); } //Mark Fake Location @@ -157,10 +206,14 @@ class DashboardApiClient { "EmployeeID": AppState().memberInformationList!.eMPLOYEENUMBER, }; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData; + }, + url, + postParams, + ); } //Check ITG Type @@ -170,15 +223,19 @@ class DashboardApiClient { Map postParams = { "EmployeeNumber": AppState().getUserName, "ItgEnableAt": "After Service Submission", //Mobile Id - "ItgServiceName": "Login" + "ItgServiceName": "Login", }; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - MohemmItgResponseItem res = MohemmItgResponseItem.fromJson(jsonDecode(responseData.mohemmITGResponseItem ?? "")); - // var jsonDecodedData = jsonDecode(jsonDecode(responseData.mohemmITGResponseItem!)['result']['data']); - return res; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + MohemmItgResponseItem res = MohemmItgResponseItem.fromJson(jsonDecode(responseData.mohemmITGResponseItem ?? "")); + // var jsonDecodedData = jsonDecode(jsonDecode(responseData.mohemmITGResponseItem!)['result']['data']); + return res; + }, + url, + postParams, + ); } //Submit ITG @@ -190,13 +247,17 @@ class DashboardApiClient { "ItgComments": comment, "ItgNotificationMasterId": masterId, "ItgQuestionResponses": itgList, - "ItgSurveyId": serviceId + "ItgSurveyId": serviceId, }; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - ItgMainRes responseData = ItgMainRes.fromJson(json); - return responseData; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + ItgMainRes responseData = ItgMainRes.fromJson(json); + return responseData; + }, + url, + postParams, + ); } Future getAdvertisementDetail(String masterID) async { @@ -207,10 +268,14 @@ class DashboardApiClient { "ItgNotificationMasterId": masterID, //Mobile Id }; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - ItgMainRes responseData = ItgMainRes.fromJson(json); - return responseData; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + ItgMainRes responseData = ItgMainRes.fromJson(json); + return responseData; + }, + url, + postParams, + ); } Future setAdvertisementViewed(String masterID, int advertisementId, String? ackValue) async { @@ -224,9 +289,27 @@ class DashboardApiClient { // "ItgAdvertisement": {"ItgAdvertisementId": advertisementId, "ItgAcknowledgment": ackValue} //Mobile Id }; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - // ItgMainRes responseData = ItgMainRes.fromJson(json); - return json; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + // ItgMainRes responseData = ItgMainRes.fromJson(json); + return json; + }, + url, + postParams, + ); } + + // Future getItgTimeCardDetails() async { + // String url = "${ApiConsts.cocRest}ITG_TimeCard_Get"; + // Map postParams = {}; + // postParams.addAll(AppState().postParamsJson); + // return await ApiClient().postJsonForObject( + // (json) { + // ItgTimeCardModel responseData = ItgTimeCardModel.fromJson(json); + // return responseData; + // }, + // url, + // postParams, + // ); + // } } diff --git a/lib/api/worklist/worklist_api_client.dart b/lib/api/worklist/worklist_api_client.dart index 9667961..51a47bb 100644 --- a/lib/api/worklist/worklist_api_client.dart +++ b/lib/api/worklist/worklist_api_client.dart @@ -45,8 +45,15 @@ class WorkListApiClient { factory WorkListApiClient() => _instance; - Future?> getWorkList(int pPageNum, String pItemType, String pNotificationType, - {String pSearchUser = "", String pSearchItemType = "", String pSentDate = "", String pSearchSubject = ""}) async { + Future?> getWorkList( + int pPageNum, + String pItemType, + String pNotificationType, { + String pSearchUser = "", + String pSearchItemType = "", + String pSentDate = "", + String pSearchSubject = "", + }) async { String url = "${ApiConsts.erpRest}GET_WORKLIST"; Map postParams = { "P_NOTIFICATION_TYPE": pNotificationType, @@ -56,171 +63,200 @@ class WorkListApiClient { "P_SEARCH_FROM_USER": pSearchUser, "P_SEARCH_ITEM_TYPE_DSP_NAME": pSearchItemType, "P_SEARCH_SENT_DATE": pSentDate, - "P_SEARCH_SUBJECT": pSearchSubject + "P_SEARCH_SUBJECT": pSearchSubject, }; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel? responseData = GenericResponseModel.fromJson(json); - return responseData.getWorkList; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel? responseData = GenericResponseModel.fromJson(json); + return responseData.getWorkList; + }, + url, + postParams, + ); } Future getITGTaskCountRequestType() async { String url = "${ApiConsts.cocRest}ITGGetTaskCountRequestType"; Map postParams = {}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - ItgFormsModel responseData = ItgFormsModel.fromJson(json); - return responseData; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + ItgFormsModel responseData = ItgFormsModel.fromJson(json); + return responseData; + }, + url, + postParams, + ); } Future getSubordinatesLeaves(String fromDate, String toDate) async { String url = "${ApiConsts.erpRest}GET_SUBORDINATES_LEAVES"; Map postParams = {"P_DATE_FROM": "/Date(1639861200000+0300)/", "P_DATE_TO": "/Date(1640120400000+0300)/"}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData; + }, + url, + postParams, + ); } Future> getAttachments(int pNotificationID) async { String url = "${ApiConsts.erpRest}GET_ATTACHMENTS"; Map postParams = {"P_NOTIFICATION_ID": pNotificationID}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.getAttachementList ?? []; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getAttachementList ?? []; + }, + url, + postParams, + ); } Future> getPRAttachments(String pOLineID) async { String url = "${ApiConsts.erpRest}GET_PR_ATTACHMENTS"; Map postParams = {"P_PO_LINE_ID": pOLineID}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.getPRAttachmentList ?? []; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getPRAttachmentList ?? []; + }, + url, + postParams, + ); } Future> getRFCEmployeeeList(int pNotificationID) async { String url = "${ApiConsts.erpRest}GET_RFC_EMPLOYEE_LIST"; Map postParams = {"P_NOTIFICATION_ID": pNotificationID, "P_PAGE_NUM": 1, "P_PAGE_LIMIT": 10}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.getRFCEmployeeListList ?? []; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getRFCEmployeeListList ?? []; + }, + url, + postParams, + ); } Future> getActionHistory(int pNotificationID) async { String url = "${ApiConsts.erpRest}GET_ACTION_HISTORY"; - Map postParams = { - "P_NOTIFICATION_ID": pNotificationID, - "P_PAGE_LIMIT": 100, - "P_PAGE_NUM": 1, - }; + Map postParams = {"P_NOTIFICATION_ID": pNotificationID, "P_PAGE_LIMIT": 100, "P_PAGE_NUM": 1}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.getActionHistoryList ?? []; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getActionHistoryList ?? []; + }, + url, + postParams, + ); } Future> getActionHistoryForPR(String pOLineID) async { String url = "${ApiConsts.erpRest}GET_PR_ACTION_HISTORY"; - Map postParams = { - "P_PO_LINE_ID": pOLineID, - "P_PAGE_LIMIT": 100, - "P_PAGE_NUM": 1, - }; + Map postParams = {"P_PO_LINE_ID": pOLineID, "P_PAGE_LIMIT": 100, "P_PAGE_NUM": 1}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.getPRActionHistoryList?.reversed.toList() ?? []; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getPRActionHistoryList?.reversed.toList() ?? []; + }, + url, + postParams, + ); } Future> getNotificationButtons(int pNotificationID) async { String url = "${ApiConsts.erpRest}GET_NOTIFICATION_BUTTONS"; Map postParams = {"P_NOTIFICATION_ID": pNotificationID}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.getNotificationButtonsList ?? []; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getNotificationButtonsList ?? []; + }, + url, + postParams, + ); } Future> notificationGetRespondAttributes(int pNotificationID) async { String url = "${ApiConsts.erpRest}NOTIFICATION_GET_RESPOND_ATTRIBUTES"; Map postParams = {"P_NOTIFICATION_ID": pNotificationID}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.notificationGetRespondAttributesList ?? []; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.notificationGetRespondAttributesList ?? []; + }, + url, + postParams, + ); } Future getBasicDetNTFBody(int pNotificationID, int pTransactionID) async { String url = "${ApiConsts.erpRest}GET_BASIC_DET_NTF_BODY"; - Map postParams = { - "P_NOTIFICATION_ID": pNotificationID, - "P_TRANSACTION_ID": pTransactionID, - "P_PAGE_LIMIT": 100, - "P_PAGE_NUM": 1, - }; + Map postParams = {"P_NOTIFICATION_ID": pNotificationID, "P_TRANSACTION_ID": pTransactionID, "P_PAGE_LIMIT": 100, "P_PAGE_NUM": 1}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData; + }, + url, + postParams, + ); } Future getUserInformation(int pSelectedResopID, String selectedEmployeeNumber) async { String url = "${ApiConsts.erpRest}Get_UserInformation"; - Map postParams = { - "P_SELECTED_RESP_ID": pSelectedResopID, - "P_PAGE_LIMIT": 100, - "P_PAGE_NUM": 1, - }; + Map postParams = {"P_SELECTED_RESP_ID": pSelectedResopID, "P_PAGE_LIMIT": 100, "P_PAGE_NUM": 1}; postParams.addAll(AppState().postParamsJson); if (selectedEmployeeNumber != null) postParams["P_SELECTED_EMPLOYEE_NUMBER"] = selectedEmployeeNumber; - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.memberInformationList![0]; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.memberInformationList![0]; + }, + url, + postParams, + ); } Future> getStampMsNotificationBody(int pNotificationID, int pTransactionID) async { String url = "${ApiConsts.erpRest}GET_STAMP_MS_NOTIFICATION_BODY"; - Map postParams = { - "P_NOTIFICATION_ID": pNotificationID, - "P_TRANSACTION_ID": pTransactionID, - "P_PAGE_LIMIT": 100, - "P_PAGE_NUM": 1, - }; + Map postParams = {"P_NOTIFICATION_ID": pNotificationID, "P_TRANSACTION_ID": pTransactionID, "P_PAGE_LIMIT": 100, "P_PAGE_NUM": 1}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.getStampMsNotificationBodyList ?? []; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getStampMsNotificationBodyList ?? []; + }, + url, + postParams, + ); } Future> getStampNsNotificationBody(int pNotificationID, int pTransactionID) async { String url = "${ApiConsts.erpRest}GET_STAMP_NS_NOTIFICATION_BODY"; - Map postParams = { - "P_NOTIFICATION_ID": pNotificationID, - "P_TRANSACTION_ID": pTransactionID, - "P_PAGE_LIMIT": 100, - "P_PAGE_NUM": 1, - }; + Map postParams = {"P_NOTIFICATION_ID": pNotificationID, "P_TRANSACTION_ID": pTransactionID, "P_PAGE_LIMIT": 100, "P_PAGE_NUM": 1}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.getStampNsNotificationBodyList ?? []; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getStampNsNotificationBodyList ?? []; + }, + url, + postParams, + ); } // Future> getAbsenceNotificationBody(int pNotificationID, int pTransactionID) async { @@ -241,227 +277,227 @@ class WorkListApiClient { Future postNotificationActions(Map postParams) async { String url = "${ApiConsts.erpRest}NOTIFICATION_ACTIONS"; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData; + }, + url, + postParams, + ); } Future> getMoNotificationBody(int pNotificationID, int pTransactionID) async { String url = "${ApiConsts.erpRest}GET_MO_NOTIFICATION_BODY"; - Map postParams = { - "P_NOTIFICATION_ID": pNotificationID, - "P_TRANSACTION_ID": pTransactionID, - "P_PAGE_LIMIT": 100, - "P_PAGE_NUM": 1, - }; + Map postParams = {"P_NOTIFICATION_ID": pNotificationID, "P_TRANSACTION_ID": pTransactionID, "P_PAGE_LIMIT": 100, "P_PAGE_NUM": 1}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.getMoNotificationBodyList ?? []; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getMoNotificationBodyList ?? []; + }, + url, + postParams, + ); } Future getPoNotificationBody(int pNotificationID, int pTransactionID) async { String url = "${ApiConsts.erpRest}GET_PO_NOTIFICATION_BODY"; - Map postParams = { - "P_NOTIFICATION_ID": pNotificationID, - "P_TRANSACTION_ID": pTransactionID, - "P_PAGE_LIMIT": 100, - "P_PAGE_NUM": 1, - }; + Map postParams = {"P_NOTIFICATION_ID": pNotificationID, "P_TRANSACTION_ID": pTransactionID, "P_PAGE_LIMIT": 100, "P_PAGE_NUM": 1}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.getPoNotificationBodyList; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getPoNotificationBodyList; + }, + url, + postParams, + ); } Future getPRNotificationBody(int pNotificationID, int pTransactionID) async { String url = "${ApiConsts.erpRest}GET_PR_NOTIFICATION_BODY"; - Map postParams = { - "P_NOTIFICATION_ID": pNotificationID, - "P_TRANSACTION_ID": pTransactionID, - "P_PAGE_LIMIT": 100, - "P_PAGE_NUM": 1, - }; + Map postParams = {"P_NOTIFICATION_ID": pNotificationID, "P_TRANSACTION_ID": pTransactionID, "P_PAGE_LIMIT": 100, "P_PAGE_NUM": 1}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.getPrNotificationBodyList; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getPrNotificationBodyList; + }, + url, + postParams, + ); } - Future getPaymentNotificationBody(int pNotificationID, int pTransactionID) async { + + Future getPaymentNotificationBody(int pNotificationID, int pTransactionID) async { String url = "${ApiConsts.erpRest}GET_PAY_REQ_NOTIFICATION_BODY"; - Map postParams = { - "P_NOTIFICATION_ID": pNotificationID, - "P_TRANSACTION_ID": pTransactionID, - "P_PAGE_LIMIT": 100, - "P_PAGE_NUM": 1, - }; + Map postParams = {"P_NOTIFICATION_ID": pNotificationID, "P_TRANSACTION_ID": pTransactionID, "P_PAGE_LIMIT": 100, "P_PAGE_NUM": 1}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.getPaymentNotificationBodyList; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getPaymentNotificationBodyList; + }, + url, + postParams, + ); } - - Future> getMoItemHistory(int pItemID, int pOrgID) async { String url = "${ApiConsts.erpRest}GET_MO_ITEM_HISTORY"; - Map postParams = { - "P_ITEM_ID": pItemID, - "P_PAGE_LIMIT": 100, - "P_PAGE_NUM": 1, - "P_ORG_ID": pOrgID, - }; + Map postParams = {"P_ITEM_ID": pItemID, "P_PAGE_LIMIT": 100, "P_PAGE_NUM": 1, "P_ORG_ID": pOrgID}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.getMoItemHistoryList ?? []; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getMoItemHistoryList ?? []; + }, + url, + postParams, + ); } Future> getPoItemHistory(int pItemID) async { String url = "${ApiConsts.erpRest}GET_PO_ITEM_HISTORY"; - Map postParams = { - "P_ITEM_ID": pItemID, - "P_PAGE_LIMIT": 100, - "P_PAGE_NUM": 1, - }; + Map postParams = {"P_ITEM_ID": pItemID, "P_PAGE_LIMIT": 100, "P_PAGE_NUM": 1}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.getPoItemHistoryList ?? []; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getPoItemHistoryList ?? []; + }, + url, + postParams, + ); } Future> getQuotationAnalysis(int pItemID, int pPoHeaderId) async { String url = "${ApiConsts.erpRest}GET_QUOTATION_ANALYSIS"; - Map postParams = { - "P_ITEM_ID": pItemID, - "P_PAGE_LIMIT": 100, - "P_PAGE_NUM": 1, - "P_PO_HEADER_ID": pPoHeaderId, - }; + Map postParams = {"P_ITEM_ID": pItemID, "P_PAGE_LIMIT": 100, "P_PAGE_NUM": 1, "P_PO_HEADER_ID": pPoHeaderId}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.getQuotationAnalysisList ?? []; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getQuotationAnalysisList ?? []; + }, + url, + postParams, + ); } Future getItemCreationNtfBody(int pNotificationID, int pTransactionID) async { String url = "${ApiConsts.erpRest}GET_ITEM_CREATION_NTF_BODY"; - Map postParams = { - "P_NOTIFICATION_ID": pNotificationID, - "P_TRANSACTION_ID": pTransactionID, - "P_PAGE_LIMIT": 100, - "P_PAGE_NUM": 1, - }; + Map postParams = {"P_NOTIFICATION_ID": pNotificationID, "P_TRANSACTION_ID": pTransactionID, "P_PAGE_LIMIT": 100, "P_PAGE_NUM": 1}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.getItemCreationNtfBodyList; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getItemCreationNtfBodyList; + }, + url, + postParams, + ); } Future getITGFormDetails(String requestType, taskId, itemId, String employeeNumber) async { String url = "${ApiConsts.cocRest}ITGGetFormDetials"; - Map postParams = { - "RequestType": requestType, - "TaskID": taskId, - "ItemIDStr": itemId, - "EmployeeNumber": employeeNumber, - }; + Map postParams = {"RequestType": requestType, "TaskID": taskId, "ItemIDStr": itemId, "EmployeeNumber": employeeNumber}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - ItgFormsModel responseData = ItgFormsModel.fromJson(json); - return responseData.itgRequest; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + ItgFormsModel responseData = ItgFormsModel.fromJson(json); + return responseData.itgRequest; + }, + url, + postParams, + ); + } + + Future getITGTimeCardDetails(String requestType, String monthStr, String employeeNumber) async { + String url = "${ApiConsts.cocRest}ITG_TimeCard_Get"; + // String url = "https://webservices.hmg.com/Services/COCWS.svc/REST/ITG_TimeCard_Get"; + Map postParams = {"MonthStr": monthStr, "EmployeeNumber": employeeNumber}; + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject( + (json) { + ItgFormsModel responseData = ItgFormsModel.fromJson(json); + return responseData.mohemmItgResponseItem; + }, + url, + postParams, + ); } Future?> getITGFormAttachments(String requestType, taskId, itemId, String employeeNumber) async { String url = "${ApiConsts.cocRest}ITGGetFormDetialsAttachment"; - Map postParams = { - "RequestType": requestType, - "TaskID": taskId, - "ItemIDStr": itemId, - "EmployeeNumber": employeeNumber, - }; + Map postParams = {"RequestType": requestType, "TaskID": taskId, "ItemIDStr": itemId, "EmployeeNumber": employeeNumber}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - ItgFormsModel responseData = ItgFormsModel.fromJson(json); - return responseData.itgFormAttachmentsList; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + ItgFormsModel responseData = ItgFormsModel.fromJson(json); + return responseData.itgFormAttachmentsList; + }, + url, + postParams, + ); } Future rejectITGRequest(String requestType, taskId, itemId, String employeeNumber, String comments) async { String url = "${ApiConsts.cocRest}ITGRejectRequest"; - Map postParams = { - "RequestType": requestType, - "TaskID": taskId, - "ItemIDStr": itemId, - "EmployeeNumber": employeeNumber, - "Comments": comments, - }; + Map postParams = {"RequestType": requestType, "TaskID": taskId, "ItemIDStr": itemId, "EmployeeNumber": employeeNumber, "Comments": comments}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - ItgFormsModel responseData = ItgFormsModel.fromJson(json); - return responseData.itgRequest; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + ItgFormsModel responseData = ItgFormsModel.fromJson(json); + return responseData.itgRequest; + }, + url, + postParams, + ); } Future approveITGRequest(String requestType, taskId, itemId, String employeeNumber, String comments) async { String url = "${ApiConsts.cocRest}ITGApproveRequest"; - Map postParams = { - "RequestType": requestType, - "TaskID": taskId, - "ItemIDStr": itemId, - "EmployeeNumber": employeeNumber, - "Comments": comments, - }; + Map postParams = {"RequestType": requestType, "TaskID": taskId, "ItemIDStr": itemId, "EmployeeNumber": employeeNumber, "Comments": comments}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - ItgFormsModel responseData = ItgFormsModel.fromJson(json); - return responseData.itgRequest; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + ItgFormsModel responseData = ItgFormsModel.fromJson(json); + return responseData.itgRequest; + }, + url, + postParams, + ); } Future delegateITGRequest(String requestType, taskId, itemId, String employeeNumber, String newUserEMPId, String comments) async { String url = "${ApiConsts.cocRest}ITGDelegateRequest"; - Map postParams = { - "RequestType": requestType, - "TaskID": taskId, - "ItemIDStr": itemId, - "EmployeeNumber": employeeNumber, - "NewUserEMPId": newUserEMPId, - "Comments": comments, - }; + Map postParams = {"RequestType": requestType, "TaskID": taskId, "ItemIDStr": itemId, "EmployeeNumber": employeeNumber, "NewUserEMPId": newUserEMPId, "Comments": comments}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - ItgFormsModel responseData = ItgFormsModel.fromJson(json); - return responseData.itgRequest; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + ItgFormsModel responseData = ItgFormsModel.fromJson(json); + return responseData.itgRequest; + }, + url, + postParams, + ); } // ANSWER = 'Services/COCWS.svc/REST/ITGAnswer'; Future answerITGRequest(String requestType, taskId, itemId, String employeeNumber, String newUserEMPId, String comments) async { String url = "${ApiConsts.cocRest}ITGAnswer"; - Map postParams = { - "RequestType": requestType, - "TaskID": taskId, - "ItemIDStr": itemId, - "EmployeeNumber": employeeNumber, - "Comments": comments, - }; + Map postParams = {"RequestType": requestType, "TaskID": taskId, "ItemIDStr": itemId, "EmployeeNumber": employeeNumber, "Comments": comments}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - ItgFormsModel responseData = ItgFormsModel.fromJson(json); - return responseData.itgRequest; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + ItgFormsModel responseData = ItgFormsModel.fromJson(json); + return responseData.itgRequest; + }, + url, + postParams, + ); } Future requestActionITGRequest(String requestType, taskId, itemId, String employeeNumber, String newUserEMPId, String comments, String email) async { @@ -478,10 +514,14 @@ class WorkListApiClient { "IsQRCodeGenerate": true, }; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - ItgFormsModel responseData = ItgFormsModel.fromJson(json); - return responseData.itgRequest; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + ItgFormsModel responseData = ItgFormsModel.fromJson(json); + return responseData.itgRequest; + }, + url, + postParams, + ); } Future grantITGRequest(String requestType, int taskId, int itemId, String employeeNumber, String newUserEMPId, String comments) async { @@ -493,212 +533,228 @@ class WorkListApiClient { "EmployeeNumber": employeeNumber, "Comments": "", "AdditionalFields": null, - "NewUserEMPId": newUserEMPId + "NewUserEMPId": newUserEMPId, }; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - ItgFormsModel responseData = ItgFormsModel.fromJson(json); - return responseData.itgRequest; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + ItgFormsModel responseData = ItgFormsModel.fromJson(json); + return responseData.itgRequest; + }, + url, + postParams, + ); } Future informationITGRequest(String requestType, taskId, itemId, String employeeNumber, String newUserEMPId, String comments) async { String url = "${ApiConsts.cocRest}ITGRequestInformation"; - Map postParams = { - "RequestType": requestType, - "TaskID": taskId, - "ItemIDStr": itemId, - "EmployeeNumber": employeeNumber, - "NewUserEMPId": newUserEMPId, - "Comments": comments, - }; + Map postParams = {"RequestType": requestType, "TaskID": taskId, "ItemIDStr": itemId, "EmployeeNumber": employeeNumber, "NewUserEMPId": newUserEMPId, "Comments": comments}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - ItgFormsModel responseData = ItgFormsModel.fromJson(json); - return responseData.itgRequest; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + ItgFormsModel responseData = ItgFormsModel.fromJson(json); + return responseData.itgRequest; + }, + url, + postParams, + ); } //HR Detail Screen Requests Future?> GetEitNotificationBody(int? notificationId) async { String url = "${ApiConsts.erpRest}GET_EIT_NOTIFICATION_BODY"; - Map postParams = { - "P_NOTIFICATION_ID": notificationId, - "P_PAGE_LIMIT": 100, - "P_PAGE_NUM": 1, - }; + Map postParams = {"P_NOTIFICATION_ID": notificationId, "P_PAGE_LIMIT": 100, "P_PAGE_NUM": 1}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.getEITCollectionNotificationBodyList; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getEITCollectionNotificationBodyList; + }, + url, + postParams, + ); } Future?> GetCeiNotificationBody(int? notificationId) async { String url = "${ApiConsts.erpRest}GET_CEI_NOTIFICATION_BODY"; - Map postParams = { - "P_NOTIFICATION_ID": notificationId, - "P_PAGE_LIMIT": 100, - "P_PAGE_NUM": 1, - }; + Map postParams = {"P_NOTIFICATION_ID": notificationId, "P_PAGE_LIMIT": 100, "P_PAGE_NUM": 1}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.getCEICollectionNotificationBodyList; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getCEICollectionNotificationBodyList; + }, + url, + postParams, + ); } Future?> getPhonesNotificationBodyList(int? notificationId) async { String url = "${ApiConsts.erpRest}GET_PHONES_NOTIFICATION_BODY"; - Map postParams = { - "P_NOTIFICATION_ID": notificationId, - "P_PAGE_LIMIT": 100, - "P_PAGE_NUM": 1, - }; + Map postParams = {"P_NOTIFICATION_ID": notificationId, "P_PAGE_LIMIT": 100, "P_PAGE_NUM": 1}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.getPhonesNotificationBodyList; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getPhonesNotificationBodyList; + }, + url, + postParams, + ); } Future?> getBasicDetNtfBodyList(int? notificationId) async { String url = "${ApiConsts.erpRest}GET_BASIC_DET_NTF_BODY"; - Map postParams = { - "P_NOTIFICATION_ID": notificationId, - "P_PAGE_LIMIT": 100, - "P_PAGE_NUM": 1, - }; + Map postParams = {"P_NOTIFICATION_ID": notificationId, "P_PAGE_LIMIT": 100, "P_PAGE_NUM": 1}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.getBasicDetNtfBodyList; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getBasicDetNtfBodyList; + }, + url, + postParams, + ); } Future?> getAbsenceNotificationBody(int? notificationId) async { String url = "${ApiConsts.erpRest}GET_ABSENCE_NOTIFICATION_BODY"; - Map postParams = { - "P_NOTIFICATION_ID": notificationId, - "P_PAGE_LIMIT": 100, - "P_PAGE_NUM": 1, - }; + Map postParams = {"P_NOTIFICATION_ID": notificationId, "P_PAGE_LIMIT": 100, "P_PAGE_NUM": 1}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.getAbsenceCollectionNotificationBodyList; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getAbsenceCollectionNotificationBodyList; + }, + url, + postParams, + ); } Future getContactNotificationBodyList(int? notificationId) async { String url = "${ApiConsts.erpRest}GET_CONTACT_NOTIFICATION_BODY"; - Map postParams = { - "P_NOTIFICATION_ID": notificationId, - "P_PAGE_LIMIT": 100, - "P_PAGE_NUM": 1, - }; + Map postParams = {"P_NOTIFICATION_ID": notificationId, "P_PAGE_LIMIT": 100, "P_PAGE_NUM": 1}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.getContactNotificationBodyList; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getContactNotificationBodyList; + }, + url, + postParams, + ); } Future?> getAddressNotificationBodyList(int? notificationId) async { String url = "${ApiConsts.erpRest}GET_ADDRESS_NOTIFICATION_BODY"; - Map postParams = { - "P_NOTIFICATION_ID": notificationId, - "P_PAGE_LIMIT": 100, - "P_PAGE_NUM": 1, - }; + Map postParams = {"P_NOTIFICATION_ID": notificationId, "P_PAGE_LIMIT": 100, "P_PAGE_NUM": 1}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.getAddressNotificationBodyList; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getAddressNotificationBodyList; + }, + url, + postParams, + ); } Future?> getTerminationNotificationBodyList(int? notificationId) async { String url = "${ApiConsts.erpRest}GET_TERM_NOTIFICATION_BODY"; - Map postParams = { - "P_NOTIFICATION_ID": notificationId, - "P_PAGE_LIMIT": 100, - "P_PAGE_NUM": 1, - }; + Map postParams = {"P_NOTIFICATION_ID": notificationId, "P_PAGE_LIMIT": 100, "P_PAGE_NUM": 1}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.getTermNotificationBodyList; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getTermNotificationBodyList; + }, + url, + postParams, + ); } Future?> getFavoriteReplacementWithoutImage() async { String url = "${ApiConsts.erpRest}Mohemm_GetFavoriteReplacementsWithoutImage"; Map postParams = {}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.mohemmGetFavoriteReplacementsList; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.mohemmGetFavoriteReplacementsList; + }, + url, + postParams, + ); } Future?> getFavoriteReplacementWithImage(String selectedFavLetter) async { String url = "${ApiConsts.erpRest}Mohemm_GetFavoriteReplacements"; Map postParams = {"ItgFilter": selectedFavLetter}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.mohemmGetFavoriteReplacementsList; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.mohemmGetFavoriteReplacementsList; + }, + url, + postParams, + ); } Future?> getFavoriteReplacementWithImageNew(String selectedFavLetter) async { String url = "${ApiConsts.erpRest}Mohemm_GetFavoriteReplacements_Images"; Map postParams = {"ItgFilter": selectedFavLetter}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.mohemmGetFavoriteReplacementsList; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.mohemmGetFavoriteReplacementsList; + }, + url, + postParams, + ); } Future changeFavoriteReplacements({required String email, required String employeName, required String image, required String userName, bool isFav = false}) async { String url = "${ApiConsts.erpRest}Mohemm_ChangeFavoriteReplacements"; - Map postParamsObj = { - "EMAIL_ADDRESS": email, - "EMPLOYEE_DISPLAY_NAME": employeName, - "EMPLOYEE_IMAGE": image, - "IsFavorite": isFav, - "USER_NAME": userName, - }; + Map postParamsObj = {"EMAIL_ADDRESS": email, "EMPLOYEE_DISPLAY_NAME": employeName, "EMPLOYEE_IMAGE": image, "IsFavorite": isFav, "USER_NAME": userName}; Map postParams = { "Mohemm_ChangeReplacementsInputList": [postParamsObj], }; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData; + }, + url, + postParams, + ); } Future?> searchUserByInput({String userId = "", String userName = "", String email = ""}) async { String url = "${ApiConsts.erpRest}GET_REPLACEMENT_LIST"; - Map postParams = { - "P_SEARCH_USER_NAME": userId, - "P_SEARCH_EMPLOYEE_DISPLAY_NAME": userName, - "P_SEARCH_EMAIL_ADDRESS": email, - "P_PAGE_LIMIT": 50, - "P_PAGE_NUM": 1, - }; - postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.replacementList; - }, url, postParams); - } - - Future submitComment( - {String? comment, String? email, String? userId, int? notificationId, required String apiMode, int? approverIndex = null, List>? attributeData = const []}) async { + Map postParams = {"P_SEARCH_USER_NAME": userId, "P_SEARCH_EMPLOYEE_DISPLAY_NAME": userName, "P_SEARCH_EMAIL_ADDRESS": email, "P_PAGE_LIMIT": 50, "P_PAGE_NUM": 1}; + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.replacementList; + }, + url, + postParams, + ); + } + + Future submitComment({ + String? comment, + String? email, + String? userId, + int? notificationId, + required String apiMode, + int? approverIndex = null, + List>? attributeData = const [], + }) async { String url = "${ApiConsts.erpRest}NOTIFICATION_ACTIONS"; Map postParams = { "P_COMMENTS": comment, @@ -707,60 +763,72 @@ class WorkListApiClient { "P_FORWARD_TO_USER_NAME": userId, "P_NOTIFICATION_ID": notificationId, "P_APPROVER_INDEX": approverIndex, - "RespondAttributeList": attributeData + "RespondAttributeList": attributeData, }; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData; + }, + url, + postParams, + ); } Future> getUserItemTypes() async { String url = "${ApiConsts.erpRest}GET_USER_ITEM_TYPES"; Map postParams = {}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.getUserItemTypesList ?? []; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getUserItemTypesList ?? []; + }, + url, + postParams, + ); } Future updateUserItemTypes(List> itemList) async { String url = "${ApiConsts.erpRest}UPDATE_USER_ITEM_TYPES"; Map postParams = {"UpdateItemTypeList": itemList}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.updateUserItemTypesList; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.updateUserItemTypesList; + }, + url, + postParams, + ); } Future getPRDetailsForPO(String poLineID) async { String url = "${ApiConsts.erpRest}GET_PR_INFORMATION"; - Map postParams = { - "P_PO_LINE_ID": poLineID, - "P_PAGE_LIMIT": 100, - "P_PAGE_NUM": 1, - }; + Map postParams = {"P_PO_LINE_ID": poLineID, "P_PAGE_LIMIT": 100, "P_PAGE_NUM": 1}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.getPRInformationList; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getPRInformationList; + }, + url, + postParams, + ); } Future?> getPaymentDetailsNotification(int? notificationId) async { String url = "${ApiConsts.erpRest}GET_PAY_REQ_NOTIFICATION_BODY"; - Map postParams = { - "P_NOTIFICATION_ID": notificationId, - "P_PAGE_LIMIT": 100, - "P_PAGE_NUM": 1, - }; - postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.getAbsenceCollectionNotificationBodyList; - }, url, postParams); + Map postParams = {"P_NOTIFICATION_ID": notificationId, "P_PAGE_LIMIT": 100, "P_PAGE_NUM": 1}; + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getAbsenceCollectionNotificationBodyList; + }, + url, + postParams, + ); } } diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index c2772b8..0214199 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -6,15 +6,15 @@ class ApiConsts { // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.201.204.101:2024"; - // static String baseUrl = "https://webservices.hmg.com"; // PreProd + static String baseUrl = "https://webservices.hmg.com"; // PreProd // static String baseUrl = "https://hmgwebservices.com"; // Live server // static String baseUrl = "https://mohemm.hmg.com"; // New Live server // - static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver + // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.20.200.111:1010/"; - // static String baseUrl = "https://webservices.hmg.com"; // PreProd + // static String baseUrl = "https://webservices.hmg.com"; // PreProd // static String baseUrl = "https://mohemm.hmg.com"; // static String baseUrl = "https://hmgwebservices.com"; // Live server @@ -66,6 +66,8 @@ class ApiConsts { static String marathonGetMarathonersCount = marathonBaseUrl + "Participant/GetRemainingParticipants"; static String marathonGetTutorial = marathonBaseUrl + "tutorial/GetTutorialNotification"; + + //DummyCards for the UI static int tabletMinLength = 500; diff --git a/lib/main.dart b/lib/main.dart index 3eabd68..39f19e5 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -19,18 +19,11 @@ import 'package:provider/provider.dart'; import 'package:provider/single_child_widget.dart'; import 'package:sizer/sizer.dart'; - // test uat account // username 199067 // pass h123456 -Logger logger = Logger( - // filter: null, // Use the default LogFilter (-> only log in debug mode) - printer: PrettyPrinter( - lineLength: 0, - ), // Use the PrettyPrinter to format and print log - // output: null, // U -); +Logger logger = Logger(printer: PrettyPrinter(lineLength: 0)); class MyHttpOverrides extends HttpOverrides { @override @@ -43,10 +36,7 @@ bool isTablet = false; Future main() async { WidgetsFlutterBinding.ensureInitialized(); - SystemChrome.setPreferredOrientations([ - DeviceOrientation.portraitUp, - DeviceOrientation.portraitDown, - ]); + SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); await EasyLocalization.ensureInitialized(); AppState().setPostParamsInitConfig(); HttpOverrides.global = MyHttpOverrides(); @@ -54,26 +44,15 @@ Future main() async { runApp( EasyLocalization( - supportedLocales: const [ - Locale('en', 'US'), - Locale('ar', 'SA'), - ], + supportedLocales: const [Locale('en', 'US'), Locale('ar', 'SA')], path: 'assets/langs', assetLoader: const CodegenLoader(), child: MultiProvider( providers: [ - ChangeNotifierProvider( - create: (_) => DashboardProviderModel(), - ), - ChangeNotifierProvider( - create: (_) => EITProviderModel(), - ), - ChangeNotifierProvider( - create: (_) => ChatProviderModel(), - ), - ChangeNotifierProvider( - create: (_) => MarathonProvider(), - ), + ChangeNotifierProvider(create: (_) => DashboardProviderModel()), + ChangeNotifierProvider(create: (_) => EITProviderModel()), + ChangeNotifierProvider(create: (_) => ChatProviderModel()), + ChangeNotifierProvider(create: (_) => MarathonProvider()), // ChangeNotifierProvider( // create: (_) => ChatCallProvider(), // ), @@ -96,30 +75,19 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return Sizer( - builder: ( - BuildContext context, - Orientation orientation, - DeviceType deviceType, - ) { + builder: (BuildContext context, Orientation orientation, DeviceType deviceType) { PostParamsModel? obj = AppState().postParamsObject; obj?.languageID = EasyLocalization.of(context)?.locale.languageCode == "ar" ? 1 : 2; AppState().setPostParamsModel(obj!); List> delegates = context.localizationDelegates; // delegates.add(GlobalMaterialLocalizations.delegate); - delegates.add( - MonthYearPickerLocalizations.delegate, - ); + delegates.add(MonthYearPickerLocalizations.delegate); return MaterialApp( navigatorKey: AppRoutes.navigatorKey, builder: (BuildContext context, Widget? child) { - return MediaQuery( - data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0), - child: child!, - ); + return MediaQuery(data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0), child: child!); }, - theme: AppTheme.getTheme( - EasyLocalization.of(context)?.locale.languageCode == "ar", - ), + theme: AppTheme.getTheme(EasyLocalization.of(context)?.locale.languageCode == "ar"), debugShowCheckedModeBanner: false, localizationsDelegates: delegates, supportedLocales: context.supportedLocales, diff --git a/lib/models/itg/itg_summary_data.dart b/lib/models/itg/itg_summary_data.dart new file mode 100644 index 0000000..7371857 --- /dev/null +++ b/lib/models/itg/itg_summary_data.dart @@ -0,0 +1,101 @@ +import 'dart:convert'; + +class ItgTimeCardSummaryData { + String? returNStatus; + String? returNMsg; + List? summeries; + List>? details; + + ItgTimeCardSummaryData({this.returNStatus, this.returNMsg, this.summeries, this.details}); + + factory ItgTimeCardSummaryData.fromRawJson(String str) => ItgTimeCardSummaryData.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory ItgTimeCardSummaryData.fromJson(Map json) => ItgTimeCardSummaryData( + returNStatus: json["returN_STATUS"], + returNMsg: json["returN_MSG"], + summeries: json["summeries"] == null ? [] : List.from(json["summeries"]!.map((x) => Summery.fromJson(x))), + details: json["details"] == null ? [] : List>.from(json["details"]!.map((x) => Map.from(x).map((k, v) => MapEntry(k, v)))), + ); + + Map toJson() => { + "returN_STATUS": returNStatus, + "returN_MSG": returNMsg, + "summeries": summeries == null ? [] : List.from(summeries!.map((x) => x.toJson())), + "details": details == null ? [] : List.from(details!.map((x) => Map.from(x).map((k, v) => MapEntry(k, v)))), + }; +} + +class Summery { + int? missinGSwipesDays; + String? scheduleDHrs; + String? actuaLHrs; + String? excesSHrs; + String? timebacKHrs; + String? shortagEHrs; + String? latEInHrs; + String? earlYOutHrs; + double? uncovereDShortageHrs; + int? sicKLeaves; + int? publiCHolidays; + int? unauthorizeDLeaves; + int? unpaiDLeaves; + int? paiDLeaves; + + Summery({ + + this.missinGSwipesDays, + this.scheduleDHrs, + this.actuaLHrs, + this.excesSHrs, + this.timebacKHrs, + this.shortagEHrs, + this.latEInHrs, + this.earlYOutHrs, + this.uncovereDShortageHrs, + this.sicKLeaves, + this.publiCHolidays, + this.unauthorizeDLeaves, + this.unpaiDLeaves, + this.paiDLeaves, + }); + + factory Summery.fromRawJson(String str) => Summery.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory Summery.fromJson(Map json) => Summery( + missinGSwipesDays: json["missinG_SWIPES_DAYS"], + scheduleDHrs: json["scheduleD_HRS"], + actuaLHrs: json["actuaL_HRS"], + excesSHrs: json["excesS_HRS"], + timebacKHrs: json["timebacK_HRS"], + shortagEHrs: json["shortagE_HRS"], + latEInHrs: json["latE_IN_HRS"], + earlYOutHrs: json["earlY_OUT_HRS"], + uncovereDShortageHrs: json["uncovereD_SHORTAGE_HRS"]?.toDouble(), + sicKLeaves: json["sicK_LEAVES"], + publiCHolidays: json["publiC_HOLIDAYS"], + unauthorizeDLeaves: json["unauthorizeD_LEAVES"], + unpaiDLeaves: json["unpaiD_LEAVES"], + paiDLeaves: json["paiD_LEAVES"], + ); + + Map toJson() => { + "missinG_SWIPES_DAYS": missinGSwipesDays, + "scheduleD_HRS": scheduleDHrs, + "actuaL_HRS": actuaLHrs, + "excesS_HRS": excesSHrs, + "timebacK_HRS": timebacKHrs, + "shortagE_HRS": shortagEHrs, + "latE_IN_HRS": latEInHrs, + "earlY_OUT_HRS": earlYOutHrs, + "uncovereD_SHORTAGE_HRS": uncovereDShortageHrs, + "sicK_LEAVES": sicKLeaves, + "publiC_HOLIDAYS": publiCHolidays, + "unauthorizeD_LEAVES": unauthorizeDLeaves, + "unpaiD_LEAVES": unpaiDLeaves, + "paiD_LEAVES": paiDLeaves, + }; +} diff --git a/lib/provider/dashboard_provider_model.dart b/lib/provider/dashboard_provider_model.dart index 9b57133..36a9f81 100644 --- a/lib/provider/dashboard_provider_model.dart +++ b/lib/provider/dashboard_provider_model.dart @@ -166,12 +166,13 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { Utils.hideLoading(context); showDialog( context: context, - builder: (cxt) => ConfirmDialog( - message: err, - onTap: () { - Navigator.pushNamedAndRemoveUntil(cxt, AppRoutes.login, (Route route) => false); - }, - ), + builder: + (cxt) => ConfirmDialog( + message: err, + onTap: () { + Navigator.pushNamedAndRemoveUntil(cxt, AppRoutes.login, (Route route) => false); + }, + ), ); }); } @@ -315,6 +316,8 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { return res; } + + void notify() { notifyListeners(); } diff --git a/lib/ui/login/verify_last_login_screen.dart b/lib/ui/login/verify_last_login_screen.dart index 9970206..faa25ac 100644 --- a/lib/ui/login/verify_last_login_screen.dart +++ b/lib/ui/login/verify_last_login_screen.dart @@ -68,17 +68,19 @@ class _VerifyLastLoginScreenState extends State { appBar: AppBar( backgroundColor: Colors.transparent, automaticallyImplyLeading: false, - title: (mobileLoginInfoListModel?.businessCardPrivilege ?? false) - ? LocaleKeys.viewBusinessCard.tr().toText12(color: MyColors.textMixColor, isUnderLine: true).onPress(() { - showMDialog(context, child: const BusinessCardDialog()); - }) - : Container(), + title: + (mobileLoginInfoListModel?.businessCardPrivilege ?? false) + ? LocaleKeys.viewBusinessCard.tr().toText12(color: MyColors.textMixColor, isUnderLine: true).onPress(() { + showMDialog(context, child: const BusinessCardDialog()); + }) + : Container(), actions: [ Center( - child: LocaleKeys.employeeDigitalID.tr().toText12(color: MyColors.textMixColor, isUnderLine: true).onPress(() { - showMDialog(context, child: EmployeeDigitialIdDialog()); - })), - 21.width + child: LocaleKeys.employeeDigitalID.tr().toText12(color: MyColors.textMixColor, isUnderLine: true).onPress(() { + showMDialog(context, child: EmployeeDigitialIdDialog()); + }), + ), + 21.width, ], ), body: Column( @@ -102,24 +104,14 @@ class _VerifyLastLoginScreenState extends State { margin: const EdgeInsets.only(top: 23, bottom: 23), alignment: Alignment.center, padding: const EdgeInsets.only(left: 17, right: 12), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - color: Colors.white, - border: Border.all( - color: const Color(0xffefefef), - width: 1, - ), - ), + decoration: BoxDecoration(borderRadius: BorderRadius.circular(10), color: Colors.white, border: Border.all(color: const Color(0xffefefef), width: 1)), child: Column( mainAxisSize: MainAxisSize.min, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, - children: [ - LocaleKeys.lastLoginDetails.tr().toText16(), - DateUtil.formatDateToDate(DateUtil.convertStringToDate(mobileLoginInfoListModel!.editedOn!), false).toText12(), - ], + children: [LocaleKeys.lastLoginDetails.tr().toText16(), DateUtil.formatDateToDate(DateUtil.convertStringToDate(mobileLoginInfoListModel!.editedOn!), false).toText12()], ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -130,7 +122,7 @@ class _VerifyLastLoginScreenState extends State { const Expanded(child: SizedBox()), DateUtil.formatDateToTime(DateUtil.convertStringToDate(mobileLoginInfoListModel!.editedOn!)).toText12(), ], - ) + ), ], ), ), @@ -141,15 +133,10 @@ class _VerifyLastLoginScreenState extends State { physics: const NeverScrollableScrollPhysics(), padding: const EdgeInsets.only(top: 9), shrinkWrap: true, - children: [ - if (!isNeedVerifyWithFaceIDAndBiometrics) getButton(3), - if (!isNeedVerifyWithFaceIDAndBiometrics) getButton(4), - getButton(2), - getButton(1), - ], - ) + children: [if (!isNeedVerifyWithFaceIDAndBiometrics) getButton(3), if (!isNeedVerifyWithFaceIDAndBiometrics) getButton(4), getButton(2), getButton(1)], + ), ], - ) + ), // else // Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ // Image.asset( @@ -187,12 +174,9 @@ class _VerifyLastLoginScreenState extends State { // ]), ], ).expanded, - DefaultButton( - LocaleKeys.useAnotherAccount.tr(), - () { - Navigator.pushNamedAndRemoveUntil(context, AppRoutes.login, (Route route) => false, arguments: false); - }, - ).insideContainer, + DefaultButton(LocaleKeys.useAnotherAccount.tr(), () { + Navigator.pushNamedAndRemoveUntil(context, AppRoutes.login, (Route route) => false, arguments: false); + }).insideContainer, ], ), ); @@ -222,14 +206,19 @@ 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'); + IOSAuthMessages iosStrings = 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', - options: const AuthenticationOptions( - useErrorDialogs: true, stickyAuth: true, biometricOnly: true, - ),authMessages: [iosStrings,const AndroidAuthMessages(),]); + authenticated = await auth.authenticate( + localizedReason: 'Scan your fingerprint to authenticate', + options: const AuthenticationOptions(useErrorDialogs: true, stickyAuth: true, biometricOnly: true), + authMessages: [iosStrings, const AndroidAuthMessages()], + ); } on PlatformException catch (e) { print(e); Utils.hideLoading(context); @@ -239,46 +228,48 @@ class _VerifyLastLoginScreenState extends State { } Widget _loginOptionButton(String _title, String _icon, int _flag, int? _loginIndex) { - bool isDisable = (_flag == 3 && !checkBiometricIsAvailable(BiometricType.face) || - _flag == 4 && !checkBiometricIsAvailable(BiometricType.fingerprint) && _flag == 4 && !checkBiometricIsAvailable(BiometricType.strong)); + bool isDisable = + (_flag == 3 && !checkBiometricIsAvailable(BiometricType.face) || + _flag == 4 && !checkBiometricIsAvailable(BiometricType.fingerprint) && _flag == 4 && !checkBiometricIsAvailable(BiometricType.strong)); return InkWell( - onTap: isDisable - ? null - : () async { - if (_flag == 0) { - setState(() { - // isMoreOption = true; - }); - } else { - if (_flag == 3 || _flag == 4) { - bool authenticateWithFaceAndTouchID = await loginWithFaceIDAndBiometrics(); - if (!authenticateWithFaceAndTouchID) { - return; - } else { - if (mobileLoginInfoListModel!.loginType == 3 || mobileLoginInfoListModel!.loginType == 4) { - // bool authenticateWithFaceAndTouchID = await loginWithFaceIDAndBiometrics(); - // if (!authenticateWithFaceAndTouchID) { - // return; - // } else { - // performApiCall(_title, _icon, _flag, isDirectLogin: true); - // } - performApiCall(_title, _icon, _flag, _flag, isDirectLogin: true); + onTap: + isDisable + ? null + : () async { + if (_flag == 0) { + setState(() { + // isMoreOption = true; + }); + } else { + if (_flag == 3 || _flag == 4) { + bool authenticateWithFaceAndTouchID = await loginWithFaceIDAndBiometrics(); + if (!authenticateWithFaceAndTouchID) { + return; } else { - isNeedVerifyWithFaceIDAndBiometrics = true; - selectedFlag = _flag; - setState(() { - return; - }); + if (mobileLoginInfoListModel!.loginType == 3 || mobileLoginInfoListModel!.loginType == 4) { + // bool authenticateWithFaceAndTouchID = await loginWithFaceIDAndBiometrics(); + // if (!authenticateWithFaceAndTouchID) { + // return; + // } else { + // performApiCall(_title, _icon, _flag, isDirectLogin: true); + // } + performApiCall(_title, _icon, _flag, _flag, isDirectLogin: true); + } else { + isNeedVerifyWithFaceIDAndBiometrics = true; + selectedFlag = _flag; + setState(() { + return; + }); + } } + } else { + if (isNeedVerifyWithFaceIDAndBiometrics) + performApiCall(_title, _icon, selectedFlag, _flag); + else + performApiCall(_title, _icon, _flag, _flag); } - } else { - if (isNeedVerifyWithFaceIDAndBiometrics) - performApiCall(_title, _icon, selectedFlag, _flag); - else - performApiCall(_title, _icon, _flag, _flag); } - } - }, + }, child: Container( padding: const EdgeInsets.only(left: 20, right: 20, bottom: 15, top: 28), decoration: BoxDecoration( @@ -289,15 +280,7 @@ class _VerifyLastLoginScreenState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - SvgPicture.asset( - _icon, - height: 38, - width: 38, - color: isDisable ? MyColors.darkTextColor.withOpacity(0.7) : null, - ), - _title.toText16(height: 20 / 16) - ], + children: [SvgPicture.asset(_icon, height: 38, width: 38, color: isDisable ? MyColors.darkTextColor.withOpacity(0.7) : null), _title.toText16(height: 20 / 16)], ), ), ); @@ -341,8 +324,12 @@ class _VerifyLastLoginScreenState extends State { await LoginApiClient().checkMobileAppVersion(); await LoginApiClient().memberLogin(AppState().getUserName!, AppState().password!); if (!isDirectLogin) { - BasicMemberInformationModel? memberInformationModel = - await LoginApiClient().mohemmSendActivationCodeByOTPNotificationType(0, AppState().memberLoginList?.pMOBILENUMBER, sendVerificationFlat, AppState().getUserName); + BasicMemberInformationModel? memberInformationModel = await LoginApiClient().mohemmSendActivationCodeByOTPNotificationType( + 0, + AppState().memberLoginList?.pMOBILENUMBER, + sendVerificationFlat, + AppState().getUserName, + ); } if (isDirectLogin) performDirectApiCall(_title, _icon, _flag, "", null); if (!isDirectLogin) Utils.hideLoading(context); @@ -355,9 +342,7 @@ class _VerifyLastLoginScreenState extends State { Utils.showLoading(context); performDirectApiCall(_title, _icon, _flag, value, _pinPutController); }, - () => { - Navigator.pop(context), - }, + () => {Navigator.pop(context)}, onResendCode: () { performApiCall(_title, _icon, _flag, sendVerificationFlat, isDirectLogin: isDirectLogin); }, @@ -373,14 +358,15 @@ class _VerifyLastLoginScreenState extends State { try { GenericResponseModel? genericResponseModel = await LoginApiClient().checkActivationCode(true, AppState().memberLoginList?.pMOBILENUMBER, value, AppState().getUserName); GenericResponseModel? genericResponseModel1 = await LoginApiClient().insertMobileLoginInfoNEW( - AppState().memberLoginList?.pEMAILADDRESS ?? "", - genericResponseModel?.pSESSIONID ?? 0, - genericResponseModel?.memberInformationList![0].eMPLOYEENAME ?? "", - _flag, - AppState().memberLoginList?.pMOBILENUMBER ?? "", - AppState().getUserName!, - AppState().getIsHuawei ? AppState().getHuaweiPushToken : mobileLoginInfoListModel!.deviceToken!, - Platform.isAndroid ? "android" : "ios"); + AppState().memberLoginList?.pEMAILADDRESS ?? "", + genericResponseModel?.pSESSIONID ?? 0, + genericResponseModel?.memberInformationList![0].eMPLOYEENAME ?? "", + _flag, + AppState().memberLoginList?.pMOBILENUMBER ?? "", + AppState().getUserName!, + AppState().getIsHuawei ? AppState().getHuaweiPushToken : mobileLoginInfoListModel!.deviceToken!, + Platform.isAndroid ? "android" : "ios", + ); AppState().setMemberInformationListModel = genericResponseModel!.memberInformationList?.first; AppState().setPrivilegeListModel = genericResponseModel!.privilegeList ?? []; if (genericResponseModel.errorMessage != null) { @@ -407,15 +393,15 @@ class _VerifyLastLoginScreenState extends State { } } -// -// formatDate(date) { -// return date; -// return DateFormat('MMM dd, yyy, kk:mm').format(date); -// } -// -// showLoader(bool isTrue) { -// setState(() { -// // isLoading = isTrue; -// }); -// } + // + // formatDate(date) { + // return date; + // return DateFormat('MMM dd, yyy, kk:mm').format(date); + // } + // + // showLoader(bool isTrue) { + // setState(() { + // // isLoading = isTrue; + // }); + // } } diff --git a/lib/ui/work_list/itg_detail_screen.dart b/lib/ui/work_list/itg_detail_screen.dart index aaef95f..dec413f 100644 --- a/lib/ui/work_list/itg_detail_screen.dart +++ b/lib/ui/work_list/itg_detail_screen.dart @@ -12,6 +12,8 @@ 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/dashboard/itg_forms_model.dart'; +import 'package:mohem_flutter_app/models/itg/itg_summary_data.dart'; import 'package:mohem_flutter_app/models/itg_forms_models/allowed_actions_model.dart'; import 'package:mohem_flutter_app/models/itg_forms_models/itg_forms_attachments_model.dart'; import 'package:mohem_flutter_app/models/itg_forms_models/itg_request_model.dart'; @@ -51,6 +53,7 @@ class _ItgDetailScreenState extends State { List itgFormAttachmentsList = []; late DashboardProviderModel providerData; + ItgTimeCardSummaryData? timeCardSummaryData; bool isAttachmentLoaded = false; @@ -73,12 +76,28 @@ class _ItgDetailScreenState extends State { Utils.showLoading(context); itgRequest = await WorkListApiClient().getITGFormDetails(requestDetails!.requestType!, requestDetails!.iD, requestDetails!.itemID, AppState().memberInformationList?.eMPLOYEENUMBER ?? ""); allowedActionList = itgRequest?.allowedActions ?? []; + if (allowedActionList.isNotEmpty) { isCloseAvailable = allowedActionList.any((element) => element.action == "CLOSE"); isApproveAvailable = itgRequest!.allowedActions!.any((element) => element.action == "Approve"); isRejectAvailable = itgRequest!.allowedActions!.any((element) => element.action == "Reject"); isGenerateAvailable = itgRequest!.allowedActions!.any((element) => element.action == "Generate"); } + + String rawDate = itgRequest!.fieldGoups![1].fields![1].value!; + String month = rawDate.split('/').first; + String year = rawDate.split('/').last; + String formattedString = "${getMonthName(month)}-$year"; + if (requestDetails!.requestType == "Timesheet Request") { + dynamic data = await WorkListApiClient().getITGTimeCardDetails("Timesheet Request", formattedString, AppState().memberInformationList?.eMPLOYEENUMBER ?? ""); + if (data != null) { + var decodedDta = jsonDecode(data); + // var decodedDta = jsonDecode( + // "{\"returN_STATUS\":\"S\",\"returN_MSG\":\"null\",\"summeries\":[{\"employeE_NUMBER\":\"410123\",\"assignmenT_NUMBER\":\"410123\",\"employeE_NAME\":\"Samiullah Abdulqadir\",\"hirE_DATE\":\"2024-07-21T00:00:00\",\"actuaL_TERMINATION_DATE\":null,\"perioD_DAYS\":31,\"schedulE_DAYS\":20,\"ofF_DAYS\":9,\"noN_SCHEDULED_DAYS\":0,\"noT_ANALAYZED_DAYS\":0,\"attendeD_DAYS\":20,\"absenT_DAYS\":0,\"missinG_SWIPES_DAYS\":0,\"scheduleD_HRS\":\"120\",\"actuaL_HRS\":\"121.96\",\"excesS_HRS\":\"2.61\",\"comP_OFF_W_HRS\":\"0\",\"comP_OFF_H_HRS\":\"0\",\"comP_OFF_N_HRS\":\"0\",\"timebacK_HRS\":\"2.61\",\"shortagE_HRS\":\".65\",\"latE_IN_HRS\":\".1\",\"earlY_OUT_HRS\":\".65\",\"uncovereD_SHORTAGE_HRS\":0.65,\"halF_DAY_LEAVES\":0,\"sicK_LEAVES\":0,\"publiC_HOLIDAYS\":2,\"worK_FROM_HOME_DAYS\":0,\"businesS_TRIPS\":0,\"unauthorizeD_LEAVES\":0,\"unpaiD_LEAVES\":0,\"paiD_LEAVES\":0}],\"details\":[{\"schedulE_DATE\":\"2025-03-01T00:00:00\",\"shifT_NAME\":\"00:00 - 00:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":null,\"shT_ACTUAL_END_DATETIME\":null,\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"00:00\",\"actuaL_HRS\":\"00:00\",\"excesS_HRS\":\"00:00\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":\"Off Shift\",\"excesS_FLAG\":\"N\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"N\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-02T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"09:58\",\"shT_ACTUAL_END_DATETIME\":\"16:01\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:03\",\"excesS_HRS\":\"00:03\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"Y\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"Y\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-03T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"10:11\",\"shT_ACTUAL_END_DATETIME\":\"16:11\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:00\",\"excesS_HRS\":\"00:00\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"N\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"N\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-04T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"10:08\",\"shT_ACTUAL_END_DATETIME\":\"16:12\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:04\",\"excesS_HRS\":\"00:04\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"Y\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"Y\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-05T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"10:09\",\"shT_ACTUAL_END_DATETIME\":\"16:12\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:03\",\"excesS_HRS\":\"00:03\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"Y\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"Y\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-06T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"09:53\",\"shT_ACTUAL_END_DATETIME\":\"15:54\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:01\",\"excesS_HRS\":\"00:01\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"Y\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"Y\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-07T00:00:00\",\"shifT_NAME\":\"00:00 - 00:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":null,\"shT_ACTUAL_END_DATETIME\":null,\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"00:00\",\"actuaL_HRS\":\"00:00\",\"excesS_HRS\":\"00:00\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":\"Off Shift\",\"excesS_FLAG\":\"N\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"N\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-08T00:00:00\",\"shifT_NAME\":\"00:00 - 00:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":null,\"shT_ACTUAL_END_DATETIME\":null,\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"00:00\",\"actuaL_HRS\":\"00:00\",\"excesS_HRS\":\"00:00\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":\"Off Shift\",\"excesS_FLAG\":\"N\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"N\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-09T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"10:06\",\"shT_ACTUAL_END_DATETIME\":\"16:08\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:02\",\"excesS_HRS\":\"00:02\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"Y\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"Y\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-10T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"11:06\",\"shT_ACTUAL_END_DATETIME\":\"17:06\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:00\",\"excesS_HRS\":\"00:00\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:06\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"N\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"N\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"Y\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-11T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"10:09\",\"shT_ACTUAL_END_DATETIME\":\"16:12\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:03\",\"excesS_HRS\":\"00:03\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"Y\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"Y\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-12T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"10:37\",\"shT_ACTUAL_END_DATETIME\":\"16:38\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:01\",\"excesS_HRS\":\"00:01\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"Y\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"Y\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-13T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"09:53\",\"shT_ACTUAL_END_DATETIME\":\"16:08\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:15\",\"excesS_HRS\":\"00:15\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"Y\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"Y\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-14T00:00:00\",\"shifT_NAME\":\"00:00 - 00:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":null,\"shT_ACTUAL_END_DATETIME\":null,\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"00:00\",\"actuaL_HRS\":\"00:00\",\"excesS_HRS\":\"00:00\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":\"Off Shift\",\"excesS_FLAG\":\"N\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"N\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-15T00:00:00\",\"shifT_NAME\":\"00:00 - 00:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":null,\"shT_ACTUAL_END_DATETIME\":null,\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"00:00\",\"actuaL_HRS\":\"00:00\",\"excesS_HRS\":\"00:00\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":\"Off Shift\",\"excesS_FLAG\":\"N\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"N\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-16T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"10:52\",\"shT_ACTUAL_END_DATETIME\":\"16:54\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:02\",\"excesS_HRS\":\"00:02\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"Y\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"Y\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-17T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"10:49\",\"shT_ACTUAL_END_DATETIME\":\"17:00\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:11\",\"excesS_HRS\":\"00:11\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"Y\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"Y\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-18T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"10:40\",\"shT_ACTUAL_END_DATETIME\":\"16:59\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:19\",\"excesS_HRS\":\"00:19\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"Y\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"Y\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-19T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"10:46\",\"shT_ACTUAL_END_DATETIME\":\"17:03\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:17\",\"excesS_HRS\":\"00:17\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"Y\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"Y\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-20T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"10:52\",\"shT_ACTUAL_END_DATETIME\":\"16:55\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:03\",\"excesS_HRS\":\"00:03\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"Y\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"Y\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-21T00:00:00\",\"shifT_NAME\":\"00:00 - 00:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":null,\"shT_ACTUAL_END_DATETIME\":null,\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"00:00\",\"actuaL_HRS\":\"00:00\",\"excesS_HRS\":\"00:00\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":\"Off Shift\",\"excesS_FLAG\":\"N\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"N\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-22T00:00:00\",\"shifT_NAME\":\"00:00 - 00:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":null,\"shT_ACTUAL_END_DATETIME\":null,\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"00:00\",\"actuaL_HRS\":\"00:00\",\"excesS_HRS\":\"00:00\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":\"Off Shift\",\"excesS_FLAG\":\"N\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"N\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-23T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"10:54\",\"shT_ACTUAL_END_DATETIME\":\"17:13\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:19\",\"excesS_HRS\":\"00:19\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"Y\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"Y\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-24T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"10:40\",\"shT_ACTUAL_END_DATETIME\":\"16:51\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:11\",\"excesS_HRS\":\"00:11\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"Y\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"Y\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-25T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"10:49\",\"shT_ACTUAL_END_DATETIME\":\"17:04\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:15\",\"excesS_HRS\":\"00:15\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"Y\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"Y\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-26T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"10:55\",\"shT_ACTUAL_END_DATETIME\":\"17:23\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:28\",\"excesS_HRS\":\"00:28\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"Y\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"Y\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-27T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"10:56\",\"shT_ACTUAL_END_DATETIME\":\"16:17\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"05:21\",\"excesS_HRS\":\"00:00\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:39\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:39\",\"remarks\":null,\"excesS_FLAG\":\"N\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"N\",\"shortagE_FLAG\":\"Y\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"Y\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-28T00:00:00\",\"shifT_NAME\":\"00:00 - 00:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":null,\"shT_ACTUAL_END_DATETIME\":null,\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"00:00\",\"actuaL_HRS\":\"00:00\",\"excesS_HRS\":\"00:00\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":\"Off Shift\",\"excesS_FLAG\":\"N\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"N\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-29T00:00:00\",\"shifT_NAME\":\"00:00 - 00:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":null,\"shT_ACTUAL_END_DATETIME\":null,\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"00:00\",\"actuaL_HRS\":\"00:00\",\"excesS_HRS\":\"00:00\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":\"Off Shift\",\"excesS_FLAG\":\"N\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"N\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-30T00:00:00\",\"shifT_NAME\":\"08:00 - 17:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"13:00 - 14:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":null,\"shT_ACTUAL_END_DATETIME\":null,\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"00:00\",\"actuaL_HRS\":\"00:00\",\"excesS_HRS\":\"00:00\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":\" From: 30-03-2025 To : 02-04-2025\\n\",\"excesS_FLAG\":\"N\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"N\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-31T00:00:00\",\"shifT_NAME\":\"08:00 - 17:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"13:00 - 14:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":null,\"shT_ACTUAL_END_DATETIME\":null,\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"00:00\",\"actuaL_HRS\":\"00:00\",\"excesS_HRS\":\"00:00\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":\" From: 30-03-2025 To : 02-04-2025\\n\",\"excesS_FLAG\":\"N\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"N\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"}]}", + // ); + timeCardSummaryData = ItgTimeCardSummaryData.fromJson(decodedDta); + } + } Utils.hideLoading(context); setState(() { controller.jumpToPage(0); @@ -90,7 +109,13 @@ class _ItgDetailScreenState extends State { } } - void getDataFromState() { + String getMonthName(String monthNumber) { + const monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; + int index = int.tryParse(monthNumber) ?? 0; + return (index >= 1 && index <= 12) ? monthNames[index - 1] : "Invalid Month"; + } + + void getDataFromState() async { if (requestDetails == null) { animationIndex = animationIndex + 1; requestDetails = AppState().requestAllList![AppState().itgWorkListIndex!]; // ModalRoute.of(context)!.settings.arguments as WorkListResponseModel; @@ -104,7 +129,6 @@ class _ItgDetailScreenState extends State { @override Widget build(BuildContext context) { getDataFromState(); - return Scaffold( appBar: AppBarWidget(context, title: LocaleKeys.details.tr()), backgroundColor: Colors.white, @@ -112,10 +136,7 @@ class _ItgDetailScreenState extends State { duration: const Duration(milliseconds: 500), switchInCurve: Curves.easeInToLinear, transitionBuilder: (Widget child, Animation animation) { - Animation custom = Tween( - begin: const Offset(1.0, 0.0), - end: Offset.zero, - ).animate(animation); + Animation custom = Tween(begin: const Offset(1.0, 0.0), end: Offset.zero).animate(animation); return ClipRect( child: SlideTransition( position: custom, @@ -132,27 +153,11 @@ class _ItgDetailScreenState extends State { Container( padding: const EdgeInsets.only(left: 21, right: 21, top: 16, bottom: 16), decoration: const BoxDecoration( - borderRadius: BorderRadius.only( - bottomLeft: Radius.circular(25), - bottomRight: Radius.circular(25), - ), - gradient: LinearGradient( - transform: GradientRotation(.83), - begin: Alignment.topRight, - end: Alignment.bottomLeft, - colors: [ - MyColors.gradiantEndColor, - MyColors.gradiantStartColor, - ], - ), + borderRadius: BorderRadius.only(bottomLeft: Radius.circular(25), bottomRight: Radius.circular(25)), + gradient: LinearGradient(transform: GradientRotation(.83), begin: Alignment.topRight, end: Alignment.bottomLeft, colors: [MyColors.gradiantEndColor, MyColors.gradiantStartColor]), ), child: Row( - children: [ - myTab(LocaleKeys.requestDetails.tr(), 0), - myTab(LocaleKeys.approvalLevel.tr(), 1), - myTab(LocaleKeys.requesterDetails.tr(), 2), - myTab(LocaleKeys.attachments.tr(), 3), - ], + children: [myTab(LocaleKeys.requestDetails.tr(), 0), myTab(LocaleKeys.approvalLevel.tr(), 1), myTab(LocaleKeys.requesterDetails.tr(), 2), myTab(LocaleKeys.attachments.tr(), 3)], ), ), PageView( @@ -167,11 +172,9 @@ class _ItgDetailScreenState extends State { fields: itgRequest?.fieldGoups?[1].fields ?? [], fieldGoups: itgRequest?.fieldGoups ?? [], taskID: itgRequest?.fieldGoups?[0].fields?[0].value ?? "", + summaryData: timeCardSummaryData, ), - ApprovalLevelfragment( - wFHistory: itgRequest?.wFHistory ?? [], - voidCallback: reloadITG, - ), + ApprovalLevelfragment(wFHistory: itgRequest?.wFHistory ?? [], voidCallback: reloadITG), RequestDetailFragment(fields: itgRequest?.fieldGoups?[0].fields ?? []), isAttachmentLoaded ? itgFormAttachmentsList.isEmpty @@ -183,72 +186,29 @@ class _ItgDetailScreenState extends State { if (isApproveAvailable || isRejectAvailable || isCloseAvailable) Container( padding: const EdgeInsets.only(top: 14, bottom: 14, left: 21, right: 21), - decoration: const BoxDecoration( - color: Colors.white, - border: Border( - top: BorderSide( - color: MyColors.lightGreyEFColor, - width: 1.0, - ), - ), - ), + decoration: const BoxDecoration(color: Colors.white, border: Border(top: BorderSide(color: MyColors.lightGreyEFColor, width: 1.0))), child: Row( children: [ - if (isRejectAvailable) - DefaultButton( - LocaleKeys.reject.tr(), - () => performAction("REJECTED"), - colors: const [ - Color(0xffE47A7E), - Color(0xffDE6D71), - ], - ).expanded, + if (isRejectAvailable) DefaultButton(LocaleKeys.reject.tr(), () => performAction("REJECTED"), colors: const [Color(0xffE47A7E), Color(0xffDE6D71)]).expanded, if (isApproveAvailable && isRejectAvailable) 8.width, - if (isApproveAvailable) - DefaultButton( - LocaleKeys.approve.tr(), - () => performAction("APPROVED"), - colors: const [ - Color(0xff28C884), - Color(0xff1BB271), - ], - ).expanded, + if (isApproveAvailable) DefaultButton(LocaleKeys.approve.tr(), () => performAction("APPROVED"), colors: const [Color(0xff28C884), Color(0xff1BB271)]).expanded, if ((isApproveAvailable || isRejectAvailable) && isGenerateAvailable) 8.width, - if (isGenerateAvailable) - DefaultButton( - LocaleKeys.generate.tr(), - () => performAction("Generate"), - colors: const [ - Color(0xff28C884), - Color(0xff1BB271), - ], - ).expanded, - if (isCloseAvailable) - DefaultButton( - LocaleKeys.ok.tr(), - () => performAction("CLOSE"), - colors: const [ - Color(0xff32D892), - Color(0xff1AB170), - ], - ).expanded, + if (isGenerateAvailable) DefaultButton(LocaleKeys.generate.tr(), () => performAction("Generate"), colors: const [Color(0xff28C884), Color(0xff1BB271)]).expanded, + if (isCloseAvailable) DefaultButton(LocaleKeys.ok.tr(), () => performAction("CLOSE"), colors: const [Color(0xff32D892), Color(0xff1AB170)]).expanded, 8.width, Container( height: 43, width: 43, - decoration: const BoxDecoration( - shape: BoxShape.circle, - color: MyColors.lightGreyE6Color, - ), + decoration: const BoxDecoration(shape: BoxShape.circle, color: MyColors.lightGreyE6Color), child: Icon(showFabOptions ? Icons.more_vert_rounded : Icons.more_horiz_rounded, color: MyColors.darkIconColor), ).onPress(() { setState(() { showFabOptions = true; }); - }) + }), ], ), - ) + ), ], ), IgnorePointer( @@ -293,21 +253,19 @@ class _ItgDetailScreenState extends State { ], ), ), - floatingActionButton: (!isApproveAvailable && !isRejectAvailable && !isCloseAvailable && !isGenerateAvailable) - ? Container( - height: 43, - width: 43, - decoration: const BoxDecoration( - shape: BoxShape.circle, - color: MyColors.lightGreyE6Color, - ), - child: Icon(showFabOptions ? Icons.more_vert_rounded : Icons.more_horiz_rounded, color: MyColors.darkIconColor), - ).onPress(() { - setState(() { - showFabOptions = true; - }); - }) - : null, + floatingActionButton: + (!isApproveAvailable && !isRejectAvailable && !isCloseAvailable && !isGenerateAvailable) + ? Container( + height: 43, + width: 43, + decoration: const BoxDecoration(shape: BoxShape.circle, color: MyColors.lightGreyE6Color), + child: Icon(showFabOptions ? Icons.more_vert_rounded : Icons.more_horiz_rounded, color: MyColors.darkIconColor), + ).onPress(() { + setState(() { + showFabOptions = true; + }); + }) + : null, ); } @@ -385,29 +343,33 @@ class _ItgDetailScreenState extends State { void handleFabAction(AllowedActions action) { switch (action.action) { case "Delegate": - showMyBottomSheet(context, + showMyBottomSheet( + context, + callBackFunc: reloadITG, + child: DelegateSheet( + title: LocaleKeys.delegate.tr(), + apiMode: action.action!, + notificationID: null, + actionHistoryList: null, + wFHistory: itgRequest?.wFHistory ?? [], callBackFunc: reloadITG, - child: DelegateSheet( - title: LocaleKeys.delegate.tr(), - apiMode: action.action!, - notificationID: null, - actionHistoryList: null, - wFHistory: itgRequest?.wFHistory ?? [], - callBackFunc: reloadITG, - )); + ), + ); break; case "RequestInformation": - showMyBottomSheet(context, + showMyBottomSheet( + context, + callBackFunc: reloadITG, + child: DelegateSheet( + title: LocaleKeys.request_info.tr(), + apiMode: action.action!, + notificationID: null, + actionHistoryList: null, + wFHistory: itgRequest?.wFHistory ?? [], callBackFunc: reloadITG, - child: DelegateSheet( - title: LocaleKeys.request_info.tr(), - apiMode: action.action!, - notificationID: null, - actionHistoryList: null, - wFHistory: itgRequest?.wFHistory ?? [], - callBackFunc: reloadITG, - )); + ), + ); break; case "Doable": performAction("APPROVED"); @@ -438,18 +400,11 @@ class _ItgDetailScreenState extends State { children: [ title.toText11(color: isSelected ? Colors.white : Colors.white.withOpacity(.74), isCenter: true), 4.height, - Container( - height: 8, - width: 8, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: isSelected ? Colors.white : Colors.transparent, - ), - ).onPress(() { + Container(height: 8, width: 8, decoration: BoxDecoration(shape: BoxShape.circle, color: isSelected ? Colors.white : Colors.transparent)).onPress(() { setState(() { showFabOptions = true; }); - }) + }), ], ).onPress(() { controller.jumpToPage(index); @@ -469,23 +424,10 @@ class _ItgDetailScreenState extends State { padding: const EdgeInsets.all(12), decoration: const BoxDecoration( shape: BoxShape.circle, - gradient: LinearGradient( - transform: GradientRotation(.46), - begin: Alignment.topRight, - end: Alignment.bottomLeft, - colors: [ - MyColors.gradiantEndColor, - MyColors.gradiantStartColor, - ], - ), + gradient: LinearGradient(transform: GradientRotation(.46), begin: Alignment.topRight, end: Alignment.bottomLeft, colors: [MyColors.gradiantEndColor, MyColors.gradiantStartColor]), ), - child: isIconAsset - ? SvgPicture.asset(icon) - : Image.memory( - base64Decode(icon), - fit: BoxFit.cover, - ), - ) + child: isIconAsset ? SvgPicture.asset(icon) : Image.memory(base64Decode(icon), fit: BoxFit.cover), + ), ], ); } @@ -493,29 +435,37 @@ class _ItgDetailScreenState extends State { void performAction(String actionMode) { showDialog( context: context, - builder: (cxt) => ITGCommentsDialog( - message: LocaleKeys.writeComment.tr(), - actionMode: actionMode, - onTap: (note) { - if (actionMode == "APPROVED") { - performApproveAction(requestDetails!.requestType!, requestDetails!.iD, requestDetails!.itemID, AppState().memberInformationList?.eMPLOYEENUMBER ?? "", note); - } else if (actionMode == "Answer") { - performAnswerAction(requestDetails!.requestType!, requestDetails!.iD, requestDetails!.itemID, AppState().memberInformationList?.eMPLOYEENUMBER ?? "", note); - } else if (actionMode == "Generate") { - performGenerateQrAction(requestDetails!.requestType!, requestDetails!.iD, requestDetails!.itemID, AppState().memberInformationList?.eMPLOYEENUMBER ?? "", note); - } else { - performRejectAction(requestDetails!.requestType!, requestDetails!.iD, requestDetails!.itemID, AppState().memberInformationList?.eMPLOYEENUMBER ?? "", note); - } - }, - ), + builder: + (cxt) => ITGCommentsDialog( + message: LocaleKeys.writeComment.tr(), + actionMode: actionMode, + onTap: (note) { + if (actionMode == "APPROVED") { + performApproveAction(requestDetails!.requestType!, requestDetails!.iD, requestDetails!.itemID, AppState().memberInformationList?.eMPLOYEENUMBER ?? "", note); + } else if (actionMode == "Answer") { + performAnswerAction(requestDetails!.requestType!, requestDetails!.iD, requestDetails!.itemID, AppState().memberInformationList?.eMPLOYEENUMBER ?? "", note); + } else if (actionMode == "Generate") { + performGenerateQrAction(requestDetails!.requestType!, requestDetails!.iD, requestDetails!.itemID, AppState().memberInformationList?.eMPLOYEENUMBER ?? "", note); + } else { + performRejectAction(requestDetails!.requestType!, requestDetails!.iD, requestDetails!.itemID, AppState().memberInformationList?.eMPLOYEENUMBER ?? "", note); + } + }, + ), ); } void performGenerateQrAction(String requestType, taskId, itemId, String employeeNumber, String comments) async { try { Utils.showLoading(context); - ITGRequest? itgRequest = - await WorkListApiClient().requestActionITGRequest(requestType, taskId, itemId, employeeNumber, "", comments, AppState().memberInformationList?.eMPLOYEEEMAILADDRESS ?? ""); + ITGRequest? itgRequest = await WorkListApiClient().requestActionITGRequest( + requestType, + taskId, + itemId, + employeeNumber, + "", + comments, + AppState().memberInformationList?.eMPLOYEEEMAILADDRESS ?? "", + ); Utils.hideLoading(context); Utils.showToast(LocaleKeys.yourChangeHasBeenSavedSuccessfully.tr()); // Navigator.pop(context, "delegate_reload"); @@ -635,11 +585,7 @@ class _ItgDetailScreenState extends State { } Widget showLoadingAnimation() { - return Lottie.asset( - 'assets/lottie/loading.json', - repeat: true, - reverse: false, - ); + return Lottie.asset('assets/lottie/loading.json', repeat: true, reverse: false); } void getItgRequestAttachments() async { diff --git a/lib/ui/work_list/itg_fragments/request_detail_fragment.dart b/lib/ui/work_list/itg_fragments/request_detail_fragment.dart index ba67ba4..f16d69c 100644 --- a/lib/ui/work_list/itg_fragments/request_detail_fragment.dart +++ b/lib/ui/work_list/itg_fragments/request_detail_fragment.dart @@ -1,150 +1 @@ -import 'package:easy_localization/easy_localization.dart'; -import 'package:flutter/material.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/itg_forms_models/field_goups_model.dart'; -import 'package:mohem_flutter_app/models/itg_forms_models/fields_model.dart'; -import 'package:mohem_flutter_app/widgets/item_detail_view_widget.dart'; - -class RequestDetailFragment extends StatelessWidget { - List fields; - List? fieldGoups; - String taskID; - - RequestDetailFragment({Key? key, this.fields = const [], this.fieldGoups = const [], this.taskID = ""}) : super(key: key); - double itemHeight = 0; - double itemWidth = 0; - - @override - Widget build(BuildContext context) { - var size = MediaQuery.of(context).size; - itemHeight = (size.height - kToolbarHeight - 24) / 9; - itemWidth = size.width / 2; - List uiList = [detailView(fields)]; - return Column( - mainAxisSize: MainAxisSize.min, - children: [ - Expanded( - child: SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.all(21), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - width: double.infinity, - // height: double.infinity, - child: fields.isEmpty - ? LocaleKeys.noDataAvailable.tr().toText16().center - : ListView( - shrinkWrap: true, - children: uiList, - ), - ), - 12.height, - if (taskID.toLowerCase().contains("vida")) - Column( - children: [ - fieldGoups![2].title!.toText14(), - 6.height, - detailView(fieldGoups![2].fields!), - 12.height, - fieldGoups![3].title!.toText14(), - 6.height, - detailView(fieldGoups![3].fields!), - 12.height, - fieldGoups![4].title!.toText14(), - 6.height, - detailView(fieldGoups![4].fields!), - ], - ) - ], - ), - ), - ), - ), - ], - ); - } - - Widget detailView(List fieldsF) { - List fields = List.from(fieldsF); - - bool isOdd = false; - if (fields.length % 2 != 0) { - isOdd = true; - fields.add(new Fields()); - } - - int descriptionFormatIndex = fields.indexWhere((element) => element.title == "Description Format" || element.title == "Description Format"); // todo add arabic in future - Widget? descriptionFormatView; - if (descriptionFormatIndex >= 0) { - Fields descriptionFormat = fields[descriptionFormatIndex]; - fields.removeAt(descriptionFormatIndex); - - descriptionFormatView = ItemDetailViewGridItem( - 2, - descriptionFormat.title, - descriptionFormat.value == null ? (descriptionFormat.multipleValue?.join(", ") ?? "") : descriptionFormat.value ?? "", - type: descriptionFormat.type, - maxLine: 0, - ); - } - - return Column( - mainAxisSize: MainAxisSize.min, - children: [ - GridView.builder( - itemCount: fields.length, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemBuilder: (context, index) { - if (fields[index].value == null) { - return ItemDetailViewGridItem( - index, - fields[index].title, - fields[index].multipleValue?.join(", ") ?? "", - isNeedToShowEmptyDivider: (fields.length == index + 1) - ? isOdd - ? true - : false - : false, - type: fields[index].type, - ); - } - return ItemDetailViewGridItem( - index, - fields[index].title, - fields[index].value ?? "", - isNeedToShowEmptyDivider: (fields.length == index + 1) - ? isOdd - ? true - : false - : false, - type: fields[index].type, - ); - }, - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, - childAspectRatio: (itemWidth / itemHeight), - ), - ), - if (descriptionFormatView != null) descriptionFormatView, - ], - ).objectContainerView(); - return ListView.separated( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemBuilder: (cxt, index) { - if (fields[index].value == null) { - return ItemDetailView(fields[index].title!, fields[index].multipleValue?.join(", ") ?? ""); - } - return ItemDetailView(fields[index].title!, fields[index].value ?? ""); - }, - separatorBuilder: (cxt, index) => 4.height, - itemCount: fields.length) - .objectContainerView(); - } -} +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.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/itg/itg_summary_data.dart'; import 'package:mohem_flutter_app/models/itg_forms_models/field_goups_model.dart'; import 'package:mohem_flutter_app/models/itg_forms_models/fields_model.dart'; import 'package:mohem_flutter_app/widgets/item_detail_view_widget.dart'; class RequestDetailFragment extends StatelessWidget { List fields; List? fieldGoups; String taskID; ItgTimeCardSummaryData? summaryData; RequestDetailFragment({Key? key, this.fields = const [], this.fieldGoups = const [], this.taskID = "", this.summaryData}) : super(key: key); double itemHeight = 0; double itemWidth = 0; @override Widget build(BuildContext context) { var size = MediaQuery.of(context).size; itemHeight = (size.height - kToolbarHeight - 24) / 9; itemWidth = size.width / 2; List uiList = [detailView(fields)]; return Column( mainAxisSize: MainAxisSize.min, children: [ Expanded( child: SingleChildScrollView( child: Padding( padding: const EdgeInsets.all(21), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( width: double.infinity, // height: double.infinity, child: fields.isEmpty ? LocaleKeys.noDataAvailable.tr().toText16().center : ListView(shrinkWrap: true, children: uiList), ), 12.height, if (taskID.toLowerCase().contains("vida")) Column( children: [ fieldGoups![2].title!.toText14(), 6.height, detailView(fieldGoups![2].fields!), 12.height, fieldGoups![3].title!.toText14(), 6.height, detailView(fieldGoups![3].fields!), 12.height, fieldGoups![4].title!.toText14(), 6.height, detailView(fieldGoups![4].fields!), ], ), if (summaryData != null && summaryData!.summeries != null && summaryData!.summeries!.isNotEmpty) buildStatsDashboard(summaryData: summaryData), ], ), ), ), ), ], ); } Widget leaveTypeHorizontalList() { return SizedBox( // height: 120, child: ListView( shrinkWrap: true, scrollDirection: Axis.vertical, physics: const NeverScrollableScrollPhysics(), padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 0), children: [ _buildLeaveTypeChip( title: 'Half-Day Leave', value: summaryData?.summeries?.first.unpaiDLeaves.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/calendar-remove.svg", ), const SizedBox(height: 12), _buildLeaveTypeChip( title: 'Unauthorised Leave', value: summaryData?.summeries?.first.unauthorizeDLeaves.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/knight-shield.svg", ), const SizedBox(height: 12), _buildLeaveTypeChip(title: 'Sick Leave', value: summaryData?.summeries?.first.sicKLeaves.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/stethoscope.svg"), const SizedBox(height: 12), _buildLeaveTypeChip(title: 'Paid Leave', value: summaryData?.summeries?.first.paiDLeaves.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/calendar.svg"), const SizedBox(height: 12), _buildLeaveTypeChip( title: 'Unpaid Leave', value: summaryData?.summeries?.first.unpaiDLeaves.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/money-not-found.svg", ), const SizedBox(height: 12), _buildLeaveTypeChip( title: 'Public Holidays', value: summaryData?.summeries?.first.publiCHolidays.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/finger-print-remove.svg", ), ], ), ); } Widget _buildLeaveTypeChip({required String title, required String value, required Color textColor, Color? valueColor, String? topIcon, String? bottomIcon, Widget? child}) { return Container( padding: const EdgeInsets.all(10), height: 110, decoration: BoxDecoration( color: const Color(0xFFEAF1F4), borderRadius: BorderRadius.circular(8), boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 8, offset: const Offset(0, 4))], ), child: child ?? Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (topIcon != null) ...[ Row(children: [Expanded(child: title.toText13(color: textColor)), SvgPicture.asset(topIcon, width: 24)]), const SizedBox(height: 21), ] else ...[ title.toText13(color: textColor), const SizedBox(height: 8), ], Row(children: [value.toText24(color: valueColor ?? textColor, isBold: true), const SizedBox(width: 10), if (bottomIcon != null) SvgPicture.asset(bottomIcon, width: 24)]), ], ), ); } Widget buildStatsDashboard({required ItgTimeCardSummaryData? summaryData}) { return Column( children: [ // First row with 2 boxes Row( children: [ buildStatBox( title: 'Missing Swipes', value: summaryData?.summeries?.first.missinGSwipesDays.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/finger-print-remove.svg", ), const SizedBox(width: 15), buildStatBox(title: 'Total Shortage', value: summaryData?.summeries?.first.shortagEHrs ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/time-quarter-pass.svg"), ], ), const SizedBox(height: 15), // Second row with 2 boxes Row( children: [ buildLateInEarlyOutBox( lateInValue: summaryData?.summeries?.first.latEInHrs ?? "0", earlyOutValue: summaryData?.summeries?.first.earlYOutHrs ?? "0", topIcon: "assets/icons/itg/coming-soon.svg", ), const SizedBox(width: 15), buildStatBox( title: 'Uncovered Shortage', value: summaryData?.summeries?.first.uncovereDShortageHrs.toString() ?? "0", textColor: const Color(0xFF3B3D4A), valueColor: const Color(0xFFEB5757), topIcon: "assets/icons/itg/time-quarter.svg", bottomIcon: "assets/icons/itg/alert.svg", ), ], ), const SizedBox(height: 15), Row( children: [ buildStatBox( title: 'Half-Day Leave', value: summaryData?.summeries?.first.unpaiDLeaves.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/calendar-remove.svg", ), const SizedBox(width: 15), buildStatBox( title: 'Unauthorised Leave', value: summaryData?.summeries?.first.unauthorizeDLeaves.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/knight-shield.svg", ), ], ), const SizedBox(height: 15), Row( children: [ buildStatBox(title: 'Sick Leave', value: summaryData?.summeries?.first.sicKLeaves.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/stethoscope.svg",), const SizedBox(width: 15), buildStatBox(title: 'Paid Leave', value: summaryData?.summeries?.first.paiDLeaves.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/calendar.svg",), ], ), const SizedBox(height: 15), Row( children: [ buildStatBox( title: 'Unpaid Leave', value: summaryData?.summeries?.first.unpaiDLeaves.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/money-not-found.svg", ), const SizedBox(width: 15), buildStatBox( title: 'Public Holidays', value: summaryData?.summeries?.first.publiCHolidays.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/finger-print-remove.svg", ), ], ), const SizedBox(height: 15), ], ); } Widget buildStatBox({required String title, required String value, required Color textColor, Color? valueColor, String? topIcon, String? bottomIcon, Widget? child}) { return Expanded( child: Container( padding: const EdgeInsets.all(10), height: 110, decoration: BoxDecoration( color: const Color(0xFFEAF1F4), borderRadius: BorderRadius.circular(8), boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 8, offset: const Offset(0, 4))], ), child: child ?? Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (topIcon != null) ...[ Row(children: [Expanded(child: title.toText13(color: textColor)), SvgPicture.asset(topIcon, width: 24)]), const SizedBox(height: 40), ] else ...[ title.toText13(color: textColor), const SizedBox(height: 8), ], Row(children: [value.toText24(color: valueColor ?? textColor, isBold: true), const SizedBox(width: 10), if (bottomIcon != null) SvgPicture.asset(bottomIcon, width: 20)]), ], ), ), ); } Widget buildLateInEarlyOutBox({required String lateInValue, required String earlyOutValue, required String topIcon}) { return buildStatBox( title: 'Late In / Early Out', textColor: const Color(0xFFEB5757), topIcon: topIcon, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row(children: ["Late In / Early Out".toText13(color: const Color(0xFF3B3D4A)), const Expanded(child: SizedBox()), SvgPicture.asset(topIcon, width: 24)]), const SizedBox(height: 22), RichText( text: TextSpan( style: const TextStyle(fontSize: 13), children: [ const TextSpan(text: 'Late In : ', style: TextStyle(color: Color(0xFF767676), fontSize: 14)), TextSpan(text: lateInValue, style: const TextStyle(color: Color(0xFF3B3D4A), fontSize: 16, fontWeight: FontWeight.w700)), ], ), ), RichText( text: TextSpan( style: const TextStyle(fontSize: 13), children: [ const TextSpan(text: 'Early Out : ', style: TextStyle(color: Color(0xFF767676), fontSize: 14)), TextSpan(text: earlyOutValue, style: const TextStyle(color: Color(0xFF3B3D4A), fontSize: 16, fontWeight: FontWeight.w700)), ], ), ), ], ), value: '', ); } Widget detailView(List fieldsF) { List fields = List.from(fieldsF); bool isOdd = false; if (fields.length % 2 != 0) { isOdd = true; fields.add(new Fields()); } int descriptionFormatIndex = fields.indexWhere((element) => element.title == "Description Format" || element.title == "Description Format"); // todo add arabic in future Widget? descriptionFormatView; if (descriptionFormatIndex >= 0) { Fields descriptionFormat = fields[descriptionFormatIndex]; fields.removeAt(descriptionFormatIndex); descriptionFormatView = ItemDetailViewGridItem( 2, descriptionFormat.title, descriptionFormat.value == null ? (descriptionFormat.multipleValue?.join(", ") ?? "") : descriptionFormat.value ?? "", type: descriptionFormat.type, maxLine: 0, ); } return Column( mainAxisSize: MainAxisSize.min, children: [ GridView.builder( itemCount: fields.length, shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemBuilder: (context, index) { if (fields[index].value == null) { return ItemDetailViewGridItem( index, fields[index].title, fields[index].multipleValue?.join(", ") ?? "", isNeedToShowEmptyDivider: (fields.length == index + 1) ? isOdd ? true : false : false, type: fields[index].type, ); } return ItemDetailViewGridItem( index, fields[index].title, fields[index].value ?? "", isNeedToShowEmptyDivider: (fields.length == index + 1) ? isOdd ? true : false : false, type: fields[index].type, ); }, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2, childAspectRatio: (itemWidth / itemHeight)), ), if (descriptionFormatView != null) descriptionFormatView, ], ).objectContainerView(); return ListView.separated( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemBuilder: (cxt, index) { if (fields[index].value == null) { return ItemDetailView(fields[index].title!, fields[index].multipleValue?.join(", ") ?? ""); } return ItemDetailView(fields[index].title!, fields[index].value ?? ""); }, separatorBuilder: (cxt, index) => 4.height, itemCount: fields.length, ).objectContainerView(); } } \ No newline at end of file diff --git a/lib/ui/work_list/work_list_screen.dart b/lib/ui/work_list/work_list_screen.dart index 6f93909..7637cd1 100644 --- a/lib/ui/work_list/work_list_screen.dart +++ b/lib/ui/work_list/work_list_screen.dart @@ -36,52 +36,95 @@ class WorkListScreen extends StatefulWidget { class _WorkListScreenState extends State { List workListItemTypes = [ WorkListItemTypeModelData( - value: 0, - name: 'HR', - fullName: LocaleKeys.humanResource.tr(), - active: false, - color: [Color(0xff32D892), Color(0xff1AB170)], - icon: "assets/images/miss_swipe.svg", - key: 'HRSSA', - disable: false), + value: 0, + name: 'HR', + fullName: LocaleKeys.humanResource.tr(), + active: false, + color: [Color(0xff32D892), Color(0xff1AB170)], + icon: "assets/images/miss_swipe.svg", + key: 'HRSSA', + disable: false, + ), WorkListItemTypeModelData( - value: 0, name: 'MR', fullName: LocaleKeys.moveOrder.tr(), active: false, color: [Color(0xff58DCFA), Color(0xff3CB9D5)], icon: "assets/images/miss_swipe.svg", key: 'INVMOA', disable: false), + value: 0, + name: 'MR', + fullName: LocaleKeys.moveOrder.tr(), + active: false, + color: [Color(0xff58DCFA), Color(0xff3CB9D5)], + icon: "assets/images/miss_swipe.svg", + key: 'INVMOA', + disable: false, + ), WorkListItemTypeModelData( - value: 0, - name: 'PR', - fullName: LocaleKeys.purchaseRequisition.tr(), - active: false, - color: [Color(0xff48EACF), Color(0xff3DCAB3)], - icon: "assets/images/miss_swipe.svg", - key: 'REQAPPRV', - disable: false), + value: 0, + name: 'PR', + fullName: LocaleKeys.purchaseRequisition.tr(), + active: false, + color: [Color(0xff48EACF), Color(0xff3DCAB3)], + icon: "assets/images/miss_swipe.svg", + key: 'REQAPPRV', + disable: false, + ), WorkListItemTypeModelData( - value: 0, - name: 'PO', - fullName: LocaleKeys.purchaseOrder.tr(), - active: false, - color: [Color(0xff5099E3), Color(0xff3670AA)], - icon: "assets/images/miss_swipe.svg", - key: 'POAPPRV', - disable: false), + value: 0, + name: 'PO', + fullName: LocaleKeys.purchaseOrder.tr(), + active: false, + color: [Color(0xff5099E3), Color(0xff3670AA)], + icon: "assets/images/miss_swipe.svg", + key: 'POAPPRV', + disable: false, + ), WorkListItemTypeModelData( - value: 0, name: 'ITG', fullName: LocaleKeys.ITGForms.tr(), active: false, color: [Color(0xffEB8C90), Color(0xffDE6C70)], icon: "assets/images/miss_swipe.svg", key: 'ITG', disable: false), + value: 0, + name: 'ITG', + fullName: LocaleKeys.ITGForms.tr(), + active: false, + color: [Color(0xffEB8C90), Color(0xffDE6C70)], + icon: "assets/images/miss_swipe.svg", + key: 'ITG', + disable: false, + ), WorkListItemTypeModelData( - value: 0, - name: 'IC', - fullName: LocaleKeys.itemCreation.tr(), - active: false, - color: [Color(0xff32D892), Color(0xff1AB170)], - icon: "assets/images/miss_swipe.svg", - key: 'INVITEM', - disable: false), + value: 0, + name: 'IC', + fullName: LocaleKeys.itemCreation.tr(), + active: false, + color: [Color(0xff32D892), Color(0xff1AB170)], + icon: "assets/images/miss_swipe.svg", + key: 'INVITEM', + disable: false, + ), WorkListItemTypeModelData( - value: 0, name: 'STAMP', fullName: LocaleKeys.stamp.tr(), active: false, color: [Color(0xff32D892), Color(0xff1AB170)], icon: "assets/images/miss_swipe.svg", key: 'STAMP', disable: false), + value: 0, + name: 'STAMP', + fullName: LocaleKeys.stamp.tr(), + active: false, + color: [Color(0xff32D892), Color(0xff1AB170)], + icon: "assets/images/miss_swipe.svg", + key: 'STAMP', + disable: false, + ), WorkListItemTypeModelData( - value: 0, name: 'COC', fullName: LocaleKeys.itemCreation.tr(), active: false, color: [Color(0xff787299), Color(0xff1AB170)], icon: "assets/images/miss_swipe.svg", key: 'COC', disable: true), + value: 0, + name: 'COC', + fullName: LocaleKeys.itemCreation.tr(), + active: false, + color: [Color(0xff787299), Color(0xff1AB170)], + icon: "assets/images/miss_swipe.svg", + key: 'COC', + disable: true, + ), WorkListItemTypeModelData( - value: 0, name: 'Payment Req', fullName: LocaleKeys.paymentRequest.tr(), active: false, color: [Color(0xff42d7bf), Color(0xff42d7bf)], icon: "assets/images/PR.svg", key: 'PAY_REQ', disable: false) - + value: 0, + name: 'Payment Req', + fullName: LocaleKeys.paymentRequest.tr(), + active: false, + color: [Color(0xff42d7bf), Color(0xff42d7bf)], + icon: "assets/images/PR.svg", + key: 'PAY_REQ', + disable: false, + ), ]; int? workListItemIndex; @@ -171,6 +214,7 @@ class _WorkListScreenState extends State { }); requestAllList = requestAllList + (itgFormsModel?.requestType![i].requestDetails ?? []); } + AppState().setRequestAllList = requestAllList; itgFormsModel?.requestType!.insert(0, RequestType(requestDetails: requestAllList, requestTypeCode: "all", requestTypeName: "All")); if ((itgFormsModel?.requestType?.length ?? 0) > 0) { @@ -199,10 +243,7 @@ class _WorkListScreenState extends State { _refreshController.refreshCompleted(); Utils.showLoading(context); pageNumber = 1; - List dataOnRefresh = await Future.wait([ - providerData.fetchWorkListCounter(context, showLoading: false), - getWorkList(showLoading: false, isCallingFromRefresh: true), - ]); + List dataOnRefresh = await Future.wait([providerData.fetchWorkListCounter(context, showLoading: false), getWorkList(showLoading: false, isCallingFromRefresh: true)]); calculateCounter(); Utils.hideLoading(context); setState(() {}); @@ -232,131 +273,137 @@ class _WorkListScreenState extends State { return Scaffold( backgroundColor: Colors.white, appBar: AppBarWidget(context, title: LocaleKeys.workList.tr(), showWorkListSettingButton: true), - body: workListItemIndex == null - ? Utils.getNoDataWidget(context) - : SizedBox( - width: double.infinity, - height: double.infinity, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - height: 40, - child: ListView.separated( - controller: _controller, - itemBuilder: (context, index) { - return Container( - padding: const EdgeInsets.only(left: 21, right: 21, top: 8, bottom: 8), - alignment: Alignment.center, - decoration: BoxDecoration(borderRadius: BorderRadius.circular(6), color: workListItemIndex == index ? MyColors.darkIconColor : MyColors.lightGreyEAColor), - child: ("${workListItemTypes[index].name} ${workListItemTypes[index].value > 0 ? "(${workListItemTypes[index].value})" : ""}") - .toText12(color: workListItemIndex == index ? MyColors.white : MyColors.black), - ).onPress(() { - if (pNotificationType != 1) { - pNotificationType = 1; - } - if (workListItemIndex != index && !workListItemTypes[index].disable) { - workListItemIndex = index; - pageNumber = 1; - if (workListItemTypes[index].value == 0) { - workList = []; - itgRequestTypeIndex = null; - } else { - workList = null; + body: + workListItemIndex == null + ? Utils.getNoDataWidget(context) + : SizedBox( + width: double.infinity, + height: double.infinity, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + height: 40, + child: ListView.separated( + controller: _controller, + itemBuilder: (context, index) { + return Container( + padding: const EdgeInsets.only(left: 21, right: 21, top: 8, bottom: 8), + alignment: Alignment.center, + decoration: BoxDecoration(borderRadius: BorderRadius.circular(6), color: workListItemIndex == index ? MyColors.darkIconColor : MyColors.lightGreyEAColor), + child: ("${workListItemTypes[index].name} ${workListItemTypes[index].value > 0 ? "(${workListItemTypes[index].value})" : ""}").toText12( + color: workListItemIndex == index ? MyColors.white : MyColors.black, + ), + ).onPress(() { + if (pNotificationType != 1) { + pNotificationType = 1; } - setState(() {}); - if (workListItemTypes[index].value > 0) { - getWorkList(); + if (workListItemIndex != index && !workListItemTypes[index].disable) { + workListItemIndex = index; + pageNumber = 1; + if (workListItemTypes[index].value == 0) { + workList = []; + itgRequestTypeIndex = null; + } else { + workList = null; + } + setState(() {}); + if (workListItemTypes[index].value > 0) { + getWorkList(); + } } - } - }); - }, - separatorBuilder: (context, index) => 8.width, - shrinkWrap: true, - itemCount: workListItemTypes.length, - scrollDirection: Axis.horizontal, - padding: const EdgeInsets.only(left: 21, right: 21), + }); + }, + separatorBuilder: (context, index) => 8.width, + shrinkWrap: true, + itemCount: workListItemTypes.length, + scrollDirection: Axis.horizontal, + padding: const EdgeInsets.only(left: 21, right: 21), + ), + ).paddingOnly(top: 21, bottom: 21), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + workListItemTypes[workListItemIndex!].fullName.toSectionHeading().paddingOnly(left: 21, right: 21), + LocaleKeys.advancedSearch + .tr() + .toText14(isUnderLine: true, color: MyColors.textMixColor) + .onPress(() { + openBottomSheet(context); + }) + .paddingOnly(left: 21, right: 21), + ], ), - ).paddingOnly(top: 21, bottom: 21), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - workListItemTypes[workListItemIndex!].fullName.toSectionHeading().paddingOnly(left: 21, right: 21), - LocaleKeys.advancedSearch.tr().toText14(isUnderLine: true, color: MyColors.textMixColor).onPress(() { - openBottomSheet(context); - }).paddingOnly(left: 21, right: 21) - ], - ), - SmartRefresher( + SmartRefresher( enablePullDown: true, enablePullUp: false, - header: const MaterialClassicHeader( - color: MyColors.gradiantEndColor, - ), + header: const MaterialClassicHeader(color: MyColors.gradiantEndColor), controller: _refreshController, onRefresh: _onRefresh, scrollController: _scrollController, child: SingleChildScrollView( physics: const BouncingScrollPhysics(), - child: itgRequestTypeIndex != null - ? Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // todo this is commented for temporary purpose, have issue when selecting any itg category and click any item showing wrong details - // SizedBox( - // height: 40, - // child: ListView.separated( - // itemBuilder: (context, index) { - // RequestType type = itgFormsModel!.requestType![index]; - // return Container( - // padding: const EdgeInsets.only(left: 21, right: 21, top: 8, bottom: 8), - // alignment: Alignment.center, - // decoration: BoxDecoration(borderRadius: BorderRadius.circular(30), color: itgRequestTypeIndex == index ? MyColors.darkIconColor : MyColors.lightGreyEAColor), - // child: ("${type.requestTypeName}").toText12(color: itgRequestTypeIndex == index ? MyColors.white : MyColors.black), - // ).onPress(() { - // if (itgRequestTypeIndex != index) { - // itgRequestTypeIndex = index; - // setState(() {}); - // } - // }); - // }, - // separatorBuilder: (context, index) => 8.width, - // shrinkWrap: true, - // itemCount: itgFormsModel?.requestType?.length ?? 0, - // scrollDirection: Axis.horizontal, - // padding: const EdgeInsets.only(left: 21, right: 21), - // ), - // ).paddingOnly(top: 16, bottom: 16), - ListView.separated( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemBuilder: (context, index) { - return itgRowItem(workListItemTypes[workListItemIndex!], itgFormsModel!.requestType![itgRequestTypeIndex!].requestDetails![index], index); - }, - separatorBuilder: (context, index) => 12.height, - itemCount: itgFormsModel!.requestType![itgRequestTypeIndex!].requestDetails?.length ?? 0, - padding: const EdgeInsets.all(21), - ), - ], - ) - : workList != null + child: + itgRequestTypeIndex != null + ? Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // todo this is commented for temporary purpose, have issue when selecting any itg category and click any item showing wrong details + // SizedBox( + // height: 40, + // child: ListView.separated( + // itemBuilder: (context, index) { + // RequestType type = itgFormsModel!.requestType![index]; + // return Container( + // padding: const EdgeInsets.only(left: 21, right: 21, top: 8, bottom: 8), + // alignment: Alignment.center, + // decoration: BoxDecoration(borderRadius: BorderRadius.circular(30), color: itgRequestTypeIndex == index ? MyColors.darkIconColor : MyColors.lightGreyEAColor), + // child: ("${type.requestTypeName}").toText12(color: itgRequestTypeIndex == index ? MyColors.white : MyColors.black), + // ).onPress(() { + // if (itgRequestTypeIndex != index) { + // itgRequestTypeIndex = index; + // setState(() {}); + // } + // }); + // }, + // separatorBuilder: (context, index) => 8.width, + // shrinkWrap: true, + // itemCount: itgFormsModel?.requestType?.length ?? 0, + // scrollDirection: Axis.horizontal, + // padding: const EdgeInsets.only(left: 21, right: 21), + // ), + // ).paddingOnly(top: 16, bottom: 16), + ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (context, index) { + return itgRowItem(workListItemTypes[workListItemIndex!], itgFormsModel!.requestType![itgRequestTypeIndex!].requestDetails![index], index); + }, + separatorBuilder: (context, index) => 12.height, + itemCount: itgFormsModel!.requestType![itgRequestTypeIndex!].requestDetails?.length ?? 0, + padding: const EdgeInsets.all(21), + ), + ], + ) + : workList != null ? ((workList!).isEmpty ? Utils.getNoDataWidget(context).paddingOnly(top: 100) : ListView.separated( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemBuilder: (context, index) { - return rowItem(workListItemTypes[workListItemIndex!], workList![index], index); - }, - separatorBuilder: (context, index) => 12.height, - itemCount: workList?.length ?? 0, - padding: const EdgeInsets.all(21), - )) + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (context, index) { + return rowItem(workListItemTypes[workListItemIndex!], workList![index], index); + }, + separatorBuilder: (context, index) => 12.height, + itemCount: workList?.length ?? 0, + padding: const EdgeInsets.all(21), + )) : const SizedBox(), - )).expanded, - ], + ), + ).expanded, + ], + ), ), - ), ); } @@ -388,13 +435,7 @@ class _WorkListScreenState extends State { decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(10), - boxShadow: [ - BoxShadow( - color: const Color(0xff000000).withOpacity(.05), - blurRadius: 26, - offset: const Offset(0, -3), - ), - ], + boxShadow: [BoxShadow(color: const Color(0xff000000).withOpacity(.05), blurRadius: 26, offset: const Offset(0, -3))], ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, @@ -509,13 +550,7 @@ class _WorkListScreenState extends State { decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(10), - boxShadow: [ - BoxShadow( - color: const Color(0xff000000).withOpacity(.05), - blurRadius: 26, - offset: const Offset(0, -3), - ), - ], + boxShadow: [BoxShadow(color: const Color(0xff000000).withOpacity(.05), blurRadius: 26, offset: const Offset(0, -3))], ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, @@ -555,10 +590,6 @@ class _WorkListScreenState extends State { } void _animateToIndex(int index, double width) { - _controller.animateTo( - index * width, - duration: const Duration(seconds: 1), - curve: Curves.fastOutSlowIn, - ); + _controller.animateTo(index * width, duration: const Duration(seconds: 1), curve: Curves.fastOutSlowIn); } } diff --git a/lib/widgets/otp_widget.dart b/lib/widgets/otp_widget.dart index 7994b1e..7196a22 100644 --- a/lib/widgets/otp_widget.dart +++ b/lib/widgets/otp_widget.dart @@ -49,23 +49,23 @@ class OTPWidget extends StatefulWidget { const OTPWidget({ Key? key, - this.maxLength: 4, + this.maxLength = 4, this.controller, - this.pinBoxWidth: 70.0, - this.pinBoxHeight: 70.0, + this.pinBoxWidth = 70.0, + this.pinBoxHeight = 70.0, this.pinTextStyle, this.onDone, - this.defaultBorderColor: Colors.black, - this.textBorderColor: Colors.black, + this.defaultBorderColor = Colors.black, + this.textBorderColor = Colors.black, this.pinTextAnimatedSwitcherTransition, - this.pinTextAnimatedSwitcherDuration: const Duration(), - this.hasError: false, - this.errorBorderColor: Colors.red, + this.pinTextAnimatedSwitcherDuration = const Duration(), + this.hasError = false, + this.errorBorderColor = Colors.red, this.onTextChanged, - this.autoFocus: false, + this.autoFocus = false, this.focusNode, - this.textDirection: TextDirection.ltr, - this.keyboardType: TextInputType.number, + this.textDirection = TextDirection.ltr, + this.keyboardType =TextInputType.number, this.pinBoxOuterPadding = const EdgeInsets.symmetric(horizontal: 4.0), this.pinBoxColor = Colors.white, this.pinBoxBorderWidth = 2.0, diff --git a/pubspec.yaml b/pubspec.yaml index 13708ea..27f23f2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -20,7 +20,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 3.7.98+3 environment: - sdk: ">=2.16.0 <3.7.0" + sdk: ^3.7.0 # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions @@ -164,6 +164,7 @@ flutter: - assets/ - assets/langs/ - assets/icons/ + - assets/icons/itg/ - assets/lottie/ - assets/audio/ - assets/json/ -- 2.30.2 From 49e520ea4b3c630f793378b7e21ae0a6be0c0574 Mon Sep 17 00:00:00 2001 From: Haroon Amjad <> Date: Thu, 1 May 2025 21:41:53 +0300 Subject: [PATCH 070/135] update --- .../offers_and_discounts/offers_and_discounts_details.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart b/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart index b4cb242..30a9fa2 100644 --- a/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart +++ b/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart @@ -76,7 +76,7 @@ class _OffersAndDiscountsDetailsState extends State { : getOffersList[0].titleEn!.toText22(isBold: true, color: const Color(0xff2B353E)).center, Html( data: AppState().isArabic(context) ? getOffersList[0].descriptionAr! : getOffersList[0].descriptionEn ?? "", - onLinkTap: (String? url, RenderContext context, Map attributes, _) { + onLinkTap: (String? url, Map attributes, _) { launchUrl(Uri.parse(url!)); }, ), -- 2.30.2 From e91b33805e06dbdb2cf5199afdb0760a4042b414 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Mon, 5 May 2025 12:00:08 +0300 Subject: [PATCH 071/135] fixes & updates, Time sheet changes, Update to stores VersionID 8.7 --- android/app/src/debug/AndroidManifest.xml | 2 +- android/app/src/main/AndroidManifest.xml | 4 ++-- ios/Runner/Info.plist | 2 +- lib/app_state/app_state.dart | 2 +- lib/provider/dashboard_provider_model.dart | 2 +- lib/ui/landing/dashboard_screen.dart | 2 +- .../offers_and_discounts_details.dart | 2 +- lib/ui/work_list/itg_detail_screen.dart | 6 +++++- lib/widgets/location/Location.dart | 2 +- pubspec.yaml | 14 +++++++------- 10 files changed, 21 insertions(+), 17 deletions(-) diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml index 11decc3..50ab38d 100644 --- a/android/app/src/debug/AndroidManifest.xml +++ b/android/app/src/debug/AndroidManifest.xml @@ -1,5 +1,5 @@ + package="com.mohem_flutter_app"> diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 8edb0f0..d6d528d 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,8 +1,8 @@ + package="com.mohem_flutter_app"> - + diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index cb62b88..01197de 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -13,7 +13,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleName - MOHEMM + MoheM CFBundlePackageType APPL CFBundleShortVersionString diff --git a/lib/app_state/app_state.dart b/lib/app_state/app_state.dart index 7269cd5..a2959ec 100644 --- a/lib/app_state/app_state.dart +++ b/lib/app_state/app_state.dart @@ -90,7 +90,7 @@ class AppState { String get getHuaweiPushToken => _huaweiPushToken; - final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 8.6, mobileType: Platform.isAndroid ? "android" : "ios"); + final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 8.7, mobileType: Platform.isAndroid ? "android" : "ios"); void setPostParamsInitConfig() { diff --git a/lib/provider/dashboard_provider_model.dart b/lib/provider/dashboard_provider_model.dart index 36a9f81..e644aa0 100644 --- a/lib/provider/dashboard_provider_model.dart +++ b/lib/provider/dashboard_provider_model.dart @@ -279,7 +279,7 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { logger.wtf(ex); isEventLoadingLoading = false; notifyListeners(); - Utils.handleException(ex, null, null); + // Utils.handleException(ex, null, null); } } diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index 4640c25..9a7c1ee 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -712,7 +712,7 @@ class _DashboardScreenState extends State with WidgetsBindingOb Widget eventActivityWidget(BuildContext context) { return (context.watch().isEventLoadingLoading) ? const MarathonBannerShimmer().paddingOnly(left: 21, right: 21, bottom: 21, top: 0) - : (context.watch().eventActivity != null && context.watch().eventActivity!.isActive ==true) + : (context.watch().eventActivity != null && context.watch().eventActivity!.isActive == true) ? const EventActivityBanner().paddingOnly(left: 21, right: 21, bottom: 21, top: 0) : const SizedBox(); } diff --git a/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart b/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart index 30a9fa2..37680f0 100644 --- a/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart +++ b/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart @@ -76,7 +76,7 @@ class _OffersAndDiscountsDetailsState extends State { : getOffersList[0].titleEn!.toText22(isBold: true, color: const Color(0xff2B353E)).center, Html( data: AppState().isArabic(context) ? getOffersList[0].descriptionAr! : getOffersList[0].descriptionEn ?? "", - onLinkTap: (String? url, Map attributes, _) { + onLinkTap: (String? url, context, Map attributes, _) { launchUrl(Uri.parse(url!)); }, ), diff --git a/lib/ui/work_list/itg_detail_screen.dart b/lib/ui/work_list/itg_detail_screen.dart index dec413f..930cfe6 100644 --- a/lib/ui/work_list/itg_detail_screen.dart +++ b/lib/ui/work_list/itg_detail_screen.dart @@ -105,7 +105,11 @@ class _ItgDetailScreenState extends State { } catch (ex) { setState(() {}); Utils.hideLoading(context); - Utils.handleException(ex, context, null); + // var decodedDta = jsonDecode( + // "{\"returN_STATUS\":\"S\",\"returN_MSG\":\"null\",\"summeries\":[{\"employeE_NUMBER\":\"410123\",\"assignmenT_NUMBER\":\"410123\",\"employeE_NAME\":\"Samiullah Abdulqadir\",\"hirE_DATE\":\"2024-07-21T00:00:00\",\"actuaL_TERMINATION_DATE\":null,\"perioD_DAYS\":31,\"schedulE_DAYS\":20,\"ofF_DAYS\":9,\"noN_SCHEDULED_DAYS\":0,\"noT_ANALAYZED_DAYS\":0,\"attendeD_DAYS\":20,\"absenT_DAYS\":0,\"missinG_SWIPES_DAYS\":0,\"scheduleD_HRS\":\"120\",\"actuaL_HRS\":\"121.96\",\"excesS_HRS\":\"2.61\",\"comP_OFF_W_HRS\":\"0\",\"comP_OFF_H_HRS\":\"0\",\"comP_OFF_N_HRS\":\"0\",\"timebacK_HRS\":\"2.61\",\"shortagE_HRS\":\".65\",\"latE_IN_HRS\":\".1\",\"earlY_OUT_HRS\":\".65\",\"uncovereD_SHORTAGE_HRS\":0.65,\"halF_DAY_LEAVES\":0,\"sicK_LEAVES\":0,\"publiC_HOLIDAYS\":2,\"worK_FROM_HOME_DAYS\":0,\"businesS_TRIPS\":0,\"unauthorizeD_LEAVES\":0,\"unpaiD_LEAVES\":0,\"paiD_LEAVES\":0}],\"details\":[{\"schedulE_DATE\":\"2025-03-01T00:00:00\",\"shifT_NAME\":\"00:00 - 00:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":null,\"shT_ACTUAL_END_DATETIME\":null,\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"00:00\",\"actuaL_HRS\":\"00:00\",\"excesS_HRS\":\"00:00\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":\"Off Shift\",\"excesS_FLAG\":\"N\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"N\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-02T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"09:58\",\"shT_ACTUAL_END_DATETIME\":\"16:01\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:03\",\"excesS_HRS\":\"00:03\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"Y\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"Y\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-03T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"10:11\",\"shT_ACTUAL_END_DATETIME\":\"16:11\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:00\",\"excesS_HRS\":\"00:00\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"N\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"N\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-04T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"10:08\",\"shT_ACTUAL_END_DATETIME\":\"16:12\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:04\",\"excesS_HRS\":\"00:04\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"Y\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"Y\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-05T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"10:09\",\"shT_ACTUAL_END_DATETIME\":\"16:12\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:03\",\"excesS_HRS\":\"00:03\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"Y\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"Y\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-06T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"09:53\",\"shT_ACTUAL_END_DATETIME\":\"15:54\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:01\",\"excesS_HRS\":\"00:01\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"Y\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"Y\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-07T00:00:00\",\"shifT_NAME\":\"00:00 - 00:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":null,\"shT_ACTUAL_END_DATETIME\":null,\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"00:00\",\"actuaL_HRS\":\"00:00\",\"excesS_HRS\":\"00:00\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":\"Off Shift\",\"excesS_FLAG\":\"N\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"N\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-08T00:00:00\",\"shifT_NAME\":\"00:00 - 00:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":null,\"shT_ACTUAL_END_DATETIME\":null,\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"00:00\",\"actuaL_HRS\":\"00:00\",\"excesS_HRS\":\"00:00\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":\"Off Shift\",\"excesS_FLAG\":\"N\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"N\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-09T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"10:06\",\"shT_ACTUAL_END_DATETIME\":\"16:08\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:02\",\"excesS_HRS\":\"00:02\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"Y\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"Y\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-10T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"11:06\",\"shT_ACTUAL_END_DATETIME\":\"17:06\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:00\",\"excesS_HRS\":\"00:00\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:06\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"N\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"N\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"Y\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-11T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"10:09\",\"shT_ACTUAL_END_DATETIME\":\"16:12\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:03\",\"excesS_HRS\":\"00:03\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"Y\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"Y\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-12T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"10:37\",\"shT_ACTUAL_END_DATETIME\":\"16:38\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:01\",\"excesS_HRS\":\"00:01\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"Y\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"Y\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-13T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"09:53\",\"shT_ACTUAL_END_DATETIME\":\"16:08\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:15\",\"excesS_HRS\":\"00:15\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"Y\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"Y\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-14T00:00:00\",\"shifT_NAME\":\"00:00 - 00:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":null,\"shT_ACTUAL_END_DATETIME\":null,\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"00:00\",\"actuaL_HRS\":\"00:00\",\"excesS_HRS\":\"00:00\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":\"Off Shift\",\"excesS_FLAG\":\"N\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"N\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-15T00:00:00\",\"shifT_NAME\":\"00:00 - 00:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":null,\"shT_ACTUAL_END_DATETIME\":null,\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"00:00\",\"actuaL_HRS\":\"00:00\",\"excesS_HRS\":\"00:00\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":\"Off Shift\",\"excesS_FLAG\":\"N\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"N\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-16T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"10:52\",\"shT_ACTUAL_END_DATETIME\":\"16:54\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:02\",\"excesS_HRS\":\"00:02\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"Y\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"Y\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-17T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"10:49\",\"shT_ACTUAL_END_DATETIME\":\"17:00\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:11\",\"excesS_HRS\":\"00:11\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"Y\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"Y\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-18T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"10:40\",\"shT_ACTUAL_END_DATETIME\":\"16:59\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:19\",\"excesS_HRS\":\"00:19\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"Y\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"Y\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-19T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"10:46\",\"shT_ACTUAL_END_DATETIME\":\"17:03\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:17\",\"excesS_HRS\":\"00:17\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"Y\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"Y\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-20T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"10:52\",\"shT_ACTUAL_END_DATETIME\":\"16:55\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:03\",\"excesS_HRS\":\"00:03\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"Y\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"Y\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-21T00:00:00\",\"shifT_NAME\":\"00:00 - 00:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":null,\"shT_ACTUAL_END_DATETIME\":null,\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"00:00\",\"actuaL_HRS\":\"00:00\",\"excesS_HRS\":\"00:00\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":\"Off Shift\",\"excesS_FLAG\":\"N\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"N\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-22T00:00:00\",\"shifT_NAME\":\"00:00 - 00:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":null,\"shT_ACTUAL_END_DATETIME\":null,\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"00:00\",\"actuaL_HRS\":\"00:00\",\"excesS_HRS\":\"00:00\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":\"Off Shift\",\"excesS_FLAG\":\"N\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"N\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-23T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"10:54\",\"shT_ACTUAL_END_DATETIME\":\"17:13\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:19\",\"excesS_HRS\":\"00:19\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"Y\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"Y\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-24T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"10:40\",\"shT_ACTUAL_END_DATETIME\":\"16:51\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:11\",\"excesS_HRS\":\"00:11\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"Y\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"Y\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-25T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"10:49\",\"shT_ACTUAL_END_DATETIME\":\"17:04\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:15\",\"excesS_HRS\":\"00:15\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"Y\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"Y\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-26T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"10:55\",\"shT_ACTUAL_END_DATETIME\":\"17:23\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"06:28\",\"excesS_HRS\":\"00:28\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":null,\"excesS_FLAG\":\"Y\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"Y\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-27T00:00:00\",\"shifT_NAME\":\"10:00 - 16:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":\"10:56\",\"shT_ACTUAL_END_DATETIME\":\"16:17\",\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"06:00\",\"actuaL_HRS\":\"05:21\",\"excesS_HRS\":\"00:00\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:39\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:39\",\"remarks\":null,\"excesS_FLAG\":\"N\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"N\",\"shortagE_FLAG\":\"Y\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"Y\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-28T00:00:00\",\"shifT_NAME\":\"00:00 - 00:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":null,\"shT_ACTUAL_END_DATETIME\":null,\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"00:00\",\"actuaL_HRS\":\"00:00\",\"excesS_HRS\":\"00:00\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":\"Off Shift\",\"excesS_FLAG\":\"N\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"N\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-29T00:00:00\",\"shifT_NAME\":\"00:00 - 00:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"00:00 - 00:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":null,\"shT_ACTUAL_END_DATETIME\":null,\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"00:00\",\"actuaL_HRS\":\"00:00\",\"excesS_HRS\":\"00:00\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":\"Off Shift\",\"excesS_FLAG\":\"N\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"N\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-30T00:00:00\",\"shifT_NAME\":\"08:00 - 17:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"13:00 - 14:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":null,\"shT_ACTUAL_END_DATETIME\":null,\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"00:00\",\"actuaL_HRS\":\"00:00\",\"excesS_HRS\":\"00:00\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":\" From: 30-03-2025 To : 02-04-2025\\n\",\"excesS_FLAG\":\"N\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"N\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"},{\"schedulE_DATE\":\"2025-03-31T00:00:00\",\"shifT_NAME\":\"08:00 - 17:00\",\"shifT_TYPE\":\"Regular\",\"breaK_NAME\":\"13:00 - 14:00\",\"actuaL_WOB_HRS\":\"00:00\",\"shT_ACTUAL_START_DATETIME\":null,\"shT_ACTUAL_END_DATETIME\":null,\"approveD_START_DATETIME\":null,\"approveD_END_DATETIME\":null,\"scheduleD_HRS\":\"00:00\",\"actuaL_HRS\":\"00:00\",\"excesS_HRS\":\"00:00\",\"comP_OFF_N_HRS\":\"00:00\",\"comP_OFF_W_HRS\":\"00:00\",\"comP_OFF_H_HRS\":\"00:00\",\"timebacK_HRS\":null,\"shortagE_HRS\":\"00:00\",\"latE_IN_HRS\":\"00:00\",\"earlY_OUT_HRS\":\"00:00\",\"remarks\":\" From: 30-03-2025 To : 02-04-2025\\n\",\"excesS_FLAG\":\"N\",\"comP_OFF_FLAG\":\"N\",\"timebacK_FLAG\":\"N\",\"shortagE_FLAG\":\"N\",\"latE_IN_FLAG\":\"N\",\"earlY_OUT_FLAG\":\"N\",\"missinG_SWIPES_FLAG\":\"N\"}]}", + // ); + // timeCardSummaryData = ItgTimeCardSummaryData.fromJson(decodedDta); + // Utils.handleException(ex, context, null); } } diff --git a/lib/widgets/location/Location.dart b/lib/widgets/location/Location.dart index 23ad0cc..fe4e976 100644 --- a/lib/widgets/location/Location.dart +++ b/lib/widgets/location/Location.dart @@ -44,7 +44,7 @@ class Location { AppPermissions.location((granted) { if (granted) { - Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.lowest, timeLimit: const Duration(seconds: 10)).then((value) { + Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.medium, timeLimit: const Duration(seconds: 10)).then((value) { done(value); }).catchError((err) { errorCallBack(); diff --git a/pubspec.yaml b/pubspec.yaml index ecaa799..4b1df68 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html #version: 3.3.01+300040 -version: 3.7.992+1 +version: 3.5.9+300069 environment: sdk: ">=2.16.0 <3.0.0" @@ -61,11 +61,11 @@ dependencies: platform_device_id: ^1.0.1 image_picker: ^0.8.5+3 file_picker: 5.2.5 - geolocator: ^9.0.2 + geolocator: ^11.1.0 month_year_picker: ^0.2.0+1 month_picker_dialog_2: ^0.5.5 -# open_file: ^3.2.1 - open_filex: ^4.6.0 + # open_file: ^3.2.1 + open_filex: ^4.4.0 wifi_iot: ^0.3.19+1 flutter_html: ^3.0.0-alpha.6 # flutter_barcode_scanner: ^2.0.0 @@ -110,13 +110,13 @@ dependencies: #Huawei Dependencies # huawei_hmsavailability: ^6.6.0+300 -# huawei_location: 6.0.0+302 + # huawei_location: 6.0.0+302 huawei_location: ^6.11.0+301 huawei_push: ^6.7.0+300 firebase_crashlytics: ^2.9.0 #Items for sale Image Carousel Slider - carousel_slider: ^5.0.0 + carousel_slider: ^4.2.1 #Huawei Specified # store_checker: ^1.1.0 @@ -228,4 +228,4 @@ flutter: # see https://flutter.dev/custom-fonts/#from-packages -# Adding this to test the push from iMac +# Adding this to test the push from iMac \ No newline at end of file -- 2.30.2 From 0e7bac455750976c1c810faf7f22480ea45d0e07 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Thu, 8 May 2025 12:08:32 +0300 Subject: [PATCH 072/135] ITG Timesheet & Approval level fixes --- lib/ui/work_list/itg_detail_screen.dart | 5 ++++- .../itg_fragments/approval_level_fragment.dart | 18 +++++++++--------- .../itg_fragments/request_detail_fragment.dart | 2 +- pubspec.yaml | 2 +- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/lib/ui/work_list/itg_detail_screen.dart b/lib/ui/work_list/itg_detail_screen.dart index 930cfe6..bbe4c3e 100644 --- a/lib/ui/work_list/itg_detail_screen.dart +++ b/lib/ui/work_list/itg_detail_screen.dart @@ -88,8 +88,9 @@ class _ItgDetailScreenState extends State { String month = rawDate.split('/').first; String year = rawDate.split('/').last; String formattedString = "${getMonthName(month)}-$year"; + if (requestDetails!.requestType == "Timesheet Request") { - dynamic data = await WorkListApiClient().getITGTimeCardDetails("Timesheet Request", formattedString, AppState().memberInformationList?.eMPLOYEENUMBER ?? ""); + dynamic data = await WorkListApiClient().getITGTimeCardDetails("Timesheet Request", formattedString, itgRequest!.fieldGoups![0].fields![1].value ?? ""); if (data != null) { var decodedDta = jsonDecode(data); // var decodedDta = jsonDecode( @@ -97,6 +98,8 @@ class _ItgDetailScreenState extends State { // ); timeCardSummaryData = ItgTimeCardSummaryData.fromJson(decodedDta); } + } else { + timeCardSummaryData = ItgTimeCardSummaryData(); } Utils.hideLoading(context); setState(() { diff --git a/lib/ui/work_list/itg_fragments/approval_level_fragment.dart b/lib/ui/work_list/itg_fragments/approval_level_fragment.dart index e617511..d7d9c7e 100644 --- a/lib/ui/work_list/itg_fragments/approval_level_fragment.dart +++ b/lib/ui/work_list/itg_fragments/approval_level_fragment.dart @@ -152,16 +152,16 @@ class ApprovalLevelfragment extends StatelessWidget { // DateTime dateTimeFrom = DateUtil.convertSimpleStringDateToDate(wFHistory[index].date!); // Duration duration = DateTime.now().difference(dateTimeFrom); // return "Action duration: " + DateUtil.formatDuration(duration); - } - else if (wFHistory[index].employeeID == AppState().memberInformationList?.eMPLOYEENUMBER) { - // if (wFHistory[index + 1].date!.isEmpty) { - // return ""; - // } - DateTime dateTimeFrom = DateUtil.convertSimpleStringDateToDate(wFHistory[index + 1].date!, isITG: true); - Duration duration = DateTime.now().difference(dateTimeFrom); - return "Action duration: " + DateUtil.formatDuration(duration); + } else if (wFHistory[index].employeeID == AppState().memberInformationList?.eMPLOYEENUMBER) { + if (wFHistory[index + 1].date!.isEmpty || wFHistory[index + 1].date! == "") { + return ""; + } else { + DateTime dateTimeFrom = DateUtil.convertSimpleStringDateToDate(wFHistory[index + 1].date!, isITG: true); + Duration duration = DateTime.now().difference(dateTimeFrom); + return "Action duration: " + DateUtil.formatDuration(duration); + } } else { - if (wFHistory[index].date!.isEmpty || wFHistory[index].action!.toLowerCase() == "NO ACTION") { + if (wFHistory[index].date!.isEmpty || wFHistory[index].action!.toLowerCase() == "NO ACTION" || wFHistory[index + 1].date! == "") { return ""; } else { DateTime dateTimeTo = DateUtil.convertSimpleStringDateToDate(wFHistory[index].date!); diff --git a/lib/ui/work_list/itg_fragments/request_detail_fragment.dart b/lib/ui/work_list/itg_fragments/request_detail_fragment.dart index f16d69c..6cd3ea5 100644 --- a/lib/ui/work_list/itg_fragments/request_detail_fragment.dart +++ b/lib/ui/work_list/itg_fragments/request_detail_fragment.dart @@ -1 +1 @@ -import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.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/itg/itg_summary_data.dart'; import 'package:mohem_flutter_app/models/itg_forms_models/field_goups_model.dart'; import 'package:mohem_flutter_app/models/itg_forms_models/fields_model.dart'; import 'package:mohem_flutter_app/widgets/item_detail_view_widget.dart'; class RequestDetailFragment extends StatelessWidget { List fields; List? fieldGoups; String taskID; ItgTimeCardSummaryData? summaryData; RequestDetailFragment({Key? key, this.fields = const [], this.fieldGoups = const [], this.taskID = "", this.summaryData}) : super(key: key); double itemHeight = 0; double itemWidth = 0; @override Widget build(BuildContext context) { var size = MediaQuery.of(context).size; itemHeight = (size.height - kToolbarHeight - 24) / 9; itemWidth = size.width / 2; List uiList = [detailView(fields)]; return Column( mainAxisSize: MainAxisSize.min, children: [ Expanded( child: SingleChildScrollView( child: Padding( padding: const EdgeInsets.all(21), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( width: double.infinity, // height: double.infinity, child: fields.isEmpty ? LocaleKeys.noDataAvailable.tr().toText16().center : ListView(shrinkWrap: true, children: uiList), ), 12.height, if (taskID.toLowerCase().contains("vida")) Column( children: [ fieldGoups![2].title!.toText14(), 6.height, detailView(fieldGoups![2].fields!), 12.height, fieldGoups![3].title!.toText14(), 6.height, detailView(fieldGoups![3].fields!), 12.height, fieldGoups![4].title!.toText14(), 6.height, detailView(fieldGoups![4].fields!), ], ), if (summaryData != null && summaryData!.summeries != null && summaryData!.summeries!.isNotEmpty) buildStatsDashboard(summaryData: summaryData), ], ), ), ), ), ], ); } Widget leaveTypeHorizontalList() { return SizedBox( // height: 120, child: ListView( shrinkWrap: true, scrollDirection: Axis.vertical, physics: const NeverScrollableScrollPhysics(), padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 0), children: [ _buildLeaveTypeChip( title: 'Half-Day Leave', value: summaryData?.summeries?.first.unpaiDLeaves.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/calendar-remove.svg", ), const SizedBox(height: 12), _buildLeaveTypeChip( title: 'Unauthorised Leave', value: summaryData?.summeries?.first.unauthorizeDLeaves.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/knight-shield.svg", ), const SizedBox(height: 12), _buildLeaveTypeChip(title: 'Sick Leave', value: summaryData?.summeries?.first.sicKLeaves.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/stethoscope.svg"), const SizedBox(height: 12), _buildLeaveTypeChip(title: 'Paid Leave', value: summaryData?.summeries?.first.paiDLeaves.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/calendar.svg"), const SizedBox(height: 12), _buildLeaveTypeChip( title: 'Unpaid Leave', value: summaryData?.summeries?.first.unpaiDLeaves.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/money-not-found.svg", ), const SizedBox(height: 12), _buildLeaveTypeChip( title: 'Public Holidays', value: summaryData?.summeries?.first.publiCHolidays.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/finger-print-remove.svg", ), ], ), ); } Widget _buildLeaveTypeChip({required String title, required String value, required Color textColor, Color? valueColor, String? topIcon, String? bottomIcon, Widget? child}) { return Container( padding: const EdgeInsets.all(10), height: 110, decoration: BoxDecoration( color: const Color(0xFFEAF1F4), borderRadius: BorderRadius.circular(8), boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 8, offset: const Offset(0, 4))], ), child: child ?? Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (topIcon != null) ...[ Row(children: [Expanded(child: title.toText13(color: textColor)), SvgPicture.asset(topIcon, width: 24)]), const SizedBox(height: 21), ] else ...[ title.toText13(color: textColor), const SizedBox(height: 8), ], Row(children: [value.toText24(color: valueColor ?? textColor, isBold: true), const SizedBox(width: 10), if (bottomIcon != null) SvgPicture.asset(bottomIcon, width: 24)]), ], ), ); } Widget buildStatsDashboard({required ItgTimeCardSummaryData? summaryData}) { return Column( children: [ // First row with 2 boxes Row( children: [ buildStatBox( title: 'Missing Swipes', value: summaryData?.summeries?.first.missinGSwipesDays.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/finger-print-remove.svg", ), const SizedBox(width: 15), buildStatBox(title: 'Total Shortage', value: summaryData?.summeries?.first.shortagEHrs ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/time-quarter-pass.svg"), ], ), const SizedBox(height: 15), // Second row with 2 boxes Row( children: [ buildLateInEarlyOutBox( lateInValue: summaryData?.summeries?.first.latEInHrs ?? "0", earlyOutValue: summaryData?.summeries?.first.earlYOutHrs ?? "0", topIcon: "assets/icons/itg/coming-soon.svg", ), const SizedBox(width: 15), buildStatBox( title: 'Uncovered Shortage', value: summaryData?.summeries?.first.uncovereDShortageHrs.toString() ?? "0", textColor: const Color(0xFF3B3D4A), valueColor: const Color(0xFFEB5757), topIcon: "assets/icons/itg/time-quarter.svg", bottomIcon: "assets/icons/itg/alert.svg", ), ], ), const SizedBox(height: 15), Row( children: [ buildStatBox( title: 'Half-Day Leave', value: summaryData?.summeries?.first.unpaiDLeaves.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/calendar-remove.svg", ), const SizedBox(width: 15), buildStatBox( title: 'Unauthorised Leave', value: summaryData?.summeries?.first.unauthorizeDLeaves.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/knight-shield.svg", ), ], ), const SizedBox(height: 15), Row( children: [ buildStatBox(title: 'Sick Leave', value: summaryData?.summeries?.first.sicKLeaves.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/stethoscope.svg",), const SizedBox(width: 15), buildStatBox(title: 'Paid Leave', value: summaryData?.summeries?.first.paiDLeaves.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/calendar.svg",), ], ), const SizedBox(height: 15), Row( children: [ buildStatBox( title: 'Unpaid Leave', value: summaryData?.summeries?.first.unpaiDLeaves.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/money-not-found.svg", ), const SizedBox(width: 15), buildStatBox( title: 'Public Holidays', value: summaryData?.summeries?.first.publiCHolidays.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/finger-print-remove.svg", ), ], ), const SizedBox(height: 15), ], ); } Widget buildStatBox({required String title, required String value, required Color textColor, Color? valueColor, String? topIcon, String? bottomIcon, Widget? child}) { return Expanded( child: Container( padding: const EdgeInsets.all(10), height: 110, decoration: BoxDecoration( color: const Color(0xFFEAF1F4), borderRadius: BorderRadius.circular(8), boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 8, offset: const Offset(0, 4))], ), child: child ?? Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (topIcon != null) ...[ Row(children: [Expanded(child: title.toText13(color: textColor)), SvgPicture.asset(topIcon, width: 24)]), const SizedBox(height: 40), ] else ...[ title.toText13(color: textColor), const SizedBox(height: 8), ], Row(children: [value.toText24(color: valueColor ?? textColor, isBold: true), const SizedBox(width: 10), if (bottomIcon != null) SvgPicture.asset(bottomIcon, width: 20)]), ], ), ), ); } Widget buildLateInEarlyOutBox({required String lateInValue, required String earlyOutValue, required String topIcon}) { return buildStatBox( title: 'Late In / Early Out', textColor: const Color(0xFFEB5757), topIcon: topIcon, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row(children: ["Late In / Early Out".toText13(color: const Color(0xFF3B3D4A)), const Expanded(child: SizedBox()), SvgPicture.asset(topIcon, width: 24)]), const SizedBox(height: 22), RichText( text: TextSpan( style: const TextStyle(fontSize: 13), children: [ const TextSpan(text: 'Late In : ', style: TextStyle(color: Color(0xFF767676), fontSize: 14)), TextSpan(text: lateInValue, style: const TextStyle(color: Color(0xFF3B3D4A), fontSize: 16, fontWeight: FontWeight.w700)), ], ), ), RichText( text: TextSpan( style: const TextStyle(fontSize: 13), children: [ const TextSpan(text: 'Early Out : ', style: TextStyle(color: Color(0xFF767676), fontSize: 14)), TextSpan(text: earlyOutValue, style: const TextStyle(color: Color(0xFF3B3D4A), fontSize: 16, fontWeight: FontWeight.w700)), ], ), ), ], ), value: '', ); } Widget detailView(List fieldsF) { List fields = List.from(fieldsF); bool isOdd = false; if (fields.length % 2 != 0) { isOdd = true; fields.add(new Fields()); } int descriptionFormatIndex = fields.indexWhere((element) => element.title == "Description Format" || element.title == "Description Format"); // todo add arabic in future Widget? descriptionFormatView; if (descriptionFormatIndex >= 0) { Fields descriptionFormat = fields[descriptionFormatIndex]; fields.removeAt(descriptionFormatIndex); descriptionFormatView = ItemDetailViewGridItem( 2, descriptionFormat.title, descriptionFormat.value == null ? (descriptionFormat.multipleValue?.join(", ") ?? "") : descriptionFormat.value ?? "", type: descriptionFormat.type, maxLine: 0, ); } return Column( mainAxisSize: MainAxisSize.min, children: [ GridView.builder( itemCount: fields.length, shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemBuilder: (context, index) { if (fields[index].value == null) { return ItemDetailViewGridItem( index, fields[index].title, fields[index].multipleValue?.join(", ") ?? "", isNeedToShowEmptyDivider: (fields.length == index + 1) ? isOdd ? true : false : false, type: fields[index].type, ); } return ItemDetailViewGridItem( index, fields[index].title, fields[index].value ?? "", isNeedToShowEmptyDivider: (fields.length == index + 1) ? isOdd ? true : false : false, type: fields[index].type, ); }, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2, childAspectRatio: (itemWidth / itemHeight)), ), if (descriptionFormatView != null) descriptionFormatView, ], ).objectContainerView(); return ListView.separated( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemBuilder: (cxt, index) { if (fields[index].value == null) { return ItemDetailView(fields[index].title!, fields[index].multipleValue?.join(", ") ?? ""); } return ItemDetailView(fields[index].title!, fields[index].value ?? ""); }, separatorBuilder: (cxt, index) => 4.height, itemCount: fields.length, ).objectContainerView(); } } \ No newline at end of file +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.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/itg/itg_summary_data.dart'; import 'package:mohem_flutter_app/models/itg_forms_models/field_goups_model.dart'; import 'package:mohem_flutter_app/models/itg_forms_models/fields_model.dart'; import 'package:mohem_flutter_app/widgets/item_detail_view_widget.dart'; class RequestDetailFragment extends StatelessWidget { List fields; List? fieldGoups; String taskID; ItgTimeCardSummaryData? summaryData; RequestDetailFragment({Key? key, this.fields = const [], this.fieldGoups = const [], this.taskID = "", this.summaryData}) : super(key: key); double itemHeight = 0; double itemWidth = 0; @override Widget build(BuildContext context) { var size = MediaQuery.of(context).size; itemHeight = (size.height - kToolbarHeight - 24) / 9; itemWidth = size.width / 2; List uiList = [detailView(fields)]; return Column( mainAxisSize: MainAxisSize.min, children: [ Expanded( child: SingleChildScrollView( child: Padding( padding: const EdgeInsets.all(21), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( width: double.infinity, // height: double.infinity, child: fields.isEmpty ? LocaleKeys.noDataAvailable.tr().toText16().center : ListView(shrinkWrap: true, children: uiList), ), 12.height, if (taskID.toLowerCase().contains("vida")) Column( children: [ fieldGoups![2].title!.toText14(), 6.height, detailView(fieldGoups![2].fields!), 12.height, fieldGoups![3].title!.toText14(), 6.height, detailView(fieldGoups![3].fields!), 12.height, fieldGoups![4].title!.toText14(), 6.height, detailView(fieldGoups![4].fields!), ], ), if (summaryData != null && summaryData!.summeries != null && summaryData!.summeries!.isNotEmpty) buildStatsDashboard(summaryData: summaryData), ], ), ), ), ), ], ); } Widget leaveTypeHorizontalList() { return SizedBox( // height: 120, child: ListView( shrinkWrap: true, scrollDirection: Axis.vertical, physics: const NeverScrollableScrollPhysics(), padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 0), children: [ _buildLeaveTypeChip( title: 'Half-Day Leave', value: summaryData?.summeries?.first.unpaiDLeaves.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/calendar-remove.svg", ), const SizedBox(height: 12), _buildLeaveTypeChip( title: 'Unauthorised Leave', value: summaryData?.summeries?.first.unauthorizeDLeaves.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/knight-shield.svg", ), const SizedBox(height: 12), _buildLeaveTypeChip(title: 'Sick Leave', value: summaryData?.summeries?.first.sicKLeaves.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/stethoscope.svg"), const SizedBox(height: 12), _buildLeaveTypeChip(title: 'Paid Leave', value: summaryData?.summeries?.first.paiDLeaves.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/calendar.svg"), const SizedBox(height: 12), _buildLeaveTypeChip( title: 'Unpaid Leave', value: summaryData?.summeries?.first.unpaiDLeaves.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/money-not-found.svg", ), const SizedBox(height: 12), _buildLeaveTypeChip( title: 'Public Holidays', value: summaryData?.summeries?.first.publiCHolidays.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/finger-print-remove.svg", ), ], ), ); } Widget _buildLeaveTypeChip({required String title, required String value, required Color textColor, Color? valueColor, String? topIcon, String? bottomIcon, Widget? child}) { return Container( padding: const EdgeInsets.all(10), height: 110, decoration: BoxDecoration( color: const Color(0xFFEAF1F4), borderRadius: BorderRadius.circular(8), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.05), blurRadius: 8, offset: const Offset(0, 4), ) ], ), child: child ?? Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ if (topIcon != null) ...[ Row( children: [ Expanded(child: title.toText13(color: textColor)), SvgPicture.asset(topIcon, width: 24), ], ), const SizedBox(height: 21), ] else ...[ title.toText13(color: textColor), const SizedBox(height: 8), ], Row(children: [value.toText24(color: valueColor ?? textColor, isBold: true), const SizedBox(width: 10), if (bottomIcon != null) SvgPicture.asset(bottomIcon, width: 24)]), ], ), ); } Widget buildStatsDashboard({required ItgTimeCardSummaryData? summaryData}) { return Column( children: [ // First row with 2 boxes Row( children: [ buildStatBox( title: 'Missing Swipes', value: summaryData?.summeries?.first.missinGSwipesDays.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/finger-print-remove.svg", ), const SizedBox(width: 15), buildStatBox(title: 'Total Shortage', value: summaryData?.summeries?.first.shortagEHrs ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/time-quarter-pass.svg"), ], ), const SizedBox(height: 15), // Second row with 2 boxes Row( children: [ buildLateInEarlyOutBox( lateInValue: summaryData?.summeries?.first.latEInHrs ?? "0", earlyOutValue: summaryData?.summeries?.first.earlYOutHrs ?? "0", topIcon: "assets/icons/itg/coming-soon.svg", ), const SizedBox(width: 15), buildStatBox( title: 'Uncovered Shortage', value: summaryData?.summeries?.first.uncovereDShortageHrs.toString() ?? "0", textColor: const Color(0xFF3B3D4A), valueColor: const Color(0xFFEB5757), topIcon: "assets/icons/itg/time-quarter.svg", bottomIcon: "assets/icons/itg/alert.svg", ), ], ), const SizedBox(height: 15), Row( children: [ buildStatBox( title: 'Half-Day Leave', value: summaryData?.summeries?.first.unpaiDLeaves.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/calendar-remove.svg", ), const SizedBox(width: 15), buildStatBox( title: 'Unauthorised Leave', value: summaryData?.summeries?.first.unauthorizeDLeaves.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/knight-shield.svg", ), ], ), const SizedBox(height: 15), Row( children: [ buildStatBox( title: 'Sick Leave', value: summaryData?.summeries?.first.sicKLeaves.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/stethoscope.svg", ), const SizedBox(width: 15), buildStatBox( title: 'Paid Leave', value: summaryData?.summeries?.first.paiDLeaves.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/calendar.svg", ), ], ), const SizedBox(height: 15), Row( children: [ buildStatBox( title: 'Unpaid Leave', value: summaryData?.summeries?.first.unpaiDLeaves.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/money-not-found.svg", ), const SizedBox(width: 15), buildStatBox( title: 'Public Holidays', value: summaryData?.summeries?.first.publiCHolidays.toString() ?? "0", textColor: const Color(0xFF3B3D4A), topIcon: "assets/icons/itg/finger-print-remove.svg", ), ], ), const SizedBox(height: 15), ], ); } Widget buildStatBox({required String title, required String value, required Color textColor, Color? valueColor, String? topIcon, String? bottomIcon, Widget? child}) { return Expanded( child: Container( padding: const EdgeInsets.all(10), height: 110, decoration: BoxDecoration( color: const Color(0xFFEAF1F4), borderRadius: BorderRadius.circular(8), boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 8, offset: const Offset(0, 4))], ), child: child ?? Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (topIcon != null) ...[ Row(children: [Expanded(child: title.toText13(color: textColor)), SvgPicture.asset(topIcon, width: 24)]), Expanded(child: SizedBox(),), ] else ...[ title.toText13(color: textColor), const SizedBox(height: 8), ], Row(children: [value.toText24(color: valueColor ?? textColor, isBold: true), const SizedBox(width: 10), if (bottomIcon != null) SvgPicture.asset(bottomIcon, width: 20)]), ], ), ), ); } Widget buildLateInEarlyOutBox({required String lateInValue, required String earlyOutValue, required String topIcon}) { return buildStatBox( title: 'Late In / Early Out', textColor: const Color(0xFFEB5757), topIcon: topIcon, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row(children: ["Late In / Early Out".toText13(color: const Color(0xFF3B3D4A)), const Expanded(child: SizedBox()), SvgPicture.asset(topIcon, width: 24)]), Expanded(child: SizedBox(),), RichText( text: TextSpan( style: const TextStyle(fontSize: 13), children: [ const TextSpan(text: 'Late In : ', style: TextStyle(color: Color(0xFF767676), fontSize: 14)), TextSpan(text: lateInValue, style: const TextStyle(color: Color(0xFF3B3D4A), fontSize: 16, fontWeight: FontWeight.w700)), ], ), ), RichText( text: TextSpan( style: const TextStyle(fontSize: 13), children: [ const TextSpan(text: 'Early Out : ', style: TextStyle(color: Color(0xFF767676), fontSize: 14)), TextSpan(text: earlyOutValue, style: const TextStyle(color: Color(0xFF3B3D4A), fontSize: 16, fontWeight: FontWeight.w700)), ], ), ), ], ), value: '', ); } Widget detailView(List fieldsF) { List fields = List.from(fieldsF); bool isOdd = false; if (fields.length % 2 != 0) { isOdd = true; fields.add(new Fields()); } int descriptionFormatIndex = fields.indexWhere((element) => element.title == "Description Format" || element.title == "Description Format"); // todo add arabic in future Widget? descriptionFormatView; if (descriptionFormatIndex >= 0) { Fields descriptionFormat = fields[descriptionFormatIndex]; fields.removeAt(descriptionFormatIndex); descriptionFormatView = ItemDetailViewGridItem( 2, descriptionFormat.title, descriptionFormat.value == null ? (descriptionFormat.multipleValue?.join(", ") ?? "") : descriptionFormat.value ?? "", type: descriptionFormat.type, maxLine: 0, ); } return Column( mainAxisSize: MainAxisSize.min, children: [ GridView.builder( itemCount: fields.length, shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemBuilder: (context, index) { if (fields[index].value == null) { return ItemDetailViewGridItem( index, fields[index].title, fields[index].multipleValue?.join(", ") ?? "", isNeedToShowEmptyDivider: (fields.length == index + 1) ? isOdd ? true : false : false, type: fields[index].type, ); } return ItemDetailViewGridItem( index, fields[index].title, fields[index].value ?? "", isNeedToShowEmptyDivider: (fields.length == index + 1) ? isOdd ? true : false : false, type: fields[index].type, ); }, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2, childAspectRatio: (itemWidth / itemHeight)), ), if (descriptionFormatView != null) descriptionFormatView, ], ).objectContainerView(); return ListView.separated( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemBuilder: (cxt, index) { if (fields[index].value == null) { return ItemDetailView(fields[index].title!, fields[index].multipleValue?.join(", ") ?? ""); } return ItemDetailView(fields[index].title!, fields[index].value ?? ""); }, separatorBuilder: (cxt, index) => 4.height, itemCount: fields.length, ).objectContainerView(); } } \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index 4b1df68..511ce1a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html #version: 3.3.01+300040 -version: 3.5.9+300069 +version: 3.6.1+300071 environment: sdk: ">=2.16.0 <3.0.0" -- 2.30.2 From 9b683235c9065ab203b56de666af10e1078a4c4b Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Sun, 11 May 2025 12:36:42 +0300 Subject: [PATCH 073/135] request information added, --- lib/api/api_client.dart | 1 + lib/ui/work_list/worklist_detail_screen.dart | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/api/api_client.dart b/lib/api/api_client.dart index e3cbee1..446905f 100644 --- a/lib/api/api_client.dart +++ b/lib/api/api_client.dart @@ -86,6 +86,7 @@ class ApiClient { var response = await postJsonForResponse(url, jsonObject, token: token, queryParameters: queryParameters, headers: _headers, retryTimes: retryTimes, isFormData: isFormData); try { if (!kReleaseMode) { + logger.i("Url: " + url); logger.i("res: " + response.body); } diff --git a/lib/ui/work_list/worklist_detail_screen.dart b/lib/ui/work_list/worklist_detail_screen.dart index 69c669f..35c0078 100644 --- a/lib/ui/work_list/worklist_detail_screen.dart +++ b/lib/ui/work_list/worklist_detail_screen.dart @@ -144,7 +144,7 @@ class _WorkListDetailScreenState extends State { getEitNotificationBody(); } else if (workListData!.rEQUESTTYPE == "CEI") { getCEINotificationBody(); - }else if (workListData!.rEQUESTTYPE == "PHONE_NUMBERS") { + } else if (workListData!.rEQUESTTYPE == "PHONE_NUMBERS") { getPhonesNotificationBody(); } else if (workListData!.rEQUESTTYPE == "BASIC_DETAILS") { getBasicDetNtfBody(); @@ -679,10 +679,12 @@ class _WorkListDetailScreenState extends State { } void performAction(String actionMode, {String? title}) { + GetActionHistoryList? object = actionHistoryList.firstWhere((element) => element.aCTIONCODE == "REQUEST_INFO"); + String question = "${object.aCTION}: ${object.nOTE}"; showDialog( context: context, builder: (BuildContext cxt) => AcceptRejectInputDialog( - message: title != null ? null : LocaleKeys.requestedItems.tr(), + message: question, title: title, notificationGetRespond: notificationNoteInput, actionMode: actionMode, @@ -1102,7 +1104,7 @@ class _WorkListDetailScreenState extends State { try { isAttachmentLoaded = false; getAttachmentList.clear(); - List _getAttachmentList = await WorkListApiClient().getAttachments(workListData!.nOTIFICATIONID!); + List _getAttachmentList = await WorkListApiClient().getAttachments(workListData!.nOTIFICATIONID!); if (!isAttachmentLoaded) { getAttachmentList = _getAttachmentList; } -- 2.30.2 From 4e2a774086204497429332f88598174bba7fe13b Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Mon, 12 May 2025 12:14:44 +0300 Subject: [PATCH 074/135] App update to stores, Version ID 8.8 --- lib/app_state/app_state.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/app_state/app_state.dart b/lib/app_state/app_state.dart index a2959ec..459a8e9 100644 --- a/lib/app_state/app_state.dart +++ b/lib/app_state/app_state.dart @@ -90,7 +90,7 @@ class AppState { String get getHuaweiPushToken => _huaweiPushToken; - final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 8.7, mobileType: Platform.isAndroid ? "android" : "ios"); + final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 8.8, mobileType: Platform.isAndroid ? "android" : "ios"); void setPostParamsInitConfig() { -- 2.30.2 From d4b7550bab843b633ccd930e51d0f6fa1cd12eea Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Sun, 18 May 2025 15:51:35 +0300 Subject: [PATCH 075/135] Worklist actions buttons updates --- lib/api/api_client.dart | 6 ++ lib/ui/work_list/worklist_detail_screen.dart | 97 +++++++++++--------- 2 files changed, 58 insertions(+), 45 deletions(-) diff --git a/lib/api/api_client.dart b/lib/api/api_client.dart index 446905f..fb415d4 100644 --- a/lib/api/api_client.dart +++ b/lib/api/api_client.dart @@ -94,6 +94,12 @@ class ApiClient { if (jsonData["IsAuthenticated"] != null) { AppState().setIsAuthenticated = jsonData["IsAuthenticated"]; } + + // if(url.contains("GetOfferDiscountsConfigData")) { + // jsonData["ErrorMessage"] = "Service Not Available"; + // jsonData["ErrorEndUserMessage"] = "Service Not Available"; + // } + if (jsonData["ErrorMessage"] == null) { return factoryConstructor(jsonData); } else { diff --git a/lib/ui/work_list/worklist_detail_screen.dart b/lib/ui/work_list/worklist_detail_screen.dart index 35c0078..45ecd4d 100644 --- a/lib/ui/work_list/worklist_detail_screen.dart +++ b/lib/ui/work_list/worklist_detail_screen.dart @@ -297,50 +297,52 @@ class _WorkListDetailScreenState extends State { ], ).expanded, if (isApproveAvailable || isRejectAvailable || isCloseAvailable) - Container( - padding: const EdgeInsets.only(top: 14, bottom: 14, left: 21, right: 21), - decoration: const BoxDecoration( - color: Colors.white, - border: Border( - top: BorderSide(color: MyColors.lightGreyEFColor, width: 1.0), + SafeArea( + child: Container( + padding: const EdgeInsets.only(top: 14, bottom: 14, left: 21, right: 21), + decoration: const BoxDecoration( + color: Colors.white, + border: Border( + top: BorderSide(color: MyColors.lightGreyEFColor, width: 1.0), + ), + ), + child: Row( + children: [ + if (isRejectAvailable) + DefaultButton( + LocaleKeys.reject.tr(), + () => performAction(rejectAction), + colors: const [Color(0xffE47A7E), Color(0xffDE6D71)], + ).expanded, + if (isApproveAvailable && isRejectAvailable) 8.width, + if (isApproveAvailable) + DefaultButton( + LocaleKeys.approve.tr(), + () => performAction(approveAction), + colors: const [Color(0xff28C884), Color(0xff1BB271)], + ).expanded, + if (isCloseAvailable) + DefaultButton( + LocaleKeys.ok.tr(), + () => performAction("CLOSE"), + colors: const [Color(0xff32D892), Color(0xff1AB170)], + ).expanded, + 8.width, + Container( + height: 43, + width: 43, + decoration: const BoxDecoration( + shape: BoxShape.circle, + color: MyColors.lightGreyE6Color, + ), + child: Icon(showFabOptions ? Icons.more_vert_rounded : Icons.more_horiz_rounded, color: MyColors.darkIconColor), + ).onPress(() { + setState(() { + showFabOptions = true; + }); + }) + ], ), - ), - child: Row( - children: [ - if (isRejectAvailable) - DefaultButton( - LocaleKeys.reject.tr(), - () => performAction(rejectAction), - colors: const [Color(0xffE47A7E), Color(0xffDE6D71)], - ).expanded, - if (isApproveAvailable && isRejectAvailable) 8.width, - if (isApproveAvailable) - DefaultButton( - LocaleKeys.approve.tr(), - () => performAction(approveAction), - colors: const [Color(0xff28C884), Color(0xff1BB271)], - ).expanded, - if (isCloseAvailable) - DefaultButton( - LocaleKeys.ok.tr(), - () => performAction("CLOSE"), - colors: const [Color(0xff32D892), Color(0xff1AB170)], - ).expanded, - 8.width, - Container( - height: 43, - width: 43, - decoration: const BoxDecoration( - shape: BoxShape.circle, - color: MyColors.lightGreyE6Color, - ), - child: Icon(showFabOptions ? Icons.more_vert_rounded : Icons.more_horiz_rounded, color: MyColors.darkIconColor), - ).onPress(() { - setState(() { - showFabOptions = true; - }); - }) - ], ), ) ], @@ -679,8 +681,13 @@ class _WorkListDetailScreenState extends State { } void performAction(String actionMode, {String? title}) { - GetActionHistoryList? object = actionHistoryList.firstWhere((element) => element.aCTIONCODE == "REQUEST_INFO"); - String question = "${object.aCTION}: ${object.nOTE}"; + String question = ""; + if (actionMode == "ANSWER_INFO") { + List list = actionHistoryList.where((element) => element.aCTIONCODE == "REQUEST_INFO").toList(); + if (list.isNotEmpty) { + question = "${list.first.aCTION}: ${list.first.nOTE}"; + } + } showDialog( context: context, builder: (BuildContext cxt) => AcceptRejectInputDialog( -- 2.30.2 From aaa4f134934821df865fb0ba82fbfe3fbd465ffc Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Sun, 18 May 2025 16:03:23 +0300 Subject: [PATCH 076/135] App update to stores, Version ID 8.9 --- lib/app_state/app_state.dart | 2 +- pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/app_state/app_state.dart b/lib/app_state/app_state.dart index 459a8e9..f8ee060 100644 --- a/lib/app_state/app_state.dart +++ b/lib/app_state/app_state.dart @@ -90,7 +90,7 @@ class AppState { String get getHuaweiPushToken => _huaweiPushToken; - final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 8.8, mobileType: Platform.isAndroid ? "android" : "ios"); + final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 8.9, mobileType: Platform.isAndroid ? "android" : "ios"); void setPostParamsInitConfig() { diff --git a/pubspec.yaml b/pubspec.yaml index 511ce1a..f4f08b1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html #version: 3.3.01+300040 -version: 3.6.1+300071 +version: 3.6.3+300073 environment: sdk: ">=2.16.0 <3.0.0" -- 2.30.2 From 3b3046804e8123a0e2b49fb246da936c07f432d8 Mon Sep 17 00:00:00 2001 From: Sultan khan Date: Tue, 17 Jun 2025 11:44:02 +0300 Subject: [PATCH 077/135] upgraded --- lib/api/chat/chat_api_client.dart | 2 +- lib/classes/consts.dart | 4 ++-- lib/dialogs/otp_dialog.dart | 4 ++-- lib/models/chat/get_user_login_token_model.dart | 8 ++++---- lib/provider/chat_provider_model.dart | 14 ++++++++++---- lib/theme/app_theme.dart | 14 +++++++------- lib/ui/attendance/monthly_attendance_screen.dart | 11 ++++++----- lib/ui/chat/chat_home.dart | 10 ++++++---- lib/ui/landing/dashboard_screen.dart | 3 ++- lib/ui/my_team/view_attendance.dart | 4 ++-- lib/widgets/image_picker.dart | 2 +- pubspec.yaml | 6 +++--- 12 files changed, 46 insertions(+), 36 deletions(-) diff --git a/lib/api/chat/chat_api_client.dart b/lib/api/chat/chat_api_client.dart index 510f6fa..a9667ec 100644 --- a/lib/api/chat/chat_api_client.dart +++ b/lib/api/chat/chat_api_client.dart @@ -28,7 +28,7 @@ class ChatApiClient { factory ChatApiClient() => _instance; Future getUserLoginToken() async { - user.UserAutoLoginModel userLoginResponse = user.UserAutoLoginModel(); + user.UserAutoLoginModel userLoginResponse = user.UserAutoLoginModel(); String? deviceToken = AppState().getIsHuawei ? AppState().getHuaweiPushToken : AppState().getDeviceToken; Response response = await ApiClient().postJsonForResponse( "${ApiConsts.chatLoginTokenUrl}externaluserlogin", diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index bee7a99..5bc445c 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -3,11 +3,11 @@ import 'package:mohem_flutter_app/ui/marathon/widgets/question_card.dart'; class ApiConsts { // static String baseUrl = "http://10.200.204.11"; // Local server // static String baseUrl = "https://erptstapp.srca.org.sa"; // SRCA server - static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver + // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.20.200.111:1010/"; // static String baseUrl = "https://webservices.hmg.com"; // PreProd - // static String baseUrl = "https://mohemm.hmg.com"; + static String baseUrl = "https://mohemm.hmg.com"; // static String baseUrl = "https://hmgwebservices.com"; // Live server static String baseUrlServices = baseUrl + "/Services/"; // server // static String baseUrlServices = "https://api.cssynapses.com/tangheem/"; // Live server diff --git a/lib/dialogs/otp_dialog.dart b/lib/dialogs/otp_dialog.dart index 1404131..6c7529a 100644 --- a/lib/dialogs/otp_dialog.dart +++ b/lib/dialogs/otp_dialog.dart @@ -203,11 +203,11 @@ class OtpDialog { ), errorBorder: OutlineInputBorder( borderRadius: const BorderRadius.all(Radius.circular(10.0)), - borderSide: BorderSide(color: Theme.of(context).errorColor), + borderSide: BorderSide(color: Colors.red), ), focusedErrorBorder: OutlineInputBorder( borderRadius: const BorderRadius.all(Radius.circular(10.0)), - borderSide: BorderSide(color: Theme.of(context).errorColor), + borderSide: BorderSide(color: Colors.red), ), ); } diff --git a/lib/models/chat/get_user_login_token_model.dart b/lib/models/chat/get_user_login_token_model.dart index 8d55461..f0620c3 100644 --- a/lib/models/chat/get_user_login_token_model.dart +++ b/lib/models/chat/get_user_login_token_model.dart @@ -5,21 +5,21 @@ UserAutoLoginModel userAutoLoginModelFromJson(String str) => UserAutoLoginModel. String userAutoLoginModelToJson(UserAutoLoginModel data) => json.encode(data.toJson()); class UserAutoLoginModel { - UserAutoLoginModel({ - this.response, - this.errorResponses, - }); + UserAutoLoginModel({this.response, this.errorResponses, this.StatusCode}); Response? response; List? errorResponses; + int? StatusCode; factory UserAutoLoginModel.fromJson(Map json) => UserAutoLoginModel( response: json["response"] == null ? null : Response.fromJson(json["response"]), + StatusCode: json["StatusCode"], errorResponses: json["errorResponses"] == null ? null : List.from(json["errorResponses"].map((x) => ErrorResponse.fromJson(x))), ); Map toJson() => { "response": response == null ? null : response!.toJson(), + "StatusCode": StatusCode, "errorResponses": errorResponses == null ? null : List.from(errorResponses!.map((x) => x.toJson())), }; } diff --git a/lib/provider/chat_provider_model.dart b/lib/provider/chat_provider_model.dart index 380278d..1ca52af 100644 --- a/lib/provider/chat_provider_model.dart +++ b/lib/provider/chat_provider_model.dart @@ -93,6 +93,12 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { Future getUserAutoLoginToken() async { userLoginToken.UserAutoLoginModel userLoginResponse = await ChatApiClient().getUserLoginToken(); + + if (userLoginResponse.StatusCode == 500) { + disbaleChatForThisUser = true; + notifyListeners(); + } + if (userLoginResponse.response != null) { AppState().setchatUserDetails = userLoginResponse; } else { @@ -399,8 +405,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { if (data.first.userChatReplyResponse != null) { if (data.first.fileTypeResponse != null) { if (data.first.userChatReplyResponse!.fileTypeId == 12 || data.first.userChatReplyResponse!.fileTypeId == 4 || data.first.userChatReplyResponse!.fileTypeId == 3) { - data.first.userChatReplyResponse!.image = - await ChatApiClient().downloadURL(fileName: data.first.userChatReplyResponse!.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 1); + data.first.userChatReplyResponse!.image = await ChatApiClient() + .downloadURL(fileName: data.first.userChatReplyResponse!.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 1); data.first.userChatReplyResponse!.isImageLoaded = true; } } @@ -476,8 +482,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { if (data.first.groupChatReplyResponse != null) { if (data.first.fileTypeResponse != null) { if (data.first.groupChatReplyResponse!.fileTypeId == 12 || data.first.groupChatReplyResponse!.fileTypeId == 4 || data.first.groupChatReplyResponse!.fileTypeId == 3) { - data.first.groupChatReplyResponse!.image = - await ChatApiClient().downloadURL(fileName: data.first.groupChatReplyResponse!.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 2); + data.first.groupChatReplyResponse!.image = await ChatApiClient() + .downloadURL(fileName: data.first.groupChatReplyResponse!.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 2); data.first.groupChatReplyResponse!.isImageLoaded = true; } } diff --git a/lib/theme/app_theme.dart b/lib/theme/app_theme.dart index f3f756f..f228600 100644 --- a/lib/theme/app_theme.dart +++ b/lib/theme/app_theme.dart @@ -18,29 +18,29 @@ class AppTheme { hintColor: Colors.grey[400], colorScheme: ColorScheme.fromSwatch(accentColor: MyColors.backgroundColor).copyWith(surfaceTint : Colors.transparent), disabledColor: Colors.grey[300], - errorColor: const Color.fromRGBO(235, 80, 60, 1.0), + // errorColor: const Color.fromRGBO(235, 80, 60, 1.0), applyElevationOverlayColor: false, scaffoldBackgroundColor: MyColors.backgroundColor, textSelectionTheme: const TextSelectionThemeData(cursorColor: Colors.grey, selectionColor: Color.fromRGBO(80, 100, 253, 0.5), selectionHandleColor: Colors.grey), canvasColor: Colors.white, - backgroundColor: const Color.fromRGBO(255, 255, 255, 1), + // backgroundColor: const Color.fromRGBO(255, 255, 255, 1), highlightColor: Colors.grey[100]!.withOpacity(0.4), splashColor: Colors.transparent, primaryColor: primaryColor, primaryColorDark: primaryColor, - toggleableActiveColor: secondaryColor, + // toggleableActiveColor: secondaryColor, indicatorColor: secondaryColor, bottomSheetTheme: const BottomSheetThemeData( backgroundColor: Color(0xFFE0E0E0), ), primaryTextTheme: const TextTheme( - bodyText2: TextStyle(color: Colors.white), + // bodyText2: TextStyle(color: Colors.white), ), iconTheme: const IconThemeData(color: MyColors.darkIconColor), textTheme: const TextTheme( - bodyText1: TextStyle(color: Colors.black, letterSpacing: 0.6), - headline1: TextStyle(color: Colors.white, letterSpacing: 0.6), - headline2: TextStyle(color: Colors.white, letterSpacing: 0.6), + // bodyText1: TextStyle(color: Colors.black, letterSpacing: 0.6), + // headline1: TextStyle(color: Colors.white, letterSpacing: 0.6), + // headline2: TextStyle(color: Colors.white, letterSpacing: 0.6), ), floatingActionButtonTheme: const FloatingActionButtonThemeData(highlightElevation: 2, disabledElevation: 0, elevation: 2), appBarTheme: AppBarTheme( diff --git a/lib/ui/attendance/monthly_attendance_screen.dart b/lib/ui/attendance/monthly_attendance_screen.dart index 821a4f0..153c999 100644 --- a/lib/ui/attendance/monthly_attendance_screen.dart +++ b/lib/ui/attendance/monthly_attendance_screen.dart @@ -117,8 +117,8 @@ class _MonthlyAttendanceScreenState extends State { initialDate: formattedDate, firstDate: DateTime(searchYear - 2), lastDate: DateTime.now(), - confirmWidget: Text(LocaleKeys.confirm.tr()), - cancelWidget: Text(LocaleKeys.cancel.tr()), + // confirmWidget: Text(LocaleKeys.confirm.tr()), + // cancelWidget: Text(LocaleKeys.cancel.tr()), ).then((selectedDate) { if (selectedDate != null) { searchMonth = getMonth(selectedDate.month); @@ -303,6 +303,7 @@ class _MonthlyAttendanceScreenState extends State { monthCellBuilder: (build, details) { if (details.date.month == formattedDate.month && details.date.year == formattedDate.year) { int val = details.date.day; + int index = val-1; //check day is off // if (getDayHoursTypeDetailsList.isNotEmpty) { // bool isDayIsOff = getDayHoursTypeDetailsList[val - 1].aTTENDEDFLAG == 'N' && getDayHoursTypeDetailsList[val - 1].dAYTYPE == 'OFF'; @@ -312,9 +313,9 @@ class _MonthlyAttendanceScreenState extends State { getDayHoursTypeDetailsList.where((GetDayHoursTypeDetailsList element) => DateFormat("MM/dd/yyyy", "en_US").parse(element.sCHEDULEDATE!).day == details.date.day).toList(); if (getDayHours.isNotEmpty) { - bool isDayIsOff = getDayHoursTypeDetailsList[0].aTTENDEDFLAG == 'N' && getDayHoursTypeDetailsList[0].dAYTYPE == 'OFF'; - bool isDayIsPresent = getDayHoursTypeDetailsList[0].aTTENDEDFLAG == 'Y'; - bool isDayIsAbsent = getDayHoursTypeDetailsList[0].aTTENDEDFLAG == 'N' && getDayHoursTypeDetailsList[0].aBSENTFLAG == 'Y'; + bool isDayIsOff = getDayHoursTypeDetailsList[index].aTTENDEDFLAG == 'N' && getDayHoursTypeDetailsList[index].dAYTYPE == 'OFF'; + bool isDayIsPresent = getDayHoursTypeDetailsList[index].aTTENDEDFLAG == 'Y'; + bool isDayIsAbsent = getDayHoursTypeDetailsList[index].aTTENDEDFLAG == 'N' && getDayHoursTypeDetailsList[index].aBSENTFLAG == 'Y'; if (isDayIsOff) { return Container( diff --git a/lib/ui/chat/chat_home.dart b/lib/ui/chat/chat_home.dart index 426c9a2..c522475 100644 --- a/lib/ui/chat/chat_home.dart +++ b/lib/ui/chat/chat_home.dart @@ -32,8 +32,11 @@ class _ChatHomeState extends State { @override void initState() { super.initState(); - data = Provider.of(context, listen: false); - data.registerEvents(); + + if (chatHubConnection.state == HubConnectionState.Connected) { + data = Provider.of(context, listen: false); + data.registerEvents(); + } } @override @@ -47,7 +50,6 @@ class _ChatHomeState extends State { data.getUserAutoLoginToken().whenComplete(() async { await data.buildHubConnection(); data.getUserRecentChats(); - }); return; } @@ -57,7 +59,7 @@ class _ChatHomeState extends State { // String isAppOpendByChat = await Utils.getStringFromPrefs("isAppOpendByChat"); // String notificationData = await Utils.getStringFromPrefs("notificationData"); // if (isAppOpendByChat != "null" || isAppOpendByChat == "true" && notificationData != "null") { - // data.openChatByNoti(context); + // data.openChatByNoti(context); // } }); } diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index 333d271..90e5ef5 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -60,10 +60,10 @@ class _DashboardScreenState extends State with WidgetsBindingOb void initState() { WidgetsBinding.instance.addObserver(this); super.initState(); + cProvider = Provider.of(context, listen: false); scheduleMicrotask(() { data = Provider.of(context, listen: false); marathonProvider = Provider.of(context, listen: false); - cProvider = Provider.of(context, listen: false); if (checkIfPrivilegedForChat()) { _bHubCon(); } @@ -117,6 +117,7 @@ class _DashboardScreenState extends State with WidgetsBindingOb } Future checkHubCon() async { + // chatHubConnection = await context.read().getHubConnection(); if (chatHubConnection.state == HubConnectionState.Connected) { await chatHubConnection.stop(); await chatHubConnection.start(); diff --git a/lib/ui/my_team/view_attendance.dart b/lib/ui/my_team/view_attendance.dart index 15c4325..cadc11d 100644 --- a/lib/ui/my_team/view_attendance.dart +++ b/lib/ui/my_team/view_attendance.dart @@ -169,8 +169,8 @@ class _ViewAttendanceState extends State { initialDate: formattedDate, firstDate: DateTime(searchYear - 2), lastDate: DateTime.now(), - confirmWidget: Text(LocaleKeys.confirm.tr()), - cancelWidget: Text(LocaleKeys.cancel.tr()), + // confirmWidget: Text(LocaleKeys.confirm.tr()), + // cancelWidget: Text(LocaleKeys.cancel.tr()), ).then( (selectedDate) { if (selectedDate != null) { diff --git a/lib/widgets/image_picker.dart b/lib/widgets/image_picker.dart index 943d68e..a5d346f 100644 --- a/lib/widgets/image_picker.dart +++ b/lib/widgets/image_picker.dart @@ -159,7 +159,7 @@ class _BottomSheet extends StatelessWidget { Widget build(BuildContext context) { return Container( padding: const EdgeInsets.symmetric(vertical: 12.0), - decoration: BoxDecoration(color: Theme.of(context).backgroundColor, borderRadius: const BorderRadius.only(topLeft: Radius.circular(16.0), topRight: Radius.circular(16.0))), + decoration: BoxDecoration( borderRadius: const BorderRadius.only(topLeft: Radius.circular(16.0), topRight: Radius.circular(16.0))), child: SafeArea( top: false, child: Column( diff --git a/pubspec.yaml b/pubspec.yaml index 4194812..bf5ea18 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -46,7 +46,7 @@ dependencies: sizer: ^2.0.15 local_auth: ^2.2.0 fluttertoast: ^8.0.8 - syncfusion_flutter_calendar: 21.2.9 + syncfusion_flutter_calendar: ^27.2.5 # flutter_calendar_carousel: ^2.1.0 pie_chart: ^5.1.0 shared_preferences: ^2.0.12 @@ -62,8 +62,8 @@ dependencies: image_picker: ^0.8.5+3 file_picker: 5.2.5 geolocator: ^9.0.2 - month_year_picker: ^0.3.0+1 - month_picker_dialog: ^2.12.0 + month_year_picker: ^0.4.0+1 + month_picker_dialog: ^3.0.0 # open_file: ^3.2.1 open_filex: ^4.4.0 wifi_iot: ^0.3.18 -- 2.30.2 From c57c22a58c1aecb51c7b666fdb18671e010e0bf8 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Sun, 29 Jun 2025 17:31:56 +0300 Subject: [PATCH 078/135] ERM Channel Text URL implemented --- lib/classes/consts.dart | 4 +- lib/models/itg/advertisement.dart | 4 + .../itg/its_add_screen_video_image.dart | 86 +++++++++++++++---- lib/ui/login/verify_last_login_screen.dart | 2 +- 4 files changed, 77 insertions(+), 19 deletions(-) diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index fea9b75..c2772b8 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -9,9 +9,9 @@ class ApiConsts { // static String baseUrl = "https://webservices.hmg.com"; // PreProd // static String baseUrl = "https://hmgwebservices.com"; // Live server - static String baseUrl = "https://mohemm.hmg.com"; // New Live server + // static String baseUrl = "https://mohemm.hmg.com"; // New Live server // - // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver + static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.20.200.111:1010/"; // static String baseUrl = "https://webservices.hmg.com"; // PreProd diff --git a/lib/models/itg/advertisement.dart b/lib/models/itg/advertisement.dart index fb172ad..002f73d 100644 --- a/lib/models/itg/advertisement.dart +++ b/lib/models/itg/advertisement.dart @@ -1,6 +1,7 @@ class Advertisement { int? advertisementId; String? advertisementTitle; + String? advertisementTitleAr; int? durationInSeconds; bool? showDelete; dynamic acknowledgment; @@ -16,6 +17,7 @@ class Advertisement { Advertisement({ this.advertisementId, this.advertisementTitle, + this.advertisementTitleAr, this.durationInSeconds, this.showDelete, this.acknowledgment, @@ -34,6 +36,7 @@ class Advertisement { Advertisement.fromJson(Map json) { advertisementId = json['advertisementId']; advertisementTitle = json['advertisementTitle']; + advertisementTitleAr = json['advertisementTitleAr']; durationInSeconds = json['durationInSeconds']; showDelete = json['showDelete']; acknowledgment = json['acknowledgment']; @@ -63,6 +66,7 @@ class Advertisement { Map data = Map(); data['advertisementId'] = this.advertisementId; data['advertisementTitle'] = this.advertisementTitle; + data['advertisementTitleAr'] = this.advertisementTitleAr; data['durationInSeconds'] = this.durationInSeconds; data['showDelete'] = this.showDelete; data['acknowledgment'] = this.acknowledgment; 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 6e1358c..99911b9 100644 --- a/lib/ui/landing/itg/its_add_screen_video_image.dart +++ b/lib/ui/landing/itg/its_add_screen_video_image.dart @@ -11,8 +11,10 @@ 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/app_bar_widget.dart'; import 'package:mohem_flutter_app/widgets/button/default_button.dart'; import 'package:mohem_flutter_app/widgets/my_video_progress_indicator.dart'; +import 'package:url_launcher/url_launcher.dart'; import 'package:video_player/video_player.dart'; class ITGAdsScreen extends StatefulWidget { @@ -31,6 +33,8 @@ class _ITGAdsScreenState extends State { bool isAudio = false; String ext = ''; + bool isTextURL = false; + // late File imageFile; late String imageUrl; ads.Advertisement? advertisementData; @@ -45,23 +49,27 @@ class _ITGAdsScreenState extends State { late CountdownTimerController timerController; void checkFileType() { - String? rFile = advertisementData!.viewAttachFileColl!.first.base64String; - try { - rFile = advertisementData!.viewAttachFileColl!.where((element) => element.languageId == AppState().getLanguageID(context)).toList().first.base64String; - } catch (ex) {} - - String? rFileExt = advertisementData!.viewAttachFileColl!.first.fileName; - ext = "." + rFileExt!.split(".").last.toLowerCase(); - if (ext == ".png" || ext == ".jpg" || ext == ".jpeg" || ext == ".gif") { - // await processImage(); - imageUrl = rFile!; - isImage = true; + if (advertisementData!.viewAttachFileColl!.first.contentType!.toLowerCase() == "text") { + isTextURL = true; } else { - if (ext == ".aac") { - isAudio = true; + String? rFile = advertisementData!.viewAttachFileColl!.first.base64String; + try { + rFile = advertisementData!.viewAttachFileColl!.where((element) => element.languageId == AppState().getLanguageID(context)).toList().first.base64String; + } catch (ex) {} + + String? rFileExt = advertisementData!.viewAttachFileColl!.first.fileName; + ext = "." + rFileExt!.split(".").last.toLowerCase(); + if (ext == ".png" || ext == ".jpg" || ext == ".jpeg" || ext == ".gif") { + // await processImage(); + imageUrl = rFile!; + isImage = true; + } else { + if (ext == ".aac") { + isAudio = true; + } + isVideo = true; + _futureController = createVideoPlayer(rFile!); } - isVideo = true; - _futureController = createVideoPlayer(rFile!); } // advertisementData?.actionButtonsColl!.forEach((element) { @@ -132,7 +140,17 @@ class _ITGAdsScreenState extends State { timerController = CountdownTimerController(endTime: DateTime.now().millisecondsSinceEpoch + 1000 * videoDuration, onEnd: onTimerEnd); } return Scaffold( - backgroundColor: Colors.black, + backgroundColor: isTextURL ? Colors.white : Colors.black, + appBar: isTextURL + ? AppBar( + centerTitle: true, + automaticallyImplyLeading: false, + backgroundColor: Colors.white, + title: (AppState().isArabic(context) ? advertisementData!.advertisementTitleAr! : advertisementData!.advertisementTitleAr!).toText24(color: MyColors.darkTextColor, isBold: true), + + //advertisementData!.viewAttachFileColl!.first.base64String!.toText24(color: MyColors.darkTextColor, isBold: true), + ) + : null, body: Stack( children: [ if (isVideo) @@ -346,6 +364,42 @@ class _ITGAdsScreenState extends State { ], ), ), + if (isTextURL) + SingleChildScrollView( + padding: const EdgeInsets.all(21), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + (AppState().isArabic(context) ? advertisementData!.viewAttachFileColl![0].base64String! : advertisementData!.viewAttachFileColl![1].base64String!) + .toText16(color: MyColors.darkTextColor), + 24.height, + ListView.separated( + itemCount: advertisementData!.actionButtonsColl?.length ?? 0, + separatorBuilder: (cxt, index) => 16.height, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + padding: EdgeInsets.zero, + itemBuilder: (cxt, index) => DefaultButton( + AppState().isArabic(context) ? advertisementData!.actionButtonsColl![index].btnTextAr : advertisementData!.actionButtonsColl![index].btnTextEn, + () async { + if (advertisementData!.actionButtonsColl![index].actionValue.toLowerCase() == "skip") { + Navigator.pop(context); + } else { + Uri uri = Uri.parse(advertisementData!.actionButtonsColl![index].iconOrImage); + if (await canLaunchUrl(uri)) { + await launchUrl(uri); + Navigator.pop(context); + } else { + Utils.showToast('Could not launch'); + } + } + }, + ), + ), + ], + ), + ), ], ), ); diff --git a/lib/ui/login/verify_last_login_screen.dart b/lib/ui/login/verify_last_login_screen.dart index 1cdab8f..05b5c35 100644 --- a/lib/ui/login/verify_last_login_screen.dart +++ b/lib/ui/login/verify_last_login_screen.dart @@ -109,7 +109,7 @@ class _VerifyLastLoginScreenState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, - children: [LocaleKeys.lastLoginDetails.tr().toText16(), DateUtil.formatDateToDate(DateUtil.convertStringToDate(mobileLoginInfoListModel!.editedOn!), false).toText12()], + children: [LocaleKeys.lastLoginDetails.tr().toText16(), DateUtil.formatDateToDate(DateUtil.convertStringToDate(mobileLoginInfoListModel!.editedOn ?? DateTime.now().toString()), false).toText12()], ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, -- 2.30.2 From dcbf7b386a611266bb251e829591ea87ddf85d93 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Mon, 7 Jul 2025 13:00:58 +0300 Subject: [PATCH 079/135] Survey link launch issue fixed, Updated to Stores VersionID 9.1 --- lib/ui/landing/itg/its_add_screen_video_image.dart | 13 ++++++++----- pubspec.yaml | 6 ++++-- 2 files changed, 12 insertions(+), 7 deletions(-) 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 99911b9..103fde1 100644 --- a/lib/ui/landing/itg/its_add_screen_video_image.dart +++ b/lib/ui/landing/itg/its_add_screen_video_image.dart @@ -387,12 +387,15 @@ class _ITGAdsScreenState extends State { Navigator.pop(context); } else { Uri uri = Uri.parse(advertisementData!.actionButtonsColl![index].iconOrImage); - if (await canLaunchUrl(uri)) { - await launchUrl(uri); - Navigator.pop(context); - } else { + // if (await canLaunchUrl(uri)) { + await launchUrl(uri, mode: LaunchMode.externalApplication).catchError((err) { + // print(err); Utils.showToast('Could not launch'); - } + }); + Navigator.pop(context); + // } else { + // Utils.showToast('Could not launch'); + // } } }, ), diff --git a/pubspec.yaml b/pubspec.yaml index f4f08b1..9f35f3b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,8 +16,9 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -#version: 3.3.01+300040 -version: 3.6.3+300073 + +version: 3.6.6+300076 +#version: 3.8.999+2 environment: sdk: ">=2.16.0 <3.0.0" @@ -64,6 +65,7 @@ dependencies: geolocator: ^11.1.0 month_year_picker: ^0.2.0+1 month_picker_dialog_2: ^0.5.5 +# month_picker_dialog: ^6.2.3 # open_file: ^3.2.1 open_filex: ^4.4.0 wifi_iot: ^0.3.19+1 -- 2.30.2 From cd36d61640288619fb349839340010c7617da33b Mon Sep 17 00:00:00 2001 From: Aamir Muhammad Date: Tue, 15 Jul 2025 10:34:01 +0300 Subject: [PATCH 080/135] logins apis --- android/app/build.gradle | 49 +- android/build.gradle | 108 +++- android/gradle.properties | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 4 +- android/settings.gradle | 49 +- ios/Runner.xcodeproj/project.pbxproj | 36 +- .../xcshareddata/xcschemes/Runner.xcscheme | 3 + lib/api/dashboard_api_client.dart | 58 +- lib/classes/consts.dart | 6 +- lib/classes/inAppWebView.dart | 33 + lib/classes/utils.dart | 146 ++--- lib/models/generic_response_model.dart | 581 +++++++++--------- lib/models/sso_auth_model.dart | 65 ++ lib/provider/dashboard_provider_model.dart | 59 +- lib/ui/landing/widget/services_widget.dart | 249 +++++--- .../offers_and_discounts_details.dart | 6 +- lib/widgets/mark_attendance_widget.dart | 1 - pubspec.yaml | 34 +- 18 files changed, 955 insertions(+), 534 deletions(-) create mode 100644 lib/classes/inAppWebView.dart create mode 100644 lib/models/sso_auth_model.dart diff --git a/android/app/build.gradle b/android/app/build.gradle index 512fe2a..217706e 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -1,25 +1,12 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} +plugins { + id "com.android.application" + id "kotlin-android" + id "com.google.gms.google-services" + id "dev.flutter.flutter-gradle-plugin" + id "com.google.firebase.crashlytics" -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' } -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} def keystoreProperties = new Properties() def keystorePropertiesFile = rootProject.file('key.properties') @@ -27,19 +14,11 @@ if (keystorePropertiesFile.exists()) { keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) } -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply plugin: 'com.google.gms.google-services' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" -apply plugin: 'com.huawei.agconnect' -android { - compileSdkVersion 34 - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } +android { + namespace 'hmg.cloudSolutions.mohem' + compileSdk 36 kotlinOptions { jvmTarget = '1.8' @@ -52,10 +31,10 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "hmg.cloudSolutions.mohem" - minSdkVersion 28 - targetSdkVersion 34 - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName + minSdkVersion 30 + targetSdk = flutter.targetSdkVersion + versionCode flutter.versionCode + versionName flutter.versionName } signingConfigs { @@ -84,5 +63,5 @@ flutter { } dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.1.20" } diff --git a/android/build.gradle b/android/build.gradle index 2c90dbd..c1b6ff6 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,34 +1,110 @@ -buildscript { - ext.kotlin_version = '1.9.10' +//buildscript { +// ext.kotlin_version = '1.9.10' +// repositories { +// google() +// mavenCentral() +// maven { url 'https://developer.huawei.com/repo/' } +// } +// +// dependencies { +// classpath 'com.android.tools.build:gradle:7.1.3' +// classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" +// classpath 'com.google.gms:google-services:4.3.8' +// classpath 'com.huawei.agconnect:agcp:1.8.0.300' +// classpath "com.android.tools:r8:8.2.33" +// } +//} +// +//allprojects { +// repositories { +// google() +// mavenCentral() +// maven { url 'https://developer.huawei.com/repo/' } +// } +//} +// +//rootProject.buildDir = '../build' +//subprojects { +// project.buildDir = "${rootProject.buildDir}/${project.name}" +// project.evaluationDependsOn(':app') +//} +// +//tasks.register("clean", Delete) { +// delete rootProject.buildDir +//} + + +allprojects { repositories { google() mavenCentral() - maven { url 'https://developer.huawei.com/repo/' } + maven { + url 'https://developer.huawei.com/repo/' + } + maven { + url "https://artifactory.ess-dev.com/artifactory/gradle-dev-local" + } } - dependencies { - classpath 'com.android.tools.build:gradle:7.1.3' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath 'com.google.gms:google-services:4.3.8' - classpath 'com.huawei.agconnect:agcp:1.8.0.300' - classpath "com.android.tools:r8:8.2.33" + // Exclude old BouncyCastle globally to avoid duplicate classes + configurations.all { + exclude group: 'org.bouncycastle', module: 'bcprov-jdk16' } -} -allprojects { - repositories { - google() - mavenCentral() - maven { url 'https://developer.huawei.com/repo/' } + tasks.withType(JavaCompile).configureEach { + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 + } + + tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach { + kotlinOptions { + jvmTarget = "21" + } + } + + subprojects { + afterEvaluate { project -> + if (project.hasProperty('android')) { + project.android { + if (namespace == null) { + namespace project.group + } + + buildFeatures { + if (buildConfig == null) { + buildConfig true + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_21 + targetCompatibility JavaVersion.VERSION_21 + } + } + } + // Force Java 17 for all JavaCompile tasks in all subprojects (including plugins) + project.tasks.withType(JavaCompile).configureEach { + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 + } + // Force Kotlin JVM target for all subprojects + project.tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach { + kotlinOptions { + jvmTarget = "21" + } + } + } } } + rootProject.buildDir = '../build' subprojects { project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { project.evaluationDependsOn(':app') } tasks.register("clean", Delete) { - delete rootProject.buildDir + delete rootProject.layout.buildDirectory } diff --git a/android/gradle.properties b/android/gradle.properties index 54e1a43..8310efa 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,4 +1,4 @@ org.gradle.jvmargs=-Xmx2048M android.useAndroidX=true android.enableJetifier=true -org.gradle.java.home=/Users/user/Library/Java/JavaVirtualMachines/jbr-17.0.12/Contents/Home/ \ No newline at end of file +#org.gradle.java.home=/Users/amirs/Library/Java/JavaVirtualMachines/jbr-17.0.12/Contents/Home/ \ No newline at end of file diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 1e830b7..941ceb1 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Thu Mar 06 11:40:30 AST 2025 +#Tue Jul 08 11:08:34 AST 2025 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/android/settings.gradle b/android/settings.gradle index 44e62bc..15303ee 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -1,11 +1,44 @@ -include ':app' +pluginManagement { + def flutterSdkPath = { + def properties = new Properties() + file("local.properties").withInputStream { properties.load(it) } + def flutterSdkPath = properties.getProperty("flutter.sdk") + assert flutterSdkPath != null, "flutter.sdk not set in local.properties" + return flutterSdkPath + }() -def localPropertiesFile = new File(rootProject.projectDir, "local.properties") -def properties = new Properties() -assert localPropertiesFile.exists() -localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") -def flutterSdkPath = properties.getProperty("flutter.sdk") -assert flutterSdkPath != null, "flutter.sdk not set in local.properties" -apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" + repositories { + google() + mavenCentral() + gradlePluginPortal() + maven { url 'https://developer.huawei.com/repo/' } + + } + + dependencyResolutionManagement { + repositories { + google() + mavenCentral() + gradlePluginPortal() + maven { url 'https://developer.huawei.com/repo/' } + maven { + url "https://artifactory.ess-dev.com/artifactory/gradle-dev-local" + } + } + } +} + +plugins { + id "dev.flutter.flutter-plugin-loader" version "1.0.0" + id "com.android.application" version '8.11.0' apply false + id("org.jetbrains.kotlin.android") version "2.2.0" apply false + id("com.google.gms.google-services") version "4.4.3" apply false + id("com.google.firebase.crashlytics") version "3.0.4" apply false + id('org.gradle.toolchains.foojay-resolver-convention') version '0.9.0' apply false + +} + +include ":app" diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 97a5b37..ea4aec9 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -144,7 +144,7 @@ 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, C4CFBC4C5CAC00182015ACD5 /* [CP] Embed Pods Frameworks */, - EF29CE25BB57F5AA48CE1136 /* [CP] Copy Pods Resources */, + 6C6E76E4FB19FAF11C24005D /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -242,6 +242,23 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; + 6C6E76E4FB19FAF11C24005D /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -274,23 +291,6 @@ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; - EF29CE25BB57F5AA48CE1136 /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Copy Pods Resources"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 5e31d3d..9c12df5 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -26,6 +26,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit" shouldUseLaunchSchemeArgsEnv = "YES"> diff --git a/lib/api/dashboard_api_client.dart b/lib/api/dashboard_api_client.dart index 145b039..e8a94cd 100644 --- a/lib/api/dashboard_api_client.dart +++ b/lib/api/dashboard_api_client.dart @@ -1,6 +1,8 @@ import 'dart:async'; import 'dart:convert'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:http/http.dart' as http; import 'package:mohem_flutter_app/api/api_client.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/consts.dart'; @@ -12,7 +14,8 @@ import 'package:mohem_flutter_app/models/dashboard/list_menu.dart'; import 'package:mohem_flutter_app/models/generic_response_model.dart'; import 'package:mohem_flutter_app/models/itg/itg_main_response.dart'; import 'package:mohem_flutter_app/models/itg/itg_response_model.dart'; -import 'package:platform_device_id/platform_device_id.dart'; +import 'package:mohem_flutter_app/models/sso_auth_model.dart'; +import 'package:platform_device_id_plus/platform_device_id.dart'; // import 'package:platform_device_id/platform_device_id.dart'; import 'package:uuid/uuid.dart'; @@ -153,6 +156,59 @@ class DashboardApiClient { ); } + Future getTicketBookingRedirection() async { + String url = "${ApiConsts.erpRest}GET_PORTAL_REDIRECTION"; + Map postParams = {"P_USER_NAME": AppState().memberInformationList?.eMPLOYEENUMBER}; + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData; + }, + url, + postParams, + ); + } + + Future getBookingSSOAuthRedirection({required String clientID}) async { + String url = "${ApiConsts.ssoAuthRedirection}?grantType=mohemm"; + //https://sso-uat.hmg.com/api/auth/connect?grantType=mohemm' + // Map postParams = {"P_USER_NAME": AppState().memberInformationList?.eMPLOYEENUMBER}; + Map postParams = { + "ClientId": clientID, + // "ClientId": "a9f4d1a0596d4aea8f830992ec4bdac1", + "PersonId": AppState().memberInformationList?.eMPLOYEENUMBER, + "Username": AppState().memberInformationList?.eMPLOYEENUMBER, + "Language": "en", + }; + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject( + (json) { + SSOAuthModel responseData = SSOAuthModel.fromJson(json); + return responseData; + }, + url, + postParams, + ); + } + + Future getBookingSSOFinalRedirection({required String token}) async { + token = "eyJhbGciOiJSUzI1NiIsImtpZCI6IjhjZTE2OWM0YjIwYjQ2ZWM5YTQyOTU3Y2ZhODUzNzQ1IiwidHlwIjoiSldUIn0.eyJ0ZW5hbnRfaWQiOiJhOWY0ZDFhMDU5NmQ0YWVhOGY4MzA5OTJlYzRiZGFjMSIsImVpZCI6IjExNzkzMCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL3NpZCI6Ijk2MDI0OGM1NzA3YzQ3MmFhYTEzM2I1N2ZhODE1ZmVhIiwibGFuZ3VhZ2UiOiJVUyIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL2VtYWlsYWRkcmVzcyI6IjExNzkzMEBobWcuY29tIiwiZXhwIjoxNzgyNDc1NzY5LCJpc3MiOiJodHRwczovL3Nzby11YXQuaG1nLmNvbSIsImF1ZCI6ImE5ZjRkMWEwNTk2ZDRhZWE4ZjgzMDk5MmVjNGJkYWMxIn0.rJcLVsG8D0XECyLERCTD2uqGeWyvp-OBVGE9uL2qKrX4etFUHgdFt_5kYF6edFTtGy-0PIZadHDmv7e-IOhVWHm5HVMClaukiXoRXR8cDN8XA1wfme3Kd-U5PXN-IRh49AyRTzLO0rYNPvH81ScosWGlsFSkOvA-0hJNa2adHdtvgNvB8wJshSU5p7sAmF8mjdDY6aInG19etu2iEuUDwHHA4ZY_ts4hboHo8fE392hFaYGonExoD7bpW5RMx5xKWeRCmWpG_PK8Aw_z1jGzdB9PANus4pteRGuln1J-kmo2lQC9pVrSyZATAKp1HfgfyZ_vUhaHEfM69cMWaCslJQ"; + var request = http.MultipartRequest('POST', Uri.parse('https://ek.techmaster.in/SSO/HMG')); + request.fields.addAll({'JWTToken': token}); + + // request.headers.addAll(headers); + + http.StreamedResponse response = await request.send(); + if (response.statusCode == 302) { + print("================== post =========="); + var res = await response.stream.bytesToString(); + return response.headers["location"]; + } else { + print(response.reasonPhrase); + } + } + //Mark Attendance Future markAttendance({ String lat = "0", diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 0214199..c7f62d8 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -6,12 +6,12 @@ class ApiConsts { // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.201.204.101:2024"; - static String baseUrl = "https://webservices.hmg.com"; // PreProd + // static String baseUrl = "https://webservices.hmg.com"; // PreProd // static String baseUrl = "https://hmgwebservices.com"; // Live server // static String baseUrl = "https://mohemm.hmg.com"; // New Live server // - // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver + static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.20.200.111:1010/"; // static String baseUrl = "https://webservices.hmg.com"; // PreProd @@ -27,6 +27,8 @@ class ApiConsts { static String user = baseUrlServices + "api/User/"; static String cocRest = baseUrlServices + "COCWS.svc/REST/"; + static String ssoAuthRedirection = "https://sso-uat.hmg.com/api/auth/connect"; + //Chat static String chatServerBaseUrl = "https://apiderichat.hmg.com/"; static String chatServerBaseApiUrl = chatServerBaseUrl + "api/"; diff --git a/lib/classes/inAppWebView.dart b/lib/classes/inAppWebView.dart new file mode 100644 index 0000000..ccb24fd --- /dev/null +++ b/lib/classes/inAppWebView.dart @@ -0,0 +1,33 @@ +import 'dart:developer'; + +import 'package:flutter_inappwebview/flutter_inappwebview.dart'; + +class MyInAppBrowser extends InAppBrowser { + final Function onExitCallback; + final Function(String) onLoadStartCallback; + + MyInAppBrowser({ + required this.onExitCallback, + required this.onLoadStartCallback, + }); + + @override + Future onBrowserCreated() async { + log("\n\nBrowser Created!\n\n"); + } + + @override + Future onLoadStart(Uri? url) async { + onLoadStartCallback(url.toString()); + } + + @override + Future onLoadStop(Uri? url) async { + log("\n\nStopped $url\n\n"); + } + + @override + void onLoadError(Uri? url, int code, String message) { + log("Can't load $url.. Error: $message"); + } +} diff --git a/lib/classes/utils.dart b/lib/classes/utils.dart index 1838cb8..0245bbf 100644 --- a/lib/classes/utils.dart +++ b/lib/classes/utils.dart @@ -31,13 +31,14 @@ class Utils { static void showToast(String message, {bool longDuration = true}) { Fluttertoast.showToast( - msg: message, - toastLength: longDuration ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT, - gravity: ToastGravity.BOTTOM, - timeInSecForIosWeb: 1, - backgroundColor: Colors.black54, - textColor: Colors.white, - fontSize: 13.0); + msg: message, + toastLength: longDuration ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT, + gravity: ToastGravity.BOTTOM, + timeInSecForIosWeb: 1, + backgroundColor: Colors.black54, + textColor: Colors.white, + fontSize: 13.0, + ); } static dynamic getNotNullValue(List list, int index) { @@ -63,12 +64,7 @@ class Utils { static void showLoading(BuildContext context) { WidgetsBinding.instance.addPostFrameCallback((_) { _isLoadingVisible = true; - showDialog( - context: context, - barrierColor: Colors.black.withOpacity(0.5), - useRootNavigator: false, - builder: (BuildContext context) => LoadingDialog(), - ).then((value) { + showDialog(context: context, barrierColor: Colors.black.withOpacity(0.5), useRootNavigator: false, builder: (BuildContext context) => LoadingDialog()).then((value) { _isLoadingVisible = false; }); }); @@ -118,13 +114,14 @@ class Utils { showDialog( barrierDismissible: false, context: cxt, - builder: (cxt) => ConfirmDialog( - message: errorMessage, - onTap: () { - Navigator.pushNamedAndRemoveUntil(cxt, AppRoutes.login, (Route route) => false); - }, - onCloseTap: () {}, - ), + builder: + (cxt) => ConfirmDialog( + message: errorMessage, + onTap: () { + Navigator.pushNamedAndRemoveUntil(cxt, AppRoutes.login, (Route route) => false); + }, + onCloseTap: () {}, + ), ); } else { if (cxt != null) { @@ -138,33 +135,18 @@ class Utils { } static Future showErrorDialog({required BuildContext context, required VoidCallback onOkTapped, required String message}) async { - return showDialog( - context: context, - builder: (BuildContext context) => ConfirmDialog( - message: message, - onTap: onOkTapped, - ), - ); + return showDialog(context: context, builder: (BuildContext context) => ConfirmDialog(message: message, onTap: onOkTapped)); } static void confirmDialog(cxt, String message, {VoidCallback? onTap}) { - showDialog( - context: cxt, - builder: (BuildContext cxt) => ConfirmDialog( - message: message, - onTap: onTap, - ), - ); + showDialog(context: cxt, builder: (BuildContext cxt) => ConfirmDialog(message: message, onTap: onTap)); } static Widget getNoDataWidget(BuildContext context) { return Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, - children: [ - SvgPicture.asset('assets/images/not_found.svg', width: 110.0, height: 110.0), - LocaleKeys.noDataAvailable.tr().toText16().paddingOnly(top: 15), - ], + children: [SvgPicture.asset('assets/images/not_found.svg', width: 110.0, height: 110.0), LocaleKeys.noDataAvailable.tr().toText16().paddingOnly(top: 15)], ).center; } @@ -172,10 +154,7 @@ class Utils { return Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, - children: [ - SvgPicture.asset('assets/images/not_found.svg', width: 110.0, height: 110.0), - LocaleKeys.noDataAvailable.tr().toText16().paddingOnly(top: 15), - ], + children: [SvgPicture.asset('assets/images/not_found.svg', width: 110.0, height: 110.0), LocaleKeys.noDataAvailable.tr().toText16().paddingOnly(top: 15)], ).center; } @@ -209,17 +188,7 @@ class Utils { return Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, - children: [ - 6.height, - alignCenter ? text.toText12().center : text.toText12(), - 5.height, - if (showDivider) - const Divider( - height: 1, - color: Color(0xff2E303A), - thickness: 1, - ) - ], + children: [6.height, alignCenter ? text.toText12().center : text.toText12(), 5.height, if (showDivider) const Divider(height: 1, color: Color(0xff2E303A), thickness: 1)], ); } @@ -227,17 +196,15 @@ class Utils { return BoxDecoration( color: background, border: Border.all( - width: 1, // - color: background // <--- border width here - ), + width: 1, // + color: background, // <--- border width here + ), borderRadius: BorderRadius.circular(radius), ); } static Widget mHeight(double h) { - return Container( - height: h, - ); + return Container(height: h); } static Widget mDivider(Color color) { @@ -352,20 +319,21 @@ class Utils { if (!Platform.isIOS) { await showCupertinoModalPopup( context: context, - builder: (BuildContext cxt) => Container( - height: 250, - color: Colors.white, - child: CupertinoDatePicker( - backgroundColor: Colors.white, - mode: CupertinoDatePickerMode.date, - onDateTimeChanged: (DateTime value) { - if (value != null && value != selectedDate) { - selectedDate = value; - } - }, - initialDateTime: selectedDate, - ), - ), + builder: + (BuildContext cxt) => Container( + height: 250, + color: Colors.white, + child: CupertinoDatePicker( + backgroundColor: Colors.white, + mode: CupertinoDatePickerMode.date, + onDateTimeChanged: (DateTime value) { + if (value != null && value != selectedDate) { + selectedDate = value; + } + }, + initialDateTime: selectedDate, + ), + ), ); } else { DateTime? picked = await showDatePicker(context: context, initialDate: selectedDate, initialEntryMode: DatePickerEntryMode.calendarOnly, firstDate: DateTime(2015, 8), lastDate: DateTime(2101)); @@ -377,19 +345,25 @@ class Utils { } static void readNFc({required 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); - }); + NfcManager.instance + .startSession( + onDiscovered: (NfcTag tag) async { + MifareUltralight f; + if (Platform.isAndroid) { + print(tag); + 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); + }, + pollingOptions: {NfcPollingOption.iso14443}, + ) + .catchError((err) { + print(err); + }); } //HUAWEI DECISION MAKING diff --git a/lib/models/generic_response_model.dart b/lib/models/generic_response_model.dart index ba48836..74cef13 100644 --- a/lib/models/generic_response_model.dart +++ b/lib/models/generic_response_model.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:mohem_flutter_app/models/add_att_success_list_model.dart'; import 'package:mohem_flutter_app/models/add_attachment_list_model.dart'; import 'package:mohem_flutter_app/models/basic_member_information_model.dart'; @@ -391,275 +393,278 @@ class GenericResponseModel { String? ePharmacyGetItemOnHandList; bool? isActiveCode; bool? isSMSSent; - - GenericResponseModel( - {this.date, - this.languageID, - this.serviceName, - this.time, - this.androidLink, - this.authenticationTokenID, - this.data, - this.dataw, - this.dietType, - this.dietTypeID, - this.errorCode, - this.errorEndUserMessage, - this.errorEndUserMessageN, - this.errorMessage, - this.errorType, - this.foodCategory, - this.iOSLink, - this.isAuthenticated, - this.mealOrderStatus, - this.mealType, - this.messageStatus, - this.numberOfResultRecords, - this.patientBlodType, - this.successMsg, - this.successMsgN, - this.vidaUpdatedResponse, - this.addAttSuccessList, - this.addAttachmentList, - this.bCDomain, - this.bCLogo, - this.basicMemberInformation, - this.businessCardPrivilege, - this.calculateAbsenceDuration, - this.cancelHRTransactionLIst, - this.chatEmployeeLoginList, - this.companyBadge, - this.companyImage, - this.companyImageDescription, - this.companyImageURL, - this.companyMainCompany, - this.countryList, - this.createVacationRuleList, - this.deleteAttachmentList, - this.deleteVacationRuleList, - this.disableSessionList, - this.employeeQR, - this.employeeDocumentsList, - this.forgetPasswordTokenID, - this.getAbsenceAttachmentsList, - this.getAbsenceAttendanceTypesList, - this.getAbsenceCollectionNotificationBodyList, - this.getAbsenceDffStructureList, - this.getAbsenceTransactionList, - this.getAccrualBalancesList, - this.getActionHistoryList, - this.getPRActionHistoryList, - this.getAddressDffStructureList, - this.getAddressNotificationBodyList, - this.getApprovesList, - this.getAttachementList, - this.getPRAttachmentList, - this.getAttendanceTrackingList, - this.getBasicDetColsStructureList, - this.getBasicDetDffStructureList, - this.getBasicDetNtfBodyList, - this.getCEICollectionNotificationBodyList, - this.getCEIDFFStructureList, - this.getCEITransactionList, - this.getCcpTransactionsList, - this.getCcpTransactionsListNew, - this.getConcurrentProgramsList, - this.getContactColsStructureList, - this.getContactDetailsList, - this.getContactDffStructureList, - this.getContactNotificationBodyList, - this.getCountriesList, - this.getDayHoursTypeDetailsList, - this.getDeductionsList, - this.getDefaultValueList, - this.getEITCollectionNotificationBodyList, - this.getEITDFFStructureList, - this.getEITTransactionList, - this.getEarningsList, - this.getEmployeeAddressList, - this.getEmployeeBasicDetailsList, - this.getEmployeeContactsList, - this.getEmployeePhonesList, - this.getEmployeeSubordinatesList, - this.getFliexfieldStructureList, - this.getHrCollectionNotificationBodyList, - this.getHrTransactionList, - this.getItemCreationNtfBodyList, - this.getItemTypeNotificationsList, - this.getItemTypesList, - this.getLookupValuesList, - this.getMenuEntriesList, - this.getEventActivityList, - this.getMoItemHistoryList, - this.getMoNotificationBodyList, - this.getNotificationButtonsList, - this.getNotificationReassignModeList, - this.getObjectValuesList, - this.getOpenMissingSwipesList, - this.getOpenNotificationsList, - this.getOpenNotificationsNumList, - this.getOpenPeriodDatesList, - this.getOrganizationsSalariesList, - this.getPaymentInformationList, - this.getPayslipList, - this.getPerformanceAppraisalList, - this.getPhonesNotificationBodyList, - this.getPoItemHistoryList, - this.getPoNotificationBodyList, - this.getPrNotificationBodyList, - this.getPaymentNotificationBodyList, - this.getPRInformationList, - this.getQuotationAnalysisList, - this.getRFCEmployeeListList, - this.getRespondAttributeValueList, - this.getSITCollectionNotificationBodyList, - this.getSITDFFStructureList, - this.getSITTransactionList, - this.getScheduleShiftsDetailsList, - this.getShiftTypesList, - this.getStampMsNotificationBodyList, - this.getStampNsNotificationBodyList, - this.getSubordinatesAttdStatusList, - this.getSubordinatesLeavesList, - this.getSubordinatesLeavesTotalVacationsList, - this.getSummaryOfPaymentList, - this.getSwipesList, - this.getTermColsStructureList, - this.getTermDffStructureList, - this.getTermNotificationBodyList, - this.getTimeCardSummaryList, - this.getTicketsByEmployeeList, - this.getTicketDetailsByEmployee, - this.getTicketTransactions, - this.getTicketTypes, - this.getSectionTopics, - this.getMowadhafhiProjects, - this.getProjectDepartments, - this.getDepartmentSections, - this.getPendingTransactionsFunctions, - this.getPendingTransactionsDetails, - this.getConcurrentProgramsModel, - this.getCCPTransactionsModel, - this.getCCPOutputModel, - this.getCCPDFFStructureModel, - this.getUserItemTypesList, - this.getVacationRulesList, - this.getVaccinationOnHandList, - this.getVaccinationsList, - this.getValueSetValuesList, - this.getWorkList, - this.hRCertificateTemplate, - this.imgURLsList, - this.insertApInv, - this.insertBooked, - this.insertEmpSwipesList, - this.insertJournal, - this.insertOrders, - this.intPortalGetEmployeeList, - this.isDeviceTokenEmpty, - this.isPasswordExpired, - this.isRegisterAllowed, - this.isRequriedValueSetEmpty, - this.isUserSMSExcluded, - this.itemOnHand, - this.languageAvailable, - this.listSupplier, - this.listUserAgreement, - this.listEITStrucrure, - this.listItemImagesDetails, - this.listItemMaster, - this.listMedicineDetails, - this.listMenu, - this.listNewEmployees, - this.listRadScreen, - this.logInTokenID, - this.memberInformationList, - this.memberLoginList, - this.mohemmGetBusinessCardEnabledList, - this.mohemmGetFavoriteReplacementsList, - this.mohemmGetMobileDeviceInfobyEmpInfoList, - this.mohemmGetMobileLoginInfoList, - this.mohemmGetPatientIDList, - this.mohemmITGResponseItem, - this.mohemmIsChangeIsActiveBusinessCardEnable, - this.mohemmIsInsertBusinessCardEnable, - this.mohemmWifiPassword, - this.mohemmWifiSSID, - this.notificationAction, - this.notificationGetRespondAttributesList, - this.notificationRespondRolesList, - this.oracleOutPutNumber, - this.pASSWORDEXPIREDMSG, - this.pCOUNTRYCODE, - this.pCOUNTRYNAME, - this.pDESCFLEXCONTEXTCODE, - this.pDESCFLEXCONTEXTNAME, - this.pForm, - this.pINFORMATION, - this.pMBLID, - this.pNUMOFSUBORDINATES, - this.pOPENNTFNUMBER, - this.pQUESTION, - this.pSESSIONID, - this.pSchema, - this.pharmacyStockAddPharmacyStockList, - this.pharmacyStockGetOnHandList, - this.privilegeList, - this.processTransactions, - this.registerUserNameList, - this.replacementList, - this.respondAttributesList, - this.respondRolesList, - this.resubmitAbsenceTransactionList, - this.resubmitEITTransactionList, - this.resubmitHrTransactionList, - this.sFHGetPoNotificationBodyList, - this.sFHGetPrNotificationBodyList, - this.startAbsenceApprovalProccess, - this.startAddressApprovalProcessList, - this.startBasicDetApprProcessList, - this.startCeiApprovalProcess, - this.startContactApprovalProcessList, - this.startEitApprovalProcess, - this.startHrApprovalProcessList, - this.startPhonesApprovalProcessList, - this.startSitApprovalProcess, - this.startTermApprovalProcessList, - this.submitAddressTransactionList, - this.submitBasicDetTransactionList, - this.submitCEITransactionList, - this.submitCcpTransactionList, - this.submitContactTransactionList, - this.submitEITTransactionList, - this.submitHrTransactionList, - this.submitPhonesTransactionList, - this.submitSITTransactionList, - this.submitTermTransactionList, - this.subordinatesOnLeavesList, - this.sumbitAbsenceTransactionList, - this.tokenID, - this.updateAttachmentList, - this.updateEmployeeImageList, - this.updateItemTypeSuccessList, - this.updateUserItemTypesList, - this.updateVacationRuleList, - this.vHREmployeeLoginList, - this.vHRGetEmployeeDetailsList, - this.vHRGetManagersDetailsList, - this.vHRGetProjectByCodeList, - this.vHRIsVerificationCodeValid, - this.validateAbsenceTransactionList, - this.validateEITTransactionList, - this.validatePhonesTransactionList, - this.vrItemTypesList, - this.wFLookUpList, - this.eLearningGETEMPLOYEEPROFILEList, - this.eLearningLOGINList, - this.eLearningValidateLoginList, - this.eLearningValidate_LoginList, - this.ePharmacyGetItemOnHandList, - this.isActiveCode, - this.isSMSSent}); + PortalDirectionData? portalDirectionData; + + GenericResponseModel({ + this.date, + this.languageID, + this.portalDirectionData, + this.serviceName, + this.time, + this.androidLink, + this.authenticationTokenID, + this.data, + this.dataw, + this.dietType, + this.dietTypeID, + this.errorCode, + this.errorEndUserMessage, + this.errorEndUserMessageN, + this.errorMessage, + this.errorType, + this.foodCategory, + this.iOSLink, + this.isAuthenticated, + this.mealOrderStatus, + this.mealType, + this.messageStatus, + this.numberOfResultRecords, + this.patientBlodType, + this.successMsg, + this.successMsgN, + this.vidaUpdatedResponse, + this.addAttSuccessList, + this.addAttachmentList, + this.bCDomain, + this.bCLogo, + this.basicMemberInformation, + this.businessCardPrivilege, + this.calculateAbsenceDuration, + this.cancelHRTransactionLIst, + this.chatEmployeeLoginList, + this.companyBadge, + this.companyImage, + this.companyImageDescription, + this.companyImageURL, + this.companyMainCompany, + this.countryList, + this.createVacationRuleList, + this.deleteAttachmentList, + this.deleteVacationRuleList, + this.disableSessionList, + this.employeeQR, + this.employeeDocumentsList, + this.forgetPasswordTokenID, + this.getAbsenceAttachmentsList, + this.getAbsenceAttendanceTypesList, + this.getAbsenceCollectionNotificationBodyList, + this.getAbsenceDffStructureList, + this.getAbsenceTransactionList, + this.getAccrualBalancesList, + this.getActionHistoryList, + this.getPRActionHistoryList, + this.getAddressDffStructureList, + this.getAddressNotificationBodyList, + this.getApprovesList, + this.getAttachementList, + this.getPRAttachmentList, + this.getAttendanceTrackingList, + this.getBasicDetColsStructureList, + this.getBasicDetDffStructureList, + this.getBasicDetNtfBodyList, + this.getCEICollectionNotificationBodyList, + this.getCEIDFFStructureList, + this.getCEITransactionList, + this.getCcpTransactionsList, + this.getCcpTransactionsListNew, + this.getConcurrentProgramsList, + this.getContactColsStructureList, + this.getContactDetailsList, + this.getContactDffStructureList, + this.getContactNotificationBodyList, + this.getCountriesList, + this.getDayHoursTypeDetailsList, + this.getDeductionsList, + this.getDefaultValueList, + this.getEITCollectionNotificationBodyList, + this.getEITDFFStructureList, + this.getEITTransactionList, + this.getEarningsList, + this.getEmployeeAddressList, + this.getEmployeeBasicDetailsList, + this.getEmployeeContactsList, + this.getEmployeePhonesList, + this.getEmployeeSubordinatesList, + this.getFliexfieldStructureList, + this.getHrCollectionNotificationBodyList, + this.getHrTransactionList, + this.getItemCreationNtfBodyList, + this.getItemTypeNotificationsList, + this.getItemTypesList, + this.getLookupValuesList, + this.getMenuEntriesList, + this.getEventActivityList, + this.getMoItemHistoryList, + this.getMoNotificationBodyList, + this.getNotificationButtonsList, + this.getNotificationReassignModeList, + this.getObjectValuesList, + this.getOpenMissingSwipesList, + this.getOpenNotificationsList, + this.getOpenNotificationsNumList, + this.getOpenPeriodDatesList, + this.getOrganizationsSalariesList, + this.getPaymentInformationList, + this.getPayslipList, + this.getPerformanceAppraisalList, + this.getPhonesNotificationBodyList, + this.getPoItemHistoryList, + this.getPoNotificationBodyList, + this.getPrNotificationBodyList, + this.getPaymentNotificationBodyList, + this.getPRInformationList, + this.getQuotationAnalysisList, + this.getRFCEmployeeListList, + this.getRespondAttributeValueList, + this.getSITCollectionNotificationBodyList, + this.getSITDFFStructureList, + this.getSITTransactionList, + this.getScheduleShiftsDetailsList, + this.getShiftTypesList, + this.getStampMsNotificationBodyList, + this.getStampNsNotificationBodyList, + this.getSubordinatesAttdStatusList, + this.getSubordinatesLeavesList, + this.getSubordinatesLeavesTotalVacationsList, + this.getSummaryOfPaymentList, + this.getSwipesList, + this.getTermColsStructureList, + this.getTermDffStructureList, + this.getTermNotificationBodyList, + this.getTimeCardSummaryList, + this.getTicketsByEmployeeList, + this.getTicketDetailsByEmployee, + this.getTicketTransactions, + this.getTicketTypes, + this.getSectionTopics, + this.getMowadhafhiProjects, + this.getProjectDepartments, + this.getDepartmentSections, + this.getPendingTransactionsFunctions, + this.getPendingTransactionsDetails, + this.getConcurrentProgramsModel, + this.getCCPTransactionsModel, + this.getCCPOutputModel, + this.getCCPDFFStructureModel, + this.getUserItemTypesList, + this.getVacationRulesList, + this.getVaccinationOnHandList, + this.getVaccinationsList, + this.getValueSetValuesList, + this.getWorkList, + this.hRCertificateTemplate, + this.imgURLsList, + this.insertApInv, + this.insertBooked, + this.insertEmpSwipesList, + this.insertJournal, + this.insertOrders, + this.intPortalGetEmployeeList, + this.isDeviceTokenEmpty, + this.isPasswordExpired, + this.isRegisterAllowed, + this.isRequriedValueSetEmpty, + this.isUserSMSExcluded, + this.itemOnHand, + this.languageAvailable, + this.listSupplier, + this.listUserAgreement, + this.listEITStrucrure, + this.listItemImagesDetails, + this.listItemMaster, + this.listMedicineDetails, + this.listMenu, + this.listNewEmployees, + this.listRadScreen, + this.logInTokenID, + this.memberInformationList, + this.memberLoginList, + this.mohemmGetBusinessCardEnabledList, + this.mohemmGetFavoriteReplacementsList, + this.mohemmGetMobileDeviceInfobyEmpInfoList, + this.mohemmGetMobileLoginInfoList, + this.mohemmGetPatientIDList, + this.mohemmITGResponseItem, + this.mohemmIsChangeIsActiveBusinessCardEnable, + this.mohemmIsInsertBusinessCardEnable, + this.mohemmWifiPassword, + this.mohemmWifiSSID, + this.notificationAction, + this.notificationGetRespondAttributesList, + this.notificationRespondRolesList, + this.oracleOutPutNumber, + this.pASSWORDEXPIREDMSG, + this.pCOUNTRYCODE, + this.pCOUNTRYNAME, + this.pDESCFLEXCONTEXTCODE, + this.pDESCFLEXCONTEXTNAME, + this.pForm, + this.pINFORMATION, + this.pMBLID, + this.pNUMOFSUBORDINATES, + this.pOPENNTFNUMBER, + this.pQUESTION, + this.pSESSIONID, + this.pSchema, + this.pharmacyStockAddPharmacyStockList, + this.pharmacyStockGetOnHandList, + this.privilegeList, + this.processTransactions, + this.registerUserNameList, + this.replacementList, + this.respondAttributesList, + this.respondRolesList, + this.resubmitAbsenceTransactionList, + this.resubmitEITTransactionList, + this.resubmitHrTransactionList, + this.sFHGetPoNotificationBodyList, + this.sFHGetPrNotificationBodyList, + this.startAbsenceApprovalProccess, + this.startAddressApprovalProcessList, + this.startBasicDetApprProcessList, + this.startCeiApprovalProcess, + this.startContactApprovalProcessList, + this.startEitApprovalProcess, + this.startHrApprovalProcessList, + this.startPhonesApprovalProcessList, + this.startSitApprovalProcess, + this.startTermApprovalProcessList, + this.submitAddressTransactionList, + this.submitBasicDetTransactionList, + this.submitCEITransactionList, + this.submitCcpTransactionList, + this.submitContactTransactionList, + this.submitEITTransactionList, + this.submitHrTransactionList, + this.submitPhonesTransactionList, + this.submitSITTransactionList, + this.submitTermTransactionList, + this.subordinatesOnLeavesList, + this.sumbitAbsenceTransactionList, + this.tokenID, + this.updateAttachmentList, + this.updateEmployeeImageList, + this.updateItemTypeSuccessList, + this.updateUserItemTypesList, + this.updateVacationRuleList, + this.vHREmployeeLoginList, + this.vHRGetEmployeeDetailsList, + this.vHRGetManagersDetailsList, + this.vHRGetProjectByCodeList, + this.vHRIsVerificationCodeValid, + this.validateAbsenceTransactionList, + this.validateEITTransactionList, + this.validatePhonesTransactionList, + this.vrItemTypesList, + this.wFLookUpList, + this.eLearningGETEMPLOYEEPROFILEList, + this.eLearningLOGINList, + this.eLearningValidateLoginList, + this.eLearningValidate_LoginList, + this.ePharmacyGetItemOnHandList, + this.isActiveCode, + this.isSMSSent, + }); GenericResponseModel.fromJson(Map json) { date = json['Date']; @@ -688,6 +693,7 @@ class GenericResponseModel { successMsg = json['SuccessMsg']; successMsgN = json['SuccessMsgN']; vidaUpdatedResponse = json['VidaUpdatedResponse']; + portalDirectionData = json["PortalDirectionData"] == null ? null : PortalDirectionData.fromJson(json["PortalDirectionData"]); if (json['AddAttSuccessList'] != null) { addAttSuccessList = []; @@ -848,9 +854,10 @@ class GenericResponseModel { }); } - getCEICollectionNotificationBodyList = json["GetCEICollectionNotificationBodyList"] == null - ? null - : List.from(json["GetCEICollectionNotificationBodyList"].map((x) => GetEitCollectionNotificationBodyList.fromJson(x))); + getCEICollectionNotificationBodyList = + json["GetCEICollectionNotificationBodyList"] == null + ? null + : List.from(json["GetCEICollectionNotificationBodyList"].map((x) => GetEitCollectionNotificationBodyList.fromJson(x))); if (json['GetCEIDFFStructureList'] != null) { getCEIDFFStructureList = []; @@ -909,9 +916,10 @@ class GenericResponseModel { }); } getDefaultValueList = json['GetDefaultValueList'] != null ? GetDefaultValueList.fromJson(json['GetDefaultValueList']) : null; - getEITCollectionNotificationBodyList = json["GetEITCollectionNotificationBodyList"] == null - ? null - : List.from(json["GetEITCollectionNotificationBodyList"].map((x) => GetEitCollectionNotificationBodyList.fromJson(x))); + getEITCollectionNotificationBodyList = + json["GetEITCollectionNotificationBodyList"] == null + ? null + : List.from(json["GetEITCollectionNotificationBodyList"].map((x) => GetEitCollectionNotificationBodyList.fromJson(x))); if (json['GetEITDFFStructureList'] != null) { getEITDFFStructureList = []; json['GetEITDFFStructureList'].forEach((v) { @@ -1475,6 +1483,7 @@ class GenericResponseModel { data['SuccessMsg'] = this.successMsg; data['SuccessMsgN'] = this.successMsgN; data['VidaUpdatedResponse'] = this.vidaUpdatedResponse; + data['PortalDirectionData'] = portalDirectionData?.toJson(); if (this.addAttSuccessList != null) { data['AddAttSuccessList'] = this.addAttSuccessList!.map((v) => v.toJson()).toList(); @@ -1930,3 +1939,25 @@ class GenericResponseModel { return data; } } + +class PortalDirectionData { + String? pRedirection; + String? clientID; + + PortalDirectionData({this.pRedirection, this.clientID}); + + factory PortalDirectionData.fromRawJson(String str) => PortalDirectionData.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory PortalDirectionData.fromJson(Map json) => PortalDirectionData(pRedirection: json["P_REDIRECTION"], clientID: json["ClientID"]); + + Map toJson() => {"P_REDIRECTION": pRedirection, "ClientID": clientID}; +} + + +class TicketBookingResult { + final bool success; + final String? clientId; + TicketBookingResult(this.success, this.clientId); +} \ No newline at end of file diff --git a/lib/models/sso_auth_model.dart b/lib/models/sso_auth_model.dart new file mode 100644 index 0000000..0ee9b98 --- /dev/null +++ b/lib/models/sso_auth_model.dart @@ -0,0 +1,65 @@ +import 'dart:convert'; + +class SSOAuthModel { + String? status; + List? message; + Data? data; + + SSOAuthModel({ + this.status, + this.message, + this.data, + }); + + factory SSOAuthModel.fromRawJson(String str) => SSOAuthModel.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory SSOAuthModel.fromJson(Map json) => SSOAuthModel( + status: json["status"], + message: json["message"] == null ? [] : List.from(json["message"]!.map((x) => x)), + data: json["data"] == null ? null : Data.fromJson(json["data"]), + ); + + Map toJson() => { + "status": status, + "message": message == null ? [] : List.from(message!.map((x) => x)), + "data": data?.toJson(), + }; +} + +class Data { + String? accessToken; + String? idToken; + int? expiresIn; + String? refreshToken; + String? postBackUrl; + + Data({ + this.accessToken, + this.idToken, + this.expiresIn, + this.refreshToken, + this.postBackUrl, + }); + + factory Data.fromRawJson(String str) => Data.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory Data.fromJson(Map json) => Data( + accessToken: json["accessToken"], + idToken: json["idToken"], + expiresIn: json["expiresIn"], + refreshToken: json["refreshToken"], + postBackUrl: json["postBackUrl"], + ); + + Map toJson() => { + "accessToken": accessToken, + "idToken": idToken, + "expiresIn": expiresIn, + "refreshToken": refreshToken, + "postBackUrl": postBackUrl, + }; +} diff --git a/lib/provider/dashboard_provider_model.dart b/lib/provider/dashboard_provider_model.dart index 36a9f81..0dcebed 100644 --- a/lib/provider/dashboard_provider_model.dart +++ b/lib/provider/dashboard_provider_model.dart @@ -21,6 +21,7 @@ import 'package:mohem_flutter_app/models/dashboard/mohemm_itg_pending_task_respo import 'package:mohem_flutter_app/models/generic_response_model.dart'; import 'package:mohem_flutter_app/models/itg/itg_response_model.dart'; import 'package:mohem_flutter_app/models/offers_and_discounts/get_offers_list.dart'; +import 'package:mohem_flutter_app/models/sso_auth_model.dart'; import 'package:mohem_flutter_app/widgets/dialogs/confirm_dialog.dart'; /// Mix-in [DiagnosticableTreeMixin] to have access to [debugFillProperties] for the devtool @@ -239,6 +240,7 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { homeMenus = parseMenus(getMenuEntriesList ?? []); if (homeMenus!.isNotEmpty) { homeMenus!.first.menuEntiesList.insert(0, GetMenuEntriesList(requestType: "MONTHLY_ATTENDANCE", prompt: LocaleKeys.monthlyAttendance.tr())); + // homeMenus!.first.menuEntiesList.insert(1, GetMenuEntriesList(requestType: "TICKET_BOOKING", prompt: "Ticket Booking")); homeMenus!.first.menuEntiesList.add(GetMenuEntriesList(requestType: "VACATION_RULE", prompt: LocaleKeys.vacationRule.tr())); } isServicesMenusLoading = false; @@ -283,6 +285,61 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } } + Future fetchTicketBooking() async { + try { + GenericResponseModel? genericResponseModel = await DashboardApiClient().getTicketBookingRedirection(); + if (genericResponseModel?.portalDirectionData?.pRedirection!.toLowerCase() == "alma") { + return TicketBookingResult(true, genericResponseModel?.portalDirectionData?.clientID); + } + return TicketBookingResult(false, null); + } catch (ex) { + logger.wtf(ex); + isEventLoadingLoading = false; + notifyListeners(); + Utils.handleException(ex, null, null); + return TicketBookingResult(false, null); // Ensure a return value in case of an exception + } + } + + Future fetchSSOAuthRedirection({String? clientID}) async { + try { + SSOAuthModel? ssoResponse = await DashboardApiClient().getBookingSSOAuthRedirection(clientID: clientID!); + logger.d("SSO Response: ${ssoResponse!.toJson()}"); + if (ssoResponse.status == "Success") { + return ssoResponse; + } else { + Utils.showToast(ssoResponse.message!.first ?? "Failed to fetch SSO Auth Token"); + return null; + } + } catch (ex) { + logger.wtf(ex); + isEventLoadingLoading = false; + notifyListeners(); + Utils.handleException(ex, null, null); + return null; // Ensure a return value in case of an exception + } + } + + Future fetchURLRedirection({required String token}) async { + try { + dynamic res = await DashboardApiClient().getBookingSSOFinalRedirection(token: token); + logger.d("SSO URL: $res"); + return res; + // if (ssoResponse.status == "Success") { + // return ssoResponse; + // } else { + // Utils.showToast(ssoResponse.message!.first ?? "Failed to fetch SSO Auth Token"); + // return null; + // } + } catch (ex) { + logger.wtf(ex); + isEventLoadingLoading = false; + notifyListeners(); + Utils.handleException(ex, null, null); + return null; // Ensure a return value in case of an exception + } + } + List parseMenus(List getMenuEntriesList) { List menus = []; for (int i = 0; i < getMenuEntriesList.length; i++) { @@ -316,8 +373,6 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { return res; } - - void notify() { notifyListeners(); } diff --git a/lib/ui/landing/widget/services_widget.dart b/lib/ui/landing/widget/services_widget.dart index 7c19b58..7589317 100644 --- a/lib/ui/landing/widget/services_widget.dart +++ b/lib/ui/landing/widget/services_widget.dart @@ -1,20 +1,55 @@ +import 'dart:convert'; +import 'dart:developer'; + import 'package:easy_localization/src/public_ext.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:flutter_svg/svg.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; +import 'package:mohem_flutter_app/classes/inAppWebView.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/main.dart'; import 'package:mohem_flutter_app/models/dashboard/menu_entries.dart'; +import 'package:mohem_flutter_app/models/generic_response_model.dart'; +import 'package:mohem_flutter_app/models/sso_auth_model.dart'; import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; import 'package:mohem_flutter_app/ui/my_attendance/dynamic_screens/dynamic_listview_screen.dart'; import 'package:mohem_flutter_app/ui/my_attendance/services_menu_list_screen.dart'; import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart'; import 'package:provider/provider.dart'; +import 'package:url_launcher/url_launcher.dart'; class ServicesWidget extends StatelessWidget { + MyInAppBrowser? myInAppBrowser; + var inAppBrowserOptions = InAppBrowserClassSettings( + webViewSettings: InAppWebViewSettings( + useShouldOverrideUrlLoading: false, + transparentBackground: false, + isInspectable: false, + applePayAPIEnabled: true, + cacheEnabled: false, + allowsBackForwardNavigationGestures: false, + ), + browserSettings: InAppBrowserSettings( + hideUrlBar: true, + hideTitleBar: true, + hideDefaultMenuItems: true, + hideToolbarBottom: true, + hideToolbarTop: false, + hideCloseButton: false, + allowGoBackWithBackButton: false, + toolbarBottomBackgroundColor: Colors.black, + closeButtonColor: Colors.white, + presentationStyle: ModalPresentationStyle.FULL_SCREEN, + // toolbarTopBackgroundColor: Colors.black + ), + ); + @override Widget build(BuildContext context) { List namesT = [LocaleKeys.monthlyAttendance.tr(), LocaleKeys.workFromHome.tr(), LocaleKeys.ticketRequest.tr(), LocaleKeys.monthlyAttendance.tr()]; @@ -26,7 +61,7 @@ class ServicesWidget extends StatelessWidget { "assets/images/vacation_rule.svg", "assets/images/ticket_request.svg", "assets/images/ticket_request.svg", - "assets/images/ticket_request.svg" + "assets/images/ticket_request.svg", ]; return Consumer( @@ -34,72 +69,69 @@ class ServicesWidget extends StatelessWidget { return data.isServicesMenusLoading ? whileLoading() : ListView.separated( - padding: const EdgeInsets.only(top: 0), - itemBuilder: (context, parentIndex) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - data.homeMenus![parentIndex].menuEntry.prompt!.toSectionHeading().paddingOnly(left: 21, right: 21), - SizedBox( - height: 105 + 26, - child: ListView.separated( - shrinkWrap: true, - physics: const BouncingScrollPhysics(), - padding: const EdgeInsets.only(left: 21, right: 21, top: 13, bottom: 13), - scrollDirection: Axis.horizontal, - itemBuilder: (cxt, index) { - return AspectRatio( - aspectRatio: 105 / 105, - child: data.isServicesMenusLoading + padding: const EdgeInsets.only(top: 0), + itemBuilder: (context, parentIndex) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + data.homeMenus![parentIndex].menuEntry.prompt!.toSectionHeading().paddingOnly(left: 21, right: 21), + SizedBox( + height: 105 + 26, + child: ListView.separated( + shrinkWrap: true, + physics: const BouncingScrollPhysics(), + padding: const EdgeInsets.only(left: 21, right: 21, top: 13, bottom: 13), + scrollDirection: Axis.horizontal, + itemBuilder: (cxt, index) { + return AspectRatio( + aspectRatio: 105 / 105, + child: + data.isServicesMenusLoading ? ServicesMenuShimmer() : Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(15), - boxShadow: [ - BoxShadow( - color: const Color(0xff000000).withOpacity(.05), - blurRadius: 26, - offset: const Offset(0, -3), - ), - ], - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SvgPicture.asset(AppState().isArabic(context) + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(15), + boxShadow: [BoxShadow(color: const Color(0xff000000).withOpacity(.05), blurRadius: 26, offset: const Offset(0, -3))], + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SvgPicture.asset( + AppState().isArabic(context) ? getMenuIconAr(data.homeMenus![parentIndex].menuEntiesList[index].prompt!) - : getMenuIconEn(data.homeMenus![parentIndex].menuEntiesList[index].prompt!)), - Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Expanded( - child: data.homeMenus![parentIndex].menuEntiesList[index].prompt!.toText11(isBold: true), - ), - RotatedBox(quarterTurns: AppState().isArabic(context) ? 2 : 4, child: SvgPicture.asset("assets/images/arrow_next.svg").paddingOnly(bottom: 4)), - ], - ) - ], - ).paddingOnly(left: 10, right: 10, bottom: 10, top: 12), - ).onPress(() { - handleOnPress(context, data.homeMenus![parentIndex].menuEntiesList[index]); - }), - ); - }, - separatorBuilder: (cxt, index) => 9.width, - itemCount: data.homeMenus![parentIndex].menuEntiesList.length), + : getMenuIconEn(data.homeMenus![parentIndex].menuEntiesList[index].prompt!), + ), + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Expanded(child: data.homeMenus![parentIndex].menuEntiesList[index].prompt!.toText11(isBold: true)), + RotatedBox(quarterTurns: AppState().isArabic(context) ? 2 : 4, child: SvgPicture.asset("assets/images/arrow_next.svg").paddingOnly(bottom: 4)), + ], + ), + ], + ).paddingOnly(left: 10, right: 10, bottom: 10, top: 12), + ).onPress(() { + handleOnPress(context, data.homeMenus![parentIndex].menuEntiesList[index]); + }), + ); + }, + separatorBuilder: (cxt, index) => 9.width, + itemCount: data.homeMenus![parentIndex].menuEntiesList.length, ), - ], - ); - }, - separatorBuilder: (context, index) { - return 12.height; - }, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: data.homeMenus!.length); + ), + ], + ); + }, + separatorBuilder: (context, index) { + return 12.height; + }, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: data.homeMenus!.length, + ); }, ); } @@ -196,7 +228,7 @@ class ServicesWidget extends StatelessWidget { return returnImage; } - void handleOnPress(context, GetMenuEntriesList menuEntry) { + Future handleOnPress(context, GetMenuEntriesList menuEntry) async { var pro = Provider.of(context, listen: false); if (menuEntry.requestType == "MONTHLY_ATTENDANCE") { Navigator.pushNamed(context, AppRoutes.monthlyAttendance); @@ -220,9 +252,87 @@ class ServicesWidget extends StatelessWidget { Navigator.pushNamed(context, AppRoutes.monthlyPaySlip); } } else { - List _menuList = - pro.getMenuEntriesList?.where((element) => element.parentMenuName == menuEntry.menuName && (element.menuEntryType == "FUNCTION" || element.menuEntryType == "MENU")).toList() ?? []; - Navigator.pushNamed(context, AppRoutes.servicesMenuListScreen, arguments: ServicesMenuListScreenParams(menuEntry.prompt!, _menuList.isEmpty ? menuList : _menuList)); + if (menuEntry.menuName == "HMG_TICKET_REQUESTS") { + Utils.showLoading(context); + print("========="); + TicketBookingResult response = await pro.fetchTicketBooking(); + Utils.hideLoading(context); + if (response.success) { + print("============ Allowed ============"); + SSOAuthModel? ssoToken = await pro.fetchSSOAuthRedirection(clientID: response.clientId); + if (ssoToken != null) { + logger.d(ssoToken.data!.toJson()); + logger.d(ssoToken.data!.accessToken); + + dynamic valu = await pro.fetchURLRedirection(token: ssoToken.data!.accessToken!); + + myInAppBrowser = MyInAppBrowser( + onExitCallback: () { + log("Browser Exited"); + }, + onLoadStartCallback: (String url) { + log("Browser LoadStart for : $url"); + if (url.contains("https://ek.techmaster.in/")) { + // Handle the URL as needed + log("SSO URL Loaded: $url"); + } + }, + ); + + await myInAppBrowser!.openUrlRequest( + urlRequest: URLRequest( + url: WebUri(valu, forceToStringRawValue: true), + allowsCellularAccess: true, + allowsConstrainedNetworkAccess: true, + allowsExpensiveNetworkAccess: true, + // headers: {'Authorization': 'Bearer ${ssoToken.data!.accessToken}'}, + ), + settings: inAppBrowserOptions, + ); + + // Navigator.of(context).push( + // MaterialPageRoute( + // builder: + // (context) => WebViewWidget( + // controller: + // WebViewController() + // ..setJavaScriptMode(JavaScriptMode.unrestricted) + // ..setNavigationDelegate( + // NavigationDelegate( + // onNavigationRequest: (NavigationRequest request) { + // return NavigationDecision.navigate; + // }, + // onHttpError: (HttpResponseError response) { + // print(response.response!.statusCode); + // }, + // onProgress: (int value) { + // print(value); + // }, + // onWebResourceError: (WebResourceError error) { + // print(error.errorCode); + // print(error.description); + // }, + // ), + // ) + // ..loadRequest(Uri.parse("https://ek.techmaster.in/SSO/HMG"), headers: {'Authorization': 'Bearer ${ssoToken.data!.accessToken}'}), + // ), + // ), + // ); + + // launchUrl(Uri.parse("https://ek.techmaster.in/SSO/HMG"),headers: {'Authorization': 'Bearer ${ssoToken.data!.accessToken}'}, mode: LaunchMode.inAppBrowserView); + // ddv + print("============ Token Fetched ============"); + } + } else { + List _menuList = + pro.getMenuEntriesList?.where((element) => element.parentMenuName == menuEntry.menuName && (element.menuEntryType == "FUNCTION" || element.menuEntryType == "MENU")).toList() ?? []; + Navigator.pushNamed(context, AppRoutes.servicesMenuListScreen, arguments: ServicesMenuListScreenParams(menuEntry.prompt!, _menuList.isEmpty ? menuList : _menuList)); + } + } else { + List _menuList = + pro.getMenuEntriesList?.where((element) => element.parentMenuName == menuEntry.menuName && (element.menuEntryType == "FUNCTION" || element.menuEntryType == "MENU")).toList() ?? []; + Navigator.pushNamed(context, AppRoutes.servicesMenuListScreen, arguments: ServicesMenuListScreenParams(menuEntry.prompt!, _menuList.isEmpty ? menuList : _menuList)); + } } return; } @@ -253,10 +363,7 @@ class ServicesWidget extends StatelessWidget { padding: const EdgeInsets.only(left: 21, right: 21, top: 13, bottom: 13), scrollDirection: Axis.horizontal, itemBuilder: (cxt, index) { - return AspectRatio( - aspectRatio: 105 / 105, - child: ServicesMenuShimmer(), - ); + return AspectRatio(aspectRatio: 105 / 105, child: ServicesMenuShimmer()); }, separatorBuilder: (cxt, index) => 9.width, itemCount: 4, diff --git a/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart b/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart index 30a9fa2..d791a18 100644 --- a/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart +++ b/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart @@ -16,7 +16,7 @@ import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; import 'package:mohem_flutter_app/models/offers_and_discounts/get_offers_list.dart'; import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; import 'package:path_provider/path_provider.dart'; -import 'package:share/share.dart'; +import 'package:share_plus/share_plus.dart'; import 'package:url_launcher/url_launcher.dart'; class OffersAndDiscountsDetails extends StatefulWidget { @@ -127,7 +127,7 @@ class _OffersAndDiscountsDetailsState extends State { Directory tempDir = await getTemporaryDirectory(); File file = await File('${tempDir.path}/${DateTime.now().toString()}.png').create(); await file.writeAsBytes(pngBytes); - await Share.shareFiles([(file.path)], text: AppState().isArabic(context) ? getOffersList[0].titleAr : getOffersList[0].titleEn); + await SharePlus.instance.share(ShareParams(files: [(XFile(file.path))], text: AppState().isArabic(context) ? getOffersList[0].titleAr : getOffersList[0].titleEn)); } catch (ex) { debugPrint(ex.toString()); } @@ -155,7 +155,7 @@ class _OffersAndDiscountsDetailsState extends State { mainAxisSize: MainAxisSize.min, children: [ Hero( - tag: "ItemImage" + getOffersList.offersDiscountId.toString()!, + tag: "ItemImage" + getOffersList.offersDiscountId.toString(), transitionOnUserGestures: true, child: AspectRatio( aspectRatio: 148 / 127, diff --git a/lib/widgets/mark_attendance_widget.dart b/lib/widgets/mark_attendance_widget.dart index 508ed00..ee258e1 100644 --- a/lib/widgets/mark_attendance_widget.dart +++ b/lib/widgets/mark_attendance_widget.dart @@ -24,7 +24,6 @@ import 'package:mohem_flutter_app/widgets/nfc/nfc_reader_sheet.dart'; import 'package:mohem_flutter_app/widgets/qr_scanner_dialog.dart'; import 'package:nfc_manager/nfc_manager.dart'; import 'package:permission_handler/permission_handler.dart'; -import 'package:platform_device_id/platform_device_id.dart'; import 'package:wifi_iot/wifi_iot.dart'; class MarkAttendanceWidget extends StatefulWidget { diff --git a/pubspec.yaml b/pubspec.yaml index 27f23f2..24bb5c2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -41,7 +41,7 @@ dependencies: provider: ^6.0.1 easy_localization: ^3.0.0 http: ^1.3.0 - permission_handler: ^10.2.0 + permission_handler: ^12.0.1 flutter_svg: any sizer: ^2.0.15 local_auth: ^2.3.0 @@ -50,19 +50,16 @@ dependencies: # flutter_calendar_carousel: ^2.1.0 pie_chart: ^5.1.0 shared_preferences: ^2.0.12 - firebase_messaging: ^13.0.4 + firebase_messaging: ^15.2.9 shimmer: ^2.0.0 logger: ^1.1.0 flutter_countdown_timer: ^4.1.0 - nfc_manager: ^3.2.0 - # uuid: ^3.0.6 - # device_info_plus: ^4.0.0 - # android_id: ^0.1.3+1 - platform_device_id: ^1.0.1 + + platform_device_id_plus: ^1.0.7 image_picker: ^0.8.5+3 file_picker: ^8.3.1 geolocator: ^9.0.2 - month_year_picker: ^0.4.0+1 + month_year_picker: ^0.5.0+1 month_picker_dialog: ^6.0.3 # open_file: ^3.2.1 open_filex: ^4.6.0 @@ -72,7 +69,7 @@ dependencies: qr_code_scanner: ^1.0.1 # qr_flutter: ^4.0.0 url_launcher: ^6.0.15 - share: 2.0.4 + share_plus: ^11.0.0 flutter_rating_bar: ^4.0.1 auto_size_text: ^3.0.0 pull_to_refresh: ^2.0.0 @@ -112,17 +109,27 @@ dependencies: # huawei_hmsavailability: ^6.6.0+300 # huawei_location: 6.0.0+302 huawei_location: ^6.11.0+301 - huawei_push: ^6.7.0+300 - firebase_crashlytics: ^2.9.0 +# huawei_push: ^6.7.0+300 + + huawei_map: + git: + url: https://github.com/fleoparra/hms-flutter-plugin.git + path: flutter-hms-map + huawei_push: + git: + url: https://github.com/crasowas/hms-flutter-plugin.git + path: flutter-hms-push + firebase_crashlytics: ^4.3.9 #Items for sale Image Carousel Slider carousel_slider: ^5.0.0 #Huawei Specified # store_checker: ^1.1.0 - google_api_availability: ^3.0.1 + google_api_availability: ^5.0.1 in_app_update: 4.1.0 + flutter_inappwebview: ^6.1.5 #todo its for temporary purpose, later will remove this. dotted_border: ^2.0.0+3 @@ -131,7 +138,8 @@ dependencies: dependency_overrides: - firebase_core_platform_interface: 4.5.1 + nfc_manager: ^3.2.0 +# firebase_core_platform_interface: 4.5.1 dev_dependencies: -- 2.30.2 From f61817937bfc16488652c123a95a3eeaf4b0e880 Mon Sep 17 00:00:00 2001 From: Aamir Muhammad Date: Tue, 22 Jul 2025 10:31:33 +0300 Subject: [PATCH 081/135] tickt booking implementation --- lib/api/dashboard_api_client.dart | 2 +- lib/ui/landing/widget/services_widget.dart | 52 +++++++++--------- lib/widgets/sso_webview_widget.dart | 61 ++++++++++++++++++++++ pubspec.yaml | 1 + 4 files changed, 90 insertions(+), 26 deletions(-) create mode 100644 lib/widgets/sso_webview_widget.dart diff --git a/lib/api/dashboard_api_client.dart b/lib/api/dashboard_api_client.dart index e8a94cd..28226ce 100644 --- a/lib/api/dashboard_api_client.dart +++ b/lib/api/dashboard_api_client.dart @@ -179,7 +179,7 @@ class DashboardApiClient { // "ClientId": "a9f4d1a0596d4aea8f830992ec4bdac1", "PersonId": AppState().memberInformationList?.eMPLOYEENUMBER, "Username": AppState().memberInformationList?.eMPLOYEENUMBER, - "Language": "en", + "Language": "US", }; postParams.addAll(AppState().postParamsJson); return await ApiClient().postJsonForObject( diff --git a/lib/ui/landing/widget/services_widget.dart b/lib/ui/landing/widget/services_widget.dart index 7589317..7bb9bd4 100644 --- a/lib/ui/landing/widget/services_widget.dart +++ b/lib/ui/landing/widget/services_widget.dart @@ -21,6 +21,7 @@ import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; import 'package:mohem_flutter_app/ui/my_attendance/dynamic_screens/dynamic_listview_screen.dart'; import 'package:mohem_flutter_app/ui/my_attendance/services_menu_list_screen.dart'; import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart'; +import 'package:mohem_flutter_app/widgets/sso_webview_widget.dart'; import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -263,32 +264,33 @@ class ServicesWidget extends StatelessWidget { if (ssoToken != null) { logger.d(ssoToken.data!.toJson()); logger.d(ssoToken.data!.accessToken); + dynamic url = await pro.fetchURLRedirection(token: ssoToken.data!.accessToken!); + Navigator.push(context, MaterialPageRoute(builder: (context) => SsoLoginWebView(url: url ?? "", jwtToken: ssoToken.data!.accessToken!))); - dynamic valu = await pro.fetchURLRedirection(token: ssoToken.data!.accessToken!); - - myInAppBrowser = MyInAppBrowser( - onExitCallback: () { - log("Browser Exited"); - }, - onLoadStartCallback: (String url) { - log("Browser LoadStart for : $url"); - if (url.contains("https://ek.techmaster.in/")) { - // Handle the URL as needed - log("SSO URL Loaded: $url"); - } - }, - ); - - await myInAppBrowser!.openUrlRequest( - urlRequest: URLRequest( - url: WebUri(valu, forceToStringRawValue: true), - allowsCellularAccess: true, - allowsConstrainedNetworkAccess: true, - allowsExpensiveNetworkAccess: true, - // headers: {'Authorization': 'Bearer ${ssoToken.data!.accessToken}'}, - ), - settings: inAppBrowserOptions, - ); + // + // myInAppBrowser = MyInAppBrowser( + // onExitCallback: () { + // log("Browser Exited"); + // }, + // onLoadStartCallback: (String url) { + // log("Browser LoadStart for : $url"); + // if (url.contains("https://ek.techmaster.in/")) { + // // Handle the URL as needed + // log("SSO URL Loaded: $url"); + // } + // }, + // ); + // + // await myInAppBrowser!.openUrlRequest( + // urlRequest: URLRequest( + // url: WebUri(valu, forceToStringRawValue: true), + // allowsCellularAccess: true, + // allowsConstrainedNetworkAccess: true, + // allowsExpensiveNetworkAccess: true, + // // headers: {'Authorization': 'Bearer ${ssoToken.data!.accessToken}'}, + // ), + // settings: inAppBrowserOptions, + // ); // Navigator.of(context).push( // MaterialPageRoute( diff --git a/lib/widgets/sso_webview_widget.dart b/lib/widgets/sso_webview_widget.dart new file mode 100644 index 0000000..e5f2759 --- /dev/null +++ b/lib/widgets/sso_webview_widget.dart @@ -0,0 +1,61 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:webview_flutter/webview_flutter.dart'; + +class SsoLoginWebView extends StatefulWidget { + final String url; + final String jwtToken; + + SsoLoginWebView({required this.url, required this.jwtToken}); + + @override + State createState() => _SsoLoginWebViewState(); +} + +class _SsoLoginWebViewState extends State { + late final WebViewController _controller; + + @override + void initState() { + // TODO: implement initState + super.initState(); + _controller = + WebViewController() + ..setJavaScriptMode(JavaScriptMode.unrestricted) + ..setNavigationDelegate( + NavigationDelegate( + onProgress: (int progress) { + print("WebView is loading (progress: $progress%)"); + }, + onPageStarted: (String url) { + print("Page started loading: $url"); + }, + onPageFinished: (String url) { + print("Page finished loading: $url"); + }, + onHttpError: (HttpResponseError error) { + print("HTTP error: ${error.toString()} for URL: ${error.response!.statusCode}"); + }, + onWebResourceError: (WebResourceError error) { + print("Web resource error: ${error.description} for URL: ${error.errorType}"); + }, + ), + ) + ..loadHtmlString(''' + + + +

+ + +

Redirecting...

+ +'''); + } + + @override + Widget build(BuildContext context) { + return Scaffold(appBar: AppBar(title: Text('Logging in...')), body: WebViewWidget(controller: _controller)); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 24bb5c2..54d313f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -133,6 +133,7 @@ dependencies: #todo its for temporary purpose, later will remove this. dotted_border: ^2.0.0+3 + webview_flutter: ^4.13.0 # saf: ^1.0.3+4 -- 2.30.2 From 515ffef14ea72653273cb4fd08239729a635990d Mon Sep 17 00:00:00 2001 From: Aamir Muhammad Date: Tue, 22 Jul 2025 10:32:21 +0300 Subject: [PATCH 082/135] tickt booking implementation --- lib/ui/landing/widget/services_widget.dart | 60 ---------------------- 1 file changed, 60 deletions(-) diff --git a/lib/ui/landing/widget/services_widget.dart b/lib/ui/landing/widget/services_widget.dart index 7bb9bd4..7d2c2b2 100644 --- a/lib/ui/landing/widget/services_widget.dart +++ b/lib/ui/landing/widget/services_widget.dart @@ -255,75 +255,15 @@ class ServicesWidget extends StatelessWidget { } else { if (menuEntry.menuName == "HMG_TICKET_REQUESTS") { Utils.showLoading(context); - print("========="); TicketBookingResult response = await pro.fetchTicketBooking(); Utils.hideLoading(context); if (response.success) { - print("============ Allowed ============"); SSOAuthModel? ssoToken = await pro.fetchSSOAuthRedirection(clientID: response.clientId); if (ssoToken != null) { logger.d(ssoToken.data!.toJson()); logger.d(ssoToken.data!.accessToken); dynamic url = await pro.fetchURLRedirection(token: ssoToken.data!.accessToken!); Navigator.push(context, MaterialPageRoute(builder: (context) => SsoLoginWebView(url: url ?? "", jwtToken: ssoToken.data!.accessToken!))); - - // - // myInAppBrowser = MyInAppBrowser( - // onExitCallback: () { - // log("Browser Exited"); - // }, - // onLoadStartCallback: (String url) { - // log("Browser LoadStart for : $url"); - // if (url.contains("https://ek.techmaster.in/")) { - // // Handle the URL as needed - // log("SSO URL Loaded: $url"); - // } - // }, - // ); - // - // await myInAppBrowser!.openUrlRequest( - // urlRequest: URLRequest( - // url: WebUri(valu, forceToStringRawValue: true), - // allowsCellularAccess: true, - // allowsConstrainedNetworkAccess: true, - // allowsExpensiveNetworkAccess: true, - // // headers: {'Authorization': 'Bearer ${ssoToken.data!.accessToken}'}, - // ), - // settings: inAppBrowserOptions, - // ); - - // Navigator.of(context).push( - // MaterialPageRoute( - // builder: - // (context) => WebViewWidget( - // controller: - // WebViewController() - // ..setJavaScriptMode(JavaScriptMode.unrestricted) - // ..setNavigationDelegate( - // NavigationDelegate( - // onNavigationRequest: (NavigationRequest request) { - // return NavigationDecision.navigate; - // }, - // onHttpError: (HttpResponseError response) { - // print(response.response!.statusCode); - // }, - // onProgress: (int value) { - // print(value); - // }, - // onWebResourceError: (WebResourceError error) { - // print(error.errorCode); - // print(error.description); - // }, - // ), - // ) - // ..loadRequest(Uri.parse("https://ek.techmaster.in/SSO/HMG"), headers: {'Authorization': 'Bearer ${ssoToken.data!.accessToken}'}), - // ), - // ), - // ); - - // launchUrl(Uri.parse("https://ek.techmaster.in/SSO/HMG"),headers: {'Authorization': 'Bearer ${ssoToken.data!.accessToken}'}, mode: LaunchMode.inAppBrowserView); - // ddv - print("============ Token Fetched ============"); } } else { List _menuList = -- 2.30.2 From 56b18c493a8cfabd184e72eb1d89f578b4a15f0e Mon Sep 17 00:00:00 2001 From: Aamir Muhammad Date: Sun, 27 Jul 2025 16:12:21 +0300 Subject: [PATCH 083/135] mazaya banner changes --- assets/icons/mazaya_brand.svg | 17 + assets/langs/ar-SA.json | 6 +- assets/langs/en-US.json | 7 +- lib/generated/codegen_loader.g.dart | 32 +- lib/generated/locale_keys.g.dart | 15 +- lib/ui/landing/dashboard_screen.dart | 315 ++++++++++++------ .../offers_and_discounts_home.dart | 2 +- lib/widgets/app_bar_widget.dart | 27 +- 8 files changed, 290 insertions(+), 131 deletions(-) create mode 100755 assets/icons/mazaya_brand.svg diff --git a/assets/icons/mazaya_brand.svg b/assets/icons/mazaya_brand.svg new file mode 100755 index 0000000..52fb265 --- /dev/null +++ b/assets/icons/mazaya_brand.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index c4c5f20..d874779 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -615,5 +615,9 @@ "searchByUserName": "البحث بواسطة اسم المستخدم", "shareScreen": "مشاركة الشاشة", "start":"يبدأ", - "about":"عن" + "about":"عن", + "explore": "يستكشف", + "mazaya": "مازيا", + "benefits": "فوائد", + "mazayaDesc": "اكتشف الخصومات والعروض الخاصة المتاحة للموظفين" } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 559b9c9..ae4dcbc 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -613,5 +613,10 @@ "bonusQty": "Bonus Qty.", "balQty": "Bal. Qty.", "start":"Start", - "about":"About" + "about":"About", + "explore": "Explore", + "mazaya": "MAZAYA", + "benefits": "Benefits", + "mazayaDesc": "Discover special Discounts and offers available to Employees" + } \ No newline at end of file diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index 0e2cfbf..fac1d05 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -1,6 +1,6 @@ // DO NOT EDIT. This is code generated via package:easy_localization/generate.dart -// ignore_for_file: prefer_single_quotes, avoid_renaming_method_parameters +// ignore_for_file: prefer_single_quotes, avoid_renaming_method_parameters, constant_identifier_names import 'dart:ui'; @@ -14,7 +14,7 @@ class CodegenLoader extends AssetLoader{ return Future.value(mapLocales[locale.toString()]); } - static const Map ar_SA = { + static const Map _ar_SA = { "mohemm": "Mohemm", "english": "English", "arabic": "عربي", @@ -116,6 +116,7 @@ class CodegenLoader extends AssetLoader{ "reject": "يرفض", "approve": "يوافق", "cancel": "إلغاء", + "generate": "يولد", "requestedItems": "العناصر المطلوبة", "request": "طلب", "myRequest": "طلبي", @@ -560,10 +561,9 @@ class CodegenLoader extends AssetLoader{ "missingDocuments": "مستندات مفقودة", "uploadedDocuments": "المستندات التي تم تحميلها", "addAtLeastOneAttachment": "الرجاء إضافة مرفق واحد على الأقل.", - "open": "يفتح", - "youCannotJoinTheMarathon": "لا يمكنك الانضمام إلى الماراثون لأنك تجاوزت الحد الزمني", "pleaseClickButtonToJoinMarathon": "الرجاء الضغط على الزر أدناه للانضمام إلى الماراثون", - "generate": "يولد", + "youCannotJoinTheMarathon": "لا يمكنك الانضمام إلى الماراثون لأنك تجاوزت الحد الزمني", + "open": "يفتح", "paymentRequest": "طلب الدفع", "paymentDetails": "تفاصيل الدفع", "requestNo": "رقم الطلب", @@ -627,10 +627,14 @@ class CodegenLoader extends AssetLoader{ "members": "الأعضاء", "searchByUserName": "البحث بواسطة اسم المستخدم", "shareScreen": "مشاركة الشاشة", - "start":"يبدأ", - "about":"عن" + "start": "يبدأ", + "about": "عن", + "explore": "يستكشف", + "mazaya": "مازيا", + "benefits": "فوائد", + "mazayaDesc": "اكتشف الخصومات والعروض الخاصة المتاحة للموظفين" }; -static const Map en_US = { +static const Map _en_US = { "mohemm": "Mohemm", "english": "English", "arabic": "عربي", @@ -725,6 +729,7 @@ static const Map en_US = { "whatsapp": "Whatsapp", "reject": "Reject", "approve": "Approve", + "generate": "Generate", "cancel": "Cancel", "requestedItems": "Requested Items", "request": "Request", @@ -1197,7 +1202,6 @@ static const Map en_US = { "pleaseClickButtonToJoinMarathon": "Press the button below to join the Marathon.", "youCannotJoinTheMarathon": "You cannot join the Marathon because you have exceeded the time limit.", "requesterOperatingUnit": "Requester Operating Unit", - "generate": "Generate", "paymentRequest": "Pay Request", "paymentDetails": "Payment Details", "requestNo": "Request No", @@ -1243,8 +1247,12 @@ static const Map en_US = { "qtyReceived": "Qty. Received", "bonusQty": "Bonus Qty.", "balQty": "Bal. Qty.", - "start":"Start", - "about":"About" + "start": "Start", + "about": "About", + "explore": "Explore", + "mazaya": "MAZAYA", + "benefits": "Benefits", + "mazayaDesc": "Discover special Discounts and offers available to Employees" }; -static const Map> mapLocales = {"ar_SA": ar_SA, "en_US": en_US}; +static const Map> mapLocales = {"ar_SA": _ar_SA, "en_US": _en_US}; } diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index f8bc858..41023f4 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -1,5 +1,7 @@ // DO NOT EDIT. This is code generated via package:easy_localization/generate.dart +// ignore_for_file: constant_identifier_names + abstract class LocaleKeys { static const mohemm = 'mohemm'; static const english = 'english'; @@ -101,6 +103,7 @@ abstract class LocaleKeys { static const reject = 'reject'; static const approve = 'approve'; static const cancel = 'cancel'; + static const generate = 'generate'; static const requestedItems = 'requestedItems'; static const request = 'request'; static const myRequest = 'myRequest'; @@ -530,10 +533,9 @@ abstract class LocaleKeys { static const missingDocuments = 'missingDocuments'; static const uploadedDocuments = 'uploadedDocuments'; static const addAtLeastOneAttachment = 'addAtLeastOneAttachment'; - static const open = 'open'; - static const youCannotJoinTheMarathon = 'youCannotJoinTheMarathon'; static const pleaseClickButtonToJoinMarathon = 'pleaseClickButtonToJoinMarathon'; - static const generate = 'generate'; + static const youCannotJoinTheMarathon = 'youCannotJoinTheMarathon'; + static const open = 'open'; static const paymentRequest = 'paymentRequest'; static const paymentDetails = 'paymentDetails'; static const requestNo = 'requestNo'; @@ -598,5 +600,10 @@ abstract class LocaleKeys { static const searchByUserName = 'searchByUserName'; static const shareScreen = 'shareScreen'; static const start = 'start'; - static const about ='about'; + static const about = 'about'; + static const explore = 'explore'; + static const mazaya = 'mazaya'; + static const benefits = 'benefits'; + static const mazayaDesc = 'mazayaDesc'; + } diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index 9a7c1ee..b2f819f 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -415,116 +415,227 @@ class _DashboardScreenState extends State with WidgetsBindingOb ), ), 9.width, - Expanded( - child: MenusWidget(), - ), + Expanded(child: MenusWidget()), ], ), ], ).paddingOnly(left: 21, right: 21, top: 7, bottom: 21), eventActivityWidget(context), - Consumer(builder: (BuildContext context, DashboardProviderModel model, Widget? child) { - if (!model.isOffersLoading && model.getOffersList.isEmpty) { - return const SizedBox(); - } - return Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - LocaleKeys.offers.tr().toText12(), - Row( - children: [ - LocaleKeys.discounts.tr().toText24(isBold: true), - 6.width, - Container( - padding: const EdgeInsets.only(left: 8, right: 8), - decoration: BoxDecoration( - color: MyColors.yellowColor, - borderRadius: BorderRadius.circular(10), - ), - child: LocaleKeys.newString.tr().toText10(isBold: true)), - ], - ), - ], + Consumer( + builder: (BuildContext context, DashboardProviderModel model, Widget? child) { + if (!model.isOffersLoading && model.getOffersList.isEmpty) { + return const SizedBox(); + } + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Directionality( + textDirection: AppState().isArabic(context) ? ui.TextDirection.rtl : ui.TextDirection.ltr, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + gradient: const LinearGradient(colors: [Color(0xFF91C481), Color(0xFF7CCED7)], begin: Alignment.centerLeft, end: Alignment.centerRight), ), - ), - LocaleKeys.viewAllOffers.tr().toText12(isUnderLine: true).onPress(() { - Navigator.pushNamed(context, AppRoutes.offersAndDiscounts); - }) - ], - ).paddingOnly(left: 21, right: 21), - Consumer( - builder: (BuildContext context, DashboardProviderModel model, Widget? child) { - return SizedBox( - height: 103 + 33, - child: ListView.separated( - shrinkWrap: true, - physics: const BouncingScrollPhysics(), - padding: const EdgeInsets.only(left: 21, right: 21, top: 13), - scrollDirection: Axis.horizontal, - itemBuilder: (BuildContext cxt, int index) { - return model.isOffersLoading - ? const OffersShimmerWidget() - : InkWell( - onTap: () { - navigateToDetails(data.getOffersList[index]); - }, - child: SizedBox( - width: 73, - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Container( - width: 73, - height: 73, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: const BorderRadius.all( - Radius.circular(100), - ), - border: Border.all(color: MyColors.lightGreyE3Color, width: 1), - ), - child: ClipRRect( - borderRadius: const BorderRadius.all( - Radius.circular(50), - ), - child: Hero( - tag: "ItemImage" + data.getOffersList[index].offersDiscountId.toString()!, - transitionOnUserGestures: true, - child: Image.network( - data.getOffersList[index].logo ?? "", - fit: BoxFit.contain, - ), - ), - ), - ), - 4.height, - Expanded( - child: AppState().isArabic(context) - ? data.getOffersList[index].titleAr!.toText12(isCenter: true, maxLine: 1) - : data.getOffersList[index].titleEn!.toText12(isCenter: true, maxLine: 1), + child: Padding( + padding: const EdgeInsets.all(3.0), // This creates the border width + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(17), // Slightly less than outer radius + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + flex: 4, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Row( + children: [ + Expanded( + flex: 2, + child: RichText( + text: + AppState().isArabic(context) + ? const TextSpan( + children: [ + TextSpan( + text: 'اطلع على مميزات', + style: TextStyle(fontSize: 16, letterSpacing: -0.2, fontWeight: FontWeight.w700, height: 24 / 16, color: Color(0xFF5D5E5E)), + ), + TextSpan( + text: ' مزايا', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w700, + letterSpacing: -0.2, + height: 24 / 16, + color: Color(0xFFED1C2B), // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed + ), + ), + ], + ) + : TextSpan( + children: [ + TextSpan( + text: LocaleKeys.explore.tr() + ' ', + style: const TextStyle(fontSize: 16, letterSpacing: -0.2, fontWeight: FontWeight.w700, height: 24 / 16, color: Color(0xFF5D5E5E)), + ), + TextSpan( + text: LocaleKeys.mazaya.tr(), + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.w700, + letterSpacing: -0.2, + height: 24 / 16, + color: Color(0xFFED1C2B), // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed + ), + ), + TextSpan( + text: ' ' + LocaleKeys.benefits.tr(), + style: const TextStyle(fontSize: 16, letterSpacing: -0.2, fontWeight: FontWeight.w700, height: 24 / 16, color: Color(0xFF5D5E5E)), + ), + ], + ), ), - ], - ), + ), + const Expanded(flex: 1, child: SizedBox()), + ], ), - ); - }, - separatorBuilder: (BuildContext cxt, int index) => 8.width, - itemCount: 9), - ); - }, - ), - ], - ); - }), + const SizedBox(height: 8), + LocaleKeys.mazayaDesc.tr().toText11(color: const Color(0xFF5D5E5E)), + ], + ), + ), + Expanded( + flex: 2, + child: Column( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + SvgPicture.asset("assets/icons/mazaya_brand.svg", width: 90, height: 47), + const SizedBox(height: 28), + LocaleKeys.viewAllOffers.tr().toText12(isUnderLine: true, color: const Color(0xFF3B3D4A)).onPress(() { + Navigator.pushNamed(context, AppRoutes.offersAndDiscounts); + }), + ], + ), + ), + ], + ).paddingOnly(left: 21, right: 21, top: 14, bottom: 14), + ), + ), + ).paddingOnly(left: 21, right: 21, top: 0, bottom: 21), + ), + + // Container( + // height: 121, + // decoration: BoxDecoration( + // borderRadius: BorderRadius.circular(12), + // border: Border.all(width: 3, color: Colors.red), + // ), + // child: Padding(padding: const EdgeInsets.all(4.0), child: Container(decoration: BoxDecoration(borderRadius: BorderRadius.circular(12), color: Colors.white))), + // ).paddingOnly(left: 21, right: 21, bottom: 21), + + // Row( + // crossAxisAlignment: CrossAxisAlignment.center, + // children: [ + // Expanded( + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // mainAxisSize: MainAxisSize.min, + // children: [ + // LocaleKeys.offers.tr().toText12(), + // Row( + // children: [ + // LocaleKeys.discounts.tr().toText24(isBold: true), + // 6.width, + // Container( + // padding: const EdgeInsets.only(left: 8, right: 8), + // decoration: BoxDecoration( + // color: MyColors.yellowColor, + // borderRadius: BorderRadius.circular(10), + // ), + // child: LocaleKeys.newString.tr().toText10(isBold: true)), + // ], + // ), + // ], + // ), + // ), + // LocaleKeys.viewAllOffers.tr().toText12(isUnderLine: true).onPress(() { + // Navigator.pushNamed(context, AppRoutes.offersAndDiscounts); + // }) + // ], + // ).paddingOnly(left: 21, right: 21), + // Consumer( + // builder: (BuildContext context, DashboardProviderModel model, Widget? child) { + // return SizedBox( + // height: 103 + 33, + // child: ListView.separated( + // shrinkWrap: true, + // physics: const BouncingScrollPhysics(), + // padding: const EdgeInsets.only(left: 21, right: 21, top: 13), + // scrollDirection: Axis.horizontal, + // itemBuilder: (BuildContext cxt, int index) { + // return model.isOffersLoading + // ? const OffersShimmerWidget() + // : InkWell( + // onTap: () { + // navigateToDetails(data.getOffersList[index]); + // }, + // child: SizedBox( + // width: 73, + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.center, + // children: [ + // Container( + // width: 73, + // height: 73, + // decoration: BoxDecoration( + // color: Colors.white, + // borderRadius: const BorderRadius.all( + // Radius.circular(100), + // ), + // border: Border.all(color: MyColors.lightGreyE3Color, width: 1), + // ), + // child: ClipRRect( + // borderRadius: const BorderRadius.all( + // Radius.circular(50), + // ), + // child: Hero( + // tag: "ItemImage" + data.getOffersList[index].offersDiscountId.toString()!, + // transitionOnUserGestures: true, + // child: Image.network( + // data.getOffersList[index].logo ?? "", + // fit: BoxFit.contain, + // ), + // ), + // ), + // ), + // 4.height, + // Expanded( + // child: AppState().isArabic(context) + // ? data.getOffersList[index].titleAr!.toText12(isCenter: true, maxLine: 1) + // : data.getOffersList[index].titleEn!.toText12(isCenter: true, maxLine: 1), + // ), + // ], + // ), + // ), + // ); + // }, + // separatorBuilder: (BuildContext cxt, int index) => 8.width, + // itemCount: 9), + // ); + // }, + // ), + ], + ); + }, + ), Container( width: double.infinity, padding: const EdgeInsets.only(top: 31), diff --git a/lib/ui/screens/offers_and_discounts/offers_and_discounts_home.dart b/lib/ui/screens/offers_and_discounts/offers_and_discounts_home.dart index fd2c19e..f67a835 100644 --- a/lib/ui/screens/offers_and_discounts/offers_and_discounts_home.dart +++ b/lib/ui/screens/offers_and_discounts/offers_and_discounts_home.dart @@ -39,7 +39,7 @@ class _OffersAndDiscountsHomeState extends State { Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, - appBar: AppBarWidget(context, title: LocaleKeys.offerAndDiscounts.tr(), showHomeButton: true), + appBar: AppBarWidget(context, title: LocaleKeys.offerAndDiscounts.tr(), showHomeButton: true, showLogo: true, logoPath: "assets/icons/mazaya_brand.svg"), body: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/widgets/app_bar_widget.dart b/lib/widgets/app_bar_widget.dart index 744b7eb..d91111d 100644 --- a/lib/widgets/app_bar_widget.dart +++ b/lib/widgets/app_bar_widget.dart @@ -1,18 +1,23 @@ import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; import 'package:mohem_flutter_app/classes/colors.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'; -AppBar AppBarWidget(BuildContext context, - {required String title, - bool showHomeButton = true, - bool showWorkListSettingButton = false, - bool showMemberButton = false, - List? actions, - void Function()? onHomeTapped, - void Function()? onBackTapped}) { +AppBar AppBarWidget( + BuildContext context, { + required String title, + bool showHomeButton = true, + bool showLogo = false, + String? logoPath, + bool showWorkListSettingButton = false, + bool showMemberButton = false, + List? actions, + void Function()? onHomeTapped, + void Function()? onBackTapped, +}) { return AppBar( leadingWidth: 0, @@ -26,8 +31,10 @@ AppBar AppBarWidget(BuildContext context, }, context), child: const Icon(Icons.arrow_back_ios, color: MyColors.darkIconColor), ), + if (showLogo) 4.width, + if (showLogo) SvgPicture.asset(logoPath!), 4.width, - title.toText24(color: MyColors.darkTextColor, isBold: true).expanded, + if (!showLogo)title.toText24(color: MyColors.darkTextColor, isBold: true).expanded, ], ), centerTitle: false, @@ -55,7 +62,7 @@ AppBar AppBarWidget(BuildContext context, }, icon: const Icon(Icons.people, color: MyColors.textMixColor), ), - ...actions ?? [] + ...actions ?? [], ], ); } -- 2.30.2 From 8d6c3ddc0bb033e3296e22e18a93dec6e15983b7 Mon Sep 17 00:00:00 2001 From: Aamir Muhammad Date: Sun, 27 Jul 2025 16:35:14 +0300 Subject: [PATCH 084/135] mazaya banner changes --- assets/icons/mazaya_brand.svg | 17 + assets/langs/ar-SA.json | 13 +- assets/langs/en-US.json | 14 +- lib/classes/consts.dart | 4 +- lib/generated/codegen_loader.g.dart | 9 +- lib/generated/locale_keys.g.dart | 13 +- lib/ui/landing/dashboard_screen.dart | 632 ++++++++++-------- lib/ui/landing/widget/services_widget.dart | 159 +++-- .../offers_and_discounts_home.dart | 2 +- lib/widgets/app_bar_widget.dart | 27 +- 10 files changed, 518 insertions(+), 372 deletions(-) create mode 100755 assets/icons/mazaya_brand.svg diff --git a/assets/icons/mazaya_brand.svg b/assets/icons/mazaya_brand.svg new file mode 100755 index 0000000..52fb265 --- /dev/null +++ b/assets/icons/mazaya_brand.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index d840a9b..d874779 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -548,8 +548,6 @@ "pleaseClickButtonToJoinMarathon": "الرجاء الضغط على الزر أدناه للانضمام إلى الماراثون", "youCannotJoinTheMarathon": "لا يمكنك الانضمام إلى الماراثون لأنك تجاوزت الحد الزمني", "open": "يفتح", -<<<<<<< HEAD -======= "youCannotJoinTheMarathon": "لا يمكنك الانضمام إلى الماراثون لأنك تجاوزت الحد الزمني", "pleaseClickButtonToJoinMarathon": "الرجاء الضغط على الزر أدناه للانضمام إلى الماراثون", "generate": "يولد", @@ -577,7 +575,6 @@ "versionStatus": "حالة الإصدار", "supplierNo": "رقم المورد", "general": "عام", ->>>>>>> master "requesterOperatingUnit":"وحدة تشغيل مقدم الطلب", "prepareEmpNum":"إعداد رقم الموظف", "supplierInfo" : "معلومات المورد", @@ -591,9 +588,6 @@ "patientName" : "اسم المريض", "invoiceDate" : "تاريخ الفاتورة", "refundInvoice" :"فاتورة الاسترجاع", -<<<<<<< HEAD - "hospitalClinic" : "عيادة المستشفى" -======= "hospitalClinic" : "عيادة المستشفى", "graphicalAnalysis": "التحليل الرسومي", "itemHistoryAnalysis": "تحليل تاريخ العنصر", @@ -621,6 +615,9 @@ "searchByUserName": "البحث بواسطة اسم المستخدم", "shareScreen": "مشاركة الشاشة", "start":"يبدأ", - "about":"عن" ->>>>>>> master + "about":"عن", + "explore": "يستكشف", + "mazaya": "مازيا", + "benefits": "فوائد", + "mazayaDesc": "اكتشف الخصومات والعروض الخاصة المتاحة للموظفين" } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 2ab3649..ae4dcbc 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -566,8 +566,6 @@ "pleaseClickButtonToJoinMarathon": "Press the button below to join the Marathon.", "youCannotJoinTheMarathon": "You cannot join the Marathon because you have exceeded the time limit.", "requesterOperatingUnit":"Requester Operating Unit", -<<<<<<< HEAD -======= "generate": "Generate", "paymentRequest": "Pay Request", "paymentDetails": "Payment Details", @@ -593,7 +591,6 @@ "versionStatus": "Version Status", "supplierNo": "Supplier No", "general": "General", ->>>>>>> master "prepareEmpNum":"Prepare Employee Num", "supplierInfo" : "Supplier Information", "supplierAcNo": "Supplier Account No", @@ -606,9 +603,6 @@ "patientName" : "Patient Name", "invoiceDate" : "Invoice Date", "refundInvoice" :"Refund Invoice", -<<<<<<< HEAD - "hospitalClinic" : "Hospital Clinic" -======= "hospitalClinic" : "Hospital Clinic", "graphicalAnalysis": "Graphical Analysis", "itemHistoryAnalysis": "Item History Analysis", @@ -619,6 +613,10 @@ "bonusQty": "Bonus Qty.", "balQty": "Bal. Qty.", "start":"Start", - "about":"About" ->>>>>>> master + "about":"About", + "explore": "Explore", + "mazaya": "MAZAYA", + "benefits": "Benefits", + "mazayaDesc": "Discover special Discounts and offers available to Employees" + } \ No newline at end of file diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 0545518..9753744 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -10,14 +10,14 @@ class ApiConsts { // static String baseUrl = "https://mohemm.hmg.com"; // static String baseUrl = "https://hmgwebservices.com"; // Live server - // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver + static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.201.204.101:2024"; // static String baseUrl = "https://webservices.hmg.com"; // PreProd // static String baseUrl = "https://hmgwebservices.com"; // Live server // static String baseUrl = "https://mohemm.hmg.com"; // New Live server // - static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver + // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.20.200.111:1010/"; // static String baseUrl = "https://webservices.hmg.com"; // PreProd diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index afdf1a8..918affc 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -1,6 +1,6 @@ // DO NOT EDIT. This is code generated via package:easy_localization/generate.dart -// ignore_for_file: prefer_single_quotes, avoid_renaming_method_parameters +// ignore_for_file: prefer_single_quotes, avoid_renaming_method_parameters, constant_identifier_names import 'dart:ui'; @@ -1798,7 +1798,12 @@ class CodegenLoader extends AssetLoader { "contactDetails": "Contact Details", "familyDetails": "Family Members", "effectiveDate": "Effective Date", - "country": "Country" + "country": "Country", + "explore": "Explore", + "mazaya": "MAZAYA", + "benefits": "Benefits", + "mazayaDesc": "Discover special Discounts and offers available to Employees" + }; diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 01a085a..57de239 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -1,5 +1,7 @@ // DO NOT EDIT. This is code generated via package:easy_localization/generate.dart +// ignore_for_file: constant_identifier_names + abstract class LocaleKeys { static const mohemm = 'mohemm'; static const english = 'english'; @@ -101,6 +103,7 @@ abstract class LocaleKeys { static const reject = 'reject'; static const approve = 'approve'; static const cancel = 'cancel'; + static const generate = 'generate'; static const requestedItems = 'requestedItems'; static const request = 'request'; static const myRequest = 'myRequest'; @@ -552,7 +555,6 @@ abstract class LocaleKeys { static const pleaseClickButtonToJoinMarathon ='pleaseClickButtonToJoinMarathon'; static const youCannotJoinTheMarathon ='youCannotJoinTheMarathon'; static const open ='open'; - static const generate = 'generate'; static const paymentDetails ='paymentDetails'; static const requestNo ='requestNo'; static const requesterEmpNum ='requesterEmpNum'; @@ -578,6 +580,7 @@ abstract class LocaleKeys { static const versionStatus ='versionStatus'; static const supplierNo ='supplierNo'; static const general ="general"; + static const paymentRequest = 'paymentRequest'; static const supplierInfo = 'supplierInfo'; static const supplierAcNo = 'supplierAcNo'; static const supplierAcName = 'supplierAcName'; @@ -590,7 +593,6 @@ abstract class LocaleKeys { static const invoiceDate = 'Invoice Date'; static const refundInvoice = 'Refund Invoice'; static const hospitalClinic = 'Hospital Clinic'; - static const paymentRequest = 'paymentRequest'; static const graphicalAnalysis = 'graphicalAnalysis'; static const itemHistoryAnalysis = 'itemHistoryAnalysis'; static const pOno = 'pOno'; @@ -599,8 +601,11 @@ abstract class LocaleKeys { static const qtyReceived = 'qtyReceived'; static const bonusQty = 'bonusQty'; static const balQty = 'balQty'; - static const Attendance = 'Attendance'; static const start = 'start'; - static const about ='about'; + static const about = 'about'; + static const explore = 'explore'; + static const mazaya = 'mazaya'; + static const benefits = 'benefits'; + static const mazayaDesc = 'mazayaDesc'; } diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index bce1f0e..9131b8e 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -176,10 +176,11 @@ class _DashboardScreenState extends State with WidgetsBindingOb if (list[ermIndex].notificationType == "Survey") { await Navigator.pushNamed(context, AppRoutes.survey, arguments: response.mohemmItgResponseItem!.result!.data!.first); } else { - await Navigator.pushNamed(context, AppRoutes.advertisement, arguments: { - "masterId": list[ermIndex].notificationMasterId, - "advertisement": response.mohemmItgResponseItem!.result!.data!.first.advertisement, - }); + await Navigator.pushNamed( + context, + AppRoutes.advertisement, + arguments: {"masterId": list[ermIndex].notificationMasterId, "advertisement": response.mohemmItgResponseItem!.result!.data!.first.advertisement}, + ); } } ermIndex++; @@ -242,53 +243,44 @@ class _DashboardScreenState extends State with WidgetsBindingOb children: [ Row( children: [ - Builder(builder: (BuildContext context) { - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - Image.memory( - Utils.dataFromBase64String( - AppState().memberInformationList!.eMPLOYEEIMAGE ?? "", - ), - errorBuilder: (BuildContext context, Object error, StackTrace? stackTrace) { - return SvgPicture.asset( - "assets/images/user.svg", - height: 34, - width: 34, - ); - }, - width: 34, - height: 34, - fit: BoxFit.cover, - ).circle(50), - // CircularAvatar( - // width: 34, - // height: 34, - // url: "https://cdn4.iconfinder.com/data/icons/professions-2-2/151/89-512.png", - // ), - 8.width, - SvgPicture.asset("assets/images/side_nav.svg"), - ], - ).onPress(() { - _scaffoldState.currentState!.openDrawer(); - }); - }), + Builder( + builder: (BuildContext context) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + Image.memory( + Utils.dataFromBase64String(AppState().memberInformationList!.eMPLOYEEIMAGE ?? ""), + errorBuilder: (BuildContext context, Object error, StackTrace? stackTrace) { + return SvgPicture.asset("assets/images/user.svg", height: 34, width: 34); + }, + width: 34, + height: 34, + fit: BoxFit.cover, + ).circle(50), + // CircularAvatar( + // width: 34, + // height: 34, + // url: "https://cdn4.iconfinder.com/data/icons/professions-2-2/151/89-512.png", + // ), + 8.width, + SvgPicture.asset("assets/images/side_nav.svg"), + ], + ).onPress(() { + _scaffoldState.currentState!.openDrawer(); + }); + }, + ), Image.asset("assets/images/logos/main_mohemm_logo.png", width: 134, height: 28).expanded, - SvgPicture.asset( - "assets/images/announcements.svg", - matchTextDirection: true, - ).onPress(() async { + SvgPicture.asset("assets/images/announcements.svg", matchTextDirection: true).onPress(() async { await Navigator.pushNamed(context, AppRoutes.announcements); - }) + }), ], ).paddingOnly(left: 21, right: 21, top: 48, bottom: 7), Expanded( child: SmartRefresher( enablePullDown: true, enablePullUp: false, - header: const MaterialClassicHeader( - color: MyColors.gradiantEndColor, - ), + header: const MaterialClassicHeader(color: MyColors.gradiantEndColor), controller: _refreshController, onRefresh: () { _onRefresh(false); @@ -312,220 +304,328 @@ class _DashboardScreenState extends State with WidgetsBindingOb return (model.isAttendanceTrackingLoading ? GetAttendanceTrackingShimmer() : Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(15), - gradient: const LinearGradient(transform: GradientRotation(.46), begin: Alignment.topRight, end: Alignment.bottomLeft, colors: [ - MyColors.gradiantEndColor, - MyColors.gradiantStartColor, - ]), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(15), + gradient: const LinearGradient( + transform: GradientRotation(.46), + begin: Alignment.topRight, + end: Alignment.bottomLeft, + colors: [MyColors.gradiantEndColor, MyColors.gradiantStartColor], ), - child: Stack( - alignment: Alignment.center, - children: [ - if (model.isTimeRemainingInSeconds == 0) SvgPicture.asset("assets/images/thumb.svg"), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - LocaleKeys.markAttendance.tr().toText14(color: Colors.white, isBold: true), - if (model.isTimeRemainingInSeconds == 0) DateTime.now().toString().split(" ")[0].toText12(color: Colors.white), - if (model.isTimeRemainingInSeconds != 0) - Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - 9.height, - Directionality( - textDirection: ui.TextDirection.ltr, - child: CountdownTimer( - endTime: model.endTime, - onEnd: null, - endWidget: "00:00:00".toText14(color: Colors.white, isBold: true), - textStyle: const TextStyle(color: Colors.white, fontSize: 14, letterSpacing: -0.48, fontWeight: FontWeight.bold), - ), - ), - LocaleKeys.timeLeftToday.tr().toText12(color: Colors.white), - 9.height, - ClipRRect( - borderRadius: const BorderRadius.all(Radius.circular(20)), - child: LinearProgressIndicator( - value: model.progress, - minHeight: 8, - valueColor: const AlwaysStoppedAnimation(Colors.white), - backgroundColor: const Color(0xff196D73), - ), - ), - ], - ), - ], - ).paddingOnly(top: 12, right: 15, left: 12), - ), - Row( + ), + child: Stack( + alignment: Alignment.center, + children: [ + if (model.isTimeRemainingInSeconds == 0) SvgPicture.asset("assets/images/thumb.svg"), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Expanded( - child: Column( + LocaleKeys.markAttendance.tr().toText14(color: Colors.white, isBold: true), + if (model.isTimeRemainingInSeconds == 0) DateTime.now().toString().split(" ")[0].toText12(color: Colors.white), + if (model.isTimeRemainingInSeconds != 0) + Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - LocaleKeys.checkIn.tr().toText12(color: Colors.white), - (model.attendanceTracking!.pSwipeIn == null ? "--:--" : model.attendanceTracking!.pSwipeIn) - .toString() - .toText14(color: Colors.white, isBold: true), - 4.height, + 9.height, + Directionality( + textDirection: ui.TextDirection.ltr, + child: CountdownTimer( + endTime: model.endTime, + onEnd: null, + endWidget: "00:00:00".toText14(color: Colors.white, isBold: true), + textStyle: const TextStyle(color: Colors.white, fontSize: 14, letterSpacing: -0.48, fontWeight: FontWeight.bold), + ), + ), + LocaleKeys.timeLeftToday.tr().toText12(color: Colors.white), + 9.height, + ClipRRect( + borderRadius: const BorderRadius.all(Radius.circular(20)), + child: LinearProgressIndicator( + value: model.progress, + minHeight: 8, + valueColor: const AlwaysStoppedAnimation(Colors.white), + backgroundColor: const Color(0xff196D73), + ), + ), ], - ).paddingOnly(left: 12, right: 12), - ), - Container( - margin: EdgeInsets.only(top: AppState().isArabic(context) ? 6 : 0), - width: 45, - height: 45, - padding: const EdgeInsets.only(left: 10, right: 10), - decoration: BoxDecoration( - color: Color(0xff259EA4), - borderRadius: BorderRadius.only( - bottomRight: AppState().isArabic(context) ? Radius.circular(0) : Radius.circular(15), - bottomLeft: AppState().isArabic(context) ? Radius.circular(15) : Radius.circular(0), - ), ), - child: SvgPicture.asset(model.isTimeRemainingInSeconds == 0 ? "assets/images/biometrics.svg" : "assets/images/biometrics.svg"), - ).onPress(() { - showMyBottomSheet( - context, - callBackFunc: () {}, - child: MarkAttendanceWidget(model, isFromDashboard: true), - ); - }), ], - ), - ], - ), - ], - ), - ).onPress( - () { - Navigator.pushNamed(context, AppRoutes.todayAttendance); - }, - )) + ).paddingOnly(top: 12, right: 15, left: 12), + ), + Row( + children: [ + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.checkIn.tr().toText12(color: Colors.white), + (model.attendanceTracking!.pSwipeIn == null ? "--:--" : model.attendanceTracking!.pSwipeIn).toString().toText14( + color: Colors.white, + isBold: true, + ), + 4.height, + ], + ).paddingOnly(left: 12, right: 12), + ), + Container( + margin: EdgeInsets.only(top: AppState().isArabic(context) ? 6 : 0), + width: 45, + height: 45, + padding: const EdgeInsets.only(left: 10, right: 10), + decoration: BoxDecoration( + color: const Color(0xff259EA4), + borderRadius: BorderRadius.only( + bottomRight: AppState().isArabic(context) ? const Radius.circular(0) : const Radius.circular(15), + bottomLeft: AppState().isArabic(context) ? const Radius.circular(15) : const Radius.circular(0), + ), + ), + child: SvgPicture.asset(model.isTimeRemainingInSeconds == 0 ? "assets/images/biometrics.svg" : "assets/images/biometrics.svg"), + ).onPress(() { + showMyBottomSheet(context, callBackFunc: () {}, child: MarkAttendanceWidget(model, isFromDashboard: true)); + }), + ], + ), + ], + ), + ], + ), + ).onPress(() { + Navigator.pushNamed(context, AppRoutes.todayAttendance); + })) .animatedSwither(); }, ), ), ), 9.width, - Expanded( - child: MenusWidget(), - ), + Expanded(child: MenusWidget()), ], ), ], ).paddingOnly(left: 21, right: 21, top: 7, bottom: 21), eventActivityWidget(context), - Consumer(builder: (BuildContext context, DashboardProviderModel model, Widget? child) { - if (!model.isOffersLoading && model.getOffersList.isEmpty) { - return const SizedBox(); - } - return Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - LocaleKeys.offers.tr().toText12(), - Row( - children: [ - LocaleKeys.discounts.tr().toText24(isBold: true), - 6.width, - Container( - padding: const EdgeInsets.only(left: 8, right: 8), - decoration: BoxDecoration( - color: MyColors.yellowColor, - borderRadius: BorderRadius.circular(10), - ), - child: LocaleKeys.newString.tr().toText10(isBold: true)), - ], - ), - ], + Consumer( + builder: (BuildContext context, DashboardProviderModel model, Widget? child) { + if (!model.isOffersLoading && model.getOffersList.isEmpty) { + return const SizedBox(); + } + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Directionality( + textDirection: AppState().isArabic(context) ? ui.TextDirection.rtl : ui.TextDirection.ltr, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + gradient: const LinearGradient(colors: [Color(0xFF91C481), Color(0xFF7CCED7)], begin: Alignment.centerLeft, end: Alignment.centerRight), ), - ), - LocaleKeys.viewAllOffers.tr().toText12(isUnderLine: true).onPress(() { - Navigator.pushNamed(context, AppRoutes.offersAndDiscounts); - }) - ], - ).paddingOnly(left: 21, right: 21), - Consumer( - builder: (BuildContext context, DashboardProviderModel model, Widget? child) { - return SizedBox( - height: 103 + 33, - child: ListView.separated( - shrinkWrap: true, - physics: const BouncingScrollPhysics(), - padding: const EdgeInsets.only(left: 21, right: 21, top: 13), - scrollDirection: Axis.horizontal, - itemBuilder: (BuildContext cxt, int index) { - return model.isOffersLoading - ? const OffersShimmerWidget() - : InkWell( - onTap: () { - navigateToDetails(data.getOffersList[index]); - }, - child: SizedBox( - width: 73, - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Container( - width: 73, - height: 73, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: const BorderRadius.all( - Radius.circular(100), - ), - border: Border.all(color: MyColors.lightGreyE3Color, width: 1), - ), - child: ClipRRect( - borderRadius: const BorderRadius.all( - Radius.circular(50), - ), - child: Hero( - tag: "ItemImage" + data.getOffersList[index].offersDiscountId.toString()!, - transitionOnUserGestures: true, - child: Image.network( - data.getOffersList[index].logo ?? "", - fit: BoxFit.contain, - ), - ), - ), - ), - 4.height, - Expanded( - child: AppState().isArabic(context) - ? data.getOffersList[index].titleAr!.toText12(isCenter: true, maxLine: 1) - : data.getOffersList[index].titleEn!.toText12(isCenter: true, maxLine: 1), + child: Padding( + padding: const EdgeInsets.all(3.0), // This creates the border width + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(17), // Slightly less than outer radius + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + flex: 4, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Row( + children: [ + Expanded( + flex: 2, + child: RichText( + text: + AppState().isArabic(context) + ? const TextSpan( + children: [ + TextSpan( + text: 'اطلع على مميزات', + style: TextStyle(fontSize: 16, letterSpacing: -0.2, fontWeight: FontWeight.w700, height: 24 / 16, color: Color(0xFF5D5E5E)), + ), + TextSpan( + text: ' مزايا', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w700, + letterSpacing: -0.2, + height: 24 / 16, + color: Color(0xFFED1C2B), // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed + ), + ), + ], + ) + : TextSpan( + children: [ + TextSpan( + text: LocaleKeys.explore.tr() + ' ', + style: const TextStyle(fontSize: 16, letterSpacing: -0.2, fontWeight: FontWeight.w700, height: 24 / 16, color: Color(0xFF5D5E5E)), + ), + TextSpan( + text: LocaleKeys.mazaya.tr(), + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.w700, + letterSpacing: -0.2, + height: 24 / 16, + color: Color(0xFFED1C2B), // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed + ), + ), + TextSpan( + text: ' ' + LocaleKeys.benefits.tr(), + style: const TextStyle(fontSize: 16, letterSpacing: -0.2, fontWeight: FontWeight.w700, height: 24 / 16, color: Color(0xFF5D5E5E)), + ), + ], + ), ), - ], - ), + ), + const Expanded(flex: 1, child: SizedBox()), + ], ), - ); - }, - separatorBuilder: (BuildContext cxt, int index) => 8.width, - itemCount: 9), - ); - }, - ), - ], - ); - }), + const SizedBox(height: 8), + LocaleKeys.mazayaDesc.tr().toText11(color: const Color(0xFF5D5E5E)), + ], + ), + ), + Expanded( + flex: 2, + child: Column( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + SvgPicture.asset("assets/icons/mazaya_brand.svg", width: 90, height: 47), + const SizedBox(height: 28), + LocaleKeys.viewAllOffers.tr().toText12(isUnderLine: true, color: const Color(0xFF3B3D4A)).onPress(() { + Navigator.pushNamed(context, AppRoutes.offersAndDiscounts); + }), + ], + ), + ), + ], + ).paddingOnly(left: 21, right: 21, top: 14, bottom: 14), + ), + ), + ).paddingOnly(left: 21, right: 21, top: 0, bottom: 21), + ), + + // Container( + // height: 121, + // decoration: BoxDecoration( + // borderRadius: BorderRadius.circular(12), + // border: Border.all(width: 3, color: Colors.red), + // ), + // child: Padding(padding: const EdgeInsets.all(4.0), child: Container(decoration: BoxDecoration(borderRadius: BorderRadius.circular(12), color: Colors.white))), + // ).paddingOnly(left: 21, right: 21, bottom: 21), + + // Row( + // crossAxisAlignment: CrossAxisAlignment.center, + // children: [ + // Expanded( + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // mainAxisSize: MainAxisSize.min, + // children: [ + // LocaleKeys.offers.tr().toText12(), + // Row( + // children: [ + // LocaleKeys.discounts.tr().toText24(isBold: true), + // 6.width, + // Container( + // padding: const EdgeInsets.only(left: 8, right: 8), + // decoration: BoxDecoration( + // color: MyColors.yellowColor, + // borderRadius: BorderRadius.circular(10), + // ), + // child: LocaleKeys.newString.tr().toText10(isBold: true)), + // ], + // ), + // ], + // ), + // ), + // LocaleKeys.viewAllOffers.tr().toText12(isUnderLine: true).onPress(() { + // Navigator.pushNamed(context, AppRoutes.offersAndDiscounts); + // }) + // ], + // ).paddingOnly(left: 21, right: 21), + // Consumer( + // builder: (BuildContext context, DashboardProviderModel model, Widget? child) { + // return SizedBox( + // height: 103 + 33, + // child: ListView.separated( + // shrinkWrap: true, + // physics: const BouncingScrollPhysics(), + // padding: const EdgeInsets.only(left: 21, right: 21, top: 13), + // scrollDirection: Axis.horizontal, + // itemBuilder: (BuildContext cxt, int index) { + // return model.isOffersLoading + // ? const OffersShimmerWidget() + // : InkWell( + // onTap: () { + // navigateToDetails(data.getOffersList[index]); + // }, + // child: SizedBox( + // width: 73, + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.center, + // children: [ + // Container( + // width: 73, + // height: 73, + // decoration: BoxDecoration( + // color: Colors.white, + // borderRadius: const BorderRadius.all( + // Radius.circular(100), + // ), + // border: Border.all(color: MyColors.lightGreyE3Color, width: 1), + // ), + // child: ClipRRect( + // borderRadius: const BorderRadius.all( + // Radius.circular(50), + // ), + // child: Hero( + // tag: "ItemImage" + data.getOffersList[index].offersDiscountId.toString()!, + // transitionOnUserGestures: true, + // child: Image.network( + // data.getOffersList[index].logo ?? "", + // fit: BoxFit.contain, + // ), + // ), + // ), + // ), + // 4.height, + // Expanded( + // child: AppState().isArabic(context) + // ? data.getOffersList[index].titleAr!.toText12(isCenter: true, maxLine: 1) + // : data.getOffersList[index].titleEn!.toText12(isCenter: true, maxLine: 1), + // ), + // ], + // ), + // ), + // ); + // }, + // separatorBuilder: (BuildContext cxt, int index) => 8.width, + // itemCount: 9), + // ); + // }, + // ), + ], + ); + }, + ), Container( width: double.infinity, padding: const EdgeInsets.only(top: 31), @@ -589,38 +689,24 @@ class _DashboardScreenState extends State with WidgetsBindingOb ), ), ), - ) + ), ], ), - drawer: SafeArea( - child: AppDrawer(onLanguageChange: _onRefresh), - ), + drawer: SafeArea(child: AppDrawer(onLanguageChange: _onRefresh)), bottomNavigationBar: SizedBox( height: Platform.isAndroid ? 70 : 100, child: BottomNavigationBar( items: [ + BottomNavigationBarItem(icon: SvgPicture.asset("assets/icons/home.svg", color: currentIndex == 0 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4), label: LocaleKeys.home.tr()), BottomNavigationBarItem( - icon: SvgPicture.asset( - "assets/icons/home.svg", - color: currentIndex == 0 ? MyColors.grey3AColor : MyColors.grey98Color, - ).paddingAll(4), - label: LocaleKeys.home.tr(), - ), - BottomNavigationBarItem( - icon: SvgPicture.asset( - "assets/icons/create_req.svg", - color: currentIndex == 1 ? MyColors.grey3AColor : MyColors.grey98Color, - ).paddingAll(4), + icon: SvgPicture.asset("assets/icons/create_req.svg", color: currentIndex == 1 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4), label: LocaleKeys.mowadhafhiRequest.tr(), ), BottomNavigationBarItem( icon: Stack( alignment: Alignment.centerLeft, children: [ - SvgPicture.asset( - "assets/icons/work_list.svg", - color: currentIndex == 2 ? MyColors.grey3AColor : MyColors.grey98Color, - ).paddingAll(4), + SvgPicture.asset("assets/icons/work_list.svg", color: currentIndex == 2 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4), Consumer( builder: (BuildContext cxt, DashboardProviderModel data, Widget? child) { if (data.workListCounter == 0) { @@ -643,10 +729,7 @@ class _DashboardScreenState extends State with WidgetsBindingOb label: LocaleKeys.workList.tr(), ), BottomNavigationBarItem( - icon: SvgPicture.asset( - "assets/icons/item_for_sale.svg", - color: currentIndex == 3 ? MyColors.grey3AColor : MyColors.grey98Color, - ).paddingAll(4), + icon: SvgPicture.asset("assets/icons/item_for_sale.svg", color: currentIndex == 3 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4), label: LocaleKeys.itemsForSale.tr(), ), BottomNavigationBarItem( @@ -655,28 +738,29 @@ class _DashboardScreenState extends State with WidgetsBindingOb children: [ SvgPicture.asset( "assets/icons/chat/chat.svg", - color: !checkIfPrivilegedForChat() - ? MyColors.lightGreyE3Color - : currentIndex == 4 + color: + !checkIfPrivilegedForChat() + ? MyColors.lightGreyE3Color + : currentIndex == 4 ? MyColors.grey3AColor : cProvider.disbaleChatForThisUser - ? MyColors.lightGreyE3Color - : MyColors.grey98Color, + ? MyColors.lightGreyE3Color + : MyColors.grey98Color, ).paddingAll(4), Consumer( builder: (BuildContext cxt, ChatProviderModel data, Widget? child) { return !checkIfPrivilegedForChat() ? const SizedBox() : Positioned( - right: 0, - top: 0, - child: Container( - padding: const EdgeInsets.only(left: 4, right: 4), - alignment: Alignment.center, - decoration: BoxDecoration(color: cProvider.disbaleChatForThisUser ? MyColors.pinkDarkColor : MyColors.redColor, borderRadius: BorderRadius.circular(17)), - child: data.chatUConvCounter.toString().toText10(color: Colors.white), - ), - ); + right: 0, + top: 0, + child: Container( + padding: const EdgeInsets.only(left: 4, right: 4), + alignment: Alignment.center, + decoration: BoxDecoration(color: cProvider.disbaleChatForThisUser ? MyColors.pinkDarkColor : MyColors.redColor, borderRadius: BorderRadius.circular(17)), + child: data.chatUConvCounter.toString().toText10(color: Colors.white), + ), + ); }, ), ], @@ -714,8 +798,8 @@ class _DashboardScreenState extends State with WidgetsBindingOb return (context.watch().isEventLoadingLoading) ? const MarathonBannerShimmer().paddingOnly(left: 21, right: 21, bottom: 21, top: 0) : (context.watch().eventActivity != null && context.watch().eventActivity!.isActive == true) - ? const EventActivityBanner().paddingOnly(left: 21, right: 21, bottom: 21, top: 0) - : const SizedBox(); + ? const EventActivityBanner().paddingOnly(left: 21, right: 21, bottom: 21, top: 0) + : const SizedBox(); } void navigateToDetails(OffersListModel offersListModelObj) { diff --git a/lib/ui/landing/widget/services_widget.dart b/lib/ui/landing/widget/services_widget.dart index 7c19b58..319c36d 100644 --- a/lib/ui/landing/widget/services_widget.dart +++ b/lib/ui/landing/widget/services_widget.dart @@ -1,20 +1,56 @@ +import 'dart:convert'; +import 'dart:developer'; + import 'package:easy_localization/src/public_ext.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:flutter_svg/svg.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; +import 'package:mohem_flutter_app/classes/inAppWebView.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/main.dart'; import 'package:mohem_flutter_app/models/dashboard/menu_entries.dart'; +import 'package:mohem_flutter_app/models/generic_response_model.dart'; +import 'package:mohem_flutter_app/models/sso_auth_model.dart'; import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; import 'package:mohem_flutter_app/ui/my_attendance/dynamic_screens/dynamic_listview_screen.dart'; import 'package:mohem_flutter_app/ui/my_attendance/services_menu_list_screen.dart'; import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart'; +import 'package:mohem_flutter_app/widgets/sso_webview_widget.dart'; import 'package:provider/provider.dart'; +import 'package:url_launcher/url_launcher.dart'; class ServicesWidget extends StatelessWidget { + MyInAppBrowser? myInAppBrowser; + var inAppBrowserOptions = InAppBrowserClassSettings( + webViewSettings: InAppWebViewSettings( + useShouldOverrideUrlLoading: false, + transparentBackground: false, + isInspectable: false, + applePayAPIEnabled: true, + cacheEnabled: false, + allowsBackForwardNavigationGestures: false, + ), + browserSettings: InAppBrowserSettings( + hideUrlBar: true, + hideTitleBar: true, + hideDefaultMenuItems: true, + hideToolbarBottom: true, + hideToolbarTop: false, + hideCloseButton: false, + allowGoBackWithBackButton: false, + toolbarBottomBackgroundColor: Colors.black, + closeButtonColor: Colors.white, + presentationStyle: ModalPresentationStyle.FULL_SCREEN, + // toolbarTopBackgroundColor: Colors.black + ), + ); + @override Widget build(BuildContext context) { List namesT = [LocaleKeys.monthlyAttendance.tr(), LocaleKeys.workFromHome.tr(), LocaleKeys.ticketRequest.tr(), LocaleKeys.monthlyAttendance.tr()]; @@ -26,7 +62,7 @@ class ServicesWidget extends StatelessWidget { "assets/images/vacation_rule.svg", "assets/images/ticket_request.svg", "assets/images/ticket_request.svg", - "assets/images/ticket_request.svg" + "assets/images/ticket_request.svg", ]; return Consumer( @@ -34,72 +70,69 @@ class ServicesWidget extends StatelessWidget { return data.isServicesMenusLoading ? whileLoading() : ListView.separated( - padding: const EdgeInsets.only(top: 0), - itemBuilder: (context, parentIndex) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - data.homeMenus![parentIndex].menuEntry.prompt!.toSectionHeading().paddingOnly(left: 21, right: 21), - SizedBox( - height: 105 + 26, - child: ListView.separated( - shrinkWrap: true, - physics: const BouncingScrollPhysics(), - padding: const EdgeInsets.only(left: 21, right: 21, top: 13, bottom: 13), - scrollDirection: Axis.horizontal, - itemBuilder: (cxt, index) { - return AspectRatio( - aspectRatio: 105 / 105, - child: data.isServicesMenusLoading + padding: const EdgeInsets.only(top: 0), + itemBuilder: (context, parentIndex) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + data.homeMenus![parentIndex].menuEntry.prompt!.toSectionHeading().paddingOnly(left: 21, right: 21), + SizedBox( + height: 105 + 26, + child: ListView.separated( + shrinkWrap: true, + physics: const BouncingScrollPhysics(), + padding: const EdgeInsets.only(left: 21, right: 21, top: 13, bottom: 13), + scrollDirection: Axis.horizontal, + itemBuilder: (cxt, index) { + return AspectRatio( + aspectRatio: 105 / 105, + child: + data.isServicesMenusLoading ? ServicesMenuShimmer() : Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(15), - boxShadow: [ - BoxShadow( - color: const Color(0xff000000).withOpacity(.05), - blurRadius: 26, - offset: const Offset(0, -3), - ), - ], - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SvgPicture.asset(AppState().isArabic(context) + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(15), + boxShadow: [BoxShadow(color: const Color(0xff000000).withOpacity(.05), blurRadius: 26, offset: const Offset(0, -3))], + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SvgPicture.asset( + AppState().isArabic(context) ? getMenuIconAr(data.homeMenus![parentIndex].menuEntiesList[index].prompt!) - : getMenuIconEn(data.homeMenus![parentIndex].menuEntiesList[index].prompt!)), - Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Expanded( - child: data.homeMenus![parentIndex].menuEntiesList[index].prompt!.toText11(isBold: true), - ), - RotatedBox(quarterTurns: AppState().isArabic(context) ? 2 : 4, child: SvgPicture.asset("assets/images/arrow_next.svg").paddingOnly(bottom: 4)), - ], - ) - ], - ).paddingOnly(left: 10, right: 10, bottom: 10, top: 12), - ).onPress(() { - handleOnPress(context, data.homeMenus![parentIndex].menuEntiesList[index]); - }), - ); - }, - separatorBuilder: (cxt, index) => 9.width, - itemCount: data.homeMenus![parentIndex].menuEntiesList.length), + : getMenuIconEn(data.homeMenus![parentIndex].menuEntiesList[index].prompt!), + ), + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Expanded(child: data.homeMenus![parentIndex].menuEntiesList[index].prompt!.toText11(isBold: true)), + RotatedBox(quarterTurns: AppState().isArabic(context) ? 2 : 4, child: SvgPicture.asset("assets/images/arrow_next.svg").paddingOnly(bottom: 4)), + ], + ), + ], + ).paddingOnly(left: 10, right: 10, bottom: 10, top: 12), + ).onPress(() { + handleOnPress(context, data.homeMenus![parentIndex].menuEntiesList[index]); + }), + ); + }, + separatorBuilder: (cxt, index) => 9.width, + itemCount: data.homeMenus![parentIndex].menuEntiesList.length, ), - ], - ); - }, - separatorBuilder: (context, index) { - return 12.height; - }, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: data.homeMenus!.length); + ), + ], + ); + }, + separatorBuilder: (context, index) { + return 12.height; + }, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: data.homeMenus!.length, + ); }, ); } diff --git a/lib/ui/screens/offers_and_discounts/offers_and_discounts_home.dart b/lib/ui/screens/offers_and_discounts/offers_and_discounts_home.dart index fd2c19e..f67a835 100644 --- a/lib/ui/screens/offers_and_discounts/offers_and_discounts_home.dart +++ b/lib/ui/screens/offers_and_discounts/offers_and_discounts_home.dart @@ -39,7 +39,7 @@ class _OffersAndDiscountsHomeState extends State { Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, - appBar: AppBarWidget(context, title: LocaleKeys.offerAndDiscounts.tr(), showHomeButton: true), + appBar: AppBarWidget(context, title: LocaleKeys.offerAndDiscounts.tr(), showHomeButton: true, showLogo: true, logoPath: "assets/icons/mazaya_brand.svg"), body: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/widgets/app_bar_widget.dart b/lib/widgets/app_bar_widget.dart index 6737945..277a414 100644 --- a/lib/widgets/app_bar_widget.dart +++ b/lib/widgets/app_bar_widget.dart @@ -1,18 +1,23 @@ import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; import 'package:mohem_flutter_app/classes/colors.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'; -AppBar AppBarWidget(BuildContext context, - {required String title, - bool showHomeButton = true, - bool showWorkListSettingButton = false, - bool showMemberButton = false, - List? actions, - void Function()? onHomeTapped, - void Function()? onBackTapped}) { +AppBar AppBarWidget( + BuildContext context, { + required String title, + bool showHomeButton = true, + bool showLogo = false, + String? logoPath, + bool showWorkListSettingButton = false, + bool showMemberButton = false, + List? actions, + void Function()? onHomeTapped, + void Function()? onBackTapped, +}) { return AppBar( leadingWidth: 0, automaticallyImplyLeading: false, @@ -26,8 +31,10 @@ AppBar AppBarWidget(BuildContext context, }, context), child: const Icon(Icons.arrow_back_ios, color: MyColors.darkIconColor), ), + if (showLogo) 4.width, + if (showLogo) SvgPicture.asset(logoPath!), 4.width, - title.toText24(color: MyColors.darkTextColor, isBold: true).expanded, + if (!showLogo)title.toText24(color: MyColors.darkTextColor, isBold: true).expanded, ], ), centerTitle: false, @@ -55,7 +62,7 @@ AppBar AppBarWidget(BuildContext context, }, icon: const Icon(Icons.people, color: MyColors.textMixColor), ), - ...actions ?? [] + ...actions ?? [], ], ); } -- 2.30.2 From 5864c772266a0b205e6b1c1a4efa01483be78579 Mon Sep 17 00:00:00 2001 From: Aamir Muhammad Date: Mon, 28 Jul 2025 10:40:37 +0300 Subject: [PATCH 085/135] worklist actions fragment action button changes --- lib/ui/work_list/worklist_detail_screen.dart | 10 +++ .../worklist_fragments/actions_fragment.dart | 70 +++++++++---------- 2 files changed, 45 insertions(+), 35 deletions(-) diff --git a/lib/ui/work_list/worklist_detail_screen.dart b/lib/ui/work_list/worklist_detail_screen.dart index 71a87f8..f1a7a3e 100644 --- a/lib/ui/work_list/worklist_detail_screen.dart +++ b/lib/ui/work_list/worklist_detail_screen.dart @@ -61,6 +61,7 @@ class _WorkListDetailScreenState extends State { int animationIndex = 0; PageController controller = PageController(); bool showFabOptions = false; + bool isShowActions = false; WorkListResponseModel? workListData; MemberInformationListModel? memberInformationListModel; @@ -286,6 +287,7 @@ class _WorkListDetailScreenState extends State { : ActionsFragment( workListData!.nOTIFICATIONID, actionHistoryList, + isShowActions, voidCallback: reloadWorkList, ) : showLoadingAnimation(), @@ -1077,6 +1079,14 @@ class _WorkListDetailScreenState extends State { } return false; }); + + if(notificationButtonsList.any((GetNotificationButtonsList element) => element.bUTTONACTION == "DELEGATE" || element.bUTTONACTION == "REQUEST_INFO" )) { + isShowActions = true; + } else { + isShowActions = false; + } + + } apiCallCount--; if (apiCallCount == 0) { diff --git a/lib/ui/work_list/worklist_fragments/actions_fragment.dart b/lib/ui/work_list/worklist_fragments/actions_fragment.dart index 29d5328..97e540c 100644 --- a/lib/ui/work_list/worklist_fragments/actions_fragment.dart +++ b/lib/ui/work_list/worklist_fragments/actions_fragment.dart @@ -17,8 +17,9 @@ class ActionsFragment extends StatelessWidget { int? notificationID; List actionHistoryList; VoidCallback voidCallback; + bool isShowActions = false; - ActionsFragment(this.notificationID, this.actionHistoryList, {Key? key, required this.voidCallback}) : super(key: key); + ActionsFragment(this.notificationID, this.actionHistoryList, this.isShowActions, {Key? key, required this.voidCallback}) : super(key: key); @override Widget build(BuildContext context) { @@ -113,42 +114,41 @@ class ActionsFragment extends StatelessWidget { ], ).paddingOnly(top: 19, left: 16, right: 16, bottom: 12), Container(width: double.infinity, height: 1, color: MyColors.lightGreyEFColor), - Row( - children: [ - LocaleKeys.request_info.tr().toText12(color: MyColors.grey67Color).center.paddingOnly(top: 6, bottom: 6).onPress(() { - showMyBottomSheet( - context, - callBackFunc: voidCallback, - child: SelectedItemSheet(LocaleKeys.request_info.tr(), apiMode: "REQUEST_INFO", notificationID: notificationID, actionHistoryList: actionHistory), - ); - }).expanded, - Container(width: 1, height: 30, color: MyColors.lightGreyEFColor), - LocaleKeys.delegate.tr().toText12(color: MyColors.gradiantEndColor).center.paddingOnly(top: 6, bottom: 6).onPress(() { - if (actionHistory.uSERNAME == AppState().memberInformationList?.eMPLOYEENUMBER) { - showMyBottomSheet(context, + isShowActions + ? Row( + children: [ + LocaleKeys.request_info.tr().toText12(color: MyColors.grey67Color).center.paddingOnly(top: 6, bottom: 6).onPress(() { + showMyBottomSheet( + context, callBackFunc: voidCallback, - child: DelegateSheet( - title: LocaleKeys.delegate.tr(), - apiMode: "DELEGATE", - notificationID: notificationID, - actionHistoryList: actionHistoryList, + child: SelectedItemSheet(LocaleKeys.request_info.tr(), apiMode: "REQUEST_INFO", notificationID: notificationID, actionHistoryList: actionHistory), + ); + }).expanded, + Container(width: 1, height: 30, color: MyColors.lightGreyEFColor), + LocaleKeys.delegate.tr().toText12(color: MyColors.gradiantEndColor).center.paddingOnly(top: 6, bottom: 6).onPress(() { + if (actionHistory.uSERNAME == AppState().memberInformationList?.eMPLOYEENUMBER) { + showMyBottomSheet( + context, callBackFunc: voidCallback, - )); - return; - } - showMyBottomSheet( - context, - callBackFunc: voidCallback, - child: SelectedItemSheet( - LocaleKeys.comments.tr(), - apiMode: "DELEGATE", - actionHistoryList: actionHistory, - notificationID: notificationID, - ), - ); - }).expanded, - ], - ), + child: DelegateSheet( + title: LocaleKeys.delegate.tr(), + apiMode: "DELEGATE", + notificationID: notificationID, + actionHistoryList: actionHistoryList, + callBackFunc: voidCallback, + ), + ); + return; + } + showMyBottomSheet( + context, + callBackFunc: voidCallback, + child: SelectedItemSheet(LocaleKeys.comments.tr(), apiMode: "DELEGATE", actionHistoryList: actionHistory, notificationID: notificationID), + ); + }).expanded, + ], + ) + : const SizedBox(), ], ), ], -- 2.30.2 From 6400678f95f7d30f4fe3e7ef1e9761db58172089 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Tue, 29 Jul 2025 10:39:35 +0300 Subject: [PATCH 086/135] updates --- lib/app_state/app_state.dart | 2 +- lib/classes/consts.dart | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/app_state/app_state.dart b/lib/app_state/app_state.dart index f8ee060..0cad41a 100644 --- a/lib/app_state/app_state.dart +++ b/lib/app_state/app_state.dart @@ -90,7 +90,7 @@ class AppState { String get getHuaweiPushToken => _huaweiPushToken; - final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 8.9, mobileType: Platform.isAndroid ? "android" : "ios"); + final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 9.1, mobileType: Platform.isAndroid ? "android" : "ios"); void setPostParamsInitConfig() { diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index c2772b8..fcc34d3 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -6,12 +6,12 @@ class ApiConsts { // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.201.204.101:2024"; - // static String baseUrl = "https://webservices.hmg.com"; // PreProd + static String baseUrl = "https://webservices.hmg.com"; // PreProd // static String baseUrl = "https://hmgwebservices.com"; // Live server // static String baseUrl = "https://mohemm.hmg.com"; // New Live server // - static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver + // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.20.200.111:1010/"; // static String baseUrl = "https://webservices.hmg.com"; // PreProd -- 2.30.2 From 0e54c7dac9a1ce17bd2508250d166c627b64fcf4 Mon Sep 17 00:00:00 2001 From: Aamir Muhammad Date: Tue, 29 Jul 2025 16:46:17 +0300 Subject: [PATCH 087/135] worklist actions fragment action button changes --- .vscode/settings.json | 3 +- android/agconnect-services.json | 57 ++ android/app/build.gradle | 21 +- android/build.gradle | 54 +- android/gradle.properties | 2 + android/settings.gradle | 31 +- assets/langs/ar-SA.json | 3 +- assets/langs/en-US.json | 3 +- lib/classes/colors.dart | 1 + lib/classes/consts.dart | 4 +- lib/generated/codegen_loader.g.dart | 10 +- lib/generated/locale_keys.g.dart | 1 + lib/ui/landing/dashboard_screen.dart | 943 ++++++++++++--------------- pubspec.yaml | 8 +- 14 files changed, 551 insertions(+), 590 deletions(-) create mode 100644 android/agconnect-services.json diff --git a/.vscode/settings.json b/.vscode/settings.json index af7c712..6558ca6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,6 @@ { "cSpell.words": [ "MPLOYEEIMAGE" - ] + ], + "java.configuration.updateBuildConfiguration": "disabled" } \ No newline at end of file diff --git a/android/agconnect-services.json b/android/agconnect-services.json new file mode 100644 index 0000000..20a7546 --- /dev/null +++ b/android/agconnect-services.json @@ -0,0 +1,57 @@ +{ + "agcgw_all":{ + "CN":"connect-drcn.dbankcloud.cn", + "CN_back":"connect-drcn.hispace.hicloud.com", + "DE":"connect-dre.dbankcloud.cn", + "DE_back":"connect-dre.hispace.hicloud.com", + "RU":"connect-drru.hispace.dbankcloud.ru", + "RU_back":"connect-drru.hispace.dbankcloud.cn", + "SG":"connect-dra.dbankcloud.cn", + "SG_back":"connect-dra.hispace.hicloud.com" + }, + "websocketgw_all":{ + "CN":"connect-ws-drcn.hispace.dbankcloud.cn", + "CN_back":"connect-ws-drcn.hispace.dbankcloud.com", + "DE":"connect-ws-dre.hispace.dbankcloud.cn", + "DE_back":"connect-ws-dre.hispace.dbankcloud.com", + "RU":"connect-ws-drru.hispace.dbankcloud.ru", + "RU_back":"connect-ws-drru.hispace.dbankcloud.cn", + "SG":"connect-ws-dra.hispace.dbankcloud.cn", + "SG_back":"connect-ws-dra.hispace.dbankcloud.com" + }, + "client":{ + "cp_id":"2640966000002322881", + "product_id":"737518067793559971", + "client_id":"715996003571874624", + "client_secret":"B5B89A56A53847C6BB9D216A8747E75952760DF9A8232239D8744CD847A8FFDA", + "project_id":"737518067793559971", + "app_id":"104737117", + "api_key":"DAEDACKDrYgyco9mjPV9ZUjCSh1kCr/GBV0nseHH0z2mnxlZ41RksOKmyTi+PUTwmGEPK+VxCup4F9oUf4VbDnCsjB7aNBShYcjR+g==", + "package_name":"hmg.cloudSolutions.mohem" + }, + "oauth_client":{ + "client_id":"104737117", + "client_type":1 + }, + "app_info":{ + "app_id":"104737117", + "package_name":"hmg.cloudSolutions.mohem" + }, + "configuration_version":"3.0", + "appInfos":[ + { + "package_name":"hmg.cloudSolutions.mohem", + "client":{ + "app_id":"104737117" + }, + "app_info":{ + "package_name":"hmg.cloudSolutions.mohem", + "app_id":"104737117" + }, + "oauth_client":{ + "client_type":1, + "client_id":"104737117" + } + } + ] +} \ No newline at end of file diff --git a/android/app/build.gradle b/android/app/build.gradle index 0236a3b..8a1cccd 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -4,7 +4,7 @@ plugins { id "com.google.gms.google-services" id "dev.flutter.flutter-gradle-plugin" id "com.google.firebase.crashlytics" - + id "com.huawei.agconnect" } @@ -18,7 +18,13 @@ if (keystorePropertiesFile.exists()) { android { namespace 'hmg.cloudSolutions.mohem' - compileSdk 36 + compileSdk 36 // Changed from 36 to a supported version + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + coreLibraryDesugaringEnabled true + } kotlinOptions { jvmTarget = '1.8' @@ -31,10 +37,12 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "hmg.cloudSolutions.mohem" - minSdkVersion 30 - targetSdk = flutter.targetSdkVersion + minSdkVersion 28 +// targetSdk = flutter.targetSdkVersion + targetSdk 35 versionCode flutter.versionCode versionName flutter.versionName + multiDexEnabled true } buildFeatures{ @@ -67,6 +75,9 @@ flutter { } dependencies { - coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.2.2' implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.1.20" + coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5' + implementation 'com.huawei.hms:push:6.11.0.300' + + } diff --git a/android/build.gradle b/android/build.gradle index c1b6ff6..8a97f51 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,49 +1,23 @@ -//buildscript { -// ext.kotlin_version = '1.9.10' -// repositories { -// google() -// mavenCentral() -// maven { url 'https://developer.huawei.com/repo/' } -// } -// -// dependencies { -// classpath 'com.android.tools.build:gradle:7.1.3' -// classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" -// classpath 'com.google.gms:google-services:4.3.8' -// classpath 'com.huawei.agconnect:agcp:1.8.0.300' -// classpath "com.android.tools:r8:8.2.33" -// } -//} -// -//allprojects { -// repositories { -// google() -// mavenCentral() -// maven { url 'https://developer.huawei.com/repo/' } -// } -//} -// -//rootProject.buildDir = '../build' -//subprojects { -// project.buildDir = "${rootProject.buildDir}/${project.name}" -// project.evaluationDependsOn(':app') -//} -// -//tasks.register("clean", Delete) { -// delete rootProject.buildDir -//} +buildscript { + repositories { + google() + mavenCentral() + maven { url 'https://developer.huawei.com/repo/' } + } + dependencies { + classpath 'com.android.tools.build:gradle:7.3.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.10" + classpath 'com.google.gms:google-services:4.3.15' + classpath 'com.huawei.agconnect:agcp:1.9.1.304' + } +} allprojects { repositories { google() mavenCentral() - maven { - url 'https://developer.huawei.com/repo/' - } - maven { - url "https://artifactory.ess-dev.com/artifactory/gradle-dev-local" - } + maven { url 'https://developer.huawei.com/repo/' } } // Exclude old BouncyCastle globally to avoid duplicate classes diff --git a/android/gradle.properties b/android/gradle.properties index 8310efa..fbdc0de 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,4 +1,6 @@ org.gradle.jvmargs=-Xmx2048M android.useAndroidX=true android.enableJetifier=true +apmsInstrumentationEnabled=false + #org.gradle.java.home=/Users/amirs/Library/Java/JavaVirtualMachines/jbr-17.0.12/Contents/Home/ \ No newline at end of file diff --git a/android/settings.gradle b/android/settings.gradle index f29151d..10a4a8d 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -15,22 +15,19 @@ pluginManagement { mavenCentral() gradlePluginPortal() maven { url 'https://developer.huawei.com/repo/' } - } - dependencyResolutionManagement { - repositories { - google() - mavenCentral() - gradlePluginPortal() - maven { url 'https://developer.huawei.com/repo/' } - maven { - url "https://artifactory.ess-dev.com/artifactory/gradle-dev-local" + resolutionStrategy { + eachPlugin { + if (requested.id.id == "com.huawei.agconnect") { + useModule("com.huawei.agconnect:agcp:1.9.1.304") } } } + } + plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" id "com.android.application" version '8.11.0' apply false @@ -38,8 +35,22 @@ plugins { id("com.google.gms.google-services") version "4.4.3" apply false id("com.google.firebase.crashlytics") version "3.0.4" apply false id('org.gradle.toolchains.foojay-resolver-convention') version '0.9.0' apply false - id("com.huawei.agconnect") version "1.9.1.304" apply false + id "com.huawei.agconnect" version "1.9.1.304" apply false +} + +dependencyResolutionManagement { + repositories { + google() + mavenCentral() + gradlePluginPortal() + maven { url 'https://developer.huawei.com/repo/' } + maven { + url "https://artifactory.ess-dev.com/artifactory/gradle-dev-local" + } + } } + + include ":app" diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index d874779..08b00da 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -619,5 +619,6 @@ "explore": "يستكشف", "mazaya": "مازيا", "benefits": "فوائد", - "mazayaDesc": "اكتشف الخصومات والعروض الخاصة المتاحة للموظفين" + "mazayaDesc": "اكتشف الخصومات والعروض الخاصة المتاحة للموظفين", + "viewallofferMazaya" : "أعرض كل المزايا" } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index ae4dcbc..ff30994 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -617,6 +617,7 @@ "explore": "Explore", "mazaya": "MAZAYA", "benefits": "Benefits", - "mazayaDesc": "Discover special Discounts and offers available to Employees" + "mazayaDesc": "Discover special Discounts and offers available to Employees", + "viewallofferMazaya" : "View All Offers" } \ No newline at end of file diff --git a/lib/classes/colors.dart b/lib/classes/colors.dart index 915f35d..1b0dd06 100644 --- a/lib/classes/colors.dart +++ b/lib/classes/colors.dart @@ -66,4 +66,5 @@ class MyColors { static const Color darkGrey3BColor = Color(0xff3B3B3B); static const Color lightGreyIconColor = Color(0xff919191); static const Color selectedBorderColor = Color(0xff37A4BE); + static const Color mazayaRedColor = Color(0xffED1C2B); } diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index be3f840..069a75d 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -6,10 +6,10 @@ class ApiConsts { // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.201.204.101:2024"; - static String baseUrl = "https://webservices.hmg.com"; // PreProd + // static String baseUrl = "https://webservices.hmg.com"; // PreProd // static String baseUrl = "https://hmgwebservices.com"; // Live server - // static String baseUrl = "https://mohemm.hmg.com"; // New Live server + static String baseUrl = "https://mohemm.hmg.com"; // New Live server // // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.20.200.111:1010/"; diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index 3da13c4..f3fda6a 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -6,7 +6,7 @@ import 'dart:ui'; import 'package:easy_localization/easy_localization.dart' show AssetLoader; -class CodegenLoader extends AssetLoader { +class CodegenLoader extends AssetLoader{ const CodegenLoader(); @override @@ -632,7 +632,8 @@ class CodegenLoader extends AssetLoader { "explore": "يستكشف", "mazaya": "مازيا", "benefits": "فوائد", - "mazayaDesc": "اكتشف الخصومات والعروض الخاصة المتاحة للموظفين" + "mazayaDesc": "اكتشف الخصومات والعروض الخاصة المتاحة للموظفين", + "viewallofferMazaya": "أعرض كل المزايا" }; static const Map _en_US = { "mohemm": "Mohemm", @@ -1252,7 +1253,8 @@ static const Map _en_US = { "explore": "Explore", "mazaya": "MAZAYA", "benefits": "Benefits", - "mazayaDesc": "Discover special Discounts and offers available to Employees" + "mazayaDesc": "Discover special Discounts and offers available to Employees", + "viewallofferMazaya": "View All Offers" }; static const Map> mapLocales = {"ar_SA": _ar_SA, "en_US": _en_US}; -} \ No newline at end of file +} diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 41023f4..b748380 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -605,5 +605,6 @@ abstract class LocaleKeys { static const mazaya = 'mazaya'; static const benefits = 'benefits'; static const mazayaDesc = 'mazayaDesc'; + static const viewallofferMazaya = 'viewallofferMazaya'; } diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index 9131b8e..d3ecb9f 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -152,7 +152,7 @@ class _DashboardScreenState extends State with WidgetsBindingOb data.fetchLeaveTicketBalance(context, DateTime.now()); data.fetchMenuEntries(); data.fetchEventActivity(); - data.getCategoryOffersListAPI(context); + // data.getCategoryOffersListAPI(context); marathonProvider.getMarathonDetailsFromApi(); marathonProvider.getMarathonTutorial(); if (isFromInit) { @@ -237,558 +237,457 @@ class _DashboardScreenState extends State with WidgetsBindingOb @override Widget build(BuildContext context) { - return Scaffold( - key: _scaffoldState, - body: Column( - children: [ - Row( - children: [ - Builder( - builder: (BuildContext context) { - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - Image.memory( - Utils.dataFromBase64String(AppState().memberInformationList!.eMPLOYEEIMAGE ?? ""), - errorBuilder: (BuildContext context, Object error, StackTrace? stackTrace) { - return SvgPicture.asset("assets/images/user.svg", height: 34, width: 34); - }, - width: 34, - height: 34, - fit: BoxFit.cover, - ).circle(50), - // CircularAvatar( - // width: 34, - // height: 34, - // url: "https://cdn4.iconfinder.com/data/icons/professions-2-2/151/89-512.png", - // ), - 8.width, - SvgPicture.asset("assets/images/side_nav.svg"), - ], - ).onPress(() { - _scaffoldState.currentState!.openDrawer(); - }); + return SafeArea( + bottom: Platform.isAndroid ? true : false, + top: false, + child: Scaffold( + key: _scaffoldState, + body: Column( + children: [ + Row( + children: [ + Builder( + builder: (BuildContext context) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + Image.memory( + Utils.dataFromBase64String(AppState().memberInformationList!.eMPLOYEEIMAGE ?? ""), + errorBuilder: (BuildContext context, Object error, StackTrace? stackTrace) { + return SvgPicture.asset("assets/images/user.svg", height: 34, width: 34); + }, + width: 34, + height: 34, + fit: BoxFit.cover, + ).circle(50), + // CircularAvatar( + // width: 34, + // height: 34, + // url: "https://cdn4.iconfinder.com/data/icons/professions-2-2/151/89-512.png", + // ), + 8.width, + SvgPicture.asset("assets/images/side_nav.svg"), + ], + ).onPress(() { + _scaffoldState.currentState!.openDrawer(); + }); + }, + ), + Image.asset("assets/images/logos/main_mohemm_logo.png", width: 134, height: 28).expanded, + SvgPicture.asset("assets/images/announcements.svg", matchTextDirection: true).onPress(() async { + await Navigator.pushNamed(context, AppRoutes.announcements); + }), + ], + ).paddingOnly(left: 21, right: 21, top: 48, bottom: 7), + Expanded( + child: SmartRefresher( + enablePullDown: true, + enablePullUp: false, + header: const MaterialClassicHeader(color: MyColors.gradiantEndColor), + controller: _refreshController, + onRefresh: () { + _onRefresh(false); }, - ), - Image.asset("assets/images/logos/main_mohemm_logo.png", width: 134, height: 28).expanded, - SvgPicture.asset("assets/images/announcements.svg", matchTextDirection: true).onPress(() async { - await Navigator.pushNamed(context, AppRoutes.announcements); - }), - ], - ).paddingOnly(left: 21, right: 21, top: 48, bottom: 7), - Expanded( - child: SmartRefresher( - enablePullDown: true, - enablePullUp: false, - header: const MaterialClassicHeader(color: MyColors.gradiantEndColor), - controller: _refreshController, - onRefresh: () { - _onRefresh(false); - }, - child: SingleChildScrollView( - child: Column( - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - LocaleKeys.welcomeBack.tr().toText14(color: MyColors.grey77Color), - (AppState().memberInformationList!.eMPLOYEENAME ?? "").toText24(isBold: true), - 16.height, - Row( - children: [ - Expanded( - child: AspectRatio( - aspectRatio: 159 / 159, - child: Consumer( - builder: (BuildContext context, DashboardProviderModel model, Widget? child) { - return (model.isAttendanceTrackingLoading - ? GetAttendanceTrackingShimmer() - : Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(15), - gradient: const LinearGradient( - transform: GradientRotation(.46), - begin: Alignment.topRight, - end: Alignment.bottomLeft, - colors: [MyColors.gradiantEndColor, MyColors.gradiantStartColor], + child: SingleChildScrollView( + child: Column( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.welcomeBack.tr().toText14(color: MyColors.grey77Color), + (AppState().memberInformationList!.eMPLOYEENAME ?? "").toText24(isBold: true), + 16.height, + Row( + children: [ + Expanded( + child: AspectRatio( + aspectRatio: 159 / 159, + child: Consumer( + builder: (BuildContext context, DashboardProviderModel model, Widget? child) { + return (model.isAttendanceTrackingLoading + ? GetAttendanceTrackingShimmer() + : Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(15), + gradient: const LinearGradient( + transform: GradientRotation(.46), + begin: Alignment.topRight, + end: Alignment.bottomLeft, + colors: [MyColors.gradiantEndColor, MyColors.gradiantStartColor], + ), ), - ), - child: Stack( - alignment: Alignment.center, - children: [ - if (model.isTimeRemainingInSeconds == 0) SvgPicture.asset("assets/images/thumb.svg"), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, + child: Stack( + alignment: Alignment.center, + children: [ + if (model.isTimeRemainingInSeconds == 0) SvgPicture.asset("assets/images/thumb.svg"), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.markAttendance.tr().toText14(color: Colors.white, isBold: true), + if (model.isTimeRemainingInSeconds == 0) DateTime.now().toString().split(" ")[0].toText12(color: Colors.white), + if (model.isTimeRemainingInSeconds != 0) + Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + 9.height, + Directionality( + textDirection: ui.TextDirection.ltr, + child: CountdownTimer( + endTime: model.endTime, + onEnd: null, + endWidget: "00:00:00".toText14(color: Colors.white, isBold: true), + textStyle: const TextStyle(color: Colors.white, fontSize: 14, letterSpacing: -0.48, fontWeight: FontWeight.bold), + ), + ), + LocaleKeys.timeLeftToday.tr().toText12(color: Colors.white), + 9.height, + ClipRRect( + borderRadius: const BorderRadius.all(Radius.circular(20)), + child: LinearProgressIndicator( + value: model.progress, + minHeight: 8, + valueColor: const AlwaysStoppedAnimation(Colors.white), + backgroundColor: const Color(0xff196D73), + ), + ), + ], + ), + ], + ).paddingOnly(top: 12, right: 15, left: 12), + ), + Row( children: [ - LocaleKeys.markAttendance.tr().toText14(color: Colors.white, isBold: true), - if (model.isTimeRemainingInSeconds == 0) DateTime.now().toString().split(" ")[0].toText12(color: Colors.white), - if (model.isTimeRemainingInSeconds != 0) - Column( + Expanded( + child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - 9.height, - Directionality( - textDirection: ui.TextDirection.ltr, - child: CountdownTimer( - endTime: model.endTime, - onEnd: null, - endWidget: "00:00:00".toText14(color: Colors.white, isBold: true), - textStyle: const TextStyle(color: Colors.white, fontSize: 14, letterSpacing: -0.48, fontWeight: FontWeight.bold), - ), - ), - LocaleKeys.timeLeftToday.tr().toText12(color: Colors.white), - 9.height, - ClipRRect( - borderRadius: const BorderRadius.all(Radius.circular(20)), - child: LinearProgressIndicator( - value: model.progress, - minHeight: 8, - valueColor: const AlwaysStoppedAnimation(Colors.white), - backgroundColor: const Color(0xff196D73), - ), + LocaleKeys.checkIn.tr().toText12(color: Colors.white), + (model.attendanceTracking!.pSwipeIn == null ? "--:--" : model.attendanceTracking!.pSwipeIn).toString().toText14( + color: Colors.white, + isBold: true, ), + 4.height, ], + ).paddingOnly(left: 12, right: 12), + ), + Container( + margin: EdgeInsets.only(top: AppState().isArabic(context) ? 6 : 0), + width: 45, + height: 45, + padding: const EdgeInsets.only(left: 10, right: 10), + decoration: BoxDecoration( + color: const Color(0xff259EA4), + borderRadius: BorderRadius.only( + bottomRight: AppState().isArabic(context) ? const Radius.circular(0) : const Radius.circular(15), + bottomLeft: AppState().isArabic(context) ? const Radius.circular(15) : const Radius.circular(0), + ), ), + child: SvgPicture.asset(model.isTimeRemainingInSeconds == 0 ? "assets/images/biometrics.svg" : "assets/images/biometrics.svg"), + ).onPress(() { + showMyBottomSheet(context, callBackFunc: () {}, child: MarkAttendanceWidget(model, isFromDashboard: true)); + }), ], - ).paddingOnly(top: 12, right: 15, left: 12), - ), - Row( - children: [ - Expanded( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, + ), + ], + ), + ], + ), + ).onPress(() { + Navigator.pushNamed(context, AppRoutes.todayAttendance); + })) + .animatedSwither(); + }, + ), + ), + ), + 9.width, + Expanded(child: MenusWidget()), + ], + ), + ], + ).paddingOnly(left: 21, right: 21, top: 7, bottom: 21), + eventActivityWidget(context), + Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Directionality( + textDirection: AppState().isArabic(context) ? ui.TextDirection.rtl : ui.TextDirection.ltr, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + gradient: const LinearGradient(colors: [Color(0xFF91C481), Color(0xFF7CCED7)], begin: Alignment.centerLeft, end: Alignment.centerRight), + ), + child: Padding( + padding: const EdgeInsets.all(3.0), // This creates the border width + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(17), // Slightly less than outer radius + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + flex: 4, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Row( + children: [ + Expanded( + flex: 2, + child: RichText( + text: + AppState().isArabic(context) + ? TextSpan( children: [ - LocaleKeys.checkIn.tr().toText12(color: Colors.white), - (model.attendanceTracking!.pSwipeIn == null ? "--:--" : model.attendanceTracking!.pSwipeIn).toString().toText14( - color: Colors.white, - isBold: true, + TextSpan( + text: 'اطلع على مميزات', + style: TextStyle(fontSize: 16, letterSpacing: -0.2, fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins', fontWeight: FontWeight.w700, height: 24 / 16, color: Color(0xFF5D5E5E)), + ), + TextSpan( + text: ' مزايا', + style: TextStyle( + fontSize: 16, + fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins', + fontWeight: FontWeight.w700, + letterSpacing: -0.2, + height: 24 / 16, + color: MyColors.mazayaRedColor, // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed + ), + ), + ], + ) + : TextSpan( + children: [ + TextSpan( + text: LocaleKeys.explore.tr() + ' ', + style: const TextStyle(fontSize: 16, letterSpacing: -0.2, fontFamily: 'Poppins', fontWeight: FontWeight.w700, height: 24 / 16, color: Color(0xFF5D5E5E)), + ), + TextSpan( + text: LocaleKeys.mazaya.tr(), + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.w700, + fontFamily: 'Poppins', + letterSpacing: -0.2, + height: 24 / 16, + color: MyColors.mazayaRedColor, // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed + ), + ), + TextSpan( + text: ' ' + LocaleKeys.benefits.tr(), + style: const TextStyle(fontSize: 16, letterSpacing: -0.2, + fontFamily: 'Poppins',fontWeight: FontWeight.w700, height: 24 / 16, color: Color(0xFF5D5E5E)), ), - 4.height, ], - ).paddingOnly(left: 12, right: 12), - ), - Container( - margin: EdgeInsets.only(top: AppState().isArabic(context) ? 6 : 0), - width: 45, - height: 45, - padding: const EdgeInsets.only(left: 10, right: 10), - decoration: BoxDecoration( - color: const Color(0xff259EA4), - borderRadius: BorderRadius.only( - bottomRight: AppState().isArabic(context) ? const Radius.circular(0) : const Radius.circular(15), - bottomLeft: AppState().isArabic(context) ? const Radius.circular(15) : const Radius.circular(0), - ), ), - child: SvgPicture.asset(model.isTimeRemainingInSeconds == 0 ? "assets/images/biometrics.svg" : "assets/images/biometrics.svg"), - ).onPress(() { - showMyBottomSheet(context, callBackFunc: () {}, child: MarkAttendanceWidget(model, isFromDashboard: true)); - }), - ], - ), - ], ), - ], - ), - ).onPress(() { - Navigator.pushNamed(context, AppRoutes.todayAttendance); - })) - .animatedSwither(); - }, + ), + const Expanded(flex: 1, child: SizedBox()), + ], + ), + const SizedBox(height: 8), + LocaleKeys.mazayaDesc.tr().toText11(color: const Color(0xFF5D5E5E)), + ], + ), + ), + Expanded( + flex: 2, + child: Column( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + SvgPicture.asset("assets/icons/mazaya_brand.svg", width: 90, height: 47), + const SizedBox(height: 28), + LocaleKeys.viewallofferMazaya.tr().toText12(isUnderLine: true, color: const Color(0xFF3B3D4A)).onPress(() { + Navigator.pushNamed(context, AppRoutes.offersAndDiscounts); + }), + ], + ), + ), + ], + ).paddingOnly(left: 21, right: 21, top: 14, bottom: 14), ), ), - ), - 9.width, - Expanded(child: MenusWidget()), + ).paddingOnly(left: 21, right: 21, top: 0, bottom: 21), + ), + ], + ), + Container( + width: double.infinity, + padding: const EdgeInsets.only(top: 31), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: const BorderRadius.only(topRight: Radius.circular(50), topLeft: Radius.circular(50)), + border: Border.all(color: MyColors.lightGreyEDColor, width: 1), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + ServicesWidget(), + context.watch().isLoading ? const MarathonBannerShimmer().paddingAll(20) : const MarathonBanner().paddingOnly(left: 21, right: 21, bottom: 8, top: 8), + // context.watch().isTutorialLoading + // ? const MarathonBannerShimmer().paddingAll(20) + // : Container( + // padding: EdgeInsets.only(bottom: 12, top: 12), + // margin: EdgeInsets.only(left: 21, right: 21, bottom: 21, top: 8), + // width: double.infinity, + // alignment: Alignment.center, + // decoration: BoxDecoration( + // color: MyColors.backgroundBlackColor, + // borderRadius: BorderRadius.circular(20), + // border: Border.all(color: MyColors.lightGreyEDColor, width: 1), + // ), + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // mainAxisSize: MainAxisSize.min, + // children: [ + // Text( + // "Tutorial:", + // style: TextStyle( + // fontSize: 11, + // fontStyle: FontStyle.italic, + // fontWeight: FontWeight.w600, + // color: MyColors.white.withOpacity(0.83), + // letterSpacing: -0.4, + // ), + // ), + // Text( + // context.read().tutorial?.tutorialName ?? "", + // overflow: TextOverflow.ellipsis, + // style: TextStyle( + // fontStyle: FontStyle.italic, + // fontSize: 19, + // fontWeight: FontWeight.bold, + // color: MyColors.white, + // height: 32 / 22, + // ), + // ), + // ], + // ), + // ).onPress(() { + // checkERMChannel(); + // // Navigator.pushNamed(context, AppRoutes.marathonTutorialScreen); + // }), ], ), - ], - ).paddingOnly(left: 21, right: 21, top: 7, bottom: 21), - eventActivityWidget(context), + ), + ], + ), + ), + ), + ), + ], + ), + drawer: AppDrawer(onLanguageChange: _onRefresh), + bottomNavigationBar: SizedBox( + height: Platform.isAndroid ? 70 : 100, + child: BottomNavigationBar( + items: [ + BottomNavigationBarItem(icon: SvgPicture.asset("assets/icons/home.svg", color: currentIndex == 0 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4), label: LocaleKeys.home.tr()), + BottomNavigationBarItem( + icon: SvgPicture.asset("assets/icons/create_req.svg", color: currentIndex == 1 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4), + label: LocaleKeys.mowadhafhiRequest.tr(), + ), + BottomNavigationBarItem( + icon: Stack( + alignment: Alignment.centerLeft, + children: [ + SvgPicture.asset("assets/icons/work_list.svg", color: currentIndex == 2 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4), Consumer( - builder: (BuildContext context, DashboardProviderModel model, Widget? child) { - if (!model.isOffersLoading && model.getOffersList.isEmpty) { + builder: (BuildContext cxt, DashboardProviderModel data, Widget? child) { + if (data.workListCounter == 0) { return const SizedBox(); } - return Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Directionality( - textDirection: AppState().isArabic(context) ? ui.TextDirection.rtl : ui.TextDirection.ltr, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - gradient: const LinearGradient(colors: [Color(0xFF91C481), Color(0xFF7CCED7)], begin: Alignment.centerLeft, end: Alignment.centerRight), - ), - child: Padding( - padding: const EdgeInsets.all(3.0), // This creates the border width - child: Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(17), // Slightly less than outer radius - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - flex: 4, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Row( - children: [ - Expanded( - flex: 2, - child: RichText( - text: - AppState().isArabic(context) - ? const TextSpan( - children: [ - TextSpan( - text: 'اطلع على مميزات', - style: TextStyle(fontSize: 16, letterSpacing: -0.2, fontWeight: FontWeight.w700, height: 24 / 16, color: Color(0xFF5D5E5E)), - ), - TextSpan( - text: ' مزايا', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w700, - letterSpacing: -0.2, - height: 24 / 16, - color: Color(0xFFED1C2B), // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed - ), - ), - ], - ) - : TextSpan( - children: [ - TextSpan( - text: LocaleKeys.explore.tr() + ' ', - style: const TextStyle(fontSize: 16, letterSpacing: -0.2, fontWeight: FontWeight.w700, height: 24 / 16, color: Color(0xFF5D5E5E)), - ), - TextSpan( - text: LocaleKeys.mazaya.tr(), - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w700, - letterSpacing: -0.2, - height: 24 / 16, - color: Color(0xFFED1C2B), // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed - ), - ), - TextSpan( - text: ' ' + LocaleKeys.benefits.tr(), - style: const TextStyle(fontSize: 16, letterSpacing: -0.2, fontWeight: FontWeight.w700, height: 24 / 16, color: Color(0xFF5D5E5E)), - ), - ], - ), - ), - ), - const Expanded(flex: 1, child: SizedBox()), - ], - ), - const SizedBox(height: 8), - LocaleKeys.mazayaDesc.tr().toText11(color: const Color(0xFF5D5E5E)), - ], - ), - ), - Expanded( - flex: 2, - child: Column( - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisAlignment: MainAxisAlignment.end, - children: [ - SvgPicture.asset("assets/icons/mazaya_brand.svg", width: 90, height: 47), - const SizedBox(height: 28), - LocaleKeys.viewAllOffers.tr().toText12(isUnderLine: true, color: const Color(0xFF3B3D4A)).onPress(() { - Navigator.pushNamed(context, AppRoutes.offersAndDiscounts); - }), - ], - ), - ), - ], - ).paddingOnly(left: 21, right: 21, top: 14, bottom: 14), - ), - ), - ).paddingOnly(left: 21, right: 21, top: 0, bottom: 21), - ), - - // Container( - // height: 121, - // decoration: BoxDecoration( - // borderRadius: BorderRadius.circular(12), - // border: Border.all(width: 3, color: Colors.red), - // ), - // child: Padding(padding: const EdgeInsets.all(4.0), child: Container(decoration: BoxDecoration(borderRadius: BorderRadius.circular(12), color: Colors.white))), - // ).paddingOnly(left: 21, right: 21, bottom: 21), - - // Row( - // crossAxisAlignment: CrossAxisAlignment.center, - // children: [ - // Expanded( - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // mainAxisSize: MainAxisSize.min, - // children: [ - // LocaleKeys.offers.tr().toText12(), - // Row( - // children: [ - // LocaleKeys.discounts.tr().toText24(isBold: true), - // 6.width, - // Container( - // padding: const EdgeInsets.only(left: 8, right: 8), - // decoration: BoxDecoration( - // color: MyColors.yellowColor, - // borderRadius: BorderRadius.circular(10), - // ), - // child: LocaleKeys.newString.tr().toText10(isBold: true)), - // ], - // ), - // ], - // ), - // ), - // LocaleKeys.viewAllOffers.tr().toText12(isUnderLine: true).onPress(() { - // Navigator.pushNamed(context, AppRoutes.offersAndDiscounts); - // }) - // ], - // ).paddingOnly(left: 21, right: 21), - // Consumer( - // builder: (BuildContext context, DashboardProviderModel model, Widget? child) { - // return SizedBox( - // height: 103 + 33, - // child: ListView.separated( - // shrinkWrap: true, - // physics: const BouncingScrollPhysics(), - // padding: const EdgeInsets.only(left: 21, right: 21, top: 13), - // scrollDirection: Axis.horizontal, - // itemBuilder: (BuildContext cxt, int index) { - // return model.isOffersLoading - // ? const OffersShimmerWidget() - // : InkWell( - // onTap: () { - // navigateToDetails(data.getOffersList[index]); - // }, - // child: SizedBox( - // width: 73, - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.center, - // children: [ - // Container( - // width: 73, - // height: 73, - // decoration: BoxDecoration( - // color: Colors.white, - // borderRadius: const BorderRadius.all( - // Radius.circular(100), - // ), - // border: Border.all(color: MyColors.lightGreyE3Color, width: 1), - // ), - // child: ClipRRect( - // borderRadius: const BorderRadius.all( - // Radius.circular(50), - // ), - // child: Hero( - // tag: "ItemImage" + data.getOffersList[index].offersDiscountId.toString()!, - // transitionOnUserGestures: true, - // child: Image.network( - // data.getOffersList[index].logo ?? "", - // fit: BoxFit.contain, - // ), - // ), - // ), - // ), - // 4.height, - // Expanded( - // child: AppState().isArabic(context) - // ? data.getOffersList[index].titleAr!.toText12(isCenter: true, maxLine: 1) - // : data.getOffersList[index].titleEn!.toText12(isCenter: true, maxLine: 1), - // ), - // ], - // ), - // ), - // ); - // }, - // separatorBuilder: (BuildContext cxt, int index) => 8.width, - // itemCount: 9), - // ); - // }, - // ), - ], + return Positioned( + right: 0, + top: 0, + child: Container( + padding: const EdgeInsets.only(left: 4, right: 4), + alignment: Alignment.center, + decoration: BoxDecoration(color: MyColors.redColor, borderRadius: BorderRadius.circular(17)), + child: data.workListCounter.toString().toText10(color: Colors.white), + ), ); }, ), - Container( - width: double.infinity, - padding: const EdgeInsets.only(top: 31), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: const BorderRadius.only(topRight: Radius.circular(50), topLeft: Radius.circular(50)), - border: Border.all(color: MyColors.lightGreyEDColor, width: 1), - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - ServicesWidget(), - context.watch().isLoading ? const MarathonBannerShimmer().paddingAll(20) : const MarathonBanner().paddingOnly(left: 21, right: 21, bottom: 8, top: 8), - // context.watch().isTutorialLoading - // ? const MarathonBannerShimmer().paddingAll(20) - // : Container( - // padding: EdgeInsets.only(bottom: 12, top: 12), - // margin: EdgeInsets.only(left: 21, right: 21, bottom: 21, top: 8), - // width: double.infinity, - // alignment: Alignment.center, - // decoration: BoxDecoration( - // color: MyColors.backgroundBlackColor, - // borderRadius: BorderRadius.circular(20), - // border: Border.all(color: MyColors.lightGreyEDColor, width: 1), - // ), - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // mainAxisSize: MainAxisSize.min, - // children: [ - // Text( - // "Tutorial:", - // style: TextStyle( - // fontSize: 11, - // fontStyle: FontStyle.italic, - // fontWeight: FontWeight.w600, - // color: MyColors.white.withOpacity(0.83), - // letterSpacing: -0.4, - // ), - // ), - // Text( - // context.read().tutorial?.tutorialName ?? "", - // overflow: TextOverflow.ellipsis, - // style: TextStyle( - // fontStyle: FontStyle.italic, - // fontSize: 19, - // fontWeight: FontWeight.bold, - // color: MyColors.white, - // height: 32 / 22, - // ), - // ), - // ], - // ), - // ).onPress(() { - // checkERMChannel(); - // // Navigator.pushNamed(context, AppRoutes.marathonTutorialScreen); - // }), - ], - ), - ), ], ), + label: LocaleKeys.workList.tr(), ), - ), - ), - ], - ), - drawer: SafeArea(child: AppDrawer(onLanguageChange: _onRefresh)), - bottomNavigationBar: SizedBox( - height: Platform.isAndroid ? 70 : 100, - child: BottomNavigationBar( - items: [ - BottomNavigationBarItem(icon: SvgPicture.asset("assets/icons/home.svg", color: currentIndex == 0 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4), label: LocaleKeys.home.tr()), - BottomNavigationBarItem( - icon: SvgPicture.asset("assets/icons/create_req.svg", color: currentIndex == 1 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4), - label: LocaleKeys.mowadhafhiRequest.tr(), - ), - BottomNavigationBarItem( - icon: Stack( - alignment: Alignment.centerLeft, - children: [ - SvgPicture.asset("assets/icons/work_list.svg", color: currentIndex == 2 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4), - Consumer( - builder: (BuildContext cxt, DashboardProviderModel data, Widget? child) { - if (data.workListCounter == 0) { - return const SizedBox(); - } - return Positioned( - right: 0, - top: 0, - child: Container( - padding: const EdgeInsets.only(left: 4, right: 4), - alignment: Alignment.center, - decoration: BoxDecoration(color: MyColors.redColor, borderRadius: BorderRadius.circular(17)), - child: data.workListCounter.toString().toText10(color: Colors.white), - ), - ); - }, - ), - ], + BottomNavigationBarItem( + icon: SvgPicture.asset("assets/icons/item_for_sale.svg", color: currentIndex == 3 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4), + label: LocaleKeys.itemsForSale.tr(), ), - label: LocaleKeys.workList.tr(), - ), - BottomNavigationBarItem( - icon: SvgPicture.asset("assets/icons/item_for_sale.svg", color: currentIndex == 3 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4), - label: LocaleKeys.itemsForSale.tr(), - ), - BottomNavigationBarItem( - icon: Stack( - alignment: Alignment.centerLeft, - children: [ - SvgPicture.asset( - "assets/icons/chat/chat.svg", - color: - !checkIfPrivilegedForChat() - ? MyColors.lightGreyE3Color - : currentIndex == 4 - ? MyColors.grey3AColor - : cProvider.disbaleChatForThisUser - ? MyColors.lightGreyE3Color - : MyColors.grey98Color, - ).paddingAll(4), - Consumer( - builder: (BuildContext cxt, ChatProviderModel data, Widget? child) { - return !checkIfPrivilegedForChat() - ? const SizedBox() - : Positioned( - right: 0, - top: 0, - child: Container( - padding: const EdgeInsets.only(left: 4, right: 4), - alignment: Alignment.center, - decoration: BoxDecoration(color: cProvider.disbaleChatForThisUser ? MyColors.pinkDarkColor : MyColors.redColor, borderRadius: BorderRadius.circular(17)), - child: data.chatUConvCounter.toString().toText10(color: Colors.white), - ), - ); - }, - ), - ], + BottomNavigationBarItem( + icon: Stack( + alignment: Alignment.centerLeft, + children: [ + SvgPicture.asset( + "assets/icons/chat/chat.svg", + color: + !checkIfPrivilegedForChat() + ? MyColors.lightGreyE3Color + : currentIndex == 4 + ? MyColors.grey3AColor + : cProvider.disbaleChatForThisUser + ? MyColors.lightGreyE3Color + : MyColors.grey98Color, + ).paddingAll(4), + Consumer( + builder: (BuildContext cxt, ChatProviderModel data, Widget? child) { + return !checkIfPrivilegedForChat() + ? const SizedBox() + : Positioned( + right: 0, + top: 0, + child: Container( + padding: const EdgeInsets.only(left: 4, right: 4), + alignment: Alignment.center, + decoration: BoxDecoration(color: cProvider.disbaleChatForThisUser ? MyColors.pinkDarkColor : MyColors.redColor, borderRadius: BorderRadius.circular(17)), + child: data.chatUConvCounter.toString().toText10(color: Colors.white), + ), + ); + }, + ), + ], + ), + label: LocaleKeys.chat.tr(), ), - label: LocaleKeys.chat.tr(), - ), - ], - currentIndex: currentIndex, - selectedLabelStyle: const TextStyle(fontSize: 10, color: MyColors.grey3AColor, fontWeight: FontWeight.w600), - unselectedLabelStyle: const TextStyle(fontSize: 10, color: MyColors.grey98Color, fontWeight: FontWeight.w600), - type: BottomNavigationBarType.fixed, - selectedItemColor: MyColors.grey3AColor, - backgroundColor: MyColors.backgroundColor, - selectedIconTheme: const IconThemeData(color: MyColors.grey3AColor, size: 28), - unselectedIconTheme: const IconThemeData(color: MyColors.grey98Color, size: 28), - onTap: (int index) { - if (index == 1) { - Navigator.pushNamed(context, AppRoutes.mowadhafhi); - } else if (index == 2) { - Navigator.pushNamed(context, AppRoutes.workList); - } else if (index == 3) { - Navigator.pushNamed(context, AppRoutes.itemsForSale); - } else if (index == 4) { - if (!cProvider.disbaleChatForThisUser && checkIfPrivilegedForChat()) { - Navigator.pushNamed(context, AppRoutes.chat); + ], + currentIndex: currentIndex, + selectedLabelStyle: const TextStyle(fontSize: 10, color: MyColors.grey3AColor, fontWeight: FontWeight.w600), + unselectedLabelStyle: const TextStyle(fontSize: 10, color: MyColors.grey98Color, fontWeight: FontWeight.w600), + type: BottomNavigationBarType.fixed, + selectedItemColor: MyColors.grey3AColor, + backgroundColor: MyColors.backgroundColor, + selectedIconTheme: const IconThemeData(color: MyColors.grey3AColor, size: 28), + unselectedIconTheme: const IconThemeData(color: MyColors.grey98Color, size: 28), + onTap: (int index) { + if (index == 1) { + Navigator.pushNamed(context, AppRoutes.mowadhafhi); + } else if (index == 2) { + Navigator.pushNamed(context, AppRoutes.workList); + } else if (index == 3) { + Navigator.pushNamed(context, AppRoutes.itemsForSale); + } else if (index == 4) { + if (!cProvider.disbaleChatForThisUser && checkIfPrivilegedForChat()) { + Navigator.pushNamed(context, AppRoutes.chat); + } } - } - }, + }, + ), ), ), ); diff --git a/pubspec.yaml b/pubspec.yaml index 084364a..e07bd99 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -56,7 +56,7 @@ dependencies: flutter_countdown_timer: ^4.1.0 platform_device_id_plus: ^1.0.7 - device_info_plus: ^9.0.0 + device_info_plus: ^11.5.0 image_picker: ^0.8.5+3 file_picker: ^8.3.1 geolocator: ^9.0.2 @@ -75,7 +75,7 @@ dependencies: flutter_rating_bar: ^4.0.1 auto_size_text: ^3.0.0 pull_to_refresh: ^2.0.0 - fl_chart: ^0.70.2 + fl_chart: ^0.66.0 # lottie json animations lottie: any # Marathon Card Swipe @@ -96,7 +96,7 @@ dependencies: #firebase_analytics: any #Chat Voice Message Recoding & Play - audio_waveforms: ^0.1.5+1 + audio_waveforms: ^1.3.0 rxdart: ^0.27.7 #Encryption @@ -110,7 +110,7 @@ dependencies: #Huawei Dependencies # huawei_hmsavailability: ^6.6.0+300 # huawei_location: 6.0.0+302 - huawei_location: ^6.11.0+301 + huawei_location: ^6.14.2+301 # huawei_push: ^6.7.0+300 huawei_map: -- 2.30.2 From 7384f22942d5743a615dea3d6342c9fd6867f1da Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Thu, 31 Jul 2025 11:39:24 +0300 Subject: [PATCH 088/135] Update to stores, VersionID 9.2 --- android/app/build.gradle | 1 + lib/app_state/app_state.dart | 2 +- .../offers_and_discounts_details.dart | 50 ++++++------------- pubspec.yaml | 5 +- 4 files changed, 19 insertions(+), 39 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 8a1cccd..cd780fb 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -19,6 +19,7 @@ if (keystorePropertiesFile.exists()) { android { namespace 'hmg.cloudSolutions.mohem' compileSdk 36 // Changed from 36 to a supported version + ndkVersion '28.2.13676358' compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 diff --git a/lib/app_state/app_state.dart b/lib/app_state/app_state.dart index 568dfaf..558ed09 100644 --- a/lib/app_state/app_state.dart +++ b/lib/app_state/app_state.dart @@ -90,7 +90,7 @@ class AppState { String get getHuaweiPushToken => _huaweiPushToken; - final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 9.0, mobileType: Platform.isAndroid ? "android" : "ios"); + final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 9.2, mobileType: Platform.isAndroid ? "android" : "ios"); void setPostParamsInitConfig() { isAuthenticated = false; diff --git a/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart b/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart index 70eecd2..be0582c 100644 --- a/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart +++ b/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart @@ -61,13 +61,7 @@ class _OffersAndDiscountsDetailsState extends State { // transitionOnUserGestures: true, child: RepaintBoundary( key: _globalKey, - child: ClipRRect( - borderRadius: BorderRadius.circular(6), - child: Image.network( - getOffersList[0].bannerImage ?? "", - fit: BoxFit.contain, - ), - ).paddingAll(12), + child: ClipRRect(borderRadius: BorderRadius.circular(6), child: Image.network(getOffersList[0].bannerImage ?? "", fit: BoxFit.contain)).paddingAll(12), ), ), 8.height, @@ -77,7 +71,6 @@ class _OffersAndDiscountsDetailsState extends State { Html( data: AppState().isArabic(context) ? getOffersList[0].descriptionAr! : getOffersList[0].descriptionEn ?? "", onLinkTap: (String? url, Map attributes, _) { - launchUrl(Uri.parse(url!)); }, ), @@ -88,19 +81,20 @@ class _OffersAndDiscountsDetailsState extends State { children: [ getOffersList[0].discountDescription!.toText16(isBold: true), InkWell( - onTap: () { - _shareOfferAsImage(); - }, - child: const Icon(Icons.share, color: MyColors.darkIconColor).paddingOnly(bottom: 4)) + onTap: () { + _shareOfferAsImage(); + }, + child: const Icon(Icons.share, color: MyColors.darkIconColor).paddingOnly(bottom: 4), + ), ], ).paddingOnly(left: 8, right: 8), getOffersList[0].isHasLocation == "true" ? InkWell( - onTap: () {}, - child: Row( - children: [const Icon(Icons.map_sharp, color: MyColors.darkIconColor).paddingOnly(bottom: 4), "Offer Location".toText16(isUnderLine: true).paddingOnly(left: 8)], - ).paddingOnly(left: 8, right: 8, top: 8), - ) + onTap: () {}, + child: Row( + children: [const Icon(Icons.map_sharp, color: MyColors.darkIconColor).paddingOnly(bottom: 4), "Offer Location".toText16(isUnderLine: true).paddingOnly(left: 8)], + ).paddingOnly(left: 8, right: 8, top: 8), + ) : 12.height, ], ).objectContainerView().paddingOnly(left: 21, right: 21, top: 21), @@ -135,11 +129,7 @@ class _OffersAndDiscountsDetailsState extends State { } void _scrollToTop() { - _scrollController.animateTo( - 0, - duration: const Duration(milliseconds: 500), - curve: Curves.linear, - ); + _scrollController.animateTo(0, duration: const Duration(milliseconds: 500), curve: Curves.linear); } List getItemsForSaleWidgets() { @@ -158,16 +148,7 @@ class _OffersAndDiscountsDetailsState extends State { Hero( tag: "ItemImage" + getOffersList.offersDiscountId.toString(), transitionOnUserGestures: true, - child: AspectRatio( - aspectRatio: 148 / 127, - child: ClipRRect( - borderRadius: BorderRadius.circular(6), - child: Image.network( - getOffersList.bannerImage ?? "", - fit: BoxFit.contain, - ), - ), - ), + child: AspectRatio(aspectRatio: 148 / 127, child: ClipRRect(borderRadius: BorderRadius.circular(6), child: Image.network(getOffersList.bannerImage ?? "", fit: BoxFit.contain))), ), 5.height, getOffersList.titleEn!.toText16(isBold: true, color: const Color(0xff2B353E), maxlines: 1), @@ -181,10 +162,7 @@ class _OffersAndDiscountsDetailsState extends State { // 16.height, getOffersList.discountDescription!.toText14(isBold: true, maxlines: 1), 8.height, - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [checkDate(getOffersList.endDate!), SvgPicture.asset("assets/images/arrow_next.svg").paddingOnly(bottom: 4)], - ), + Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [checkDate(getOffersList.endDate!), SvgPicture.asset("assets/images/arrow_next.svg").paddingOnly(bottom: 4)]), ], ).objectContainerView().onPress(() { this.getOffersList[0] = getOffersList; diff --git a/pubspec.yaml b/pubspec.yaml index e07bd99..a3c0c99 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,8 +16,9 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -#version: 3.3.01+300040 -version: 3.7.98+3 + +version: 3.6.7+300077 +#version: 3.9.0+1 environment: sdk: ^3.7.0 -- 2.30.2 From c8fa64171e4534872c015ca47b22a4ef63e27a81 Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Sun, 24 Aug 2025 14:40:28 +0300 Subject: [PATCH 089/135] coreLibraryDesugaringEnabled --- android/app/build.gradle | 8 ++++++++ ios/Runner.xcodeproj/project.pbxproj | 6 +++--- lib/ui/landing/widget/services_widget.dart | 3 ++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 217706e..c4619f4 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -20,6 +20,7 @@ android { namespace 'hmg.cloudSolutions.mohem' compileSdk 36 + kotlinOptions { jvmTarget = '1.8' } @@ -35,6 +36,11 @@ android { targetSdk = flutter.targetSdkVersion versionCode flutter.versionCode versionName flutter.versionName + multiDexEnabled true + } + + compileOptions { + coreLibraryDesugaringEnabled true } signingConfigs { @@ -64,4 +70,6 @@ flutter { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.1.20" + implementation 'androidx.multidex:multidex:2.0.1' + coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3' } diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index ea4aec9..a9aed20 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -391,7 +391,7 @@ ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = Mohemm; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.6; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -530,7 +530,7 @@ ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = Mohemm; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.6; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -561,7 +561,7 @@ ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = Mohemm; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.6; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/lib/ui/landing/widget/services_widget.dart b/lib/ui/landing/widget/services_widget.dart index 7d2c2b2..0bd9acc 100644 --- a/lib/ui/landing/widget/services_widget.dart +++ b/lib/ui/landing/widget/services_widget.dart @@ -256,13 +256,14 @@ class ServicesWidget extends StatelessWidget { if (menuEntry.menuName == "HMG_TICKET_REQUESTS") { Utils.showLoading(context); TicketBookingResult response = await pro.fetchTicketBooking(); - Utils.hideLoading(context); + if (response.success) { SSOAuthModel? ssoToken = await pro.fetchSSOAuthRedirection(clientID: response.clientId); if (ssoToken != null) { logger.d(ssoToken.data!.toJson()); logger.d(ssoToken.data!.accessToken); dynamic url = await pro.fetchURLRedirection(token: ssoToken.data!.accessToken!); + Utils.hideLoading(context); Navigator.push(context, MaterialPageRoute(builder: (context) => SsoLoginWebView(url: url ?? "", jwtToken: ssoToken.data!.accessToken!))); } } else { -- 2.30.2 From 1bcecde59bde0b6ce32645bb9adfde135a74938d Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Tue, 26 Aug 2025 10:39:53 +0300 Subject: [PATCH 090/135] ticket changes moved to dashboard --- lib/provider/dashboard_provider_model.dart | 9 +- lib/ui/landing/dashboard_screen.dart | 495 ++++++++++----------- lib/ui/landing/widget/services_widget.dart | 7 +- 3 files changed, 240 insertions(+), 271 deletions(-) diff --git a/lib/provider/dashboard_provider_model.dart b/lib/provider/dashboard_provider_model.dart index 0dcebed..6686574 100644 --- a/lib/provider/dashboard_provider_model.dart +++ b/lib/provider/dashboard_provider_model.dart @@ -56,6 +56,7 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { List? getMenuEntriesList; EventActivityList? eventActivity; + TicketBookingResult? ticketBookingResponse; //Offers And Discounts bool isOffersLoading = true; @@ -285,19 +286,19 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } } - Future fetchTicketBooking() async { + void fetchTicketBooking() async { try { GenericResponseModel? genericResponseModel = await DashboardApiClient().getTicketBookingRedirection(); if (genericResponseModel?.portalDirectionData?.pRedirection!.toLowerCase() == "alma") { - return TicketBookingResult(true, genericResponseModel?.portalDirectionData?.clientID); + ticketBookingResponse = TicketBookingResult(true, genericResponseModel?.portalDirectionData?.clientID); } - return TicketBookingResult(false, null); + ticketBookingResponse = TicketBookingResult(false, null); } catch (ex) { logger.wtf(ex); isEventLoadingLoading = false; notifyListeners(); Utils.handleException(ex, null, null); - return TicketBookingResult(false, null); // Ensure a return value in case of an exception + ticketBookingResponse = TicketBookingResult(false, null); // Ensure a return value in case of an exception } } diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index 4640c25..2ddd706 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -159,6 +159,9 @@ class _DashboardScreenState extends State with WidgetsBindingOb } if (!cProvider.disbaleChatForThisUser && !isFromInit) checkHubCon(); _refreshController.refreshCompleted(); + + data.fetchTicketBooking(); + //continue here } int ermIndex = 0; @@ -175,10 +178,11 @@ class _DashboardScreenState extends State with WidgetsBindingOb if (list[ermIndex].notificationType == "Survey") { await Navigator.pushNamed(context, AppRoutes.survey, arguments: response.mohemmItgResponseItem!.result!.data!.first); } else { - await Navigator.pushNamed(context, AppRoutes.advertisement, arguments: { - "masterId": list[ermIndex].notificationMasterId, - "advertisement": response.mohemmItgResponseItem!.result!.data!.first.advertisement, - }); + await Navigator.pushNamed( + context, + AppRoutes.advertisement, + arguments: {"masterId": list[ermIndex].notificationMasterId, "advertisement": response.mohemmItgResponseItem!.result!.data!.first.advertisement}, + ); } } ermIndex++; @@ -241,53 +245,44 @@ class _DashboardScreenState extends State with WidgetsBindingOb children: [ Row( children: [ - Builder(builder: (BuildContext context) { - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - Image.memory( - Utils.dataFromBase64String( - AppState().memberInformationList!.eMPLOYEEIMAGE ?? "", - ), - errorBuilder: (BuildContext context, Object error, StackTrace? stackTrace) { - return SvgPicture.asset( - "assets/images/user.svg", - height: 34, - width: 34, - ); - }, - width: 34, - height: 34, - fit: BoxFit.cover, - ).circle(50), - // CircularAvatar( - // width: 34, - // height: 34, - // url: "https://cdn4.iconfinder.com/data/icons/professions-2-2/151/89-512.png", - // ), - 8.width, - SvgPicture.asset("assets/images/side_nav.svg"), - ], - ).onPress(() { - _scaffoldState.currentState!.openDrawer(); - }); - }), + Builder( + builder: (BuildContext context) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + Image.memory( + Utils.dataFromBase64String(AppState().memberInformationList!.eMPLOYEEIMAGE ?? ""), + errorBuilder: (BuildContext context, Object error, StackTrace? stackTrace) { + return SvgPicture.asset("assets/images/user.svg", height: 34, width: 34); + }, + width: 34, + height: 34, + fit: BoxFit.cover, + ).circle(50), + // CircularAvatar( + // width: 34, + // height: 34, + // url: "https://cdn4.iconfinder.com/data/icons/professions-2-2/151/89-512.png", + // ), + 8.width, + SvgPicture.asset("assets/images/side_nav.svg"), + ], + ).onPress(() { + _scaffoldState.currentState!.openDrawer(); + }); + }, + ), Image.asset("assets/images/logos/main_mohemm_logo.png", width: 134, height: 28).expanded, - SvgPicture.asset( - "assets/images/announcements.svg", - matchTextDirection: true, - ).onPress(() async { + SvgPicture.asset("assets/images/announcements.svg", matchTextDirection: true).onPress(() async { await Navigator.pushNamed(context, AppRoutes.announcements); - }) + }), ], ).paddingOnly(left: 21, right: 21, top: 48, bottom: 7), Expanded( child: SmartRefresher( enablePullDown: true, enablePullUp: false, - header: const MaterialClassicHeader( - color: MyColors.gradiantEndColor, - ), + header: const MaterialClassicHeader(color: MyColors.gradiantEndColor), controller: _refreshController, onRefresh: () { _onRefresh(false); @@ -311,161 +306,155 @@ class _DashboardScreenState extends State with WidgetsBindingOb return (model.isAttendanceTrackingLoading ? GetAttendanceTrackingShimmer() : Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(15), - gradient: const LinearGradient(transform: GradientRotation(.46), begin: Alignment.topRight, end: Alignment.bottomLeft, colors: [ - MyColors.gradiantEndColor, - MyColors.gradiantStartColor, - ]), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(15), + gradient: const LinearGradient( + transform: GradientRotation(.46), + begin: Alignment.topRight, + end: Alignment.bottomLeft, + colors: [MyColors.gradiantEndColor, MyColors.gradiantStartColor], ), - child: Stack( - alignment: Alignment.center, - children: [ - if (model.isTimeRemainingInSeconds == 0) SvgPicture.asset("assets/images/thumb.svg"), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - LocaleKeys.markAttendance.tr().toText14(color: Colors.white, isBold: true), - if (model.isTimeRemainingInSeconds == 0) DateTime.now().toString().split(" ")[0].toText12(color: Colors.white), - if (model.isTimeRemainingInSeconds != 0) - Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - 9.height, - Directionality( - textDirection: ui.TextDirection.ltr, - child: CountdownTimer( - endTime: model.endTime, - onEnd: null, - endWidget: "00:00:00".toText14(color: Colors.white, isBold: true), - textStyle: const TextStyle(color: Colors.white, fontSize: 14, letterSpacing: -0.48, fontWeight: FontWeight.bold), - ), - ), - LocaleKeys.timeLeftToday.tr().toText12(color: Colors.white), - 9.height, - ClipRRect( - borderRadius: const BorderRadius.all(Radius.circular(20)), - child: LinearProgressIndicator( - value: model.progress, - minHeight: 8, - valueColor: const AlwaysStoppedAnimation(Colors.white), - backgroundColor: const Color(0xff196D73), - ), - ), - ], - ), - ], - ).paddingOnly(top: 12, right: 15, left: 12), - ), - Row( + ), + child: Stack( + alignment: Alignment.center, + children: [ + if (model.isTimeRemainingInSeconds == 0) SvgPicture.asset("assets/images/thumb.svg"), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Expanded( - child: Column( + LocaleKeys.markAttendance.tr().toText14(color: Colors.white, isBold: true), + if (model.isTimeRemainingInSeconds == 0) DateTime.now().toString().split(" ")[0].toText12(color: Colors.white), + if (model.isTimeRemainingInSeconds != 0) + Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - LocaleKeys.checkIn.tr().toText12(color: Colors.white), - (model.attendanceTracking!.pSwipeIn == null ? "--:--" : model.attendanceTracking!.pSwipeIn) - .toString() - .toText14(color: Colors.white, isBold: true), - 4.height, + 9.height, + Directionality( + textDirection: ui.TextDirection.ltr, + child: CountdownTimer( + endTime: model.endTime, + onEnd: null, + endWidget: "00:00:00".toText14(color: Colors.white, isBold: true), + textStyle: const TextStyle(color: Colors.white, fontSize: 14, letterSpacing: -0.48, fontWeight: FontWeight.bold), + ), + ), + LocaleKeys.timeLeftToday.tr().toText12(color: Colors.white), + 9.height, + ClipRRect( + borderRadius: const BorderRadius.all(Radius.circular(20)), + child: LinearProgressIndicator( + value: model.progress, + minHeight: 8, + valueColor: const AlwaysStoppedAnimation(Colors.white), + backgroundColor: const Color(0xff196D73), + ), + ), ], - ).paddingOnly(left: 12, right: 12), - ), - Container( - margin: EdgeInsets.only(top: AppState().isArabic(context) ? 6 : 0), - width: 45, - height: 45, - padding: const EdgeInsets.only(left: 10, right: 10), - decoration: BoxDecoration( - color: Color(0xff259EA4), - borderRadius: BorderRadius.only( - bottomRight: AppState().isArabic(context) ? Radius.circular(0) : Radius.circular(15), - bottomLeft: AppState().isArabic(context) ? Radius.circular(15) : Radius.circular(0), - ), ), - child: SvgPicture.asset(model.isTimeRemainingInSeconds == 0 ? "assets/images/biometrics.svg" : "assets/images/biometrics.svg"), - ).onPress(() { - showMyBottomSheet( - context, - callBackFunc: () {}, - child: MarkAttendanceWidget(model, isFromDashboard: true), - ); - }), ], - ), - ], - ), - ], - ), - ).onPress( - () { - Navigator.pushNamed(context, AppRoutes.todayAttendance); - }, - )) + ).paddingOnly(top: 12, right: 15, left: 12), + ), + Row( + children: [ + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.checkIn.tr().toText12(color: Colors.white), + (model.attendanceTracking!.pSwipeIn == null ? "--:--" : model.attendanceTracking!.pSwipeIn).toString().toText14( + color: Colors.white, + isBold: true, + ), + 4.height, + ], + ).paddingOnly(left: 12, right: 12), + ), + Container( + margin: EdgeInsets.only(top: AppState().isArabic(context) ? 6 : 0), + width: 45, + height: 45, + padding: const EdgeInsets.only(left: 10, right: 10), + decoration: BoxDecoration( + color: Color(0xff259EA4), + borderRadius: BorderRadius.only( + bottomRight: AppState().isArabic(context) ? Radius.circular(0) : Radius.circular(15), + bottomLeft: AppState().isArabic(context) ? Radius.circular(15) : Radius.circular(0), + ), + ), + child: SvgPicture.asset(model.isTimeRemainingInSeconds == 0 ? "assets/images/biometrics.svg" : "assets/images/biometrics.svg"), + ).onPress(() { + showMyBottomSheet(context, callBackFunc: () {}, child: MarkAttendanceWidget(model, isFromDashboard: true)); + }), + ], + ), + ], + ), + ], + ), + ).onPress(() { + Navigator.pushNamed(context, AppRoutes.todayAttendance); + })) .animatedSwither(); }, ), ), ), 9.width, - Expanded( - child: MenusWidget(), - ), + Expanded(child: MenusWidget()), ], ), ], ).paddingOnly(left: 21, right: 21, top: 7, bottom: 21), eventActivityWidget(context), - Consumer(builder: (BuildContext context, DashboardProviderModel model, Widget? child) { - if (!model.isOffersLoading && model.getOffersList.isEmpty) { - return const SizedBox(); - } - return Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - LocaleKeys.offers.tr().toText12(), - Row( - children: [ - LocaleKeys.discounts.tr().toText24(isBold: true), - 6.width, - Container( + Consumer( + builder: (BuildContext context, DashboardProviderModel model, Widget? child) { + if (!model.isOffersLoading && model.getOffersList.isEmpty) { + return const SizedBox(); + } + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + LocaleKeys.offers.tr().toText12(), + Row( + children: [ + LocaleKeys.discounts.tr().toText24(isBold: true), + 6.width, + Container( padding: const EdgeInsets.only(left: 8, right: 8), - decoration: BoxDecoration( - color: MyColors.yellowColor, - borderRadius: BorderRadius.circular(10), - ), - child: LocaleKeys.newString.tr().toText10(isBold: true)), - ], - ), - ], + decoration: BoxDecoration(color: MyColors.yellowColor, borderRadius: BorderRadius.circular(10)), + child: LocaleKeys.newString.tr().toText10(isBold: true), + ), + ], + ), + ], + ), ), - ), - LocaleKeys.viewAllOffers.tr().toText12(isUnderLine: true).onPress(() { - Navigator.pushNamed(context, AppRoutes.offersAndDiscounts); - }) - ], - ).paddingOnly(left: 21, right: 21), - Consumer( - builder: (BuildContext context, DashboardProviderModel model, Widget? child) { - return SizedBox( - height: 103 + 33, - child: ListView.separated( + LocaleKeys.viewAllOffers.tr().toText12(isUnderLine: true).onPress(() { + Navigator.pushNamed(context, AppRoutes.offersAndDiscounts); + }), + ], + ).paddingOnly(left: 21, right: 21), + Consumer( + builder: (BuildContext context, DashboardProviderModel model, Widget? child) { + return SizedBox( + height: 103 + 33, + child: ListView.separated( shrinkWrap: true, physics: const BouncingScrollPhysics(), padding: const EdgeInsets.only(left: 21, right: 21, top: 13), @@ -474,57 +463,53 @@ class _DashboardScreenState extends State with WidgetsBindingOb return model.isOffersLoading ? const OffersShimmerWidget() : InkWell( - onTap: () { - navigateToDetails(data.getOffersList[index]); - }, - child: SizedBox( - width: 73, - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Container( - width: 73, - height: 73, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: const BorderRadius.all( - Radius.circular(100), - ), - border: Border.all(color: MyColors.lightGreyE3Color, width: 1), - ), - child: ClipRRect( - borderRadius: const BorderRadius.all( - Radius.circular(50), - ), - child: Hero( - tag: "ItemImage" + data.getOffersList[index].offersDiscountId.toString()!, - transitionOnUserGestures: true, - child: Image.network( - data.getOffersList[index].logo ?? "", - fit: BoxFit.contain, - ), - ), - ), + onTap: () { + navigateToDetails(data.getOffersList[index]); + }, + child: SizedBox( + width: 73, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + width: 73, + height: 73, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: const BorderRadius.all(Radius.circular(100)), + border: Border.all(color: MyColors.lightGreyE3Color, width: 1), ), - 4.height, - Expanded( - child: AppState().isArabic(context) - ? data.getOffersList[index].titleAr!.toText12(isCenter: true, maxLine: 1) - : data.getOffersList[index].titleEn!.toText12(isCenter: true, maxLine: 1), + child: ClipRRect( + borderRadius: const BorderRadius.all(Radius.circular(50)), + child: Hero( + tag: "ItemImage" + data.getOffersList[index].offersDiscountId.toString()!, + transitionOnUserGestures: true, + child: Image.network(data.getOffersList[index].logo ?? "", fit: BoxFit.contain), + ), ), - ], - ), + ), + 4.height, + Expanded( + child: + AppState().isArabic(context) + ? data.getOffersList[index].titleAr!.toText12(isCenter: true, maxLine: 1) + : data.getOffersList[index].titleEn!.toText12(isCenter: true, maxLine: 1), + ), + ], ), - ); + ), + ); }, separatorBuilder: (BuildContext cxt, int index) => 8.width, - itemCount: 9), - ); - }, - ), - ], - ); - }), + itemCount: 9, + ), + ); + }, + ), + ], + ); + }, + ), Container( width: double.infinity, padding: const EdgeInsets.only(top: 31), @@ -588,38 +573,24 @@ class _DashboardScreenState extends State with WidgetsBindingOb ), ), ), - ) + ), ], ), - drawer: SafeArea( - child: AppDrawer(onLanguageChange: _onRefresh), - ), + drawer: SafeArea(child: AppDrawer(onLanguageChange: _onRefresh)), bottomNavigationBar: SizedBox( height: Platform.isAndroid ? 70 : 100, child: BottomNavigationBar( items: [ + BottomNavigationBarItem(icon: SvgPicture.asset("assets/icons/home.svg", color: currentIndex == 0 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4), label: LocaleKeys.home.tr()), BottomNavigationBarItem( - icon: SvgPicture.asset( - "assets/icons/home.svg", - color: currentIndex == 0 ? MyColors.grey3AColor : MyColors.grey98Color, - ).paddingAll(4), - label: LocaleKeys.home.tr(), - ), - BottomNavigationBarItem( - icon: SvgPicture.asset( - "assets/icons/create_req.svg", - color: currentIndex == 1 ? MyColors.grey3AColor : MyColors.grey98Color, - ).paddingAll(4), + icon: SvgPicture.asset("assets/icons/create_req.svg", color: currentIndex == 1 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4), label: LocaleKeys.mowadhafhiRequest.tr(), ), BottomNavigationBarItem( icon: Stack( alignment: Alignment.centerLeft, children: [ - SvgPicture.asset( - "assets/icons/work_list.svg", - color: currentIndex == 2 ? MyColors.grey3AColor : MyColors.grey98Color, - ).paddingAll(4), + SvgPicture.asset("assets/icons/work_list.svg", color: currentIndex == 2 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4), Consumer( builder: (BuildContext cxt, DashboardProviderModel data, Widget? child) { if (data.workListCounter == 0) { @@ -642,10 +613,7 @@ class _DashboardScreenState extends State with WidgetsBindingOb label: LocaleKeys.workList.tr(), ), BottomNavigationBarItem( - icon: SvgPicture.asset( - "assets/icons/item_for_sale.svg", - color: currentIndex == 3 ? MyColors.grey3AColor : MyColors.grey98Color, - ).paddingAll(4), + icon: SvgPicture.asset("assets/icons/item_for_sale.svg", color: currentIndex == 3 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4), label: LocaleKeys.itemsForSale.tr(), ), BottomNavigationBarItem( @@ -654,28 +622,29 @@ class _DashboardScreenState extends State with WidgetsBindingOb children: [ SvgPicture.asset( "assets/icons/chat/chat.svg", - color: !checkIfPrivilegedForChat() - ? MyColors.lightGreyE3Color - : currentIndex == 4 + color: + !checkIfPrivilegedForChat() + ? MyColors.lightGreyE3Color + : currentIndex == 4 ? MyColors.grey3AColor : cProvider.disbaleChatForThisUser - ? MyColors.lightGreyE3Color - : MyColors.grey98Color, + ? MyColors.lightGreyE3Color + : MyColors.grey98Color, ).paddingAll(4), Consumer( builder: (BuildContext cxt, ChatProviderModel data, Widget? child) { return !checkIfPrivilegedForChat() ? const SizedBox() : Positioned( - right: 0, - top: 0, - child: Container( - padding: const EdgeInsets.only(left: 4, right: 4), - alignment: Alignment.center, - decoration: BoxDecoration(color: cProvider.disbaleChatForThisUser ? MyColors.pinkDarkColor : MyColors.redColor, borderRadius: BorderRadius.circular(17)), - child: data.chatUConvCounter.toString().toText10(color: Colors.white), - ), - ); + right: 0, + top: 0, + child: Container( + padding: const EdgeInsets.only(left: 4, right: 4), + alignment: Alignment.center, + decoration: BoxDecoration(color: cProvider.disbaleChatForThisUser ? MyColors.pinkDarkColor : MyColors.redColor, borderRadius: BorderRadius.circular(17)), + child: data.chatUConvCounter.toString().toText10(color: Colors.white), + ), + ); }, ), ], @@ -712,9 +681,9 @@ class _DashboardScreenState extends State with WidgetsBindingOb Widget eventActivityWidget(BuildContext context) { return (context.watch().isEventLoadingLoading) ? const MarathonBannerShimmer().paddingOnly(left: 21, right: 21, bottom: 21, top: 0) - : (context.watch().eventActivity != null && context.watch().eventActivity!.isActive ==true) - ? const EventActivityBanner().paddingOnly(left: 21, right: 21, bottom: 21, top: 0) - : const SizedBox(); + : (context.watch().eventActivity != null && context.watch().eventActivity!.isActive == true) + ? const EventActivityBanner().paddingOnly(left: 21, right: 21, bottom: 21, top: 0) + : const SizedBox(); } void navigateToDetails(OffersListModel offersListModelObj) { diff --git a/lib/ui/landing/widget/services_widget.dart b/lib/ui/landing/widget/services_widget.dart index 0bd9acc..5695217 100644 --- a/lib/ui/landing/widget/services_widget.dart +++ b/lib/ui/landing/widget/services_widget.dart @@ -255,10 +255,9 @@ class ServicesWidget extends StatelessWidget { } else { if (menuEntry.menuName == "HMG_TICKET_REQUESTS") { Utils.showLoading(context); - TicketBookingResult response = await pro.fetchTicketBooking(); - - if (response.success) { - SSOAuthModel? ssoToken = await pro.fetchSSOAuthRedirection(clientID: response.clientId); +//Ticket Work + if (pro.ticketBookingResponse != null && pro.ticketBookingResponse!.success) { + SSOAuthModel? ssoToken = await pro.fetchSSOAuthRedirection(clientID: pro.ticketBookingResponse!.clientId); if (ssoToken != null) { logger.d(ssoToken.data!.toJson()); logger.d(ssoToken.data!.accessToken); -- 2.30.2 From cca95cee6a65146e2021d327e9a3b6e90ce5f6dd Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Wed, 17 Sep 2025 11:16:23 +0300 Subject: [PATCH 091/135] ticket changes moved to dashboard & wallet balance --- lib/api/dashboard_api_client.dart | 19 ++- lib/provider/dashboard_provider_model.dart | 20 ++- lib/ui/landing/dashboard_screen.dart | 6 +- lib/ui/landing/widget/menus_widget.dart | 181 ++++++++++----------- lib/ui/landing/widget/services_widget.dart | 2 +- 5 files changed, 126 insertions(+), 102 deletions(-) diff --git a/lib/api/dashboard_api_client.dart b/lib/api/dashboard_api_client.dart index 28226ce..4fc8545 100644 --- a/lib/api/dashboard_api_client.dart +++ b/lib/api/dashboard_api_client.dart @@ -170,6 +170,21 @@ class DashboardApiClient { ); } + Future getTicketBalance() async { + String url = "${ApiConsts.erpRest}GET_TICKET_BALANCE"; + Map postParams = {"P_USER_NAME": AppState().memberInformationList?.eMPLOYEENUMBER}; + + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData; + }, + url, + postParams, + ); + } + Future getBookingSSOAuthRedirection({required String clientID}) async { String url = "${ApiConsts.ssoAuthRedirection}?grantType=mohemm"; //https://sso-uat.hmg.com/api/auth/connect?grantType=mohemm' @@ -180,6 +195,7 @@ class DashboardApiClient { "PersonId": AppState().memberInformationList?.eMPLOYEENUMBER, "Username": AppState().memberInformationList?.eMPLOYEENUMBER, "Language": "US", + "SessionId": AppState().postParamsObject?.pSessionId, }; postParams.addAll(AppState().postParamsJson); return await ApiClient().postJsonForObject( @@ -193,7 +209,8 @@ class DashboardApiClient { } Future getBookingSSOFinalRedirection({required String token}) async { - token = "eyJhbGciOiJSUzI1NiIsImtpZCI6IjhjZTE2OWM0YjIwYjQ2ZWM5YTQyOTU3Y2ZhODUzNzQ1IiwidHlwIjoiSldUIn0.eyJ0ZW5hbnRfaWQiOiJhOWY0ZDFhMDU5NmQ0YWVhOGY4MzA5OTJlYzRiZGFjMSIsImVpZCI6IjExNzkzMCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL3NpZCI6Ijk2MDI0OGM1NzA3YzQ3MmFhYTEzM2I1N2ZhODE1ZmVhIiwibGFuZ3VhZ2UiOiJVUyIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL2VtYWlsYWRkcmVzcyI6IjExNzkzMEBobWcuY29tIiwiZXhwIjoxNzgyNDc1NzY5LCJpc3MiOiJodHRwczovL3Nzby11YXQuaG1nLmNvbSIsImF1ZCI6ImE5ZjRkMWEwNTk2ZDRhZWE4ZjgzMDk5MmVjNGJkYWMxIn0.rJcLVsG8D0XECyLERCTD2uqGeWyvp-OBVGE9uL2qKrX4etFUHgdFt_5kYF6edFTtGy-0PIZadHDmv7e-IOhVWHm5HVMClaukiXoRXR8cDN8XA1wfme3Kd-U5PXN-IRh49AyRTzLO0rYNPvH81ScosWGlsFSkOvA-0hJNa2adHdtvgNvB8wJshSU5p7sAmF8mjdDY6aInG19etu2iEuUDwHHA4ZY_ts4hboHo8fE392hFaYGonExoD7bpW5RMx5xKWeRCmWpG_PK8Aw_z1jGzdB9PANus4pteRGuln1J-kmo2lQC9pVrSyZATAKp1HfgfyZ_vUhaHEfM69cMWaCslJQ"; + token = + "eyJhbGciOiJSUzI1NiIsImtpZCI6IjhjZTE2OWM0YjIwYjQ2ZWM5YTQyOTU3Y2ZhODUzNzQ1IiwidHlwIjoiSldUIn0.eyJ0ZW5hbnRfaWQiOiJhOWY0ZDFhMDU5NmQ0YWVhOGY4MzA5OTJlYzRiZGFjMSIsImVpZCI6IjExNzkzMCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL3NpZCI6Ijk2MDI0OGM1NzA3YzQ3MmFhYTEzM2I1N2ZhODE1ZmVhIiwibGFuZ3VhZ2UiOiJVUyIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL2VtYWlsYWRkcmVzcyI6IjExNzkzMEBobWcuY29tIiwiZXhwIjoxNzgyNDc1NzY5LCJpc3MiOiJodHRwczovL3Nzby11YXQuaG1nLmNvbSIsImF1ZCI6ImE5ZjRkMWEwNTk2ZDRhZWE4ZjgzMDk5MmVjNGJkYWMxIn0.rJcLVsG8D0XECyLERCTD2uqGeWyvp-OBVGE9uL2qKrX4etFUHgdFt_5kYF6edFTtGy-0PIZadHDmv7e-IOhVWHm5HVMClaukiXoRXR8cDN8XA1wfme3Kd-U5PXN-IRh49AyRTzLO0rYNPvH81ScosWGlsFSkOvA-0hJNa2adHdtvgNvB8wJshSU5p7sAmF8mjdDY6aInG19etu2iEuUDwHHA4ZY_ts4hboHo8fE392hFaYGonExoD7bpW5RMx5xKWeRCmWpG_PK8Aw_z1jGzdB9PANus4pteRGuln1J-kmo2lQC9pVrSyZATAKp1HfgfyZ_vUhaHEfM69cMWaCslJQ"; var request = http.MultipartRequest('POST', Uri.parse('https://ek.techmaster.in/SSO/HMG')); request.fields.addAll({'JWTToken': token}); diff --git a/lib/provider/dashboard_provider_model.dart b/lib/provider/dashboard_provider_model.dart index 6686574..beddf0c 100644 --- a/lib/provider/dashboard_provider_model.dart +++ b/lib/provider/dashboard_provider_model.dart @@ -48,6 +48,7 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { double get leaveBalance => leaveBalanceAccrual?.accrualNetEntitlement ?? 0; double ticketBalance = 0; + double walletBalance = 0; //Menu Entries bool isServicesMenusLoading = true; @@ -202,6 +203,8 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { isLeaveTicketBalanceLoading = false; leaveBalanceAccrual = accrualList![0]; ticketBalance = (accrualList![1].accrualNetEntitlement ?? 0.0) + (accrualList![2].accrualNetEntitlement ?? 0.0) + (accrualList![3].accrualNetEntitlement ?? 0.0); + walletBalance = (accrualList![4].accrualNetEntitlement ?? 0.0); + print("================ Ticket Balance: $ticketBalance ==============="); notifyListeners(); } catch (ex) { isLeaveTicketBalanceLoading = false; @@ -286,11 +289,12 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } } - void fetchTicketBooking() async { + Future fetchTicketBooking() async { try { GenericResponseModel? genericResponseModel = await DashboardApiClient().getTicketBookingRedirection(); if (genericResponseModel?.portalDirectionData?.pRedirection!.toLowerCase() == "alma") { ticketBookingResponse = TicketBookingResult(true, genericResponseModel?.portalDirectionData?.clientID); + return; } ticketBookingResponse = TicketBookingResult(false, null); } catch (ex) { @@ -302,6 +306,20 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } } + void fetchTicketBalance() async { + try { + GenericResponseModel? ticketResponse = await DashboardApiClient().getTicketBalance(); + logger.d("Ticket Balance Response: ${ticketResponse?.toJson()}"); + print(" ========= Ticket Balance Response ======= "); + } catch (ex) { + logger.wtf(ex); + isEventLoadingLoading = false; + notifyListeners(); + Utils.handleException(ex, null, null); + // ticketBookingResponse = TicketBookingResult(false, null); // Ensure a return value in case of an exception + } + } + Future fetchSSOAuthRedirection({String? clientID}) async { try { SSOAuthModel? ssoResponse = await DashboardApiClient().getBookingSSOAuthRedirection(clientID: clientID!); diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index 2ddd706..8c0e415 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -148,6 +148,7 @@ class _DashboardScreenState extends State with WidgetsBindingOb data.fetchAttendanceTracking(context); data.fetchWorkListCounter(context); data.fetchMissingSwipe(context); + data.fetchLeaveTicketBalance(context, DateTime.now()); data.fetchMenuEntries(); data.fetchEventActivity(); @@ -160,7 +161,10 @@ class _DashboardScreenState extends State with WidgetsBindingOb if (!cProvider.disbaleChatForThisUser && !isFromInit) checkHubCon(); _refreshController.refreshCompleted(); - data.fetchTicketBooking(); + await data.fetchTicketBooking(); + // if (data.ticketBookingResponse != null && !data.ticketBookingResponse!.success) { + // // data.fetchTicketBalance(); + // } //continue here } diff --git a/lib/ui/landing/widget/menus_widget.dart b/lib/ui/landing/widget/menus_widget.dart index 64855ee..bc5dceb 100644 --- a/lib/ui/landing/widget/menus_widget.dart +++ b/lib/ui/landing/widget/menus_widget.dart @@ -27,114 +27,99 @@ class MenusWidget extends StatelessWidget { children: [ data.isWorkListLoading ? MenuShimmer().onPress(() { - data.fetchWorkListCounter(context, showLoading: true); - }) + data.fetchWorkListCounter(context, showLoading: true); + }) : Container( - decoration: BoxDecoration( - color: Color(namesColor[0]), - borderRadius: BorderRadius.circular(10), - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - LocaleKeys.workList.tr().toText12(color: Colors.white), - Row( - children: [ - Expanded( - child: data.workListCounter.toString().toText16(color: Colors.white, isBold: true, maxlines: 1), - ), - RotatedBox(quarterTurns: AppState().isArabic(context) ? 2 : 4, child: SvgPicture.asset("assets/images/arrow_next.svg", color: Colors.white)), - ], - ) - ], - ).paddingOnly(left: 10, right: 10, bottom: 6, top: 6), - ).onPress(() { - Navigator.pushNamed(context, AppRoutes.workList); - }), + decoration: BoxDecoration(color: Color(namesColor[0]), borderRadius: BorderRadius.circular(10)), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.workList.tr().toText12(color: Colors.white), + Row( + children: [ + Expanded(child: data.workListCounter.toString().toText16(color: Colors.white, isBold: true, maxlines: 1)), + RotatedBox(quarterTurns: AppState().isArabic(context) ? 2 : 4, child: SvgPicture.asset("assets/images/arrow_next.svg", color: Colors.white)), + ], + ), + ], + ).paddingOnly(left: 10, right: 10, bottom: 6, top: 6), + ).onPress(() { + Navigator.pushNamed(context, AppRoutes.workList); + }), data.isMissingSwipeLoading ? MenuShimmer().onPress(() { - data.fetchWorkListCounter(context); - }) + data.fetchWorkListCounter(context); + }) : Container( - decoration: BoxDecoration( - color: Color(namesColor[1]), - borderRadius: BorderRadius.circular(10), - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - LocaleKeys.missingSwipes.tr().toText12(color: Colors.white), - Row( - children: [ - Expanded( - child: data.missingSwipeCounter.toString().toText16(color: Colors.white, isBold: true, maxlines: 1), - ), - RotatedBox(quarterTurns: AppState().isArabic(context) ? 2 : 4, child: SvgPicture.asset("assets/images/arrow_next.svg", color: Colors.white)), - ], - ) - ], - ).paddingOnly(left: 10, right: 10, bottom: 6, top: 6), - ).onPress(() { - Navigator.pushNamed(context, AppRoutes.dynamicScreen, arguments: DynamicListViewParams(LocaleKeys.missingSwipes.tr(), "HMG_OTL_MISSING_SWIPE_EIT_SS")); - }), + decoration: BoxDecoration(color: Color(namesColor[1]), borderRadius: BorderRadius.circular(10)), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.missingSwipes.tr().toText12(color: Colors.white), + Row( + children: [ + Expanded(child: data.missingSwipeCounter.toString().toText16(color: Colors.white, isBold: true, maxlines: 1)), + RotatedBox(quarterTurns: AppState().isArabic(context) ? 2 : 4, child: SvgPicture.asset("assets/images/arrow_next.svg", color: Colors.white)), + ], + ), + ], + ).paddingOnly(left: 10, right: 10, bottom: 6, top: 6), + ).onPress(() { + Navigator.pushNamed(context, AppRoutes.dynamicScreen, arguments: DynamicListViewParams(LocaleKeys.missingSwipes.tr(), "HMG_OTL_MISSING_SWIPE_EIT_SS")); + }), data.isLeaveTicketBalanceLoading ? MenuShimmer().onPress(() { - data.fetchWorkListCounter(context); - }) + data.fetchWorkListCounter(context); + }) : Container( - decoration: BoxDecoration( - color: Color(namesColor[2]), - borderRadius: BorderRadius.circular(10), - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - LocaleKeys.leaveBalance.tr().toText12(color: Colors.white), - Row( - children: [ - Expanded( - child: data.leaveBalance.toStringAsFixed(2).toText16(color: Colors.white, isBold: true, maxlines: 1), - ), - RotatedBox(quarterTurns: AppState().isArabic(context) ? 2 : 4, child: SvgPicture.asset("assets/images/arrow_next.svg", color: Colors.white)), - ], - ) - ], - ).paddingOnly(left: 10, right: 10, bottom: 6, top: 6), - ).onPress(() { - Navigator.pushNamed(context, AppRoutes.leaveBalance); - }), + decoration: BoxDecoration(color: Color(namesColor[2]), borderRadius: BorderRadius.circular(10)), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.leaveBalance.tr().toText12(color: Colors.white), + Row( + children: [ + Expanded(child: data.leaveBalance.toStringAsFixed(2).toText16(color: Colors.white, isBold: true, maxlines: 1)), + RotatedBox(quarterTurns: AppState().isArabic(context) ? 2 : 4, child: SvgPicture.asset("assets/images/arrow_next.svg", color: Colors.white)), + ], + ), + ], + ).paddingOnly(left: 10, right: 10, bottom: 6, top: 6), + ).onPress(() { + Navigator.pushNamed(context, AppRoutes.leaveBalance); + }), data.isLeaveTicketBalanceLoading ? MenuShimmer().onPress(() { - data.fetchWorkListCounter(context); - }) + data.fetchWorkListCounter(context); + }) : Container( - decoration: BoxDecoration( - color: Color(namesColor[3]), - borderRadius: BorderRadius.circular(10), - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - LocaleKeys.ticketBalance.tr().toText12(color: Colors.white), - Row( - children: [ - Expanded( - child: data.ticketBalance.toStringAsFixed(2).toText16(color: Colors.white, isBold: true, maxlines: 1), - ), - RotatedBox(quarterTurns: AppState().isArabic(context) ? 2 : 4, child: SvgPicture.asset("assets/images/arrow_next.svg", color: Colors.white)), - ], - ) - ], - ).paddingOnly(left: 10, right: 10, bottom: 6, top: 6), - ).onPress( - () { - Navigator.pushNamed(context, AppRoutes.dynamicScreen, arguments: DynamicListViewParams(LocaleKeys.ticketBalance.tr(), "HMG_TKT_NEW_EIT_SS")); - }, - ) + decoration: BoxDecoration(color: Color(namesColor[3]), borderRadius: BorderRadius.circular(10)), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + data.ticketBookingResponse != null && data.ticketBookingResponse!.success + ? "Wallet Balance".toText12(color: Colors.white) + : LocaleKeys.ticketBalance.tr().toText12(color: Colors.white), + Row( + children: [ + Expanded( + child: + data.ticketBookingResponse != null && data.ticketBookingResponse!.success + ? data.walletBalance.toStringAsFixed(0).toText16(color: Colors.white, isBold: true, maxlines: 1) + : data.ticketBalance.toStringAsFixed(2).toText16(color: Colors.white, isBold: true, maxlines: 1), + ), + RotatedBox(quarterTurns: AppState().isArabic(context) ? 2 : 4, child: SvgPicture.asset("assets/images/arrow_next.svg", color: Colors.white)), + ], + ), + ], + ).paddingOnly(left: 10, right: 10, bottom: 6, top: 6), + ).onPress(() { + Navigator.pushNamed(context, AppRoutes.dynamicScreen, arguments: DynamicListViewParams(LocaleKeys.ticketBalance.tr(), "HMG_TKT_NEW_EIT_SS")); + }), ], ); }, diff --git a/lib/ui/landing/widget/services_widget.dart b/lib/ui/landing/widget/services_widget.dart index 5695217..6dfeab5 100644 --- a/lib/ui/landing/widget/services_widget.dart +++ b/lib/ui/landing/widget/services_widget.dart @@ -255,7 +255,7 @@ class ServicesWidget extends StatelessWidget { } else { if (menuEntry.menuName == "HMG_TICKET_REQUESTS") { Utils.showLoading(context); -//Ticket Work + //Ticket Work if (pro.ticketBookingResponse != null && pro.ticketBookingResponse!.success) { SSOAuthModel? ssoToken = await pro.fetchSSOAuthRedirection(clientID: pro.ticketBookingResponse!.clientId); if (ssoToken != null) { -- 2.30.2 From c06c020fb32a5eadc15f12f28bcb5ff39de71973 Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Sun, 12 Oct 2025 15:13:15 +0300 Subject: [PATCH 092/135] favorites search enabled. --- lib/ui/work_list/sheets/delegate_sheet.dart | 618 ++++++++++---------- 1 file changed, 296 insertions(+), 322 deletions(-) diff --git a/lib/ui/work_list/sheets/delegate_sheet.dart b/lib/ui/work_list/sheets/delegate_sheet.dart index d505099..de724a1 100644 --- a/lib/ui/work_list/sheets/delegate_sheet.dart +++ b/lib/ui/work_list/sheets/delegate_sheet.dart @@ -1,4 +1,5 @@ import 'dart:collection'; +import 'dart:convert'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/cupertino.dart'; @@ -32,8 +33,16 @@ class DelegateSheet extends StatefulWidget { VoidCallback callBackFunc; List getNotificationRespondAttributes; - DelegateSheet( - {required this.title, required this.apiMode, this.notificationID, this.actionHistoryList, this.wFHistory, required this.callBackFunc, this.getNotificationRespondAttributes = const []}); + DelegateSheet({ + super.key, + required this.title, + required this.apiMode, + this.notificationID, + this.actionHistoryList, + this.wFHistory, + required this.callBackFunc, + this.getNotificationRespondAttributes = const [], + }); @override State createState() => _DelegateSheetState(); @@ -46,8 +55,8 @@ class _DelegateSheetState extends State { String? selectedFavLetter; String selectedType = "Workflow"; String inputRes = ""; - List? favLetters; List? favUsersList; + List? filteredFavUsersList = []; List? replacementList; bool isImageLoaded = false; @@ -57,14 +66,14 @@ class _DelegateSheetState extends State { super.initState(); if (widget.wFHistory != null) { widget.wFHistory = widget.wFHistory!.reversed.toList(); - var ids = widget.wFHistory!.map((e) => e.employeeID).toSet(); - widget.wFHistory!.retainWhere((x) => ids.remove(x.employeeID)); + Set ids = widget.wFHistory!.map((WFHistory e) => e.employeeID).toSet(); + widget.wFHistory!.retainWhere((WFHistory x) => ids.remove(x.employeeID)); } if (widget.actionHistoryList != null) { widget.actionHistoryList = widget.actionHistoryList!.reversed.toList(); - var ids = widget.actionHistoryList!.map((e) => e.uSERNAME).toSet(); - widget.actionHistoryList!.retainWhere((x) => ids.remove(x.uSERNAME)); + Set ids = widget.actionHistoryList!.map((GetActionHistoryList e) => e.uSERNAME).toSet(); + widget.actionHistoryList!.retainWhere((GetActionHistoryList x) => ids.remove(x.uSERNAME)); } } @@ -73,36 +82,96 @@ class _DelegateSheetState extends State { super.dispose(); } - Future fetchFavLetters({bool isNeedLoading = true}) async { - favLetters = []; + Future fetchFavUsers({bool isNeedLoading = true}) async { + favUsersList = []; + filteredFavUsersList = []; + if (isNeedLoading) Utils.showLoading(context); - List? favList = await WorkListApiClient().getFavoriteReplacementWithoutImage(); - List result = []; - favList!.forEach((element) { - result.add(element.employeeDisplayName![0]); - }); - favLetters = LinkedHashSet.from(result).toList(); - if (isNeedLoading) Utils.hideLoading(context); - setState(() { - favLetters!.sort((a, b) { - return a.toLowerCase().compareTo(b.toLowerCase()); - }); - }); - return null; + + try { + List? favList = await WorkListApiClient().getFavoriteReplacementWithoutImage(); + favUsersList = favList; + + if (favUsersList != null && favUsersList!.isNotEmpty) { + favUsersList!.sort((GetFavoriteReplacements a, GetFavoriteReplacements b) => (a.employeeDisplayName ?? '').toLowerCase().compareTo((b.employeeDisplayName ?? '').toLowerCase())); + filteredFavUsersList = favUsersList; + + if (isNeedLoading) Utils.hideLoading(context); + setState(() {}); + _fetchAndAttachUserImages(); + } else { + if (isNeedLoading) Utils.hideLoading(context); + setState(() {}); + } + } catch (e) { + if (isNeedLoading) Utils.hideLoading(context); + setState(() {}); + } } - Future fetchFavUsersList({bool isNeedLoading = true}) async { - if (isNeedLoading) Utils.showLoading(context); - favUsersList = await WorkListApiClient().getFavoriteReplacementWithImage(selectedFavLetter ?? ""); - if (isNeedLoading) Utils.hideLoading(context); - setState(() {}); - fetchFavUsersListNew(isNeedLoading: false); - return null; + Future _fetchAndAttachUserImages() async { + try { + List? tempList = await WorkListApiClient().getFavoriteReplacementWithImageNew(""); + + if (tempList != null && tempList.isNotEmpty && favUsersList != null) { + for (GetFavoriteReplacements element in favUsersList!) { + for (GetFavoriteReplacements element2 in tempList) { + if (element.userName == element2.userName && element2.employeeImage != null && element2.employeeImage!.isNotEmpty) { + element.employeeImage = element2.employeeImage; + } + } + } + filteredFavUsersList = favUsersList; + setState(() {}); + } + } catch (e) {} } + // Future fetchFavUsers({bool isNeedLoading = true}) async { + // favUsersList = []; + // if (isNeedLoading) Utils.showLoading(context); + // + // try { + // List? favList = await WorkListApiClient().getFavoriteReplacementWithoutImage(); + // favUsersList = favList; + // + // if (favUsersList != null && favUsersList!.isNotEmpty) { + // setState(() { + // favUsersList!.sort((GetFavoriteReplacements a, GetFavoriteReplacements b) => (a.employeeDisplayName ?? '').toLowerCase().compareTo((b.employeeDisplayName ?? '').toLowerCase())); + // }); + // if (isNeedLoading) Utils.hideLoading(context); + // + // List? tempList = await WorkListApiClient().getFavoriteReplacementWithImageNew(""); + // if (tempList != null && tempList.isNotEmpty) { + // for (GetFavoriteReplacements element in favUsersList!) { + // for (GetFavoriteReplacements element2 in tempList) { + // if (element.userName == element2.userName) { + // if (element2.employeeImage != null && element2.employeeImage!.isNotEmpty) { + // element.employeeImage = element2.employeeImage; + // } + // } + // } + // } + // setState(() {}); + // } + // } + // } catch (e) { + // // if (isNeedLoading) Utils.hideLoading(context); + // } + // } + + // Future fetchFavUsersList({bool isNeedLoading = true}) async { + // if (isNeedLoading) Utils.showLoading(context); + // favUsersList = await WorkListApiClient().getFavoriteReplacementWithImage(selectedFavLetter ?? ""); + // if (isNeedLoading) Utils.hideLoading(context); + // setState(() {}); + // fetchFavUsersListNew(isNeedLoading: false); + // return null; + // } + Future fetchFavUsersListNew({bool isNeedLoading = true}) async { if (isNeedLoading) Utils.showLoading(context); - favUsersList = await WorkListApiClient().getFavoriteReplacementWithImageNew(selectedFavLetter ?? ""); + filteredFavUsersList = await WorkListApiClient().getFavoriteReplacementWithImageNew(selectedFavLetter ?? ""); if (isNeedLoading) Utils.hideLoading(context); setState(() { isImageLoaded = true; @@ -112,18 +181,10 @@ class _DelegateSheetState extends State { void fetchChangeFav({required String email, required String employeName, required String image, required String userName, bool isFav = false, bool isNeedToRefresh = false}) async { Utils.showLoading(context); - favLetters = null; - selectedFavLetter = null; - GenericResponseModel model = await WorkListApiClient().changeFavoriteReplacements( - email: email, - employeName: employeName, - image: image, - userName: userName, - isFav: isFav, - ); + GenericResponseModel model = await WorkListApiClient().changeFavoriteReplacements(email: email, employeName: employeName, image: image, userName: userName, isFav: isFav); if (isNeedToRefresh) { - await fetchFavLetters(isNeedLoading: false); - if (favLetters != null) await fetchFavUsersList(isNeedLoading: false); + await fetchFavUsers(isNeedLoading: false); + // if (favUsersList != null) await fetchFavUsersList(isNeedLoading: false); } Utils.hideLoading(context); @@ -137,44 +198,58 @@ class _DelegateSheetState extends State { userName: selectedType == "Employee Name" ? inputRes : "", email: selectedType == "Employee Email" ? inputRes : "", ); + if (isNeedLoading) Utils.hideLoading(context); setState(() {}); return null; } + Future searchFavUser() async { + if (favUsersList != null && favUsersList!.isNotEmpty) { + if (inputRes.length > 3) { + filteredFavUsersList = + favUsersList!.where((GetFavoriteReplacements element) { + String query = inputRes.toLowerCase(); + return (element.employeeDisplayName != null && element.employeeDisplayName!.toLowerCase().contains(query)) || + (element.userName != null && element.userName!.toLowerCase().contains(query)) || + (element.emailAddress != null && element.emailAddress!.toLowerCase().contains(query)); + }).toList(); + } else { + filteredFavUsersList = favUsersList; + } + } else { + filteredFavUsersList = []; + } + + setState(() {}); + } + @override Widget build(BuildContext context) { - return Container( + return SizedBox( width: double.infinity, height: MediaQuery.of(context).size.height - 80, child: Column( - children: [ + children: [ Expanded( child: SingleChildScrollView( child: Padding( padding: const EdgeInsets.all(21), child: Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [ + children: [ widget.title.toText24(isBold: true), 21.height, LocaleKeys.search.tr().toText16(), 11.height, Column( crossAxisAlignment: CrossAxisAlignment.end, - children: [ + children: [ Container( - padding: EdgeInsets.only(left: 8, right: 4, top: 6, bottom: 6), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(15), - color: Colors.transparent, - border: Border.all( - color: Color(0xffefefef), - width: 1, - ), - ), + padding: const EdgeInsets.only(left: 8, right: 4, top: 6, bottom: 6), + decoration: BoxDecoration(borderRadius: BorderRadius.circular(15), color: Colors.transparent, border: Border.all(color: const Color(0xffefefef), width: 1)), child: Row( - children: [ + children: [ Expanded( child: InputWidget( "Search By " + selectedType, @@ -185,29 +260,18 @@ class _DelegateSheetState extends State { verticalPadding: 3, isInputTypeNum: selectedType == "Employee ID" ? true : false, isEnable: isNeedEnableTextField, - onChange: (v) { + onChange: (String v) { inputRes = v; + if (selectedType == "Favorites") { + searchFavUser(); + } }, ), ), + Container(height: 36, width: 1, color: const Color(0xffE5E5E5)), Container( - height: 36, - width: 1, - color: Color(0xffE5E5E5), - ), - Container( - padding: EdgeInsets.all(8), - child: Row( - children: [ - selectedType.toText12(), - 4.width, - const Icon( - Icons.keyboard_arrow_down, - color: Colors.black, - size: 16, - ), - ], - ), + padding: const EdgeInsets.all(8), + child: Row(children: [selectedType.toText12(), 4.width, const Icon(Icons.keyboard_arrow_down, color: Colors.black, size: 16)]), ).onPress(() { showMyBottomSheet( context, @@ -220,18 +284,16 @@ class _DelegateSheetState extends State { setState(() { isNeedEnableTextField = false; selectedFavLetter = null; - favLetters = null; - favUsersList = null; + filteredFavUsersList = null; }); } else if (value == "Favorites") { - isNeedEnableTextField = false; - fetchFavLetters(); + isNeedEnableTextField = true; + fetchFavUsers(); } else { setState(() { isNeedEnableTextField = true; selectedFavLetter = null; - favLetters = null; - favUsersList = null; + filteredFavUsersList = null; }); } }, @@ -241,143 +303,105 @@ class _DelegateSheetState extends State { ], ), ), - if (isNeedEnableTextField) + if (isNeedEnableTextField && selectedType != "Favorites") TextButton( onPressed: () { fetchUserByInput(); }, - child: const Text( - "Search", - style: TextStyle( - color: Colors.blue, - decoration: TextDecoration.underline, - ), - ), - ) + child: const Text("Search", style: TextStyle(color: Colors.blue, decoration: TextDecoration.underline)), + ), ], ), if (!isNeedEnableTextField) 12.height, Row( - children: [ + children: [ Expanded( - child: Container( + child: SizedBox( width: double.infinity, - child: selectedFavLetter == null && favLetters != null - ? Container( - width: double.infinity, - alignment: Alignment.center, - child: "Please select letter to see Fav results".toText12(), - ) - : favUsersList != null + child: + // selectedFavLetter == null && favLetters != null + // ? Container(width: double.infinity, alignment: Alignment.center, child: "Please select letter to see Fav results".toText12()) + // : + filteredFavUsersList != null ? ListView.separated( - itemBuilder: (context, index) { - return showFavUserItem(favUsersList![index]); - }, - separatorBuilder: (context, index) { - return Container( - color: MyColors.borderColor, - width: double.infinity, - height: 1, - margin: EdgeInsets.only(top: 8, bottom: 8), - ).onPress(() {}); - }, - physics: NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemCount: favUsersList!.length, - padding: EdgeInsets.only(top: 8, bottom: 8), - ) + itemBuilder: (BuildContext context, int index) { + return showFavUserItem(filteredFavUsersList![index]); + }, + separatorBuilder: (BuildContext context, int index) { + return Container(color: MyColors.borderColor, width: double.infinity, height: 1, margin: const EdgeInsets.only(top: 8, bottom: 8)).onPress(() {}); + }, + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemCount: filteredFavUsersList!.length, + padding: const EdgeInsets.only(top: 8, bottom: 8), + ) : isNeedEnableTextField && replacementList == null - ? Container( - width: double.infinity, - alignment: Alignment.center, - child: "Search User".toText12(), - ) - : isNeedEnableTextField && replacementList!.length == 0 - ? Container( - width: double.infinity, - alignment: Alignment.center, - child: "No Data Found".toText12(), - ) - : isNeedEnableTextField - ? ListView.separated( - itemBuilder: (context, index) { - return showInputUserItem(replacementList![index]); - }, - separatorBuilder: (context, index) { - return Container( - color: MyColors.borderE3Color, - width: double.infinity, - height: 1, - margin: EdgeInsets.only(top: 8, bottom: 8), - ); - }, - physics: NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemCount: replacementList!.length, - padding: EdgeInsets.only(top: 8, bottom: 8), - ) - : (widget.wFHistory != null - ? ListView.separated( - itemBuilder: (context, index) { - return showItgItem(widget.wFHistory![index]); - }, - separatorBuilder: (context, index) { - return Container( - color: MyColors.borderE3Color, - width: double.infinity, - height: 1, - margin: EdgeInsets.only(top: 8, bottom: 8), - ); - }, - physics: NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemCount: widget.wFHistory!.length, - padding: EdgeInsets.only(top: 8, bottom: 8), - ) - : ListView.separated( - itemBuilder: (context, index) { - return showItem(widget.actionHistoryList![index]); - }, - separatorBuilder: (context, index) { - return Container( - color: MyColors.borderE3Color, - width: double.infinity, - height: 1, - margin: EdgeInsets.only(top: 8, bottom: 8), - ); - }, - physics: NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemCount: widget.actionHistoryList!.length, - padding: EdgeInsets.only(top: 8, bottom: 8), - )), + ? Container(width: double.infinity, alignment: Alignment.center, child: "Search User".toText12()) + : isNeedEnableTextField && replacementList!.isEmpty + ? Container(width: double.infinity, alignment: Alignment.center, child: "No Data Found".toText12()) + : isNeedEnableTextField + ? ListView.separated( + itemBuilder: (BuildContext context, int index) { + return showInputUserItem(replacementList![index]); + }, + separatorBuilder: (BuildContext context, int index) { + return Container(color: MyColors.borderE3Color, width: double.infinity, height: 1, margin: const EdgeInsets.only(top: 8, bottom: 8)); + }, + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemCount: replacementList!.length, + padding: const EdgeInsets.only(top: 8, bottom: 8), + ) + : (widget.wFHistory != null + ? ListView.separated( + itemBuilder: (BuildContext context, int index) { + return showItgItem(widget.wFHistory![index]); + }, + separatorBuilder: (BuildContext context, int index) { + return Container(color: MyColors.borderE3Color, width: double.infinity, height: 1, margin: const EdgeInsets.only(top: 8, bottom: 8)); + }, + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemCount: widget.wFHistory!.length, + padding: const EdgeInsets.only(top: 8, bottom: 8), + ) + : ListView.separated( + itemBuilder: (BuildContext context, int index) { + return showItem(widget.actionHistoryList![index]); + }, + separatorBuilder: (BuildContext context, int index) { + return Container(color: MyColors.borderE3Color, width: double.infinity, height: 1, margin: const EdgeInsets.only(top: 8, bottom: 8)); + }, + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemCount: widget.actionHistoryList!.length, + padding: const EdgeInsets.only(top: 8, bottom: 8), + )), ), ), - if (favLetters != null) - Container( - width: 30, - // color: Colors.red, - child: ListView.separated( - itemBuilder: (context, index) { - return Container( - padding: EdgeInsets.all(8), - alignment: Alignment.center, - child: favLetters![index].toText14(color: selectedFavLetter == favLetters![index] ? MyColors.gradiantStartColor : Colors.black), - ).onPress(() { - selectedFavLetter = favLetters![index].toUpperCase(); - fetchFavUsersList(); - }); - }, - separatorBuilder: (context, index) { - return SizedBox( - height: 0, - ); - }, - physics: NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemCount: favLetters!.length, - ), - ), + // if (favLetters != null) + // SizedBox( + // width: 30, + // // color: Colors.red, + // child: ListView.separated( + // itemBuilder: (BuildContext context, int index) { + // return Container( + // padding: const EdgeInsets.all(8), + // alignment: Alignment.center, + // child: favLetters![index].toText14(color: selectedFavLetter == favLetters![index] ? MyColors.gradiantStartColor : Colors.black), + // ).onPress(() { + // selectedFavLetter = favLetters![index].toUpperCase(); + // fetchFavUsersList(); + // }); + // }, + // separatorBuilder: (BuildContext context, int index) { + // return const SizedBox(height: 0); + // }, + // physics: const NeverScrollableScrollPhysics(), + // shrinkWrap: true, + // itemCount: favLetters!.length, + // ), + // ), ], ), ], @@ -385,22 +409,15 @@ class _DelegateSheetState extends State { ), ), ), - Container( - width: double.infinity, - height: 1, - color: MyColors.borderColor, - ), + Container(width: double.infinity, height: 1, color: MyColors.borderColor), DefaultButton( "Cancel", () { Navigator.pop(context); }, textColor: Colors.black, - colors: [ - Color(0xffE6E6E6), - Color(0xffE6E6E6), - ], - ).insideContainer + colors: const [Color(0xffE6E6E6), Color(0xffE6E6E6)], + ).insideContainer, ], ), ); @@ -410,25 +427,22 @@ class _DelegateSheetState extends State { return InkWell( onTap: () { Navigator.pop(context); - showMyBottomSheet(context, - callBackFunc: widget.callBackFunc, - child: SelectedItemSheet( - "Comment", - apiMode: widget.apiMode, - actionHistoryList: actionHistory, - notificationID: widget.notificationID, - isITGRequest: widget.wFHistory != null, - getNotificationRespondAttributes: widget.getNotificationRespondAttributes, - )); + showMyBottomSheet( + context, + callBackFunc: widget.callBackFunc, + child: SelectedItemSheet( + "Comment", + apiMode: widget.apiMode, + actionHistoryList: actionHistory, + notificationID: widget.notificationID, + isITGRequest: widget.wFHistory != null, + getNotificationRespondAttributes: widget.getNotificationRespondAttributes, + ), + ); }, child: Row( - children: [ - CircularAvatar( - url: actionHistory.eMPLOYEEIMAGE ?? "", - height: 30, - width: 30, - isImageBase64: true, - ), + children: [ + CircularAvatar(url: actionHistory.eMPLOYEEIMAGE ?? "", height: 30, width: 30, isImageBase64: true), 9.width, (actionHistory.nAME ?? "").toText12().expanded, IconButton( @@ -444,12 +458,8 @@ class _DelegateSheetState extends State { isFav: true, ); }, - icon: Icon( - Icons.star, - size: 16, - color: (actionHistory.isFavorite ?? false) ? MyColors.yellowColor : MyColors.borderColor, - ), - ) + icon: Icon(Icons.star, size: 16, color: (actionHistory.isFavorite ?? false) ? MyColors.yellowColor : MyColors.borderColor), + ), ], ), ); @@ -459,25 +469,18 @@ class _DelegateSheetState extends State { return InkWell( onTap: () { Navigator.pop(context); - showMyBottomSheet(context, - callBackFunc: widget.callBackFunc, - child: SelectedItgItemSheet( - "Comment", - apiMode: widget.apiMode, - wfHistory: wfHistory, - // notificationID: widget.notificationID, - )); - }, - child: Row( - children: [ - CircularAvatar( - height: 30, - width: 30, + showMyBottomSheet( + context, + callBackFunc: widget.callBackFunc, + child: SelectedItgItemSheet( + "Comment", + apiMode: widget.apiMode, + wfHistory: wfHistory, + // notificationID: widget.notificationID, ), - 9.width, - (wfHistory.name ?? "").toText12().expanded, - ], - ), + ); + }, + child: Row(children: [CircularAvatar(height: 30, width: 30), 9.width, (wfHistory.name ?? "").toText12().expanded]), ); } @@ -485,47 +488,31 @@ class _DelegateSheetState extends State { return InkWell( onTap: () { Navigator.pop(context); - showMyBottomSheet(context, - callBackFunc: widget.callBackFunc, - child: SelectedItemSheet( - "Comment", - apiMode: widget.apiMode, - favoriteReplacements: actionHistory, - notificationID: widget.notificationID, - isITGRequest: widget.wFHistory != null, - getNotificationRespondAttributes: widget.getNotificationRespondAttributes, - )); + showMyBottomSheet( + context, + callBackFunc: widget.callBackFunc, + child: SelectedItemSheet( + "Comment", + apiMode: widget.apiMode, + favoriteReplacements: actionHistory, + notificationID: widget.notificationID, + isITGRequest: widget.wFHistory != null, + getNotificationRespondAttributes: widget.getNotificationRespondAttributes, + ), + ); }, child: Row( - children: [ - actionHistory.employeeImage != "" - ? CircularAvatar( - url: actionHistory.employeeImage, - height: 40, - width: 40, - isImageBase64: (actionHistory.employeeImage != null || actionHistory.employeeImage!.isNotEmpty) ? true : false, - ) + children: [ + actionHistory.employeeImage != "" && actionHistory.employeeImage != null + ? CircularAvatar(url: actionHistory.employeeImage, height: 40, width: 40, isImageBase64: (actionHistory.employeeImage != null || actionHistory.employeeImage!.isNotEmpty) ? true : false) : isImageLoaded - ? CircularAvatar( - height: 40, - width: 40, - isImageBase64: false, - ) - : ClipRRect( - borderRadius: const BorderRadius.all( - Radius.circular(50), - ), - child: Image.network( - "https://play-lh.googleusercontent.com/NPo88ojmhah4HDiposucJmfQIop4z4xc8kqJK9ITO9o-yCab2zxIp7PPB_XPj2iUojo", - fit: BoxFit.cover, - height: 40, - width: 40, - ).toShimmer(), - ), + ? CircularAvatar(height: 40, width: 40, isImageBase64: false) + : ClipRRect( + borderRadius: const BorderRadius.all(Radius.circular(50)), + child: Image.network("https://play-lh.googleusercontent.com/NPo88ojmhah4HDiposucJmfQIop4z4xc8kqJK9ITO9o-yCab2zxIp7PPB_XPj2iUojo", fit: BoxFit.cover, height: 40, width: 40).toShimmer(), + ), 16.width, - Expanded( - child: (actionHistory.employeeDisplayName ?? "").toText12(), - ), + Expanded(child: (actionHistory.employeeDisplayName ?? "").toText12()), IconButton( onPressed: () { fetchChangeFav( @@ -537,12 +524,8 @@ class _DelegateSheetState extends State { isNeedToRefresh: true, ); }, - icon: Icon( - Icons.star, - size: 16, - color: MyColors.yellowColor, - ), - ) + icon: const Icon(Icons.star, size: 16, color: MyColors.yellowColor), + ), ], ), ); @@ -552,29 +535,24 @@ class _DelegateSheetState extends State { return InkWell( onTap: () { Navigator.pop(context); - showMyBottomSheet(context, - callBackFunc: widget.callBackFunc, - child: SelectedItemSheet( - LocaleKeys.comments.tr(), - apiMode: widget.apiMode, - replacementList: actionHistory, - notificationID: widget.notificationID, - isITGRequest: widget.wFHistory != null, - getNotificationRespondAttributes: widget.getNotificationRespondAttributes, - )); + showMyBottomSheet( + context, + callBackFunc: widget.callBackFunc, + child: SelectedItemSheet( + LocaleKeys.comments.tr(), + apiMode: widget.apiMode, + replacementList: actionHistory, + notificationID: widget.notificationID, + isITGRequest: widget.wFHistory != null, + getNotificationRespondAttributes: widget.getNotificationRespondAttributes, + ), + ); }, child: Row( - children: [ - CircularAvatar( - url: actionHistory.employeeImage, - height: 30, - width: 30, - isImageBase64: actionHistory.employeeImage != null ? true : false, - ), + children: [ + CircularAvatar(url: actionHistory.employeeImage, height: 30, width: 30, isImageBase64: actionHistory.employeeImage != null ? true : false), 16.width, - Expanded( - child: (actionHistory.employeeDisplayName ?? "").toText12(), - ), + Expanded(child: (actionHistory.employeeDisplayName ?? "").toText12()), IconButton( onPressed: () { actionHistory.isFavorite = !(actionHistory.isFavorite ?? false); @@ -587,12 +565,8 @@ class _DelegateSheetState extends State { isNeedToRefresh: false, ); }, - icon: Icon( - Icons.star, - size: 16, - color: (actionHistory.isFavorite ?? false) ? MyColors.yellowColor : MyColors.borderColor, - ), - ) + icon: Icon(Icons.star, size: 16, color: (actionHistory.isFavorite ?? false) ? MyColors.yellowColor : MyColors.borderColor), + ), ], ), ); -- 2.30.2 From 413db572063f6b3b073dade7410dc45486cb5062 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Sun, 12 Oct 2025 15:39:17 +0300 Subject: [PATCH 093/135] favourites list changes --- lib/ui/work_list/sheets/delegate_sheet.dart | 24 ++++++++++----------- pubspec.yaml | 5 +++-- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/lib/ui/work_list/sheets/delegate_sheet.dart b/lib/ui/work_list/sheets/delegate_sheet.dart index de724a1..ef38ce0 100644 --- a/lib/ui/work_list/sheets/delegate_sheet.dart +++ b/lib/ui/work_list/sheets/delegate_sheet.dart @@ -206,17 +206,17 @@ class _DelegateSheetState extends State { Future searchFavUser() async { if (favUsersList != null && favUsersList!.isNotEmpty) { - if (inputRes.length > 3) { - filteredFavUsersList = - favUsersList!.where((GetFavoriteReplacements element) { + // if (inputRes.length > 0) { + filteredFavUsersList = + favUsersList!.where((GetFavoriteReplacements element) { String query = inputRes.toLowerCase(); - return (element.employeeDisplayName != null && element.employeeDisplayName!.toLowerCase().contains(query)) || - (element.userName != null && element.userName!.toLowerCase().contains(query)) || - (element.emailAddress != null && element.emailAddress!.toLowerCase().contains(query)); + return (element.employeeDisplayName != null && element.employeeDisplayName!.toLowerCase().startsWith(query)) || + (element.userName != null && element.userName!.toLowerCase().contains(query)) || + (element.emailAddress != null && element.emailAddress!.toLowerCase().contains(query)); }).toList(); - } else { - filteredFavUsersList = favUsersList; - } + // } else { + // filteredFavUsersList = favUsersList; + // } } else { filteredFavUsersList = []; } @@ -283,7 +283,7 @@ class _DelegateSheetState extends State { if (value == "Workflow") { setState(() { isNeedEnableTextField = false; - selectedFavLetter = null; + // selectedFavLetter = null; filteredFavUsersList = null; }); } else if (value == "Favorites") { @@ -292,7 +292,7 @@ class _DelegateSheetState extends State { } else { setState(() { isNeedEnableTextField = true; - selectedFavLetter = null; + // selectedFavLetter = null; filteredFavUsersList = null; }); } @@ -322,7 +322,7 @@ class _DelegateSheetState extends State { // selectedFavLetter == null && favLetters != null // ? Container(width: double.infinity, alignment: Alignment.center, child: "Please select letter to see Fav results".toText12()) // : - filteredFavUsersList != null + filteredFavUsersList != null && selectedType == "Favorites" ? ListView.separated( itemBuilder: (BuildContext context, int index) { return showFavUserItem(filteredFavUsersList![index]); diff --git a/pubspec.yaml b/pubspec.yaml index a3c0c99..25f3c96 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -58,7 +58,7 @@ dependencies: platform_device_id_plus: ^1.0.7 device_info_plus: ^11.5.0 - image_picker: ^0.8.5+3 + image_picker: ^1.1.2 file_picker: ^8.3.1 geolocator: ^9.0.2 month_year_picker: ^0.5.0+1 @@ -92,7 +92,8 @@ dependencies: logging: ^1.0.1 swipe_to: ^1.0.2 flutter_webrtc: ^0.12.11 - camera: ^0.10.3 +# camera: ^0.10.3 + camera: ^0.11.2 flutter_local_notifications: ^18.0.1 #firebase_analytics: any -- 2.30.2 From 04a2561f7fd99fa702abc2117970bc01501c7582 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Mon, 13 Oct 2025 17:34:43 +0300 Subject: [PATCH 094/135] Update to stores VersionID 9.2 --- lib/app_state/app_state.dart | 2 +- lib/classes/consts.dart | 4 ++-- lib/ui/landing/widget/services_widget.dart | 26 +++++++++++----------- pubspec.yaml | 4 ++-- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/lib/app_state/app_state.dart b/lib/app_state/app_state.dart index 558ed09..e68e169 100644 --- a/lib/app_state/app_state.dart +++ b/lib/app_state/app_state.dart @@ -90,7 +90,7 @@ class AppState { String get getHuaweiPushToken => _huaweiPushToken; - final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 9.2, mobileType: Platform.isAndroid ? "android" : "ios"); + final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 9.3, mobileType: Platform.isAndroid ? "android" : "ios"); void setPostParamsInitConfig() { isAuthenticated = false; diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 12635a6..6b43bbd 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -9,13 +9,13 @@ class ApiConsts { // static String baseUrl = "https://webservices.hmg.com"; // PreProd // static String baseUrl = "https://hmgwebservices.com"; // Live server - static String baseUrl = "https://mohemm.hmg.com"; // New Live server + // static String baseUrl = "https://mohemm.hmg.com"; // New Live server // // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.20.200.111:1010/"; // static String baseUrl = "https://webservices.hmg.com"; // PreProd - // static String baseUrl = "https://mohemm.hmg.com"; + static String baseUrl = "https://mohemm.hmg.com"; // static String baseUrl = "https://hmgwebservices.com"; // Live server static String baseUrlServices = baseUrl + "/Services/"; // server diff --git a/lib/ui/landing/widget/services_widget.dart b/lib/ui/landing/widget/services_widget.dart index 7d2c2b2..426765d 100644 --- a/lib/ui/landing/widget/services_widget.dart +++ b/lib/ui/landing/widget/services_widget.dart @@ -254,22 +254,22 @@ class ServicesWidget extends StatelessWidget { } } else { if (menuEntry.menuName == "HMG_TICKET_REQUESTS") { - Utils.showLoading(context); - TicketBookingResult response = await pro.fetchTicketBooking(); - Utils.hideLoading(context); - if (response.success) { - SSOAuthModel? ssoToken = await pro.fetchSSOAuthRedirection(clientID: response.clientId); - if (ssoToken != null) { - logger.d(ssoToken.data!.toJson()); - logger.d(ssoToken.data!.accessToken); - dynamic url = await pro.fetchURLRedirection(token: ssoToken.data!.accessToken!); - Navigator.push(context, MaterialPageRoute(builder: (context) => SsoLoginWebView(url: url ?? "", jwtToken: ssoToken.data!.accessToken!))); - } - } else { + // Utils.showLoading(context); + // TicketBookingResult response = await pro.fetchTicketBooking(); + // Utils.hideLoading(context); + // if (response.success) { + // SSOAuthModel? ssoToken = await pro.fetchSSOAuthRedirection(clientID: response.clientId); + // if (ssoToken != null) { + // logger.d(ssoToken.data!.toJson()); + // logger.d(ssoToken.data!.accessToken); + // dynamic url = await pro.fetchURLRedirection(token: ssoToken.data!.accessToken!); + // Navigator.push(context, MaterialPageRoute(builder: (context) => SsoLoginWebView(url: url ?? "", jwtToken: ssoToken.data!.accessToken!))); + // } + // } else { List _menuList = pro.getMenuEntriesList?.where((element) => element.parentMenuName == menuEntry.menuName && (element.menuEntryType == "FUNCTION" || element.menuEntryType == "MENU")).toList() ?? []; Navigator.pushNamed(context, AppRoutes.servicesMenuListScreen, arguments: ServicesMenuListScreenParams(menuEntry.prompt!, _menuList.isEmpty ? menuList : _menuList)); - } + // } } else { List _menuList = pro.getMenuEntriesList?.where((element) => element.parentMenuName == menuEntry.menuName && (element.menuEntryType == "FUNCTION" || element.menuEntryType == "MENU")).toList() ?? []; diff --git a/pubspec.yaml b/pubspec.yaml index 25f3c96..7e97774 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,8 +17,8 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 3.6.7+300077 -#version: 3.9.0+1 +version: 3.6.8+300078 +#version: 3.9.1+1 environment: sdk: ^3.7.0 -- 2.30.2 From c7e44965d6fb68f57cd1afaa042f2d5bd67f68c5 Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Wed, 15 Oct 2025 11:15:04 +0300 Subject: [PATCH 095/135] Get Ticket Accural Balance Changes --- lib/api/dashboard_api_client.dart | 16 +++ .../get_accural_ticket_balance_model.dart | 25 ++++ lib/models/generic_response_model.dart | 10 +- lib/provider/dashboard_provider_model.dart | 17 ++- lib/ui/landing/widget/services_widget.dart | 8 +- .../ticket/ticket_detailed_screen.dart | 124 ++++++++++++++++++ lib/widgets/sso_webview_widget.dart | 6 +- 7 files changed, 197 insertions(+), 9 deletions(-) create mode 100644 lib/models/dashboard/get_accural_ticket_balance_model.dart create mode 100644 lib/ui/screens/ticket/ticket_detailed_screen.dart diff --git a/lib/api/dashboard_api_client.dart b/lib/api/dashboard_api_client.dart index 4fc8545..1d45bbf 100644 --- a/lib/api/dashboard_api_client.dart +++ b/lib/api/dashboard_api_client.dart @@ -8,6 +8,7 @@ import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/consts.dart'; import 'package:mohem_flutter_app/classes/date_uitl.dart'; import 'package:mohem_flutter_app/models/dashboard/get_accrual_balances_list_model.dart'; +import 'package:mohem_flutter_app/models/dashboard/get_accural_ticket_balance_model.dart'; import 'package:mohem_flutter_app/models/dashboard/get_attendance_tracking_list_model.dart'; import 'package:mohem_flutter_app/models/dashboard/itg_forms_model.dart'; import 'package:mohem_flutter_app/models/dashboard/list_menu.dart'; @@ -98,6 +99,21 @@ class DashboardApiClient { ); } + Future> getTicketAccuralBalance(String effectiveDate, {String? empID}) async { + String url = "${ApiConsts.erpRest}GET_TICKET_ACCRUAL_BALANCES"; + Map postParams = {"P_EFFECTIVE_DATE": effectiveDate}; + postParams.addAll(AppState().postParamsJson); + if (empID != null) postParams["P_SELECTED_EMPLOYEE_NUMBER"] = empID; + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getAccrualBalancesTicketList ?? []; + }, + url, + postParams, + ); + } + Future getOpenMissingSwipes() async { String url = "${ApiConsts.erpRest}GET_OPEN_MISSING_SWIPES"; Map postParams = {}; diff --git a/lib/models/dashboard/get_accural_ticket_balance_model.dart b/lib/models/dashboard/get_accural_ticket_balance_model.dart new file mode 100644 index 0000000..cc6520d --- /dev/null +++ b/lib/models/dashboard/get_accural_ticket_balance_model.dart @@ -0,0 +1,25 @@ +import 'dart:convert'; + +class GetTicketAccuralBalanceModel { + int? accrualNetEntitlement; + String? accuralPlanCode; + + GetTicketAccuralBalanceModel({ + this.accrualNetEntitlement, + this.accuralPlanCode, + }); + + factory GetTicketAccuralBalanceModel.fromRawJson(String str) => GetTicketAccuralBalanceModel.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory GetTicketAccuralBalanceModel.fromJson(Map json) => GetTicketAccuralBalanceModel( + accrualNetEntitlement: json["ACCRUAL_NET_ENTITLEMENT"], + accuralPlanCode: json["ACCURAL_PLAN_CODE"], + ); + + Map toJson() => { + "ACCRUAL_NET_ENTITLEMENT": accrualNetEntitlement, + "ACCURAL_PLAN_CODE": accuralPlanCode, + }; +} diff --git a/lib/models/generic_response_model.dart b/lib/models/generic_response_model.dart index 74cef13..b7e786c 100644 --- a/lib/models/generic_response_model.dart +++ b/lib/models/generic_response_model.dart @@ -5,6 +5,7 @@ import 'package:mohem_flutter_app/models/add_attachment_list_model.dart'; import 'package:mohem_flutter_app/models/basic_member_information_model.dart'; import 'package:mohem_flutter_app/models/dashboard/event_activity.dart'; import 'package:mohem_flutter_app/models/dashboard/get_accrual_balances_list_model.dart'; +import 'package:mohem_flutter_app/models/dashboard/get_accural_ticket_balance_model.dart'; import 'package:mohem_flutter_app/models/dashboard/get_attendance_tracking_list_model.dart'; import 'package:mohem_flutter_app/models/dashboard/get_open_missing_swipes_list_model.dart'; import 'package:mohem_flutter_app/models/dashboard/get_open_notifications_list.dart'; @@ -177,6 +178,7 @@ class GenericResponseModel { List? getAbsenceDffStructureList; List? getAbsenceTransactionList; List? getAccrualBalancesList; + List? getAccrualBalancesTicketList; List? getActionHistoryList; List? getPRActionHistoryList; List? getAddressDffStructureList; @@ -451,6 +453,7 @@ class GenericResponseModel { this.getAbsenceDffStructureList, this.getAbsenceTransactionList, this.getAccrualBalancesList, + this.getAccrualBalancesTicketList, this.getActionHistoryList, this.getPRActionHistoryList, this.getAddressDffStructureList, @@ -782,6 +785,8 @@ class GenericResponseModel { } getAccrualBalancesList = json["GetAccrualBalancesList"] == null ? null : List.from(json["GetAccrualBalancesList"].map((x) => GetAccrualBalancesList.fromJson(x))); + getAccrualBalancesTicketList = + json["GetAccrualBalancesTicketList"] == null ? null : List.from(json["GetAccrualBalancesTicketList"].map((x) => GetTicketAccuralBalanceModel.fromJson(x))); if (json['GetActionHistoryList'] != null) { getActionHistoryList = []; @@ -1545,6 +1550,7 @@ class GenericResponseModel { data['GetAbsenceTransactionList'] = this.getAbsenceTransactionList!.map((v) => v.toJson()).toList(); } data['GetAccrualBalancesList'] = this.getAccrualBalancesList; + data['GetAccrualBalancesTicketList'] = this.getAccrualBalancesTicketList; if (this.getActionHistoryList != null) { data['GetActionHistoryList'] = this.getActionHistoryList!.map((v) => v.toJson()).toList(); @@ -1955,9 +1961,9 @@ class PortalDirectionData { Map toJson() => {"P_REDIRECTION": pRedirection, "ClientID": clientID}; } - class TicketBookingResult { final bool success; final String? clientId; + TicketBookingResult(this.success, this.clientId); -} \ No newline at end of file +} diff --git a/lib/provider/dashboard_provider_model.dart b/lib/provider/dashboard_provider_model.dart index beddf0c..9e421ab 100644 --- a/lib/provider/dashboard_provider_model.dart +++ b/lib/provider/dashboard_provider_model.dart @@ -11,6 +11,7 @@ import 'package:mohem_flutter_app/main.dart'; import 'package:mohem_flutter_app/models/dashboard/drawer_menu_item_model.dart'; import 'package:mohem_flutter_app/models/dashboard/event_activity.dart'; import 'package:mohem_flutter_app/models/dashboard/get_accrual_balances_list_model.dart'; +import 'package:mohem_flutter_app/models/dashboard/get_accural_ticket_balance_model.dart'; import 'package:mohem_flutter_app/models/dashboard/get_attendance_tracking_list_model.dart'; import 'package:mohem_flutter_app/models/dashboard/get_open_notifications_list.dart'; import 'package:mohem_flutter_app/models/dashboard/itg_forms_model.dart'; @@ -44,6 +45,7 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { //Leave and Ticket Balance bool isLeaveTicketBalanceLoading = true; List? accrualList; + List? accrualTicketBalanceList; GetAccrualBalancesList? leaveBalanceAccrual; double get leaveBalance => leaveBalanceAccrual?.accrualNetEntitlement ?? 0; @@ -101,6 +103,7 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { isLeaveTicketBalanceLoading = true; accrualList = null; + accrualTicketBalanceList = null; leaveBalanceAccrual = null; ticketBalance = 0; @@ -204,7 +207,19 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { leaveBalanceAccrual = accrualList![0]; ticketBalance = (accrualList![1].accrualNetEntitlement ?? 0.0) + (accrualList![2].accrualNetEntitlement ?? 0.0) + (accrualList![3].accrualNetEntitlement ?? 0.0); walletBalance = (accrualList![4].accrualNetEntitlement ?? 0.0); - print("================ Ticket Balance: $ticketBalance ==============="); + notifyListeners(); + } catch (ex) { + isLeaveTicketBalanceLoading = false; + logger.wtf(ex); + notifyListeners(); + Utils.handleException(ex, context, null); + } + } + + Future fetchTicketAccuralBalance(context, DateTime date) async { + try { + accrualTicketBalanceList = await DashboardApiClient().getTicketAccuralBalance(DateFormat("MM/dd/yyyy", "en_US").format(date)); + isLeaveTicketBalanceLoading = false; notifyListeners(); } catch (ex) { isLeaveTicketBalanceLoading = false; diff --git a/lib/ui/landing/widget/services_widget.dart b/lib/ui/landing/widget/services_widget.dart index 6dfeab5..723adb9 100644 --- a/lib/ui/landing/widget/services_widget.dart +++ b/lib/ui/landing/widget/services_widget.dart @@ -14,12 +14,14 @@ 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/main.dart'; +import 'package:mohem_flutter_app/models/dashboard/get_accural_ticket_balance_model.dart'; import 'package:mohem_flutter_app/models/dashboard/menu_entries.dart'; import 'package:mohem_flutter_app/models/generic_response_model.dart'; import 'package:mohem_flutter_app/models/sso_auth_model.dart'; import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; import 'package:mohem_flutter_app/ui/my_attendance/dynamic_screens/dynamic_listview_screen.dart'; import 'package:mohem_flutter_app/ui/my_attendance/services_menu_list_screen.dart'; +import 'package:mohem_flutter_app/ui/screens/ticket/ticket_detailed_screen.dart'; import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart'; import 'package:mohem_flutter_app/widgets/sso_webview_widget.dart'; import 'package:provider/provider.dart'; @@ -259,11 +261,11 @@ class ServicesWidget extends StatelessWidget { if (pro.ticketBookingResponse != null && pro.ticketBookingResponse!.success) { SSOAuthModel? ssoToken = await pro.fetchSSOAuthRedirection(clientID: pro.ticketBookingResponse!.clientId); if (ssoToken != null) { - logger.d(ssoToken.data!.toJson()); - logger.d(ssoToken.data!.accessToken); dynamic url = await pro.fetchURLRedirection(token: ssoToken.data!.accessToken!); + await pro.fetchTicketAccuralBalance(context, DateTime.now()); Utils.hideLoading(context); - Navigator.push(context, MaterialPageRoute(builder: (context) => SsoLoginWebView(url: url ?? "", jwtToken: ssoToken.data!.accessToken!))); + // Here Need Work + Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => TicketDetailedScreen(url: url, jwtToken: ssoToken.data!.accessToken))); } } else { List _menuList = diff --git a/lib/ui/screens/ticket/ticket_detailed_screen.dart b/lib/ui/screens/ticket/ticket_detailed_screen.dart new file mode 100644 index 0000000..fe41527 --- /dev/null +++ b/lib/ui/screens/ticket/ticket_detailed_screen.dart @@ -0,0 +1,124 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.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/date_uitl.dart'; +import 'package:mohem_flutter_app/classes/utils.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/models/dashboard/get_accural_ticket_balance_model.dart'; +import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; +import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; +import 'package:mohem_flutter_app/widgets/balances_dashboard_widget.dart'; +import 'package:mohem_flutter_app/widgets/button/default_button.dart'; +import 'package:mohem_flutter_app/widgets/sso_webview_widget.dart'; +import 'package:provider/provider.dart'; + +class TicketDetailedScreen extends StatefulWidget { + final String? url; + final String? jwtToken; + + const TicketDetailedScreen({super.key, this.url, this.jwtToken}); + + @override + State createState() => _TicketDetailedScreenState(); +} + +class _TicketDetailedScreenState extends State { + DashboardProviderModel? dashboardProviderModel; + late DateTime accrualDateTime; + + @override + void initState() { + dashboardProviderModel = Provider.of(context, listen: false); + accrualDateTime = DateTime.now(); + super.initState(); + } + + void changeAccrualDate(bool showLoading) async { + try { + if (showLoading) Utils.showLoading(context); + await dashboardProviderModel?.fetchTicketAccuralBalance(context, accrualDateTime); + if (showLoading) Utils.hideLoading(context); + setState(() {}); + } catch (ex) { + if (showLoading) Utils.hideLoading(context); + Utils.handleException(ex, context, null); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBarWidget(context, title: "Ticket Details"), + body: Column( + children: [ + ListView( + padding: const EdgeInsets.all(21), + physics: const BouncingScrollPhysics(), + children: [ + if (dashboardProviderModel == null && dashboardProviderModel?.accrualTicketBalanceList == null) ...[Utils.getNoDataWidget(context).paddingOnly(top: 50)] else ...[ + // const BalancesDashboardWidget("Current Ticket Balance", false, showLoading: false), 12.height, + Container( + padding: const EdgeInsets.all(16.0), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12.0), + boxShadow: [BoxShadow(color: Colors.grey.withOpacity(0.2), spreadRadius: 2, blurRadius: 5, offset: const Offset(0, 3))], + ), + child: Column( + children: [ + Row( + children: [ + "Current Ticket Balance".toText20().expanded, + Row( + children: [ + const Icon(Icons.calendar_month_rounded, color: MyColors.darkIconColor, size: 16), + 5.width, + DateUtil.formatDateToDate(accrualDateTime, AppState().isArabic(context)).toText13(isUnderLine: true), + 8.width, + ], + ).onPress(() async { + DateTime selectedDate = await Utils.selectDate(context, accrualDateTime); + if (selectedDate != accrualDateTime) { + accrualDateTime = selectedDate; + changeAccrualDate(true); + } + }), + ], + ), + 8.height, + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: + dashboardProviderModel!.accrualTicketBalanceList!.map((GetTicketAccuralBalanceModel item) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 6.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + item.accuralPlanCode.toString().replaceAll('_', ' ').toCamelCase.toText14(), + item.accrualNetEntitlement.toString().toText16(color: MyColors.textMixColor, isBold: true), + ], + ), + ); + }).toList(), + ), + ], + ), + ), + ], + ], + ).expanded, + DefaultButton("Proceed For Booking", () { + if (widget.url != null && widget.jwtToken != null) { + Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => SsoLoginWebView(url: widget.url, jwtToken: widget.jwtToken))); + } + }).insideContainer, + ], + ), + ); + } +} diff --git a/lib/widgets/sso_webview_widget.dart b/lib/widgets/sso_webview_widget.dart index e5f2759..070f270 100644 --- a/lib/widgets/sso_webview_widget.dart +++ b/lib/widgets/sso_webview_widget.dart @@ -4,10 +4,10 @@ import 'package:flutter/material.dart'; import 'package:webview_flutter/webview_flutter.dart'; class SsoLoginWebView extends StatefulWidget { - final String url; - final String jwtToken; + final String? url; + final String? jwtToken; - SsoLoginWebView({required this.url, required this.jwtToken}); + SsoLoginWebView({this.url, this.jwtToken}); @override State createState() => _SsoLoginWebViewState(); -- 2.30.2 From 0b08606813201dc0152331159d6964b8f7f11a32 Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Tue, 21 Oct 2025 10:22:43 +0300 Subject: [PATCH 096/135] Ticket History --- lib/api/eit_api_client.dart | 23 ++++-- lib/provider/dashboard_provider_model.dart | 2 + lib/provider/eit_provider_model.dart | 1 + lib/ui/landing/widget/services_widget.dart | 4 + .../ticket/ticket_detailed_screen.dart | 75 +++++++++++++++++-- 5 files changed, 94 insertions(+), 11 deletions(-) diff --git a/lib/api/eit_api_client.dart b/lib/api/eit_api_client.dart index 9e4f292..d473aaf 100644 --- a/lib/api/eit_api_client.dart +++ b/lib/api/eit_api_client.dart @@ -19,13 +19,26 @@ class EITApiClient { factory EITApiClient() => _instance; - Future?> getEITTransactions(String functionName) async { + Future getEITTransactions(String functionName, {bool isCompleteList = false}) async { String url = "${ApiConsts.erpRest}GET_EIT_TRANSACTIONS"; Map postParams = {'P_FUNCTION_NAME': functionName, "P_MENU_TYPE": "E", "P_PAGE_LIMIT": 50, "P_PAGE_NUM": 1}; postParams.addAll(AppState().postParamsJson); - return await ApiClient().postJsonForObject((json) { - List? responseData = GetEitTransactionsModel.fromJson(json['GetEITTransactionList'][0]).collectionTransaction; - return responseData; - }, url, postParams); + return await ApiClient().postJsonForObject( + (json) { + if (isCompleteList) { + List> responseData = []; + json['GetEITTransactionList'].forEach((element) { + var transactionList = GetEitTransactionsModel.fromJson(element).collectionTransaction; + if (transactionList != null) responseData.add(transactionList); + }); + return responseData; + } else { + List? responseData = GetEitTransactionsModel.fromJson(json['GetEITTransactionList'][0]).collectionTransaction; + return responseData; + } + }, + url, + postParams, + ); } } diff --git a/lib/provider/dashboard_provider_model.dart b/lib/provider/dashboard_provider_model.dart index 6e441b3..05c9ebb 100644 --- a/lib/provider/dashboard_provider_model.dart +++ b/lib/provider/dashboard_provider_model.dart @@ -19,6 +19,7 @@ import 'package:mohem_flutter_app/models/dashboard/list_menu.dart'; import 'package:mohem_flutter_app/models/dashboard/menu_entries.dart'; import 'package:mohem_flutter_app/models/dashboard/menus.dart'; import 'package:mohem_flutter_app/models/dashboard/mohemm_itg_pending_task_responseitem.dart'; +import 'package:mohem_flutter_app/models/eit/get_eit_transaction_model.dart'; import 'package:mohem_flutter_app/models/generic_response_model.dart'; import 'package:mohem_flutter_app/models/itg/itg_response_model.dart'; import 'package:mohem_flutter_app/models/offers_and_discounts/get_offers_list.dart'; @@ -60,6 +61,7 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { EventActivityList? eventActivity; TicketBookingResult? ticketBookingResponse; + List>? ticketHistoryTransactionList = []; //Offers And Discounts bool isOffersLoading = true; diff --git a/lib/provider/eit_provider_model.dart b/lib/provider/eit_provider_model.dart index 1543184..75a210f 100644 --- a/lib/provider/eit_provider_model.dart +++ b/lib/provider/eit_provider_model.dart @@ -18,6 +18,7 @@ import 'package:mohem_flutter_app/widgets/Updater.dart'; class EITProviderModel with ChangeNotifier, DiagnosticableTreeMixin { List? eitTransactionList; late bool isEitLoaded = false; + void getEITList(String functionName) async { try { eitTransactionList = await EITApiClient().getEITTransactions(functionName); diff --git a/lib/ui/landing/widget/services_widget.dart b/lib/ui/landing/widget/services_widget.dart index 723adb9..deea7e9 100644 --- a/lib/ui/landing/widget/services_widget.dart +++ b/lib/ui/landing/widget/services_widget.dart @@ -5,6 +5,7 @@ import 'package:easy_localization/src/public_ext.dart'; import 'package:flutter/material.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:mohem_flutter_app/api/eit_api_client.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/inAppWebView.dart'; import 'package:mohem_flutter_app/classes/utils.dart'; @@ -263,6 +264,9 @@ class ServicesWidget extends StatelessWidget { if (ssoToken != null) { dynamic url = await pro.fetchURLRedirection(token: ssoToken.data!.accessToken!); await pro.fetchTicketAccuralBalance(context, DateTime.now()); + pro.ticketHistoryTransactionList = await EITApiClient().getEITTransactions("HMG_TICKET_ITENARY_HR_EIT_SS", isCompleteList: true); + + Utils.hideLoading(context); // Here Need Work Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => TicketDetailedScreen(url: url, jwtToken: ssoToken.data!.accessToken))); diff --git a/lib/ui/screens/ticket/ticket_detailed_screen.dart b/lib/ui/screens/ticket/ticket_detailed_screen.dart index fe41527..d406153 100644 --- a/lib/ui/screens/ticket/ticket_detailed_screen.dart +++ b/lib/ui/screens/ticket/ticket_detailed_screen.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; @@ -12,6 +14,7 @@ import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; import 'package:mohem_flutter_app/widgets/balances_dashboard_widget.dart'; import 'package:mohem_flutter_app/widgets/button/default_button.dart'; +import 'package:mohem_flutter_app/widgets/item_detail_view_widget.dart'; import 'package:mohem_flutter_app/widgets/sso_webview_widget.dart'; import 'package:provider/provider.dart'; @@ -54,27 +57,26 @@ class _TicketDetailedScreenState extends State { backgroundColor: Colors.white, appBar: AppBarWidget(context, title: "Ticket Details"), body: Column( - children: [ + children: [ ListView( padding: const EdgeInsets.all(21), physics: const BouncingScrollPhysics(), children: [ if (dashboardProviderModel == null && dashboardProviderModel?.accrualTicketBalanceList == null) ...[Utils.getNoDataWidget(context).paddingOnly(top: 50)] else ...[ - // const BalancesDashboardWidget("Current Ticket Balance", false, showLoading: false), 12.height, Container( padding: const EdgeInsets.all(16.0), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12.0), - boxShadow: [BoxShadow(color: Colors.grey.withOpacity(0.2), spreadRadius: 2, blurRadius: 5, offset: const Offset(0, 3))], + boxShadow: [BoxShadow(color: Colors.grey.withOpacity(0.2), spreadRadius: 2, blurRadius: 5, offset: const Offset(0, 3))], ), child: Column( - children: [ + children: [ Row( - children: [ + children: [ "Current Ticket Balance".toText20().expanded, Row( - children: [ + children: [ const Icon(Icons.calendar_month_rounded, color: MyColors.darkIconColor, size: 16), 5.width, DateUtil.formatDateToDate(accrualDateTime, AppState().isArabic(context)).toText13(isUnderLine: true), @@ -109,6 +111,67 @@ class _TicketDetailedScreenState extends State { ], ), ), + const SizedBox(height: 21), + dashboardProviderModel == null && dashboardProviderModel!.ticketHistoryTransactionList == null + ? const SizedBox() + : ListView( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + children: [ + "Tickets History".toText20().expanded, + 12.height, + ListView.separated( + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + padding: EdgeInsets.zero, + itemBuilder: (BuildContext cxt, int cardIndex) { + var transactionDetails = dashboardProviderModel!.ticketHistoryTransactionList![cardIndex]; + const allowedSegmentNames = { + "TICKETS_ROUTE", + "TRAVELER_NAME", + "TICKETS_EFFECTIVE_DATE", + "TICKET_ARRIVAL", + "TICKET_AMOUNT", + "TICKET_COMP_SHARE", + "TICKET_EMP_SHARE", + }; + var uniqueDetails = + transactionDetails + .where((item) => item.dISPLAYFLAG != 'N' && item.sEGMENTPROMPT != null && item.sEGMENTPROMPT!.isNotEmpty && allowedSegmentNames.contains(item.sEGMENTNAME)) + .toList(); + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + ListView.builder( + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemCount: (uniqueDetails.length / 2).ceil(), + itemBuilder: (context, rowIndex) { + int firstIndex = rowIndex * 2; + int? secondIndex = (firstIndex + 1 < uniqueDetails.length) ? firstIndex + 1 : null; + bool isLastRow = (rowIndex == (uniqueDetails.length / 2).ceil() - 1); + var item1 = uniqueDetails[firstIndex]; + var child1 = ItemDetailViewCol(item1.sEGMENTPROMPT!, item1.vARCHAR2VALUE ?? item1.nUMBERVALUE?.toString() ?? ""); + Widget child2; + if (secondIndex != null) { + var item2 = uniqueDetails[secondIndex]; + child2 = ItemDetailViewCol(item2.sEGMENTPROMPT!, item2.vARCHAR2VALUE ?? item2.nUMBERVALUE?.toString() ?? ""); + } else { + child2 = const SizedBox(); // Empty widget if there is no second item + } + return ItemDetailGrid(child1, child2, isItLast: isLastRow); + }, + ), + ], + ).objectContainerView(); + }, + separatorBuilder: (BuildContext cxt, int index) => 12.height, + itemCount: dashboardProviderModel!.ticketHistoryTransactionList!.length, + ), + ], + ), ], ], ).expanded, -- 2.30.2 From c191d4c0c093be9a9f91c371ecdd4a5e7cceb20c Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Tue, 21 Oct 2025 11:09:56 +0300 Subject: [PATCH 097/135] Survey Title Key Fix --- lib/ui/landing/itg/its_add_screen_video_image.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 103fde1..2076d7c 100644 --- a/lib/ui/landing/itg/its_add_screen_video_image.dart +++ b/lib/ui/landing/itg/its_add_screen_video_image.dart @@ -146,7 +146,7 @@ class _ITGAdsScreenState extends State { centerTitle: true, automaticallyImplyLeading: false, backgroundColor: Colors.white, - title: (AppState().isArabic(context) ? advertisementData!.advertisementTitleAr! : advertisementData!.advertisementTitleAr!).toText24(color: MyColors.darkTextColor, isBold: true), + title: (AppState().isArabic(context) ? advertisementData!.advertisementTitleAr! : advertisementData!.advertisementTitle!).toText24(color: MyColors.darkTextColor, isBold: true), //advertisementData!.viewAttachFileColl!.first.base64String!.toText24(color: MyColors.darkTextColor, isBold: true), ) -- 2.30.2 From bf3f9b55fca4442c764b332fab515b4a6ee39d40 Mon Sep 17 00:00:00 2001 From: Sultan khan Date: Wed, 22 Oct 2025 17:53:07 +0300 Subject: [PATCH 098/135] changes for security ogout attempt.. --- lib/api/api_client.dart | 9 +- lib/classes/consts.dart | 4 +- lib/classes/utils.dart | 13 + lib/ui/landing/dashboard_screen.dart | 548 +++++++++++------- lib/ui/landing/widget/app_drawer.dart | 20 +- .../offers_and_discounts_home.dart | 2 +- 6 files changed, 374 insertions(+), 222 deletions(-) diff --git a/lib/api/api_client.dart b/lib/api/api_client.dart index fb415d4..91fd28a 100644 --- a/lib/api/api_client.dart +++ b/lib/api/api_client.dart @@ -6,6 +6,8 @@ import 'package:flutter/foundation.dart'; import 'package:http/http.dart'; import 'package:http/io_client.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; +import 'package:mohem_flutter_app/classes/utils.dart'; +import 'package:mohem_flutter_app/config/routes.dart'; import 'package:mohem_flutter_app/exceptions/api_exception.dart'; import 'package:mohem_flutter_app/main.dart'; // ignore_for_file: avoid_annotating_with_dynamic @@ -13,7 +15,7 @@ import 'package:mohem_flutter_app/main.dart'; typedef FactoryConstructor = U Function(dynamic); class APIError { - int? errorCode; + dynamic errorCode; int? errorType; String? errorMessage; int? errorStatusCode; @@ -102,7 +104,10 @@ class ApiClient { if (jsonData["ErrorMessage"] == null) { return factoryConstructor(jsonData); - } else { + } else if (jsonData["MessageStatus"] == 2 && jsonData["IsOTPMaxLimitExceed"] == true) { + await Utils.performLogout(AppRoutes.navigatorKey.currentContext, null); + throw const APIException(APIException.UNAUTHORIZED, error: null); + } else { APIError? apiError; apiError = APIError(jsonData['ErrorCode'], jsonData['ErrorEndUserMessage'], jsonData['ErrorType'] ?? 0, jsonData['ErrorStatusCode']); throw APIException(APIException.BAD_REQUEST, error: apiError); diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 6b43bbd..51e8066 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -9,13 +9,13 @@ class ApiConsts { // static String baseUrl = "https://webservices.hmg.com"; // PreProd // static String baseUrl = "https://hmgwebservices.com"; // Live server - // static String baseUrl = "https://mohemm.hmg.com"; // New Live server + static String baseUrl = "https://mohemm.hmg.com"; // New Live server // // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.20.200.111:1010/"; // static String baseUrl = "https://webservices.hmg.com"; // PreProd - static String baseUrl = "https://mohemm.hmg.com"; + // static String baseUrl = "https://mohemm.hmg.com"; // static String baseUrl = "https://hmgwebservices.com"; // Live server static String baseUrlServices = baseUrl + "/Services/"; // server diff --git a/lib/classes/utils.dart b/lib/classes/utils.dart index 0245bbf..6a9b16b 100644 --- a/lib/classes/utils.dart +++ b/lib/classes/utils.dart @@ -16,6 +16,7 @@ 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/provider/chat_provider_model.dart'; import 'package:mohem_flutter_app/widgets/dialogs/confirm_dialog.dart'; import 'package:mohem_flutter_app/widgets/loading_dialog.dart'; import 'package:nfc_manager/nfc_manager.dart'; @@ -386,4 +387,16 @@ class Utils { return false; } } + + static Future performLogout(BuildContext? context, ChatProviderModel? chatData) async { + AppState().isAuthenticated = false; + AppState().isLogged = false; + AppState().setPostParamsInitConfig(); + if (chatData != null) { + chatData.disposeData(); + } + // SharedPreferences prefs = await SharedPreferences.getInstance(); + // await prefs.clear(); + Navigator.pushNamedAndRemoveUntil(context!, AppRoutes.login, (Route route) => false, arguments: null); + } } diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index d3ecb9f..8b14f2c 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -56,6 +56,8 @@ class _DashboardScreenState extends State with WidgetsBindingOb int currentIndex = 0; + bool isDisplayMazaya = false; + @override void initState() { WidgetsBinding.instance.addObserver(this); @@ -149,10 +151,11 @@ class _DashboardScreenState extends State with WidgetsBindingOb data.fetchAttendanceTracking(context); data.fetchWorkListCounter(context); data.fetchMissingSwipe(context); + data.fetchLeaveTicketBalance(context, DateTime.now()); data.fetchMenuEntries(); data.fetchEventActivity(); - // data.getCategoryOffersListAPI(context); + data.getCategoryOffersListAPI(context); marathonProvider.getMarathonDetailsFromApi(); marathonProvider.getMarathonTutorial(); if (isFromInit) { @@ -160,6 +163,12 @@ class _DashboardScreenState extends State with WidgetsBindingOb } if (!cProvider.disbaleChatForThisUser && !isFromInit) checkHubCon(); _refreshController.refreshCompleted(); + + await data.fetchTicketBooking(); + // if (data.ticketBookingResponse != null && !data.ticketBookingResponse!.success) { + // // data.fetchTicketBalance(); + // } + //continue here } int ermIndex = 0; @@ -305,103 +314,103 @@ class _DashboardScreenState extends State with WidgetsBindingOb child: Consumer( builder: (BuildContext context, DashboardProviderModel model, Widget? child) { return (model.isAttendanceTrackingLoading - ? GetAttendanceTrackingShimmer() - : Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(15), - gradient: const LinearGradient( - transform: GradientRotation(.46), - begin: Alignment.topRight, - end: Alignment.bottomLeft, - colors: [MyColors.gradiantEndColor, MyColors.gradiantStartColor], - ), - ), - child: Stack( - alignment: Alignment.center, - children: [ - if (model.isTimeRemainingInSeconds == 0) SvgPicture.asset("assets/images/thumb.svg"), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - LocaleKeys.markAttendance.tr().toText14(color: Colors.white, isBold: true), - if (model.isTimeRemainingInSeconds == 0) DateTime.now().toString().split(" ")[0].toText12(color: Colors.white), - if (model.isTimeRemainingInSeconds != 0) - Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - 9.height, - Directionality( - textDirection: ui.TextDirection.ltr, - child: CountdownTimer( - endTime: model.endTime, - onEnd: null, - endWidget: "00:00:00".toText14(color: Colors.white, isBold: true), - textStyle: const TextStyle(color: Colors.white, fontSize: 14, letterSpacing: -0.48, fontWeight: FontWeight.bold), - ), - ), - LocaleKeys.timeLeftToday.tr().toText12(color: Colors.white), - 9.height, - ClipRRect( - borderRadius: const BorderRadius.all(Radius.circular(20)), - child: LinearProgressIndicator( - value: model.progress, - minHeight: 8, - valueColor: const AlwaysStoppedAnimation(Colors.white), - backgroundColor: const Color(0xff196D73), - ), - ), - ], - ), - ], - ).paddingOnly(top: 12, right: 15, left: 12), - ), - Row( + ? GetAttendanceTrackingShimmer() + : Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(15), + gradient: const LinearGradient( + transform: GradientRotation(.46), + begin: Alignment.topRight, + end: Alignment.bottomLeft, + colors: [MyColors.gradiantEndColor, MyColors.gradiantStartColor], + ), + ), + child: Stack( + alignment: Alignment.center, + children: [ + if (model.isTimeRemainingInSeconds == 0) SvgPicture.asset("assets/images/thumb.svg"), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.markAttendance.tr().toText14(color: Colors.white, isBold: true), + if (model.isTimeRemainingInSeconds == 0) DateTime.now().toString().split(" ")[0].toText12(color: Colors.white), + if (model.isTimeRemainingInSeconds != 0) + Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Expanded( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - LocaleKeys.checkIn.tr().toText12(color: Colors.white), - (model.attendanceTracking!.pSwipeIn == null ? "--:--" : model.attendanceTracking!.pSwipeIn).toString().toText14( - color: Colors.white, - isBold: true, - ), - 4.height, - ], - ).paddingOnly(left: 12, right: 12), + 9.height, + Directionality( + textDirection: ui.TextDirection.ltr, + child: CountdownTimer( + endTime: model.endTime, + onEnd: null, + endWidget: "00:00:00".toText14(color: Colors.white, isBold: true), + textStyle: const TextStyle(color: Colors.white, fontSize: 14, letterSpacing: -0.48, fontWeight: FontWeight.bold), + ), ), - Container( - margin: EdgeInsets.only(top: AppState().isArabic(context) ? 6 : 0), - width: 45, - height: 45, - padding: const EdgeInsets.only(left: 10, right: 10), - decoration: BoxDecoration( - color: const Color(0xff259EA4), - borderRadius: BorderRadius.only( - bottomRight: AppState().isArabic(context) ? const Radius.circular(0) : const Radius.circular(15), - bottomLeft: AppState().isArabic(context) ? const Radius.circular(15) : const Radius.circular(0), - ), + LocaleKeys.timeLeftToday.tr().toText12(color: Colors.white), + 9.height, + ClipRRect( + borderRadius: const BorderRadius.all(Radius.circular(20)), + child: LinearProgressIndicator( + value: model.progress, + minHeight: 8, + valueColor: const AlwaysStoppedAnimation(Colors.white), + backgroundColor: const Color(0xff196D73), ), - child: SvgPicture.asset(model.isTimeRemainingInSeconds == 0 ? "assets/images/biometrics.svg" : "assets/images/biometrics.svg"), - ).onPress(() { - showMyBottomSheet(context, callBackFunc: () {}, child: MarkAttendanceWidget(model, isFromDashboard: true)); - }), + ), ], ), - ], + ], + ).paddingOnly(top: 12, right: 15, left: 12), + ), + Row( + children: [ + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.checkIn.tr().toText12(color: Colors.white), + (model.attendanceTracking!.pSwipeIn == null ? "--:--" : model.attendanceTracking!.pSwipeIn).toString().toText14( + color: Colors.white, + isBold: true, + ), + 4.height, + ], + ).paddingOnly(left: 12, right: 12), ), + Container( + margin: EdgeInsets.only(top: AppState().isArabic(context) ? 6 : 0), + width: 45, + height: 45, + padding: const EdgeInsets.only(left: 10, right: 10), + decoration: BoxDecoration( + color: const Color(0xff259EA4), + borderRadius: BorderRadius.only( + bottomRight: AppState().isArabic(context) ? const Radius.circular(0) : const Radius.circular(15), + bottomLeft: AppState().isArabic(context) ? const Radius.circular(15) : const Radius.circular(0), + ), + ), + child: SvgPicture.asset(model.isTimeRemainingInSeconds == 0 ? "assets/images/biometrics.svg" : "assets/images/biometrics.svg"), + ).onPress(() { + showMyBottomSheet(context, callBackFunc: () {}, child: MarkAttendanceWidget(model, isFromDashboard: true)); + }), ], ), - ).onPress(() { - Navigator.pushNamed(context, AppRoutes.todayAttendance); - })) + ], + ), + ], + ), + ).onPress(() { + Navigator.pushNamed(context, AppRoutes.todayAttendance); + })) .animatedSwither(); }, ), @@ -414,116 +423,238 @@ class _DashboardScreenState extends State with WidgetsBindingOb ], ).paddingOnly(left: 21, right: 21, top: 7, bottom: 21), eventActivityWidget(context), + + if (isDisplayMazaya) ...[ + Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Directionality( + textDirection: AppState().isArabic(context) ? ui.TextDirection.rtl : ui.TextDirection.ltr, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + gradient: const LinearGradient(colors: [Color(0xFF91C481), Color(0xFF7CCED7)], begin: Alignment.centerLeft, end: Alignment.centerRight), + ), + child: Padding( + padding: const EdgeInsets.all(3.0), // This creates the border width + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(17), // Slightly less than outer radius + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + flex: 4, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Row( + children: [ + Expanded( + flex: 2, + child: RichText( + text: + AppState().isArabic(context) + ? TextSpan( + children: [ + TextSpan( + text: 'اطلع على مميزات', + style: TextStyle( + fontSize: 16, + letterSpacing: -0.2, + fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins', + fontWeight: FontWeight.w700, + height: 24 / 16, + color: Color(0xFF5D5E5E), + ), + ), + TextSpan( + text: ' مزايا', + style: TextStyle( + fontSize: 16, + fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins', + fontWeight: FontWeight.w700, + letterSpacing: -0.2, + height: 24 / 16, + color: MyColors.mazayaRedColor, // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed + ), + ), + ], + ) + : TextSpan( + children: [ + TextSpan( + text: LocaleKeys.explore.tr() + ' ', + style: const TextStyle( + fontSize: 16, + letterSpacing: -0.2, + fontFamily: 'Poppins', + fontWeight: FontWeight.w700, + height: 24 / 16, + color: Color(0xFF5D5E5E), + ), + ), + TextSpan( + text: LocaleKeys.mazaya.tr(), + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.w700, + fontFamily: 'Poppins', + letterSpacing: -0.2, + height: 24 / 16, + color: MyColors.mazayaRedColor, // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed + ), + ), + TextSpan( + text: ' ' + LocaleKeys.benefits.tr(), + style: const TextStyle( + fontSize: 16, + letterSpacing: -0.2, + fontFamily: 'Poppins', + fontWeight: FontWeight.w700, + height: 24 / 16, + color: Color(0xFF5D5E5E), + ), + ), + ], + ), + ), + ), + const Expanded(flex: 1, child: SizedBox()), + ], + ), + const SizedBox(height: 8), + LocaleKeys.mazayaDesc.tr().toText11(color: const Color(0xFF5D5E5E)), + ], + ), + ), + Expanded( + flex: 2, + child: Column( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + SvgPicture.asset("assets/icons/mazaya_brand.svg", width: 90, height: 47), + const SizedBox(height: 28), + LocaleKeys.viewallofferMazaya.tr().toText12(isUnderLine: true, color: const Color(0xFF3B3D4A)).onPress(() { + Navigator.pushNamed(context, AppRoutes.offersAndDiscounts); + }), + ], + ), + ), + ], + ).paddingOnly(left: 21, right: 21, top: 14, bottom: 14), + ), + ), + ).paddingOnly(left: 21, right: 21, top: 0, bottom: 21), + ), + ], + ), + ], + Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Directionality( - textDirection: AppState().isArabic(context) ? ui.TextDirection.rtl : ui.TextDirection.ltr, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - gradient: const LinearGradient(colors: [Color(0xFF91C481), Color(0xFF7CCED7)], begin: Alignment.centerLeft, end: Alignment.centerRight), + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + LocaleKeys.offers.tr().toText12(), + Row( + children: [ + LocaleKeys.discounts.tr().toText24(isBold: true), + 6.width, + Container( + padding: const EdgeInsets.only(left: 8, right: 8), + decoration: BoxDecoration( + color: MyColors.yellowColor, + borderRadius: BorderRadius.circular(10), + ), + child: LocaleKeys.newString.tr().toText10(isBold: true)), + ], + ), + ], + ), ), - child: Padding( - padding: const EdgeInsets.all(3.0), // This creates the border width - child: Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(17), // Slightly less than outer radius - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - flex: 4, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Row( - children: [ - Expanded( - flex: 2, - child: RichText( - text: - AppState().isArabic(context) - ? TextSpan( - children: [ - TextSpan( - text: 'اطلع على مميزات', - style: TextStyle(fontSize: 16, letterSpacing: -0.2, fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins', fontWeight: FontWeight.w700, height: 24 / 16, color: Color(0xFF5D5E5E)), - ), - TextSpan( - text: ' مزايا', - style: TextStyle( - fontSize: 16, - fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins', - fontWeight: FontWeight.w700, - letterSpacing: -0.2, - height: 24 / 16, - color: MyColors.mazayaRedColor, // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed - ), - ), - ], - ) - : TextSpan( - children: [ - TextSpan( - text: LocaleKeys.explore.tr() + ' ', - style: const TextStyle(fontSize: 16, letterSpacing: -0.2, fontFamily: 'Poppins', fontWeight: FontWeight.w700, height: 24 / 16, color: Color(0xFF5D5E5E)), - ), - TextSpan( - text: LocaleKeys.mazaya.tr(), - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w700, - fontFamily: 'Poppins', - letterSpacing: -0.2, - height: 24 / 16, - color: MyColors.mazayaRedColor, // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed - ), - ), - TextSpan( - text: ' ' + LocaleKeys.benefits.tr(), - style: const TextStyle(fontSize: 16, letterSpacing: -0.2, - fontFamily: 'Poppins',fontWeight: FontWeight.w700, height: 24 / 16, color: Color(0xFF5D5E5E)), - ), - ], - ), + LocaleKeys.viewAllOffers.tr().toText12(isUnderLine: true).onPress(() { + Navigator.pushNamed(context, AppRoutes.offersAndDiscounts); + }) + ], + ).paddingOnly(left: 21, right: 21), + Consumer( + builder: (BuildContext context, DashboardProviderModel model, Widget? child) { + return SizedBox( + height: 103 + 33, + child: ListView.separated( + shrinkWrap: true, + physics: const BouncingScrollPhysics(), + padding: const EdgeInsets.only(left: 21, right: 21, top: 13), + scrollDirection: Axis.horizontal, + itemBuilder: (BuildContext cxt, int index) { + return model.isOffersLoading + ? const OffersShimmerWidget() + : InkWell( + onTap: () { + navigateToDetails(data.getOffersList[index]); + }, + child: SizedBox( + width: 73, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + width: 73, + height: 73, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: const BorderRadius.all( + Radius.circular(100), ), + border: Border.all(color: MyColors.lightGreyE3Color, width: 1), ), - const Expanded(flex: 1, child: SizedBox()), - ], - ), - const SizedBox(height: 8), - LocaleKeys.mazayaDesc.tr().toText11(color: const Color(0xFF5D5E5E)), - ], - ), - ), - Expanded( - flex: 2, - child: Column( - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisAlignment: MainAxisAlignment.end, - children: [ - SvgPicture.asset("assets/icons/mazaya_brand.svg", width: 90, height: 47), - const SizedBox(height: 28), - LocaleKeys.viewallofferMazaya.tr().toText12(isUnderLine: true, color: const Color(0xFF3B3D4A)).onPress(() { - Navigator.pushNamed(context, AppRoutes.offersAndDiscounts); - }), - ], + child: ClipRRect( + borderRadius: const BorderRadius.all( + Radius.circular(50), + ), + child: Hero( + tag: "ItemImage" + data.getOffersList[index].offersDiscountId.toString()!, + transitionOnUserGestures: true, + child: Image.network( + data.getOffersList[index].logo ?? "", + fit: BoxFit.contain, + ), + ), + ), + ), + 4.height, + Expanded( + child: AppState().isArabic(context) + ? data.getOffersList[index].titleAr!.toText12(isCenter: true, maxLine: 1) + : data.getOffersList[index].titleEn!.toText12(isCenter: true, maxLine: 1), + ), + ], + ), ), - ), - ], - ).paddingOnly(left: 21, right: 21, top: 14, bottom: 14), - ), - ), - ).paddingOnly(left: 21, right: 21, top: 0, bottom: 21), + ); + }, + separatorBuilder: (BuildContext cxt, int index) => 8.width, + itemCount: 9), + ); + }, ), ], ), + Container( width: double.infinity, padding: const EdgeInsets.only(top: 31), @@ -595,7 +726,10 @@ class _DashboardScreenState extends State with WidgetsBindingOb height: Platform.isAndroid ? 70 : 100, child: BottomNavigationBar( items: [ - BottomNavigationBarItem(icon: SvgPicture.asset("assets/icons/home.svg", color: currentIndex == 0 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4), label: LocaleKeys.home.tr()), + BottomNavigationBarItem( + icon: SvgPicture.asset("assets/icons/home.svg", color: currentIndex == 0 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4), + label: LocaleKeys.home.tr(), + ), BottomNavigationBarItem( icon: SvgPicture.asset("assets/icons/create_req.svg", color: currentIndex == 1 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4), label: LocaleKeys.mowadhafhiRequest.tr(), @@ -637,28 +771,28 @@ class _DashboardScreenState extends State with WidgetsBindingOb SvgPicture.asset( "assets/icons/chat/chat.svg", color: - !checkIfPrivilegedForChat() - ? MyColors.lightGreyE3Color - : currentIndex == 4 - ? MyColors.grey3AColor - : cProvider.disbaleChatForThisUser - ? MyColors.lightGreyE3Color - : MyColors.grey98Color, + !checkIfPrivilegedForChat() + ? MyColors.lightGreyE3Color + : currentIndex == 4 + ? MyColors.grey3AColor + : cProvider.disbaleChatForThisUser + ? MyColors.lightGreyE3Color + : MyColors.grey98Color, ).paddingAll(4), Consumer( builder: (BuildContext cxt, ChatProviderModel data, Widget? child) { return !checkIfPrivilegedForChat() ? const SizedBox() : Positioned( - right: 0, - top: 0, - child: Container( - padding: const EdgeInsets.only(left: 4, right: 4), - alignment: Alignment.center, - decoration: BoxDecoration(color: cProvider.disbaleChatForThisUser ? MyColors.pinkDarkColor : MyColors.redColor, borderRadius: BorderRadius.circular(17)), - child: data.chatUConvCounter.toString().toText10(color: Colors.white), - ), - ); + right: 0, + top: 0, + child: Container( + padding: const EdgeInsets.only(left: 4, right: 4), + alignment: Alignment.center, + decoration: BoxDecoration(color: cProvider.disbaleChatForThisUser ? MyColors.pinkDarkColor : MyColors.redColor, borderRadius: BorderRadius.circular(17)), + child: data.chatUConvCounter.toString().toText10(color: Colors.white), + ), + ); }, ), ], @@ -729,4 +863,4 @@ class _DashboardScreenState extends State with WidgetsBindingOb } return false; } -} +} \ No newline at end of file diff --git a/lib/ui/landing/widget/app_drawer.dart b/lib/ui/landing/widget/app_drawer.dart index 4721470..e18518b 100644 --- a/lib/ui/landing/widget/app_drawer.dart +++ b/lib/ui/landing/widget/app_drawer.dart @@ -120,7 +120,7 @@ class _AppDrawerState extends State { menuItem("assets/images/drawer/employee_id.svg", LocaleKeys.employeeDigitalID.tr(), "", closeDrawer: false, onPress: () => showMDialog(context, child: EmployeeDigitialIdDialog())), if (AppState().businessCardPrivilege) menuItem("assets/images/drawer/view_business_card.svg", LocaleKeys.viewBusinessCard.tr(), "", closeDrawer: false, onPress: () => showMDialog(context, child: BusinessCardDialog(), isBusniessCard: true)), - menuItem("assets/images/drawer/logout.svg", LocaleKeys.logout.tr(), "", color: MyColors.redA3Color, closeDrawer: false, onPress: performLogout), + menuItem("assets/images/drawer/logout.svg", LocaleKeys.logout.tr(), "", color: MyColors.redA3Color, closeDrawer: false, onPress: (){Utils.performLogout(context, chatData);}), // menuItem("assets/images/drawer/logout.svg", LocaleKeys.logout.tr(), "", color: MyColors.redA3Color, closeDrawer: false, onPress: () {Navigator.pushNamed(context, AppRoutes.survey,); ], ).expanded, @@ -171,13 +171,13 @@ class _AppDrawerState extends State { setState(() {}); } - void performLogout() async { - AppState().isAuthenticated = false; - AppState().isLogged = false; - AppState().setPostParamsInitConfig(); - chatData.disposeData(); - // SharedPreferences prefs = await SharedPreferences.getInstance(); - // await prefs.clear(); - Navigator.pushNamedAndRemoveUntil(context, AppRoutes.login, (Route route) => false, arguments: null); - } + // void performLogout() async { + // // AppState().isAuthenticated = false; + // // AppState().isLogged = false; + // // AppState().setPostParamsInitConfig(); + // // chatData.disposeData(); + // // // SharedPreferences prefs = await SharedPreferences.getInstance(); + // // // await prefs.clear(); + // // Navigator.pushNamedAndRemoveUntil(context, AppRoutes.login, (Route route) => false, arguments: null); + // } } diff --git a/lib/ui/screens/offers_and_discounts/offers_and_discounts_home.dart b/lib/ui/screens/offers_and_discounts/offers_and_discounts_home.dart index f67a835..dbc2366 100644 --- a/lib/ui/screens/offers_and_discounts/offers_and_discounts_home.dart +++ b/lib/ui/screens/offers_and_discounts/offers_and_discounts_home.dart @@ -39,7 +39,7 @@ class _OffersAndDiscountsHomeState extends State { Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, - appBar: AppBarWidget(context, title: LocaleKeys.offerAndDiscounts.tr(), showHomeButton: true, showLogo: true, logoPath: "assets/icons/mazaya_brand.svg"), + appBar: AppBarWidget(context, title: LocaleKeys.offerAndDiscounts.tr(), showHomeButton: true, showLogo: false, logoPath: "assets/icons/mazaya_brand.svg"), body: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, -- 2.30.2 From b96c460d6b268a9a138a298ef2fab63bfa0f2c78 Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Thu, 23 Oct 2025 15:04:29 +0300 Subject: [PATCH 099/135] Get Notification User Information Updates --- lib/api/worklist/worklist_api_client.dart | 21 ++++++++++++++++--- lib/classes/consts.dart | 4 ++-- .../work_list/sheets/selected_item_sheet.dart | 2 +- lib/ui/work_list/worklist_detail_screen.dart | 2 +- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/lib/api/worklist/worklist_api_client.dart b/lib/api/worklist/worklist_api_client.dart index 51a47bb..626ac6a 100644 --- a/lib/api/worklist/worklist_api_client.dart +++ b/lib/api/worklist/worklist_api_client.dart @@ -216,9 +216,24 @@ class WorkListApiClient { ); } - Future getUserInformation(int pSelectedResopID, String selectedEmployeeNumber) async { - String url = "${ApiConsts.erpRest}Get_UserInformation"; - Map postParams = {"P_SELECTED_RESP_ID": pSelectedResopID, "P_PAGE_LIMIT": 100, "P_PAGE_NUM": 1}; + // Future getUserInformation(int pSelectedResopID, String selectedEmployeeNumber) async { + // String url = "${ApiConsts.erpRest}Get_UserInformation"; + // Map postParams = {"P_SELECTED_RESP_ID": pSelectedResopID, "P_PAGE_LIMIT": 100, "P_PAGE_NUM": 1}; + // postParams.addAll(AppState().postParamsJson); + // if (selectedEmployeeNumber != null) postParams["P_SELECTED_EMPLOYEE_NUMBER"] = selectedEmployeeNumber; + // return await ApiClient().postJsonForObject( + // (json) { + // GenericResponseModel responseData = GenericResponseModel.fromJson(json); + // return responseData.memberInformationList![0]; + // }, + // url, + // postParams, + // ); + // } + + Future getNotificationUserInformation(int pSelectedResopID, String selectedEmployeeNumber, int pNotificationID) async { + String url = "${ApiConsts.erpRest}Get_Notification_UserInformation"; + Map postParams = {"P_SELECTED_RESP_ID": pSelectedResopID, "P_PAGE_LIMIT": 100, "P_PAGE_NUM": 1, "P_NOTIFICATION_ID": pNotificationID}; postParams.addAll(AppState().postParamsJson); if (selectedEmployeeNumber != null) postParams["P_SELECTED_EMPLOYEE_NUMBER"] = selectedEmployeeNumber; return await ApiClient().postJsonForObject( diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 51e8066..0f939bf 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -9,9 +9,9 @@ class ApiConsts { // static String baseUrl = "https://webservices.hmg.com"; // PreProd // static String baseUrl = "https://hmgwebservices.com"; // Live server - static String baseUrl = "https://mohemm.hmg.com"; // New Live server + // static String baseUrl = "https://mohemm.hmg.com"; // New Live server // - // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver + static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.20.200.111:1010/"; // static String baseUrl = "https://webservices.hmg.com"; // PreProd diff --git a/lib/ui/work_list/sheets/selected_item_sheet.dart b/lib/ui/work_list/sheets/selected_item_sheet.dart index 2efe88b..9b98c8b 100644 --- a/lib/ui/work_list/sheets/selected_item_sheet.dart +++ b/lib/ui/work_list/sheets/selected_item_sheet.dart @@ -175,7 +175,7 @@ class SelectedItemSheet extends StatelessWidget { if (favoriteReplacements != null) empID = favoriteReplacements!.userName; if (replacementList != null) empID = replacementList!.userName; try { - memberInformationListModel = await WorkListApiClient().getUserInformation(-999, empID!); + memberInformationListModel = await WorkListApiClient().getNotificationUserInformation(-999, empID!, notificationID!); if (actionHistoryList != null) empID = actionHistoryList!.eMPLOYEEIMAGE = memberInformationListModel!.eMPLOYEEIMAGE ?? AppState().getBase64ImageEmp; if (favoriteReplacements != null) empID = favoriteReplacements!.employeeImage = memberInformationListModel!.eMPLOYEEIMAGE ?? AppState().getBase64ImageEmp; if (replacementList != null) empID = replacementList!.employeeImage = memberInformationListModel!.eMPLOYEEIMAGE ?? AppState().getBase64ImageEmp; diff --git a/lib/ui/work_list/worklist_detail_screen.dart b/lib/ui/work_list/worklist_detail_screen.dart index f1a7a3e..20cb0ea 100644 --- a/lib/ui/work_list/worklist_detail_screen.dart +++ b/lib/ui/work_list/worklist_detail_screen.dart @@ -813,7 +813,7 @@ class _WorkListDetailScreenState extends State { if (apiCallCount == 0) Utils.showLoading(context); apiCallCount++; memberInformationListModel = null; - memberInformationListModel = await WorkListApiClient().getUserInformation(-999, workListData!.sELECTEDEMPLOYEENUMBER!); + memberInformationListModel = await WorkListApiClient().getNotificationUserInformation(-999, workListData!.sELECTEDEMPLOYEENUMBER!, workListData!.nOTIFICATIONID!); apiCallCount--; if (apiCallCount == 0) { Utils.hideLoading(context); -- 2.30.2 From c9d5ab98a3ceb7b3ee3abf1b3afa40edf98cce2e Mon Sep 17 00:00:00 2001 From: Sultan khan Date: Tue, 4 Nov 2025 10:03:29 +0300 Subject: [PATCH 100/135] work-list fixes --- lib/api/worklist/worklist_api_client.dart | 15 +++++ lib/classes/consts.dart | 4 +- lib/extensions/string_extensions.dart | 10 +-- lib/generated/codegen_loader.g.dart | 8 ++- lib/generated/locale_keys.g.dart | 3 +- lib/ui/work_list/work_list_screen.dart | 11 ++++ lib/widgets/bottom_sheet.dart | 79 +++++++++++++++++++++++ lib/widgets/item_detail_view_widget.dart | 55 +++++++++++++--- 8 files changed, 167 insertions(+), 18 deletions(-) diff --git a/lib/api/worklist/worklist_api_client.dart b/lib/api/worklist/worklist_api_client.dart index 626ac6a..1adfe29 100644 --- a/lib/api/worklist/worklist_api_client.dart +++ b/lib/api/worklist/worklist_api_client.dart @@ -846,4 +846,19 @@ class WorkListApiClient { postParams, ); } + + + Future?> getFADisposalNtfDetails(int? notificationId) async { + String url = "${ApiConsts.erpRest}GET_PAY_REQ_NOTIFICATION_BODY"; + Map postParams = {"P_NOTIFICATION_ID": notificationId, "P_PAGE_LIMIT": 100, "P_PAGE_NUM": 1}; + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject( + (json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getAbsenceCollectionNotificationBodyList; + }, + url, + postParams, + ); + } } diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 0f939bf..6b43bbd 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -11,11 +11,11 @@ class ApiConsts { // static String baseUrl = "https://mohemm.hmg.com"; // New Live server // - static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver + // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.20.200.111:1010/"; // static String baseUrl = "https://webservices.hmg.com"; // PreProd - // static String baseUrl = "https://mohemm.hmg.com"; + static String baseUrl = "https://mohemm.hmg.com"; // static String baseUrl = "https://hmgwebservices.com"; // Live server static String baseUrlServices = baseUrl + "/Services/"; // server diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index 91ded82..93a6cf8 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -81,28 +81,30 @@ extension EmailValidator on String { ), ); - Widget toText12({Color? color, bool isUnderLine = false, bool isBold = false, bool isCenter = false, int maxLine = 0}) => Text( + Widget toText12({Color? color, bool isUnderLine = false, bool isBold = false, bool isCenter = false, int? maxLine, TextOverflow? overflow}) => Text( this, textAlign: isCenter ? TextAlign.center : null, - maxLines: (maxLine > 0) ? maxLine : null, + maxLines: maxLine == 0 ? null : maxLine, style: TextStyle( fontSize: 12, fontWeight: isBold ? FontWeight.bold : FontWeight.w600, color: color ?? MyColors.darkTextColor, letterSpacing: -0.72, decoration: isUnderLine ? TextDecoration.underline : null, + overflow: TextOverflow.visible ), ); - Widget toText12Auto({Color? color, bool isUnderLine = false, bool isBold = false, bool isCenter = false, int maxLine = 0}) => AutoSizeText( + Widget toText12Auto({Color? color, bool isUnderLine = false, bool isBold = false, bool isCenter = false, int? maxLine,TextOverflow? overflow}) => AutoSizeText( this, textAlign: isCenter ? TextAlign.center : null, - maxLines: (maxLine > 0) ? maxLine : null, + maxLines: maxLine == 0 ? null : maxLine, minFontSize: 8, style: TextStyle( fontSize: 12, fontWeight: isBold ? FontWeight.bold : FontWeight.w600, color: color ?? MyColors.darkTextColor, + overflow: overflow, letterSpacing: -0.72, decoration: isUnderLine ? TextDecoration.underline : null, ), diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index f3fda6a..f4c247c 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -633,7 +633,9 @@ class CodegenLoader extends AssetLoader{ "mazaya": "مازيا", "benefits": "فوائد", "mazayaDesc": "اكتشف الخصومات والعروض الخاصة المتاحة للموظفين", - "viewallofferMazaya": "أعرض كل المزايا" + "viewallofferMazaya": "أعرض كل المزايا", + "faDisposalRequest":"طلب التخلص من FA", + "showMore": "إظهار المزيد" }; static const Map _en_US = { "mohemm": "Mohemm", @@ -1254,7 +1256,9 @@ static const Map _en_US = { "mazaya": "MAZAYA", "benefits": "Benefits", "mazayaDesc": "Discover special Discounts and offers available to Employees", - "viewallofferMazaya": "View All Offers" + "viewallofferMazaya": "View All Offers", + "faDisposalRequest":"FA Disposal Request", + "showMore":"Show More" }; static const Map> mapLocales = {"ar_SA": _ar_SA, "en_US": _en_US}; } diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index b748380..5abf026 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -606,5 +606,6 @@ abstract class LocaleKeys { static const benefits = 'benefits'; static const mazayaDesc = 'mazayaDesc'; static const viewallofferMazaya = 'viewallofferMazaya'; - + static const faRequest = 'faDisposalRequest'; + static const showMore = 'showMore'; } diff --git a/lib/ui/work_list/work_list_screen.dart b/lib/ui/work_list/work_list_screen.dart index 7637cd1..954558d 100644 --- a/lib/ui/work_list/work_list_screen.dart +++ b/lib/ui/work_list/work_list_screen.dart @@ -125,6 +125,17 @@ class _WorkListScreenState extends State { key: 'PAY_REQ', disable: false, ), + // WorkListItemTypeModelData( + // value: 0, + // name: 'FA Disposal Request ', + // fullName: LocaleKeys.faRequest.tr(), + // active: false, + // color: [Color(0xff42d7bf), Color(0xff42d7bf)], + // icon: "assets/images/miss_swipe.svg", + // key: 'HMG_FA_D', + // disable: false, + // ), + ]; int? workListItemIndex; diff --git a/lib/widgets/bottom_sheet.dart b/lib/widgets/bottom_sheet.dart index 4101746..7db0935 100644 --- a/lib/widgets/bottom_sheet.dart +++ b/lib/widgets/bottom_sheet.dart @@ -1,5 +1,8 @@ +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; +import 'package:mohem_flutter_app/classes/colors.dart'; import 'package:mohem_flutter_app/extensions/int_extensions.dart'; +import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; void showMyBottomSheet(BuildContext context, {required Widget child, required VoidCallback callBackFunc, String? type}) { showModalBottomSheet( @@ -49,6 +52,82 @@ void showMyBottomSheet(BuildContext context, {required Widget child, required Vo }); } + + Widget openWorkListBottomSheet(BuildContext context, String? val, String? title){ + return SafeArea( + child: Container( + padding: const EdgeInsets.all(16), + height: MediaQuery.of(context).size.height * 0.3 , // half-screen height + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // ---- Top Row with Title & Close Button ---- + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + title ?? "Details", + style: const TextStyle( + color: Color(0xff2BB8A6), + fontSize: 14, + fontWeight: FontWeight.bold, + ), + ), + IconButton( + icon: const Icon(Icons.close, color: Colors.black54, size: 20), + onPressed: () { + Navigator.pop(context); + }, + ), + ], + ), + const Divider(height: 1, color: Colors.grey), + const SizedBox(height: 12), + + // ---- Scrollable Content ---- + Expanded( + child: SingleChildScrollView( + child: Text( + (val?.isEmpty ?? true) + ? "--" + : val.toString(), + style: TextStyle( + color: MyColors.normalTextColor, + fontSize: 14, + height: 1.4, + ), + ), + ), + ), + SizedBox( + width: double.infinity, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xff2BB8A6), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + padding: const EdgeInsets.symmetric(vertical: 12), + ), + onPressed: () { + Navigator.pop(context); + }, + child: Text( + LocaleKeys.close.tr(), + style: const TextStyle( + color: Colors.white, + fontSize: 14, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], + ), + ), + ); +} + class BottomSheetItem extends StatelessWidget { final Function onTap; final IconData icon; diff --git a/lib/widgets/item_detail_view_widget.dart b/lib/widgets/item_detail_view_widget.dart index 64bbd01..de82afe 100644 --- a/lib/widgets/item_detail_view_widget.dart +++ b/lib/widgets/item_detail_view_widget.dart @@ -1,11 +1,14 @@ import 'dart:convert'; +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:mohem_flutter_app/classes/colors.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/itg_forms_models/itg_worklist_table_model.dart'; +import 'package:mohem_flutter_app/widgets/bottom_sheet.dart'; class ItemDetailView extends StatelessWidget { final String title; @@ -40,7 +43,7 @@ class ItemDetailViewCol extends StatelessWidget { children: [ "$title:".toText12(isBold: true, color: const Color(0xff2BB8A6), maxLine: 2), 4.width, - (value.isEmpty ? "--" : value).toText12(color: MyColors.normalTextColor, maxLine: 5), + Flexible(child: (value.isEmpty ? "--" : value).toText12(color: MyColors.normalTextColor, maxLine: null)), ], ); } @@ -84,18 +87,51 @@ class ItemDetailViewGridItem extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ - title != null ? Flexible(child: "$title:".toText12Auto(isBold: true, color: const Color(0xff2BB8A6))) : Container(), + title != null ? Flexible(child: "$title:".toText12(isBold: true, color: const Color(0xff2BB8A6))) : Container(), 4.width, - type != null - ? type!.toLowerCase() == "table" - ? getStringFromJSON(value!) - // : Flexible(child: (value!.isEmpty ? "--" : value).toString().toText12Auto(color: MyColors.normalTextColor, maxLine: 5)) - : (value!.isEmpty ? "--" : value).toString().toText12Auto(color: MyColors.normalTextColor, maxLine: maxLine) - : Container(), + type != null + ? type!.toLowerCase() == "table" + ? getStringFromJSON(value!) + // : Flexible(child: (value!.isEmpty ? "--" : value).toString().toText12Auto(color: MyColors.normalTextColor, maxLine: 5)) + : (value!.isEmpty ? "--" : value).toString().toText12(color: MyColors.normalTextColor, maxLine: 2) + : Container(), + if (value!.length > 100) + GestureDetector( + onTap: () { + showModalBottomSheet( + context: context, + enableDrag: true, + isDismissible: true, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only(topLeft: Radius.circular(12), topRight: Radius.circular(12)), + ), + backgroundColor: Colors.white, + builder: (context) { + return openWorkListBottomSheet(context, value, title); + }, + ); + + }, + child: Padding( + padding: const EdgeInsets.only(top: 4), + child: Text( + LocaleKeys.showMore.tr(), + textAlign: TextAlign.right, + style: const TextStyle( + color: Color(0xff2BB8A6), + fontSize: 12, + fontWeight: FontWeight.w600, + + ), + ), + ), + ), ], - ).paddingOnly(top: showSpaceAfterLine ? 16 : 0), + + ).paddingOnly(top: showSpaceAfterLine ? 16 : 0, left: 2, right: 2), ); } + } class ItemDetailGrid extends StatelessWidget { @@ -153,3 +189,4 @@ Widget getStringFromJSON(String jsonString) { return Flexible(child: ("-").toString().toText12Auto(color: MyColors.normalTextColor)); } } + -- 2.30.2 From fb35e256e7637e2e3690bb155153a8ec0c99f816 Mon Sep 17 00:00:00 2001 From: Sultan khan Date: Mon, 10 Nov 2025 10:14:13 +0300 Subject: [PATCH 101/135] CS Standard Change Request CR-7260 Fixed Asset Disposal Request amendment --- assets/langs/ar-SA.json | 24 +- assets/langs/en-US.json | 25 +- lib/api/worklist/worklist_api_client.dart | 7 +- lib/classes/consts.dart | 4 +- lib/generated/codegen_loader.g.dart | 48 +++- lib/generated/locale_keys.g.dart | 23 +- lib/models/generic_response_model.dart | 7 + .../worklist/get_fad_notifications.dart | 233 ++++++++++++++++++ lib/ui/work_list/work_list_screen.dart | 20 +- lib/ui/work_list/worklist_detail_screen.dart | 24 +- .../worklist_fragments/info_fragments.dart | 132 +++++++++- 11 files changed, 520 insertions(+), 27 deletions(-) create mode 100644 lib/models/worklist/get_fad_notifications.dart diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 08b00da..916e8fb 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -620,5 +620,27 @@ "mazaya": "مازيا", "benefits": "فوائد", "mazayaDesc": "اكتشف الخصومات والعروض الخاصة المتاحة للموظفين", - "viewallofferMazaya" : "أعرض كل المزايا" + "viewallofferMazaya" : "أعرض كل المزايا", + "buyerName": "اسم المشتري", + "buyerNumber": "رقم المشتري", + "highestBidder": "أعلى مزايد", + "remarks": "ملاحظات", + "faHeader": "تفاصيل رأس الصفحة FA", + "bookTypeCode": "رمز نوع الكتاب", + "categoryCode": "رمز الفئة", + "categoryGroup": "مجموعة الفئات", + "faLINES": "تفاصيل الأصول", + "assetNumber": "رقم الأصول", + "assetDescription": "وصف الأصول", + "barCodeNumber": "رقم الباركود", + "datePlaceInService": "تاريخ وضعه في الخدمة", + "serialNumber": "رقم سري", + "disposedDate": "تاريخ التخلص", + "netBookValue": "القيمة الدفترية الصافية", + "purchasedPrice": "سعر الشراء", + "usefulLife": "العمر الإنتاجي", + "yearsUsed": "سنوات الاستخدام", + "faRequest": "طلب التخلص من FA", + "showMore": "عرض المزيد", + "buyerDetails": "تفاصيل المشتري" } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index ff30994..5fcb35c 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -618,6 +618,27 @@ "mazaya": "MAZAYA", "benefits": "Benefits", "mazayaDesc": "Discover special Discounts and offers available to Employees", - "viewallofferMazaya" : "View All Offers" - + "viewallofferMazaya" : "View All Offers", + "buyerName": "Buyer Name", + "buyerNumber": "Buyer Number", + "highestBidder": "Highest Bidder", + "remarks": "Remarks", + "faHeader": "FA Header Details", + "bookTypeCode": "Book Type Code", + "categoryCode": "Category Code", + "categoryGroup": "Category Group", + "faLINES": "Asset Details", + "assetNumber": "Asset Number", + "assetDescription": "Asset Description", + "barCodeNumber": "BarCode Number", + "datePlaceInService": "Date place In Service", + "serialNumber": "Serial Number", + "disposedDate": "Disposed Date", + "netBookValue": "Net Book Value", + "purchasedPrice": "Purchased Price", + "usefulLife": "Useful Life", + "yearsUsed": "Years Used", + "faRequest":"FA Disposal Request", + "showMore": "Show More", + "buyerDetails": "Buyer Details" } \ No newline at end of file diff --git a/lib/api/worklist/worklist_api_client.dart b/lib/api/worklist/worklist_api_client.dart index 1adfe29..10d9472 100644 --- a/lib/api/worklist/worklist_api_client.dart +++ b/lib/api/worklist/worklist_api_client.dart @@ -28,6 +28,7 @@ import 'package:mohem_flutter_app/models/notification_get_respond_attributes_lis import 'package:mohem_flutter_app/models/termination/termination_notification_body.dart'; import 'package:mohem_flutter_app/models/update_user_item_type_list.dart'; import 'package:mohem_flutter_app/models/worklist/GetRFCEmployeeList.dart'; +import 'package:mohem_flutter_app/models/worklist/get_fad_notifications.dart'; import 'package:mohem_flutter_app/models/worklist/get_favorite_replacements_model.dart'; import 'package:mohem_flutter_app/models/worklist/hr/eit_otification_body_model.dart'; import 'package:mohem_flutter_app/models/worklist/hr/get_address_notification_body_list.dart'; @@ -848,14 +849,14 @@ class WorkListApiClient { } - Future?> getFADisposalNtfDetails(int? notificationId) async { - String url = "${ApiConsts.erpRest}GET_PAY_REQ_NOTIFICATION_BODY"; + Future getFADNotificationBody(int? notificationId) async { + String url = "${ApiConsts.erpRest}GetFADisposalNtfDetails"; Map postParams = {"P_NOTIFICATION_ID": notificationId, "P_PAGE_LIMIT": 100, "P_PAGE_NUM": 1}; postParams.addAll(AppState().postParamsJson); return await ApiClient().postJsonForObject( (json) { GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData.getAbsenceCollectionNotificationBodyList; + return responseData.getFADisposalNtfDetails; }, url, postParams, diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 6b43bbd..cfc240f 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -4,7 +4,7 @@ class ApiConsts { // static String baseUrl = "http://10.200.204.11"; // Local server // static String baseUrl = "https://erptstapp.srca.org.sa"; // SRCA server - // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver + static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.201.204.101:2024"; // static String baseUrl = "https://webservices.hmg.com"; // PreProd // static String baseUrl = "https://hmgwebservices.com"; // Live server @@ -15,7 +15,7 @@ class ApiConsts { // static String baseUrl = "http://10.20.200.111:1010/"; // static String baseUrl = "https://webservices.hmg.com"; // PreProd - static String baseUrl = "https://mohemm.hmg.com"; + // static String baseUrl = "https://mohemm.hmg.com"; // static String baseUrl = "https://hmgwebservices.com"; // Live server static String baseUrlServices = baseUrl + "/Services/"; // server diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index f4c247c..6feb438 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -634,8 +634,28 @@ class CodegenLoader extends AssetLoader{ "benefits": "فوائد", "mazayaDesc": "اكتشف الخصومات والعروض الخاصة المتاحة للموظفين", "viewallofferMazaya": "أعرض كل المزايا", - "faDisposalRequest":"طلب التخلص من FA", - "showMore": "إظهار المزيد" + "buyerName": "اسم المشتري", + "buyerNumber": "رقم المشتري", + "highestBidder": "أعلى مزايد", + "remarks": "ملاحظات", + "faHeader": "تفاصيل رأس الصفحة FA", + "bookTypeCode": "رمز نوع الكتاب", + "categoryCode": "رمز الفئة", + "categoryGroup": "مجموعة الفئات", + "faLINES": "تفاصيل الأصول", + "assetNumber": "رقم الأصول", + "assetDescription": "وصف الأصول", + "barCodeNumber": "رقم الباركود", + "datePlaceInService": "تاريخ وضعه في الخدمة", + "serialNumber": "رقم سري", + "disposedDate": "تاريخ التخلص", + "netBookValue": "القيمة الدفترية الصافية", + "purchasedPrice": "سعر الشراء", + "usefulLife": "العمر الإنتاجي", + "yearsUsed": "سنوات الاستخدام", + "faRequest": "طلب التخلص من FA", + "showMore": "عرض المزيد", + "buyerDetails": "تفاصيل المشتري" }; static const Map _en_US = { "mohemm": "Mohemm", @@ -1257,8 +1277,28 @@ static const Map _en_US = { "benefits": "Benefits", "mazayaDesc": "Discover special Discounts and offers available to Employees", "viewallofferMazaya": "View All Offers", - "faDisposalRequest":"FA Disposal Request", - "showMore":"Show More" + "buyerName": "Buyer Name", + "buyerNumber": "Buyer Number", + "highestBidder": "Highest Bidder", + "remarks": "Remarks", + "faHeader": "FA Header Details", + "bookTypeCode": "Book Type Code", + "categoryCode": "Category Code", + "categoryGroup": "Category Group", + "faLINES": "Asset Details", + "assetNumber": "Asset Number", + "assetDescription": "Asset Description", + "barCodeNumber": "BarCode Number", + "datePlaceInService": "Date place In Service", + "serialNumber": "Serial Number", + "disposedDate": "Disposed Date", + "netBookValue": "Net Book Value", + "purchasedPrice": "Purchased Price", + "usefulLife": "Useful Life", + "yearsUsed": "Years Used", + "faRequest": "FA Disposal Request", + "showMore": "Show More", + "buyerDetails": "Buyer Details" }; static const Map> mapLocales = {"ar_SA": _ar_SA, "en_US": _en_US}; } diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 5abf026..1a1cf95 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -606,6 +606,27 @@ abstract class LocaleKeys { static const benefits = 'benefits'; static const mazayaDesc = 'mazayaDesc'; static const viewallofferMazaya = 'viewallofferMazaya'; - static const faRequest = 'faDisposalRequest'; + static const buyerName = 'buyerName'; + static const buyerNumber = 'buyerNumber'; + static const highestBidder = 'highestBidder'; + static const remarks = 'remarks'; + static const faHeader = 'faHeader'; + static const bookTypeCode = 'bookTypeCode'; + static const categoryCode = 'categoryCode'; + static const categoryGroup = 'categoryGroup'; + static const faLINES = 'faLINES'; + static const assetNumber = 'assetNumber'; + static const assetDescription = 'assetDescription'; + static const barCodeNumber = 'barCodeNumber'; + static const datePlaceInService = 'datePlaceInService'; + static const serialNumber = 'serialNumber'; + static const disposedDate = 'disposedDate'; + static const netBookValue = 'netBookValue'; + static const purchasedPrice = 'purchasedPrice'; + static const usefulLife = 'usefulLife'; + static const yearsUsed = 'yearsUsed'; + static const faRequest = 'faRequest'; static const showMore = 'showMore'; + static const buyerDetails = 'buyerDetails'; + } diff --git a/lib/models/generic_response_model.dart b/lib/models/generic_response_model.dart index 74cef13..8c653aa 100644 --- a/lib/models/generic_response_model.dart +++ b/lib/models/generic_response_model.dart @@ -107,6 +107,7 @@ import 'package:mohem_flutter_app/models/vacation_rule/vr_item_types_list_model. import 'package:mohem_flutter_app/models/vacation_rule/wf_look_up_list_model.dart'; import 'package:mohem_flutter_app/models/validate_eit_transaction_list_model.dart'; import 'package:mohem_flutter_app/models/worklist/GetRFCEmployeeList.dart'; +import 'package:mohem_flutter_app/models/worklist/get_fad_notifications.dart'; import 'package:mohem_flutter_app/models/worklist/get_favorite_replacements_model.dart'; import 'package:mohem_flutter_app/models/worklist/hr/eit_otification_body_model.dart'; import 'package:mohem_flutter_app/models/worklist/hr/get_address_notification_body_list.dart'; @@ -386,6 +387,7 @@ class GenericResponseModel { String? validatePhonesTransactionList; List? vrItemTypesList; List? wFLookUpList; + GetFaDisposalNtfDetails? getFADisposalNtfDetails; String? eLearningGETEMPLOYEEPROFILEList; String? eLearningLOGINList; String? eLearningValidateLoginList; @@ -664,6 +666,7 @@ class GenericResponseModel { this.ePharmacyGetItemOnHandList, this.isActiveCode, this.isSMSSent, + this.getFADisposalNtfDetails }); GenericResponseModel.fromJson(Map json) { @@ -933,6 +936,9 @@ class GenericResponseModel { }); } + getFADisposalNtfDetails = json['GetFADisposalNtfDetails'] != null ? GetFaDisposalNtfDetails.fromJson(json['GetFADisposalNtfDetails']) : null; + + if (json['GetEarningsList'] != null) { getEarningsList = []; json['GetEarningsList'].forEach((v) { @@ -1549,6 +1555,7 @@ class GenericResponseModel { if (this.getActionHistoryList != null) { data['GetActionHistoryList'] = this.getActionHistoryList!.map((v) => v.toJson()).toList(); } + data['GetFADisposalNtfDetails'] =this.getFADisposalNtfDetails; data['GetAddressDffStructureList'] = this.getAddressDffStructureList; data['GetAddressNotificationBodyList'] = this.getAddressNotificationBodyList; diff --git a/lib/models/worklist/get_fad_notifications.dart b/lib/models/worklist/get_fad_notifications.dart new file mode 100644 index 0000000..3a7ed2d --- /dev/null +++ b/lib/models/worklist/get_fad_notifications.dart @@ -0,0 +1,233 @@ +import 'dart:convert'; + +class GetFaDisposalNtfDetails { + List? pFaBuyers; + List? pFaHeader; + List? pFaLines; + String? pInformation; + dynamic pQuestion; + + GetFaDisposalNtfDetails({ + this.pFaBuyers, + this.pFaHeader, + this.pFaLines, + this.pInformation, + this.pQuestion, + }); + + factory GetFaDisposalNtfDetails.fromRawJson(String str) => GetFaDisposalNtfDetails.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory GetFaDisposalNtfDetails.fromJson(Map json) => GetFaDisposalNtfDetails( + pFaBuyers: json["P_FA_BUYERS"] == null ? [] : List.from(json["P_FA_BUYERS"]!.map((x) => PFaBuyer.fromJson(x))), + pFaHeader: json["P_FA_HEADER"] == null ? [] : List.from(json["P_FA_HEADER"]!.map((x) => PFaHeader.fromJson(x))), + pFaLines: json["P_FA_LINES"] == null ? [] : List.from(json["P_FA_LINES"]!.map((x) => PFaLine.fromJson(x))), + pInformation: json["P_INFORMATION"], + pQuestion: json["P_QUESTION"], + ); + + Map toJson() => { + "P_FA_BUYERS": pFaBuyers == null ? [] : List.from(pFaBuyers!.map((x) => x.toJson())), + "P_FA_HEADER": pFaHeader == null ? [] : List.from(pFaHeader!.map((x) => x.toJson())), + "P_FA_LINES": pFaLines == null ? [] : List.from(pFaLines!.map((x) => x.toJson())), + "P_INFORMATION": pInformation, + "P_QUESTION": pQuestion, + }; +} + +class PFaBuyer { + int? amount; + String? buyerName; + String? buyerNumber; + int? fromRowNum; + String? highestBidder; + int? noOfRows; + String? receiptNumber; + String? remarks; + int? requestNo; + int? rowNum; + int? toRowNum; + + PFaBuyer({ + this.amount, + this.buyerName, + this.buyerNumber, + this.fromRowNum, + this.highestBidder, + this.noOfRows, + this.receiptNumber, + this.remarks, + this.requestNo, + this.rowNum, + this.toRowNum, + }); + + factory PFaBuyer.fromRawJson(String str) => PFaBuyer.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory PFaBuyer.fromJson(Map json) => PFaBuyer( + amount: json["AMOUNT"], + buyerName: json["BUYER_NAME"], + buyerNumber: json["BUYER_NUMBER"], + fromRowNum: json["FROM_ROW_NUM"], + highestBidder: json["HIGHEST_BIDDER"], + noOfRows: json["NO_OF_ROWS"], + receiptNumber: json["RECEIPT_NUMBER"], + remarks: json["REMARKS"], + requestNo: json["REQUEST_NO"], + rowNum: json["ROW_NUM"], + toRowNum: json["TO_ROW_NUM"], + ); + + Map toJson() => { + "AMOUNT": amount, + "BUYER_NAME": buyerName, + "BUYER_NUMBER": buyerNumber, + "FROM_ROW_NUM": fromRowNum, + "HIGHEST_BIDDER": highestBidder, + "NO_OF_ROWS": noOfRows, + "RECEIPT_NUMBER": receiptNumber, + "REMARKS": remarks, + "REQUEST_NO": requestNo, + "ROW_NUM": rowNum, + "TO_ROW_NUM": toRowNum, + }; +} + +class PFaHeader { + String? bookTypeCode; + String? categoryCode; + String? categoryGroup; + String? comments; + int? requestNo; + String? status; + + PFaHeader({ + this.bookTypeCode, + this.categoryCode, + this.categoryGroup, + this.comments, + this.requestNo, + this.status, + }); + + factory PFaHeader.fromRawJson(String str) => PFaHeader.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory PFaHeader.fromJson(Map json) => PFaHeader( + bookTypeCode: json["BOOK_TYPE_CODE"], + categoryCode: json["CATEGORY_CODE"], + categoryGroup: json["CATEGORY_GROUP"], + comments: json["COMMENTS"], + requestNo: json["REQUEST_NO"], + status: json["STATUS"], + ); + + Map toJson() => { + "BOOK_TYPE_CODE": bookTypeCode, + "CATEGORY_CODE": categoryCode, + "CATEGORY_GROUP": categoryGroup, + "COMMENTS": comments, + "REQUEST_NO": requestNo, + "STATUS": status, + }; +} + +class PFaLine { + String? action; + String? assetDescription; + int? assetNumber; + String? barcodeNumber; + String? bme; + String? datePlacedInService; + String? department; + String? disposedDate; + int? fromRowNum; + double? netBookValue; + int? noOfRows; + String? poNumber; + double? purchasePrice; + int? quantity; + int? requestNo; + int? rowNum; + String? serialNumber; + int? toRowNum; + int? usefulLife; + String? yearsUsed; + + PFaLine({ + this.action, + this.assetDescription, + this.assetNumber, + this.barcodeNumber, + this.bme, + this.datePlacedInService, + this.department, + this.disposedDate, + this.fromRowNum, + this.netBookValue, + this.noOfRows, + this.poNumber, + this.purchasePrice, + this.quantity, + this.requestNo, + this.rowNum, + this.serialNumber, + this.toRowNum, + this.usefulLife, + this.yearsUsed, + }); + + factory PFaLine.fromRawJson(String str) => PFaLine.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory PFaLine.fromJson(Map json) => PFaLine( + action: json["ACTION"], + assetDescription: json["ASSET_DESCRIPTION"], + assetNumber: json["ASSET_NUMBER"], + barcodeNumber: json["BARCODE_NUMBER"], + bme: json["BME"], + datePlacedInService: json["DATE_PLACED_IN_SERVICE"], + department: json["DEPARTMENT"], + disposedDate: json["DISPOSED_DATE"], + fromRowNum: json["FROM_ROW_NUM"], + netBookValue: json["NET_BOOK_VALUE"]?.toDouble(), + noOfRows: json["NO_OF_ROWS"], + poNumber: json["PO_NUMBER"], + purchasePrice: json["PURCHASE_PRICE"]?.toDouble(), + quantity: json["QUANTITY"], + requestNo: json["REQUEST_NO"], + rowNum: json["ROW_NUM"], + serialNumber: json["SERIAL_NUMBER"], + toRowNum: json["TO_ROW_NUM"], + usefulLife: json["USEFUL_LIFE"], + yearsUsed: json["YEARS_USED"], + ); + + Map toJson() => { + "ACTION": action, + "ASSET_DESCRIPTION": assetDescription, + "ASSET_NUMBER": assetNumber, + "BARCODE_NUMBER": barcodeNumber, + "BME": bme, + "DATE_PLACED_IN_SERVICE": datePlacedInService, + "DEPARTMENT": department, + "DISPOSED_DATE": disposedDate, + "FROM_ROW_NUM": fromRowNum, + "NET_BOOK_VALUE": netBookValue, + "NO_OF_ROWS": noOfRows, + "PO_NUMBER": poNumber, + "PURCHASE_PRICE": purchasePrice, + "QUANTITY": quantity, + "REQUEST_NO": requestNo, + "ROW_NUM": rowNum, + "SERIAL_NUMBER": serialNumber, + "TO_ROW_NUM": toRowNum, + "USEFUL_LIFE": usefulLife, + "YEARS_USED": yearsUsed, + }; +} diff --git a/lib/ui/work_list/work_list_screen.dart b/lib/ui/work_list/work_list_screen.dart index 954558d..d659ea6 100644 --- a/lib/ui/work_list/work_list_screen.dart +++ b/lib/ui/work_list/work_list_screen.dart @@ -125,16 +125,16 @@ class _WorkListScreenState extends State { key: 'PAY_REQ', disable: false, ), - // WorkListItemTypeModelData( - // value: 0, - // name: 'FA Disposal Request ', - // fullName: LocaleKeys.faRequest.tr(), - // active: false, - // color: [Color(0xff42d7bf), Color(0xff42d7bf)], - // icon: "assets/images/miss_swipe.svg", - // key: 'HMG_FA_D', - // disable: false, - // ), + WorkListItemTypeModelData( + value: 0, + name: 'FA Disposal Request ', + fullName: LocaleKeys.faRequest.tr(), + active: false, + color: [Color(0xff42d7bf), Color(0xff42d7bf)], + icon: "assets/images/miss_swipe.svg", + key: 'HMG_FA_D', + disable: false, + ), ]; diff --git a/lib/ui/work_list/worklist_detail_screen.dart b/lib/ui/work_list/worklist_detail_screen.dart index 20cb0ea..6bf8ea9 100644 --- a/lib/ui/work_list/worklist_detail_screen.dart +++ b/lib/ui/work_list/worklist_detail_screen.dart @@ -25,6 +25,7 @@ import 'package:mohem_flutter_app/models/member_information_list_model.dart'; import 'package:mohem_flutter_app/models/notification_get_respond_attributes_list_model.dart'; import 'package:mohem_flutter_app/models/termination/termination_notification_body.dart'; import 'package:mohem_flutter_app/models/worklist/GetRFCEmployeeList.dart'; +import 'package:mohem_flutter_app/models/worklist/get_fad_notifications.dart'; import 'package:mohem_flutter_app/models/worklist/hr/eit_otification_body_model.dart'; import 'package:mohem_flutter_app/models/worklist/hr/get_address_notification_body_list.dart'; import 'package:mohem_flutter_app/models/worklist/hr/get_basic_det_ntf_body_list_model.dart'; @@ -92,7 +93,7 @@ class _WorkListDetailScreenState extends State { GetPrNotificationBodyList? getPrNotificationBody; GetItemCreationNtfBodyList? getItemCreationNtfBody; GetPaymentNotificationBodyList? getPaymentNotificationBodyList; - + GetFaDisposalNtfDetails? getFADNotificationBody; bool isCloseAvailable = false; bool isApproveAvailable = false; bool isRejectAvailable = false; @@ -177,6 +178,9 @@ class _WorkListDetailScreenState extends State { if (workListData!.iTEMTYPE == "PAY_REQ") { getPaymentNotification(); } + if (workListData!.iTEMTYPE == "HMG_FA_D") { + getFADNotification(); + } if (controller.hasClients) { controller.jumpToPage(0); @@ -272,6 +276,7 @@ class _WorkListDetailScreenState extends State { getPrNotificationBodyList: getPrNotificationBody, getTerminationNotificationBodyList: getTerminationNotificationBodyList, getPaymentNotificationBodyList: getPaymentNotificationBodyList, + getFADNotificationBodyList: getFADNotificationBody ), (workListData!.iTEMTYPE == "HRSSA" || workListData!.iTEMTYPE == "STAMP" || workListData!.iTEMTYPE == "PAY_REQ") ? DetailFragment(workListData, memberInformationListModel) @@ -1036,6 +1041,23 @@ class _WorkListDetailScreenState extends State { } } + Future getFADNotification() async { + try { + if (apiCallCount == 0) Utils.showLoading(context); + apiCallCount++; + getFADNotificationBody = await WorkListApiClient().getFADNotificationBody(workListData!.nOTIFICATIONID); + apiCallCount--; + if (apiCallCount == 0) { + Utils.hideLoading(context); + setState(() {}); + } + } catch (ex) { + apiCallCount--; + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + } + } + void notificationGetRespondAttributes() async { try { if (apiCallCount == 0) Utils.showLoading(context); diff --git a/lib/ui/work_list/worklist_fragments/info_fragments.dart b/lib/ui/work_list/worklist_fragments/info_fragments.dart index 73a87f7..541d347 100644 --- a/lib/ui/work_list/worklist_fragments/info_fragments.dart +++ b/lib/ui/work_list/worklist_fragments/info_fragments.dart @@ -12,6 +12,7 @@ import 'package:mohem_flutter_app/models/get_po_notification_body_list_model.dar import 'package:mohem_flutter_app/models/get_pr_notification_body_list_model.dart'; import 'package:mohem_flutter_app/models/get_stamp_ms_notification_body_list_model.dart'; import 'package:mohem_flutter_app/models/get_stamp_ns_notification_body_list_model.dart'; +import 'package:mohem_flutter_app/models/worklist/get_fad_notifications.dart'; import 'package:mohem_flutter_app/models/worklist/hr/eit_otification_body_model.dart'; import 'package:mohem_flutter_app/models/worklist/hr/get_address_notification_body_list.dart'; import 'package:mohem_flutter_app/models/worklist/hr/get_basic_det_ntf_body_list_model.dart'; @@ -39,7 +40,7 @@ class InfoFragment extends StatelessWidget { List? getAddressNotificationBodyList = []; List? getTerminationNotificationBodyList = []; GetPaymentNotificationBodyList? getPaymentNotificationBodyList; - + GetFaDisposalNtfDetails? getFADNotificationBodyList; InfoFragment( {this.workListData, this.poHeaderList = const [], @@ -54,7 +55,9 @@ class InfoFragment extends StatelessWidget { this.getPrNotificationBodyList, this.getAddressNotificationBodyList, this.getTerminationNotificationBodyList, - this.getPaymentNotificationBodyList}); + this.getPaymentNotificationBodyList, + this.getFADNotificationBodyList + }); double itemHeight = 0; double itemWidth = 0; @@ -129,7 +132,10 @@ class InfoFragment extends StatelessWidget { getTerminationNotificationBodyList!), if (getPaymentNotificationBodyList != null) getPaymentNotificationBodyListWidget(getPaymentNotificationBodyList ?? - GetPaymentNotificationBodyList()) + GetPaymentNotificationBodyList()), + if (getFADNotificationBodyList != null) + getFANotificationBodyListWidget(getFADNotificationBodyList ?? + GetFaDisposalNtfDetails()) .objectContainerView(), ]; return Container( @@ -922,5 +928,125 @@ class InfoFragment extends StatelessWidget { ], ); + } + + Widget getFANotificationBodyListWidget( + GetFaDisposalNtfDetails? data) { + return Column( + children: [ + 12.height, + + if (data!.pFaHeader!.isNotEmpty) + Column( + children: [ + LocaleKeys.faHeader.tr().toText14(color: MyColors.textMixColor), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.requestNo.tr(), + data.pFaHeader![0].requestNo.toString() ?? ""), + ItemDetailViewCol( + LocaleKeys.stats.tr(), data.pFaHeader![0].status ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol( + LocaleKeys.bookTypeCode.tr(), data.pFaHeader![0].bookTypeCode ?? ""), + ItemDetailViewCol(LocaleKeys.categoryCode.tr(), + data.pFaHeader![0].categoryCode ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.categoryGroup.tr(), + data.pFaHeader![0].categoryGroup ?? ""), + ItemDetailViewCol( + LocaleKeys.comments.tr(), data.pFaHeader![0].comments ?? ""), + ), + + + ], + ).objectContainerView(), + if (data!.pFaLines!.isNotEmpty) + Column( + children: [ + LocaleKeys.faLINES.tr().toText14(color: MyColors.textMixColor), + ItemDetailGrid( + ItemDetailViewCol( LocaleKeys.requestNo.tr(), + data.pFaLines![0].requestNo.toString() ?? ""), + ItemDetailViewCol( + LocaleKeys.quantity.tr(), data.pFaLines![0].quantity.toString() ?? "" ), + + ), + ItemDetailGrid( + ItemDetailViewCol( + LocaleKeys.assetNumber.tr(), data.pFaLines![0].assetNumber.toString() ?? ""), + ItemDetailViewCol(LocaleKeys.assetDescription.tr(), + data.pFaLines![0].assetDescription ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.barCodeNumber.tr(), + data.pFaLines![0] .barcodeNumber.toString() ?? ""), + ItemDetailViewCol( + LocaleKeys.datePlaceInService.tr(), DateUtil.formatDateToDate( + DateUtil.convertStringToDate( data.pFaLines![0].datePlacedInService ?? ""), false)), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.departmentName.tr(), + data.pFaLines![0].department ?? ""), + ItemDetailViewCol(LocaleKeys.serialNumber.tr(), + data.pFaLines![0].serialNumber ?? "") , + ), + ItemDetailGrid( + ItemDetailViewCol( + LocaleKeys.disposedDate.tr(), DateUtil.formatDateToDate( + DateUtil.convertStringToDate( data.pFaLines![0].disposedDate ?? ""), false)), + ItemDetailViewCol(LocaleKeys.netBookValue.tr(), + data.pFaLines![0].netBookValue.toString() ?? ""), + + ), + ItemDetailGrid( + ItemDetailViewCol( + LocaleKeys.poNumber.tr(), data.pFaLines![0].poNumber.toString() ?? "" ), + ItemDetailViewCol(LocaleKeys.purchasedPrice.tr(), + data.pFaLines![0].purchasePrice.toString() ?? ""), + + ), + ItemDetailGrid( + ItemDetailViewCol( + LocaleKeys.usefulLife.tr(), data.pFaLines![0].usefulLife.toString() ?? "" ), + ItemDetailViewCol(LocaleKeys.yearsUsed.tr(), + data.pFaLines![0].yearsUsed.toString() ?? ""), + + ), + ], + ).objectContainerView(), + + if (data!.pFaBuyers!.isNotEmpty) + Column( + children: [ + LocaleKeys.buyer.tr().toText14(color: MyColors.textMixColor), + ItemDetailGrid( + ItemDetailViewCol( + LocaleKeys.requestNo.tr(), data.pFaBuyers![0].requestNo.toString() ?? ""), + ItemDetailViewCol( LocaleKeys.amount.tr(), + data.pFaBuyers![0].amount.toString() ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol(LocaleKeys.buyerNumber.tr(), + data.pFaBuyers![0].buyerName!), + ItemDetailViewCol( + LocaleKeys.buyerNumber.tr(), data.pFaBuyers![0].buyerNumber ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol( LocaleKeys.highestBidder.tr(), + data.pFaBuyers![0].highestBidder ?? ""), + ItemDetailViewCol( + LocaleKeys.remarks.tr(), data.pFaBuyers![0].remarks ?? ""), + ), + + ], + ).objectContainerView(), + + ]); + + + + } } -- 2.30.2 From 3d91a1444e5681ea9fe220a9a09e5512aea26468 Mon Sep 17 00:00:00 2001 From: Sultan khan Date: Wed, 26 Nov 2025 12:06:37 +0300 Subject: [PATCH 102/135] wallet ticket fix --- lib/ui/landing/widget/menus_widget.dart | 31 +++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/lib/ui/landing/widget/menus_widget.dart b/lib/ui/landing/widget/menus_widget.dart index bc5dceb..be04937 100644 --- a/lib/ui/landing/widget/menus_widget.dart +++ b/lib/ui/landing/widget/menus_widget.dart @@ -1,13 +1,17 @@ import 'package:easy_localization/src/public_ext.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:mohem_flutter_app/api/eit_api_client.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; +import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/config/routes.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/sso_auth_model.dart'; import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; import 'package:mohem_flutter_app/ui/my_attendance/dynamic_screens/dynamic_listview_screen.dart'; +import 'package:mohem_flutter_app/ui/screens/ticket/ticket_detailed_screen.dart'; import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart'; import 'package:provider/provider.dart'; @@ -117,8 +121,31 @@ class MenusWidget extends StatelessWidget { ), ], ).paddingOnly(left: 10, right: 10, bottom: 6, top: 6), - ).onPress(() { - Navigator.pushNamed(context, AppRoutes.dynamicScreen, arguments: DynamicListViewParams(LocaleKeys.ticketBalance.tr(), "HMG_TKT_NEW_EIT_SS")); + ).onPress(() async { + // + // // Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => TicketDetailedScreen(url: url, jwtToken: ssoToken.data!.accessToken))); + // + // Navigator.pushNamed(context, AppRoutes.dynamicScreen, arguments: DynamicListViewParams(LocaleKeys.ticketBalance.tr(), "HMG_TKT_NEW_EIT_SS")); + var pro = Provider.of(context, listen: false); + + // if (menuEntry.menuName == "HMG_TICKET_REQUESTS") { + Utils.showLoading(context); + //Ticket Work + if (pro.ticketBookingResponse != null && pro.ticketBookingResponse!.success) { + SSOAuthModel? ssoToken = await pro.fetchSSOAuthRedirection(clientID: pro.ticketBookingResponse!.clientId); + if (ssoToken != null) { + dynamic url = await pro.fetchURLRedirection(token: ssoToken.data!.accessToken!); + await pro.fetchTicketAccuralBalance(context, DateTime.now()); + pro.ticketHistoryTransactionList = await EITApiClient().getEITTransactions("HMG_TICKET_ITENARY_HR_EIT_SS", isCompleteList: true); + + Utils.hideLoading(context); + // Here Need Work + Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => TicketDetailedScreen(url: url, jwtToken: ssoToken.data!.accessToken))); + } + //} + } else { + Navigator.pushNamed(context, AppRoutes.dynamicScreen, arguments: DynamicListViewParams(LocaleKeys.ticketBalance.tr(), "HMG_TKT_NEW_EIT_SS")); + } }), ], ); -- 2.30.2 From 9b3601f06afb99a96c7137e9d164212376837fd3 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Mon, 8 Dec 2025 10:49:00 +0300 Subject: [PATCH 103/135] Update to Stores for Fixed Asset Disposal, VersionID 9.4 --- lib/app_state/app_state.dart | 2 +- lib/classes/consts.dart | 10 ++++----- lib/ui/landing/dashboard_screen.dart | 3 ++- lib/ui/landing/widget/services_widget.dart | 2 +- lib/widgets/bottom_sheet.dart | 26 +++++----------------- pubspec.yaml | 7 +++--- 6 files changed, 19 insertions(+), 31 deletions(-) diff --git a/lib/app_state/app_state.dart b/lib/app_state/app_state.dart index e68e169..3dfd812 100644 --- a/lib/app_state/app_state.dart +++ b/lib/app_state/app_state.dart @@ -90,7 +90,7 @@ class AppState { String get getHuaweiPushToken => _huaweiPushToken; - final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 9.3, mobileType: Platform.isAndroid ? "android" : "ios"); + final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 9.4, mobileType: Platform.isAndroid ? "android" : "ios"); void setPostParamsInitConfig() { isAuthenticated = false; diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index cfc240f..dbec87d 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -4,15 +4,15 @@ class ApiConsts { // static String baseUrl = "http://10.200.204.11"; // Local server // static String baseUrl = "https://erptstapp.srca.org.sa"; // SRCA server - static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver - // static String baseUrl = "http://10.201.204.101:2024"; + // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver + // static String baseUrl = "http://10.201.204.101:2024"; // static String baseUrl = "https://webservices.hmg.com"; // PreProd // static String baseUrl = "https://hmgwebservices.com"; // Live server - // static String baseUrl = "https://mohemm.hmg.com"; // New Live server + static String baseUrl = "https://mohemm.hmg.com"; // New Live server // - // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver - // static String baseUrl = "http://10.20.200.111:1010/"; + // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver + // static String baseUrl = "http://10.20.200.111:1010/"; // static String baseUrl = "https://webservices.hmg.com"; // PreProd // static String baseUrl = "https://mohemm.hmg.com"; diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index 8b14f2c..3122d17 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -164,7 +164,8 @@ class _DashboardScreenState extends State with WidgetsBindingOb if (!cProvider.disbaleChatForThisUser && !isFromInit) checkHubCon(); _refreshController.refreshCompleted(); - await data.fetchTicketBooking(); + // await data.fetchTicketBooking(); + // if (data.ticketBookingResponse != null && !data.ticketBookingResponse!.success) { // // data.fetchTicketBalance(); // } diff --git a/lib/ui/landing/widget/services_widget.dart b/lib/ui/landing/widget/services_widget.dart index deea7e9..879173b 100644 --- a/lib/ui/landing/widget/services_widget.dart +++ b/lib/ui/landing/widget/services_widget.dart @@ -257,9 +257,9 @@ class ServicesWidget extends StatelessWidget { } } else { if (menuEntry.menuName == "HMG_TICKET_REQUESTS") { - Utils.showLoading(context); //Ticket Work if (pro.ticketBookingResponse != null && pro.ticketBookingResponse!.success) { + Utils.showLoading(context); SSOAuthModel? ssoToken = await pro.fetchSSOAuthRedirection(clientID: pro.ticketBookingResponse!.clientId); if (ssoToken != null) { dynamic url = await pro.fetchURLRedirection(token: ssoToken.data!.accessToken!); diff --git a/lib/widgets/bottom_sheet.dart b/lib/widgets/bottom_sheet.dart index 7db0935..d5cb271 100644 --- a/lib/widgets/bottom_sheet.dart +++ b/lib/widgets/bottom_sheet.dart @@ -2,6 +2,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:mohem_flutter_app/classes/colors.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'; void showMyBottomSheet(BuildContext context, {required Widget child, required VoidCallback callBackFunc, String? type}) { @@ -65,14 +66,7 @@ void showMyBottomSheet(BuildContext context, {required Widget child, required Vo Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text( - title ?? "Details", - style: const TextStyle( - color: Color(0xff2BB8A6), - fontSize: 14, - fontWeight: FontWeight.bold, - ), - ), + (title ?? "Details").toText14(isBold: true, color: Color(0xff2BB8A6)), IconButton( icon: const Icon(Icons.close, color: Colors.black54, size: 20), onPressed: () { @@ -83,20 +77,12 @@ void showMyBottomSheet(BuildContext context, {required Widget child, required Vo ), const Divider(height: 1, color: Colors.grey), const SizedBox(height: 12), - // ---- Scrollable Content ---- Expanded( child: SingleChildScrollView( - child: Text( - (val?.isEmpty ?? true) - ? "--" - : val.toString(), - style: TextStyle( - color: MyColors.normalTextColor, - fontSize: 14, - height: 1.4, - ), - ), + child: ((val?.isEmpty ?? true) + ? "--" + : val.toString()).toText14(), ), ), SizedBox( @@ -112,7 +98,7 @@ void showMyBottomSheet(BuildContext context, {required Widget child, required Vo onPressed: () { Navigator.pop(context); }, - child: Text( + child: Text( LocaleKeys.close.tr(), style: const TextStyle( color: Colors.white, diff --git a/pubspec.yaml b/pubspec.yaml index 7e97774..0149086 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,8 +17,8 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 3.6.8+300078 -#version: 3.9.1+1 +#version: 3.6.8+300078 +version: 3.9.2+1 environment: sdk: ^3.7.0 @@ -139,12 +139,13 @@ dependencies: #todo its for temporary purpose, later will remove this. dotted_border: ^2.0.0+3 webview_flutter: ^4.13.0 + nfc_manager: ^3.2.0 # saf: ^1.0.3+4 dependency_overrides: - nfc_manager: ^3.2.0 +# nfc_manager: 3.2.0 # firebase_core_platform_interface: 4.5.1 -- 2.30.2 From 1ee51a7597a2db33717c8cd483da1c87e78f23ad Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Thu, 11 Dec 2025 09:59:25 +0300 Subject: [PATCH 104/135] Changed the device identifier, Update to Stores VersionID 9.5 --- android/app/src/main/AndroidManifest.xml | 4 +- android/gradle.properties | 3 +- lib/api/dashboard_api_client.dart | 13 +- lib/app_state/app_state.dart | 2 +- lib/main.dart | 28 +- lib/ui/work_list/sheets/delegate_sheet.dart | 626 ++++++++++---------- lib/widgets/sso_webview_widget.dart | 2 +- pubspec.yaml | 7 +- 8 files changed, 360 insertions(+), 325 deletions(-) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 132ad69..6d2f83f 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -8,13 +8,13 @@ - + - + diff --git a/android/gradle.properties b/android/gradle.properties index fbdc0de..8df3fe9 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,4 +1,5 @@ -org.gradle.jvmargs=-Xmx2048M +org.gradle.jvmargs=-Xmx4096m +kotlin.daemon.jvmargs=-Xmx4096m android.useAndroidX=true android.enableJetifier=true apmsInstrumentationEnabled=false diff --git a/lib/api/dashboard_api_client.dart b/lib/api/dashboard_api_client.dart index ae5fda8..2bddb42 100644 --- a/lib/api/dashboard_api_client.dart +++ b/lib/api/dashboard_api_client.dart @@ -5,6 +5,7 @@ import 'dart:io'; import 'package:easy_localization/easy_localization.dart'; import 'package:http/http.dart' as http; import 'package:device_info_plus/device_info_plus.dart'; +import 'package:mobile_device_identifier/mobile_device_identifier.dart'; import 'package:mohem_flutter_app/api/api_client.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/consts.dart'; @@ -18,10 +19,7 @@ import 'package:mohem_flutter_app/models/generic_response_model.dart'; import 'package:mohem_flutter_app/models/itg/itg_main_response.dart'; import 'package:mohem_flutter_app/models/itg/itg_response_model.dart'; import 'package:mohem_flutter_app/models/sso_auth_model.dart'; -import 'package:platform_device_id_plus/platform_device_id.dart'; -// import 'package:platform_device_id/platform_device_id.dart'; -// import 'package:platform_device_id/platform_device_id.dart'; import 'package:uuid/uuid.dart'; class DashboardApiClient { @@ -230,7 +228,8 @@ class DashboardApiClient { Future getBookingSSOFinalRedirection({required String token}) async { token = "eyJhbGciOiJSUzI1NiIsImtpZCI6IjhjZTE2OWM0YjIwYjQ2ZWM5YTQyOTU3Y2ZhODUzNzQ1IiwidHlwIjoiSldUIn0.eyJ0ZW5hbnRfaWQiOiJhOWY0ZDFhMDU5NmQ0YWVhOGY4MzA5OTJlYzRiZGFjMSIsImVpZCI6IjExNzkzMCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL3NpZCI6Ijk2MDI0OGM1NzA3YzQ3MmFhYTEzM2I1N2ZhODE1ZmVhIiwibGFuZ3VhZ2UiOiJVUyIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL2VtYWlsYWRkcmVzcyI6IjExNzkzMEBobWcuY29tIiwiZXhwIjoxNzgyNDc1NzY5LCJpc3MiOiJodHRwczovL3Nzby11YXQuaG1nLmNvbSIsImF1ZCI6ImE5ZjRkMWEwNTk2ZDRhZWE4ZjgzMDk5MmVjNGJkYWMxIn0.rJcLVsG8D0XECyLERCTD2uqGeWyvp-OBVGE9uL2qKrX4etFUHgdFt_5kYF6edFTtGy-0PIZadHDmv7e-IOhVWHm5HVMClaukiXoRXR8cDN8XA1wfme3Kd-U5PXN-IRh49AyRTzLO0rYNPvH81ScosWGlsFSkOvA-0hJNa2adHdtvgNvB8wJshSU5p7sAmF8mjdDY6aInG19etu2iEuUDwHHA4ZY_ts4hboHo8fE392hFaYGonExoD7bpW5RMx5xKWeRCmWpG_PK8Aw_z1jGzdB9PANus4pteRGuln1J-kmo2lQC9pVrSyZATAKp1HfgfyZ_vUhaHEfM69cMWaCslJQ"; - var request = http.MultipartRequest('POST', Uri.parse('https://ek.techmaster.in/SSO/HMG')); + // var request = http.MultipartRequest('POST', Uri.parse('https://ek.techmaster.in/SSO/HMG')); + var request = http.MultipartRequest('POST', Uri.parse('https://Paxes-release.techmaster.in/SSO/HMG')); request.fields.addAll({'JWTToken': token}); // request.headers.addAll(headers); @@ -255,13 +254,17 @@ class DashboardApiClient { String QRValue = "", String payrollCode = "", }) async { + var _mobileDeviceIdentifierPlugin = MobileDeviceIdentifier(); + Codec stringToBase64 = utf8.fuse(base64); String url = "${ApiConsts.swpRest}AuthenticateAndSwipeUserSupportNFC"; var uuid = Uuid(); String? deviceId = ""; // Generate a v4 (random) id if (Platform.isAndroid) { AndroidDeviceInfo androidInfo = await DeviceInfoPlugin().androidInfo; - deviceId = androidInfo.id; + deviceId = await _mobileDeviceIdentifierPlugin.getDeviceId() ?? androidInfo.id; + deviceId = stringToBase64.encode(deviceId); + deviceId = deviceId.length >= 50 ? deviceId.substring(0, 48) : deviceId; } else if (Platform.isIOS) { IosDeviceInfo iosInfo = await DeviceInfoPlugin().iosInfo; deviceId = iosInfo.identifierForVendor; diff --git a/lib/app_state/app_state.dart b/lib/app_state/app_state.dart index 3dfd812..799bcb5 100644 --- a/lib/app_state/app_state.dart +++ b/lib/app_state/app_state.dart @@ -90,7 +90,7 @@ class AppState { String get getHuaweiPushToken => _huaweiPushToken; - final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 9.4, mobileType: Platform.isAndroid ? "android" : "ios"); + final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 9.5, mobileType: Platform.isAndroid ? "android" : "ios"); void setPostParamsInitConfig() { isAuthenticated = false; diff --git a/lib/main.dart b/lib/main.dart index 39f19e5..263ed8e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -82,18 +82,22 @@ class MyApp extends StatelessWidget { List> delegates = context.localizationDelegates; // delegates.add(GlobalMaterialLocalizations.delegate); delegates.add(MonthYearPickerLocalizations.delegate); - return MaterialApp( - navigatorKey: AppRoutes.navigatorKey, - builder: (BuildContext context, Widget? child) { - return MediaQuery(data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0), child: child!); - }, - theme: AppTheme.getTheme(EasyLocalization.of(context)?.locale.languageCode == "ar"), - debugShowCheckedModeBanner: false, - localizationsDelegates: delegates, - supportedLocales: context.supportedLocales, - locale: context.locale, - initialRoute: AppRoutes.initialRoute, - routes: AppRoutes.routes, + return SafeArea( + top: false, // Set to true if you want to avoid the notch area as well + bottom: Platform.isIOS ? false : true, + child: MaterialApp( + navigatorKey: AppRoutes.navigatorKey, + builder: (BuildContext context, Widget? child) { + return MediaQuery(data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0), child: child!); + }, + theme: AppTheme.getTheme(EasyLocalization.of(context)?.locale.languageCode == "ar"), + debugShowCheckedModeBanner: false, + localizationsDelegates: delegates, + supportedLocales: context.supportedLocales, + locale: context.locale, + initialRoute: AppRoutes.initialRoute, + routes: AppRoutes.routes, + ), ); }, ); diff --git a/lib/ui/work_list/sheets/delegate_sheet.dart b/lib/ui/work_list/sheets/delegate_sheet.dart index ef38ce0..d72b041 100644 --- a/lib/ui/work_list/sheets/delegate_sheet.dart +++ b/lib/ui/work_list/sheets/delegate_sheet.dart @@ -1,5 +1,4 @@ import 'dart:collection'; -import 'dart:convert'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/cupertino.dart'; @@ -33,16 +32,8 @@ class DelegateSheet extends StatefulWidget { VoidCallback callBackFunc; List getNotificationRespondAttributes; - DelegateSheet({ - super.key, - required this.title, - required this.apiMode, - this.notificationID, - this.actionHistoryList, - this.wFHistory, - required this.callBackFunc, - this.getNotificationRespondAttributes = const [], - }); + DelegateSheet( + {required this.title, required this.apiMode, this.notificationID, this.actionHistoryList, this.wFHistory, required this.callBackFunc, this.getNotificationRespondAttributes = const []}); @override State createState() => _DelegateSheetState(); @@ -55,8 +46,8 @@ class _DelegateSheetState extends State { String? selectedFavLetter; String selectedType = "Workflow"; String inputRes = ""; + List? favLetters; List? favUsersList; - List? filteredFavUsersList = []; List? replacementList; bool isImageLoaded = false; @@ -66,14 +57,14 @@ class _DelegateSheetState extends State { super.initState(); if (widget.wFHistory != null) { widget.wFHistory = widget.wFHistory!.reversed.toList(); - Set ids = widget.wFHistory!.map((WFHistory e) => e.employeeID).toSet(); - widget.wFHistory!.retainWhere((WFHistory x) => ids.remove(x.employeeID)); + var ids = widget.wFHistory!.map((e) => e.employeeID).toSet(); + widget.wFHistory!.retainWhere((x) => ids.remove(x.employeeID)); } if (widget.actionHistoryList != null) { widget.actionHistoryList = widget.actionHistoryList!.reversed.toList(); - Set ids = widget.actionHistoryList!.map((GetActionHistoryList e) => e.uSERNAME).toSet(); - widget.actionHistoryList!.retainWhere((GetActionHistoryList x) => ids.remove(x.uSERNAME)); + var ids = widget.actionHistoryList!.map((e) => e.uSERNAME).toSet(); + widget.actionHistoryList!.retainWhere((x) => ids.remove(x.uSERNAME)); } } @@ -82,96 +73,36 @@ class _DelegateSheetState extends State { super.dispose(); } - Future fetchFavUsers({bool isNeedLoading = true}) async { - favUsersList = []; - filteredFavUsersList = []; - + Future fetchFavLetters({bool isNeedLoading = true}) async { + favLetters = []; if (isNeedLoading) Utils.showLoading(context); - - try { - List? favList = await WorkListApiClient().getFavoriteReplacementWithoutImage(); - favUsersList = favList; - - if (favUsersList != null && favUsersList!.isNotEmpty) { - favUsersList!.sort((GetFavoriteReplacements a, GetFavoriteReplacements b) => (a.employeeDisplayName ?? '').toLowerCase().compareTo((b.employeeDisplayName ?? '').toLowerCase())); - filteredFavUsersList = favUsersList; - - if (isNeedLoading) Utils.hideLoading(context); - setState(() {}); - _fetchAndAttachUserImages(); - } else { - if (isNeedLoading) Utils.hideLoading(context); - setState(() {}); - } - } catch (e) { - if (isNeedLoading) Utils.hideLoading(context); - setState(() {}); - } + List? favList = await WorkListApiClient().getFavoriteReplacementWithoutImage(); + List result = []; + favList!.forEach((element) { + result.add(element.employeeDisplayName![0]); + }); + favLetters = LinkedHashSet.from(result).toList(); + if (isNeedLoading) Utils.hideLoading(context); + setState(() { + favLetters!.sort((a, b) { + return a.toLowerCase().compareTo(b.toLowerCase()); + }); + }); + return null; } - Future _fetchAndAttachUserImages() async { - try { - List? tempList = await WorkListApiClient().getFavoriteReplacementWithImageNew(""); - - if (tempList != null && tempList.isNotEmpty && favUsersList != null) { - for (GetFavoriteReplacements element in favUsersList!) { - for (GetFavoriteReplacements element2 in tempList) { - if (element.userName == element2.userName && element2.employeeImage != null && element2.employeeImage!.isNotEmpty) { - element.employeeImage = element2.employeeImage; - } - } - } - filteredFavUsersList = favUsersList; - setState(() {}); - } - } catch (e) {} + Future fetchFavUsersList({bool isNeedLoading = true}) async { + if (isNeedLoading) Utils.showLoading(context); + favUsersList = await WorkListApiClient().getFavoriteReplacementWithImage(selectedFavLetter ?? ""); + if (isNeedLoading) Utils.hideLoading(context); + setState(() {}); + fetchFavUsersListNew(isNeedLoading: false); + return null; } - // Future fetchFavUsers({bool isNeedLoading = true}) async { - // favUsersList = []; - // if (isNeedLoading) Utils.showLoading(context); - // - // try { - // List? favList = await WorkListApiClient().getFavoriteReplacementWithoutImage(); - // favUsersList = favList; - // - // if (favUsersList != null && favUsersList!.isNotEmpty) { - // setState(() { - // favUsersList!.sort((GetFavoriteReplacements a, GetFavoriteReplacements b) => (a.employeeDisplayName ?? '').toLowerCase().compareTo((b.employeeDisplayName ?? '').toLowerCase())); - // }); - // if (isNeedLoading) Utils.hideLoading(context); - // - // List? tempList = await WorkListApiClient().getFavoriteReplacementWithImageNew(""); - // if (tempList != null && tempList.isNotEmpty) { - // for (GetFavoriteReplacements element in favUsersList!) { - // for (GetFavoriteReplacements element2 in tempList) { - // if (element.userName == element2.userName) { - // if (element2.employeeImage != null && element2.employeeImage!.isNotEmpty) { - // element.employeeImage = element2.employeeImage; - // } - // } - // } - // } - // setState(() {}); - // } - // } - // } catch (e) { - // // if (isNeedLoading) Utils.hideLoading(context); - // } - // } - - // Future fetchFavUsersList({bool isNeedLoading = true}) async { - // if (isNeedLoading) Utils.showLoading(context); - // favUsersList = await WorkListApiClient().getFavoriteReplacementWithImage(selectedFavLetter ?? ""); - // if (isNeedLoading) Utils.hideLoading(context); - // setState(() {}); - // fetchFavUsersListNew(isNeedLoading: false); - // return null; - // } - Future fetchFavUsersListNew({bool isNeedLoading = true}) async { if (isNeedLoading) Utils.showLoading(context); - filteredFavUsersList = await WorkListApiClient().getFavoriteReplacementWithImageNew(selectedFavLetter ?? ""); + favUsersList = await WorkListApiClient().getFavoriteReplacementWithImageNew(selectedFavLetter ?? ""); if (isNeedLoading) Utils.hideLoading(context); setState(() { isImageLoaded = true; @@ -181,10 +112,18 @@ class _DelegateSheetState extends State { void fetchChangeFav({required String email, required String employeName, required String image, required String userName, bool isFav = false, bool isNeedToRefresh = false}) async { Utils.showLoading(context); - GenericResponseModel model = await WorkListApiClient().changeFavoriteReplacements(email: email, employeName: employeName, image: image, userName: userName, isFav: isFav); + favLetters = null; + selectedFavLetter = null; + GenericResponseModel model = await WorkListApiClient().changeFavoriteReplacements( + email: email, + employeName: employeName, + image: image, + userName: userName, + isFav: isFav, + ); if (isNeedToRefresh) { - await fetchFavUsers(isNeedLoading: false); - // if (favUsersList != null) await fetchFavUsersList(isNeedLoading: false); + await fetchFavLetters(isNeedLoading: false); + if (favLetters != null) await fetchFavUsersList(isNeedLoading: false); } Utils.hideLoading(context); @@ -198,58 +137,44 @@ class _DelegateSheetState extends State { userName: selectedType == "Employee Name" ? inputRes : "", email: selectedType == "Employee Email" ? inputRes : "", ); - if (isNeedLoading) Utils.hideLoading(context); setState(() {}); return null; } - Future searchFavUser() async { - if (favUsersList != null && favUsersList!.isNotEmpty) { - // if (inputRes.length > 0) { - filteredFavUsersList = - favUsersList!.where((GetFavoriteReplacements element) { - String query = inputRes.toLowerCase(); - return (element.employeeDisplayName != null && element.employeeDisplayName!.toLowerCase().startsWith(query)) || - (element.userName != null && element.userName!.toLowerCase().contains(query)) || - (element.emailAddress != null && element.emailAddress!.toLowerCase().contains(query)); - }).toList(); - // } else { - // filteredFavUsersList = favUsersList; - // } - } else { - filteredFavUsersList = []; - } - - setState(() {}); - } - @override Widget build(BuildContext context) { - return SizedBox( + return Container( width: double.infinity, height: MediaQuery.of(context).size.height - 80, child: Column( - children: [ + children: [ Expanded( child: SingleChildScrollView( child: Padding( padding: const EdgeInsets.all(21), child: Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [ + children: [ widget.title.toText24(isBold: true), 21.height, LocaleKeys.search.tr().toText16(), 11.height, Column( crossAxisAlignment: CrossAxisAlignment.end, - children: [ + children: [ Container( - padding: const EdgeInsets.only(left: 8, right: 4, top: 6, bottom: 6), - decoration: BoxDecoration(borderRadius: BorderRadius.circular(15), color: Colors.transparent, border: Border.all(color: const Color(0xffefefef), width: 1)), + padding: EdgeInsets.only(left: 8, right: 4, top: 6, bottom: 6), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(15), + color: Colors.transparent, + border: Border.all( + color: Color(0xffefefef), + width: 1, + ), + ), child: Row( - children: [ + children: [ Expanded( child: InputWidget( "Search By " + selectedType, @@ -260,18 +185,29 @@ class _DelegateSheetState extends State { verticalPadding: 3, isInputTypeNum: selectedType == "Employee ID" ? true : false, isEnable: isNeedEnableTextField, - onChange: (String v) { + onChange: (v) { inputRes = v; - if (selectedType == "Favorites") { - searchFavUser(); - } }, ), ), - Container(height: 36, width: 1, color: const Color(0xffE5E5E5)), Container( - padding: const EdgeInsets.all(8), - child: Row(children: [selectedType.toText12(), 4.width, const Icon(Icons.keyboard_arrow_down, color: Colors.black, size: 16)]), + height: 36, + width: 1, + color: Color(0xffE5E5E5), + ), + Container( + padding: EdgeInsets.all(8), + child: Row( + children: [ + selectedType.toText12(), + 4.width, + const Icon( + Icons.keyboard_arrow_down, + color: Colors.black, + size: 16, + ), + ], + ), ).onPress(() { showMyBottomSheet( context, @@ -283,17 +219,19 @@ class _DelegateSheetState extends State { if (value == "Workflow") { setState(() { isNeedEnableTextField = false; - // selectedFavLetter = null; - filteredFavUsersList = null; + selectedFavLetter = null; + favLetters = null; + favUsersList = null; }); } else if (value == "Favorites") { - isNeedEnableTextField = true; - fetchFavUsers(); + isNeedEnableTextField = false; + fetchFavLetters(); } else { setState(() { isNeedEnableTextField = true; - // selectedFavLetter = null; - filteredFavUsersList = null; + selectedFavLetter = null; + favLetters = null; + favUsersList = null; }); } }, @@ -303,105 +241,143 @@ class _DelegateSheetState extends State { ], ), ), - if (isNeedEnableTextField && selectedType != "Favorites") + if (isNeedEnableTextField) TextButton( onPressed: () { fetchUserByInput(); }, - child: const Text("Search", style: TextStyle(color: Colors.blue, decoration: TextDecoration.underline)), - ), + child: const Text( + "Search", + style: TextStyle( + color: Colors.blue, + decoration: TextDecoration.underline, + ), + ), + ) ], ), if (!isNeedEnableTextField) 12.height, Row( - children: [ + children: [ Expanded( - child: SizedBox( + child: Container( width: double.infinity, - child: - // selectedFavLetter == null && favLetters != null - // ? Container(width: double.infinity, alignment: Alignment.center, child: "Please select letter to see Fav results".toText12()) - // : - filteredFavUsersList != null && selectedType == "Favorites" - ? ListView.separated( - itemBuilder: (BuildContext context, int index) { - return showFavUserItem(filteredFavUsersList![index]); - }, - separatorBuilder: (BuildContext context, int index) { - return Container(color: MyColors.borderColor, width: double.infinity, height: 1, margin: const EdgeInsets.only(top: 8, bottom: 8)).onPress(() {}); - }, - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemCount: filteredFavUsersList!.length, - padding: const EdgeInsets.only(top: 8, bottom: 8), - ) - : isNeedEnableTextField && replacementList == null - ? Container(width: double.infinity, alignment: Alignment.center, child: "Search User".toText12()) - : isNeedEnableTextField && replacementList!.isEmpty - ? Container(width: double.infinity, alignment: Alignment.center, child: "No Data Found".toText12()) - : isNeedEnableTextField - ? ListView.separated( - itemBuilder: (BuildContext context, int index) { - return showInputUserItem(replacementList![index]); - }, - separatorBuilder: (BuildContext context, int index) { - return Container(color: MyColors.borderE3Color, width: double.infinity, height: 1, margin: const EdgeInsets.only(top: 8, bottom: 8)); - }, - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemCount: replacementList!.length, - padding: const EdgeInsets.only(top: 8, bottom: 8), - ) - : (widget.wFHistory != null - ? ListView.separated( - itemBuilder: (BuildContext context, int index) { - return showItgItem(widget.wFHistory![index]); - }, - separatorBuilder: (BuildContext context, int index) { - return Container(color: MyColors.borderE3Color, width: double.infinity, height: 1, margin: const EdgeInsets.only(top: 8, bottom: 8)); - }, - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemCount: widget.wFHistory!.length, - padding: const EdgeInsets.only(top: 8, bottom: 8), - ) - : ListView.separated( - itemBuilder: (BuildContext context, int index) { - return showItem(widget.actionHistoryList![index]); - }, - separatorBuilder: (BuildContext context, int index) { - return Container(color: MyColors.borderE3Color, width: double.infinity, height: 1, margin: const EdgeInsets.only(top: 8, bottom: 8)); - }, - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemCount: widget.actionHistoryList!.length, - padding: const EdgeInsets.only(top: 8, bottom: 8), - )), + child: selectedFavLetter == null && favLetters != null + ? Container( + width: double.infinity, + alignment: Alignment.center, + child: "Please select letter to see Fav results".toText12(), + ) + : favUsersList != null + ? ListView.separated( + itemBuilder: (context, index) { + return showFavUserItem(favUsersList![index]); + }, + separatorBuilder: (context, index) { + return Container( + color: MyColors.borderColor, + width: double.infinity, + height: 1, + margin: EdgeInsets.only(top: 8, bottom: 8), + ).onPress(() {}); + }, + physics: NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemCount: favUsersList!.length, + padding: EdgeInsets.only(top: 8, bottom: 8), + ) + : isNeedEnableTextField && replacementList == null + ? Container( + width: double.infinity, + alignment: Alignment.center, + child: "Search User".toText12(), + ) + : isNeedEnableTextField && replacementList!.length == 0 + ? Container( + width: double.infinity, + alignment: Alignment.center, + child: "No Data Found".toText12(), + ) + : isNeedEnableTextField + ? ListView.separated( + itemBuilder: (context, index) { + return showInputUserItem(replacementList![index]); + }, + separatorBuilder: (context, index) { + return Container( + color: MyColors.borderE3Color, + width: double.infinity, + height: 1, + margin: EdgeInsets.only(top: 8, bottom: 8), + ); + }, + physics: NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemCount: replacementList!.length, + padding: EdgeInsets.only(top: 8, bottom: 8), + ) + : (widget.wFHistory != null + ? ListView.separated( + itemBuilder: (context, index) { + return showItgItem(widget.wFHistory![index]); + }, + separatorBuilder: (context, index) { + return Container( + color: MyColors.borderE3Color, + width: double.infinity, + height: 1, + margin: EdgeInsets.only(top: 8, bottom: 8), + ); + }, + physics: NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemCount: widget.wFHistory!.length, + padding: EdgeInsets.only(top: 8, bottom: 8), + ) + : ListView.separated( + itemBuilder: (context, index) { + return showItem(widget.actionHistoryList![index]); + }, + separatorBuilder: (context, index) { + return Container( + color: MyColors.borderE3Color, + width: double.infinity, + height: 1, + margin: EdgeInsets.only(top: 8, bottom: 8), + ); + }, + physics: NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemCount: widget.actionHistoryList!.length, + padding: EdgeInsets.only(top: 8, bottom: 8), + )), ), ), - // if (favLetters != null) - // SizedBox( - // width: 30, - // // color: Colors.red, - // child: ListView.separated( - // itemBuilder: (BuildContext context, int index) { - // return Container( - // padding: const EdgeInsets.all(8), - // alignment: Alignment.center, - // child: favLetters![index].toText14(color: selectedFavLetter == favLetters![index] ? MyColors.gradiantStartColor : Colors.black), - // ).onPress(() { - // selectedFavLetter = favLetters![index].toUpperCase(); - // fetchFavUsersList(); - // }); - // }, - // separatorBuilder: (BuildContext context, int index) { - // return const SizedBox(height: 0); - // }, - // physics: const NeverScrollableScrollPhysics(), - // shrinkWrap: true, - // itemCount: favLetters!.length, - // ), - // ), + if (favLetters != null) + Container( + width: 30, + // color: Colors.red, + child: ListView.separated( + itemBuilder: (context, index) { + return Container( + padding: EdgeInsets.all(8), + alignment: Alignment.center, + child: favLetters![index].toText14(color: selectedFavLetter == favLetters![index] ? MyColors.gradiantStartColor : Colors.black), + ).onPress(() { + selectedFavLetter = favLetters![index].toUpperCase(); + fetchFavUsersList(); + }); + }, + separatorBuilder: (context, index) { + return SizedBox( + height: 0, + ); + }, + physics: NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemCount: favLetters!.length, + ), + ), ], ), ], @@ -409,15 +385,22 @@ class _DelegateSheetState extends State { ), ), ), - Container(width: double.infinity, height: 1, color: MyColors.borderColor), + Container( + width: double.infinity, + height: 1, + color: MyColors.borderColor, + ), DefaultButton( "Cancel", - () { + () { Navigator.pop(context); }, textColor: Colors.black, - colors: const [Color(0xffE6E6E6), Color(0xffE6E6E6)], - ).insideContainer, + colors: [ + Color(0xffE6E6E6), + Color(0xffE6E6E6), + ], + ).insideContainer ], ), ); @@ -427,22 +410,25 @@ class _DelegateSheetState extends State { return InkWell( onTap: () { Navigator.pop(context); - showMyBottomSheet( - context, - callBackFunc: widget.callBackFunc, - child: SelectedItemSheet( - "Comment", - apiMode: widget.apiMode, - actionHistoryList: actionHistory, - notificationID: widget.notificationID, - isITGRequest: widget.wFHistory != null, - getNotificationRespondAttributes: widget.getNotificationRespondAttributes, - ), - ); + showMyBottomSheet(context, + callBackFunc: widget.callBackFunc, + child: SelectedItemSheet( + "Comment", + apiMode: widget.apiMode, + actionHistoryList: actionHistory, + notificationID: widget.notificationID, + isITGRequest: widget.wFHistory != null, + getNotificationRespondAttributes: widget.getNotificationRespondAttributes, + )); }, child: Row( - children: [ - CircularAvatar(url: actionHistory.eMPLOYEEIMAGE ?? "", height: 30, width: 30, isImageBase64: true), + children: [ + CircularAvatar( + url: actionHistory.eMPLOYEEIMAGE ?? "", + height: 30, + width: 30, + isImageBase64: true, + ), 9.width, (actionHistory.nAME ?? "").toText12().expanded, IconButton( @@ -458,8 +444,12 @@ class _DelegateSheetState extends State { isFav: true, ); }, - icon: Icon(Icons.star, size: 16, color: (actionHistory.isFavorite ?? false) ? MyColors.yellowColor : MyColors.borderColor), - ), + icon: Icon( + Icons.star, + size: 16, + color: (actionHistory.isFavorite ?? false) ? MyColors.yellowColor : MyColors.borderColor, + ), + ) ], ), ); @@ -469,18 +459,25 @@ class _DelegateSheetState extends State { return InkWell( onTap: () { Navigator.pop(context); - showMyBottomSheet( - context, - callBackFunc: widget.callBackFunc, - child: SelectedItgItemSheet( - "Comment", - apiMode: widget.apiMode, - wfHistory: wfHistory, - // notificationID: widget.notificationID, - ), - ); + showMyBottomSheet(context, + callBackFunc: widget.callBackFunc, + child: SelectedItgItemSheet( + "Comment", + apiMode: widget.apiMode, + wfHistory: wfHistory, + // notificationID: widget.notificationID, + )); }, - child: Row(children: [CircularAvatar(height: 30, width: 30), 9.width, (wfHistory.name ?? "").toText12().expanded]), + child: Row( + children: [ + CircularAvatar( + height: 30, + width: 30, + ), + 9.width, + (wfHistory.name ?? "").toText12().expanded, + ], + ), ); } @@ -488,31 +485,47 @@ class _DelegateSheetState extends State { return InkWell( onTap: () { Navigator.pop(context); - showMyBottomSheet( - context, - callBackFunc: widget.callBackFunc, - child: SelectedItemSheet( - "Comment", - apiMode: widget.apiMode, - favoriteReplacements: actionHistory, - notificationID: widget.notificationID, - isITGRequest: widget.wFHistory != null, - getNotificationRespondAttributes: widget.getNotificationRespondAttributes, - ), - ); + showMyBottomSheet(context, + callBackFunc: widget.callBackFunc, + child: SelectedItemSheet( + "Comment", + apiMode: widget.apiMode, + favoriteReplacements: actionHistory, + notificationID: widget.notificationID, + isITGRequest: widget.wFHistory != null, + getNotificationRespondAttributes: widget.getNotificationRespondAttributes, + )); }, child: Row( - children: [ - actionHistory.employeeImage != "" && actionHistory.employeeImage != null - ? CircularAvatar(url: actionHistory.employeeImage, height: 40, width: 40, isImageBase64: (actionHistory.employeeImage != null || actionHistory.employeeImage!.isNotEmpty) ? true : false) + children: [ + actionHistory.employeeImage != "" + ? CircularAvatar( + url: actionHistory.employeeImage, + height: 40, + width: 40, + isImageBase64: (actionHistory.employeeImage != null || actionHistory.employeeImage!.isNotEmpty) ? true : false, + ) : isImageLoaded - ? CircularAvatar(height: 40, width: 40, isImageBase64: false) + ? CircularAvatar( + height: 40, + width: 40, + isImageBase64: false, + ) : ClipRRect( - borderRadius: const BorderRadius.all(Radius.circular(50)), - child: Image.network("https://play-lh.googleusercontent.com/NPo88ojmhah4HDiposucJmfQIop4z4xc8kqJK9ITO9o-yCab2zxIp7PPB_XPj2iUojo", fit: BoxFit.cover, height: 40, width: 40).toShimmer(), - ), + borderRadius: const BorderRadius.all( + Radius.circular(50), + ), + child: Image.network( + "https://play-lh.googleusercontent.com/NPo88ojmhah4HDiposucJmfQIop4z4xc8kqJK9ITO9o-yCab2zxIp7PPB_XPj2iUojo", + fit: BoxFit.cover, + height: 40, + width: 40, + ).toShimmer(), + ), 16.width, - Expanded(child: (actionHistory.employeeDisplayName ?? "").toText12()), + Expanded( + child: (actionHistory.employeeDisplayName ?? "").toText12(), + ), IconButton( onPressed: () { fetchChangeFav( @@ -524,8 +537,12 @@ class _DelegateSheetState extends State { isNeedToRefresh: true, ); }, - icon: const Icon(Icons.star, size: 16, color: MyColors.yellowColor), - ), + icon: Icon( + Icons.star, + size: 16, + color: MyColors.yellowColor, + ), + ) ], ), ); @@ -535,24 +552,29 @@ class _DelegateSheetState extends State { return InkWell( onTap: () { Navigator.pop(context); - showMyBottomSheet( - context, - callBackFunc: widget.callBackFunc, - child: SelectedItemSheet( - LocaleKeys.comments.tr(), - apiMode: widget.apiMode, - replacementList: actionHistory, - notificationID: widget.notificationID, - isITGRequest: widget.wFHistory != null, - getNotificationRespondAttributes: widget.getNotificationRespondAttributes, - ), - ); + showMyBottomSheet(context, + callBackFunc: widget.callBackFunc, + child: SelectedItemSheet( + LocaleKeys.comments.tr(), + apiMode: widget.apiMode, + replacementList: actionHistory, + notificationID: widget.notificationID, + isITGRequest: widget.wFHistory != null, + getNotificationRespondAttributes: widget.getNotificationRespondAttributes, + )); }, child: Row( - children: [ - CircularAvatar(url: actionHistory.employeeImage, height: 30, width: 30, isImageBase64: actionHistory.employeeImage != null ? true : false), + children: [ + CircularAvatar( + url: actionHistory.employeeImage, + height: 30, + width: 30, + isImageBase64: actionHistory.employeeImage != null ? true : false, + ), 16.width, - Expanded(child: (actionHistory.employeeDisplayName ?? "").toText12()), + Expanded( + child: (actionHistory.employeeDisplayName ?? "").toText12(), + ), IconButton( onPressed: () { actionHistory.isFavorite = !(actionHistory.isFavorite ?? false); @@ -565,8 +587,12 @@ class _DelegateSheetState extends State { isNeedToRefresh: false, ); }, - icon: Icon(Icons.star, size: 16, color: (actionHistory.isFavorite ?? false) ? MyColors.yellowColor : MyColors.borderColor), - ), + icon: Icon( + Icons.star, + size: 16, + color: (actionHistory.isFavorite ?? false) ? MyColors.yellowColor : MyColors.borderColor, + ), + ) ], ), ); diff --git a/lib/widgets/sso_webview_widget.dart b/lib/widgets/sso_webview_widget.dart index 070f270..5877a63 100644 --- a/lib/widgets/sso_webview_widget.dart +++ b/lib/widgets/sso_webview_widget.dart @@ -46,7 +46,7 @@ class _SsoLoginWebViewState extends State { -
+

Redirecting...

diff --git a/pubspec.yaml b/pubspec.yaml index 0149086..6abe6fc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,8 +17,8 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -#version: 3.6.8+300078 -version: 3.9.2+1 +#version: 3.7.1+300081 +version: 3.9.3+1 environment: sdk: ^3.7.0 @@ -56,7 +56,8 @@ dependencies: logger: ^1.1.0 flutter_countdown_timer: ^4.1.0 - platform_device_id_plus: ^1.0.7 +# platform_device_id_plus: ^1.0.7 + mobile_device_identifier: ^0.0.3 device_info_plus: ^11.5.0 image_picker: ^1.1.2 file_picker: ^8.3.1 -- 2.30.2 From 90bf529865a76b7e4003c53704843de650106223 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Tue, 6 Jan 2026 09:24:29 +0300 Subject: [PATCH 105/135] CR-19329 - ERP MOWADHFAI System changes --- lib/ui/screens/mowadhafhi/mowadhafhi_hr_request.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/ui/screens/mowadhafhi/mowadhafhi_hr_request.dart b/lib/ui/screens/mowadhafhi/mowadhafhi_hr_request.dart index 44b3833..e7d2fde 100644 --- a/lib/ui/screens/mowadhafhi/mowadhafhi_hr_request.dart +++ b/lib/ui/screens/mowadhafhi/mowadhafhi_hr_request.dart @@ -150,7 +150,9 @@ class _MowadhafhiHRRequestState extends State { isReadOnly: false, onChange: (String value) { debugPrint(value); - description = value; + setState(() { + description = value; + }); }, ), ], @@ -171,7 +173,7 @@ class _MowadhafhiHRRequestState extends State { } bool checkValidation() { - if (selectedServiceType == null || selectedDepartment == null || selectedSection == null || selectedTopic == null) { + if (selectedServiceType == null || selectedDepartment == null || selectedSection == null || selectedTopic == null || description == "") { return false; } else { return true; -- 2.30.2 From 99414bf787122b2610936699cc7ac110723fc505 Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Wed, 7 Jan 2026 14:57:25 +0300 Subject: [PATCH 106/135] Itiqan Ovr Completed --- assets/langs/ar-SA.json | 6 +- assets/langs/en-US.json | 6 +- lib/api/etqan_ovr_api_client.dart | 129 ++++++++ lib/classes/consts.dart | 4 +- lib/config/routes.dart | 14 +- lib/generated/codegen_loader.g.dart | 12 +- lib/generated/locale_keys.g.dart | 4 + lib/main.dart | 2 + .../etqan_get_employee_incident_report.dart | 45 +++ .../etqan_ovr/etqan_get_requests_model.dart | 53 ++++ .../etqan_ovr/etqan_getprojects_model.dart | 53 ++++ lib/provider/dashboard_provider_model.dart | 1 + lib/provider/etqan_ovr_provider.dart | 181 ++++++++++++ lib/ui/etqan_ovr/etqan_create_request.dart | 279 ++++++++++++++++++ lib/ui/etqan_ovr/etqan_ovr_home.dart | 105 +++++++ lib/ui/etqan_ovr/etqan_request_detailed.dart | 110 +++++++ pubspec.yaml | 3 + 17 files changed, 1000 insertions(+), 7 deletions(-) create mode 100644 lib/api/etqan_ovr_api_client.dart create mode 100644 lib/models/etqan_ovr/etqan_get_employee_incident_report.dart create mode 100644 lib/models/etqan_ovr/etqan_get_requests_model.dart create mode 100644 lib/models/etqan_ovr/etqan_getprojects_model.dart create mode 100644 lib/provider/etqan_ovr_provider.dart create mode 100644 lib/ui/etqan_ovr/etqan_create_request.dart create mode 100644 lib/ui/etqan_ovr/etqan_ovr_home.dart create mode 100644 lib/ui/etqan_ovr/etqan_request_detailed.dart diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 916e8fb..ea64f78 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -642,5 +642,9 @@ "yearsUsed": "سنوات الاستخدام", "faRequest": "طلب التخلص من FA", "showMore": "عرض المزيد", - "buyerDetails": "تفاصيل المشتري" + "buyerDetails": "تفاصيل المشتري", + "etqanOVR": "إتقان (OVR)", + "etqanRequest": "طلب إلكتروني", + "selectProject": "حدد المشروع", + "project": "مشروع" } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 5fcb35c..630e0ad 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -640,5 +640,9 @@ "yearsUsed": "Years Used", "faRequest":"FA Disposal Request", "showMore": "Show More", - "buyerDetails": "Buyer Details" + "buyerDetails": "Buyer Details", + "etqanOVR": "Etqan (OVR)", + "etqanRequest": "Etqan Request", + "selectProject": "Select Project", + "project": "Project" } \ No newline at end of file diff --git a/lib/api/etqan_ovr_api_client.dart b/lib/api/etqan_ovr_api_client.dart new file mode 100644 index 0000000..f9d97bd --- /dev/null +++ b/lib/api/etqan_ovr_api_client.dart @@ -0,0 +1,129 @@ +import 'dart:convert'; + +import 'package:flutter/foundation.dart'; +import 'package:mohem_flutter_app/api/api_client.dart'; +import 'package:mohem_flutter_app/app_state/app_state.dart'; +import 'package:mohem_flutter_app/classes/consts.dart'; +import 'package:mohem_flutter_app/models/etqan_ovr/etqan_get_employee_incident_report.dart'; +import 'package:mohem_flutter_app/models/etqan_ovr/etqan_get_requests_model.dart'; +import 'package:mohem_flutter_app/models/etqan_ovr/etqan_getprojects_model.dart'; +import 'package:mohem_flutter_app/models/generic_response_model.dart'; +import 'package:mohem_flutter_app/models/mowadhafhi/get_department_sections.dart'; +import 'package:mohem_flutter_app/models/mowadhafhi/get_project_departments.dart'; +import 'package:mohem_flutter_app/models/mowadhafhi/get_projects.dart'; +import 'package:mohem_flutter_app/models/mowadhafhi/get_section_topics.dart'; +import 'package:mohem_flutter_app/models/mowadhafhi/get_ticket_details.dart'; +import 'package:mohem_flutter_app/models/mowadhafhi/get_ticket_transactions.dart'; +import 'package:mohem_flutter_app/models/mowadhafhi/get_ticket_types.dart'; +import 'package:mohem_flutter_app/models/mowadhafhi/get_tickets_list.dart'; +import 'package:mohem_flutter_app/models/mowadhafhi/get_transaction_attachment_model.dart'; + +class EtqanApiClient { + static final EtqanApiClient _instance = EtqanApiClient._internal(); + + EtqanApiClient._internal(); + + factory EtqanApiClient() => _instance; + + Future> getEtqanProjects() async { + String url = "${ApiConsts.cocRest}ETQAN_GetProjects"; + Map postParams = {"P_SELECTED_EMPLOYEE_NUMBER": AppState().memberInformationList?.eMPLOYEENUMBER}; + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject( + (json) { + List? responseData = []; + if (json["ETQAN_GetProjects_Response"] != null && json["ETQAN_GetProjects_Response"].isNotEmpty) { + json["ETQAN_GetProjects_Response"].forEach((element) { + responseData.add(EtqanGetProjectsResponse.fromJson(element)); + }); + } + return responseData; + }, + url, + postParams, + ); + } + + Future> getEmployeeEtqanRequests() async { + String url = "${ApiConsts.cocRest}ETQAN_GetEmployeeOVRRequests"; + Map postParams = { + "ETQAN_EmployeeID": AppState().memberInformationList?.eMPLOYEENUMBER, + "P_SELECTED_EMPLOYEE_NUMBER": AppState().memberInformationList?.eMPLOYEENUMBER, + }; + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject( + (json) { + List responseData = []; + if (json["ETQAN_GetEmployeeOVRRequests_Response"] != null && json["ETQAN_GetEmployeeOVRRequests_Response"].isNotEmpty) { + json["ETQAN_GetEmployeeOVRRequests_Response"].forEach((element) { + responseData.add(EtqanGetEmployeeOvrRequestsResponse.fromJson(element)); + }); + } + + if (responseData.isNotEmpty) { + for (EtqanGetEmployeeOvrRequestsResponse action in responseData) { + action.createdDate = action.createdDate?.split(" ")[0]; + } + responseData.sort((EtqanGetEmployeeOvrRequestsResponse a, EtqanGetEmployeeOvrRequestsResponse b) => (b.createdDate ?? '').compareTo(a.createdDate ?? '')); + } + + return responseData; + }, + url, + postParams, + ); + } + + Future> getEtqanIncidentRequests(String ticketNo) async { + String url = "${ApiConsts.cocRest}ETQAN_GetIncidentRequest"; + Map postParams = {"ETQAN_TicketNumber": ticketNo, "P_SELECTED_EMPLOYEE_NUMBER": AppState().memberInformationList?.eMPLOYEENUMBER}; + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject( + (json) { + List responseData = []; + if (json["ETQAN_GetIncidentRequest_Response"] != null && json["ETQAN_GetIncidentRequest_Response"].isNotEmpty) { + json["ETQAN_GetIncidentRequest_Response"].forEach((element) { + responseData.add(EtqanGetIncidentRequestResponse.fromJson(element)); + }); + } + return responseData; + }, + url, + postParams, + ); + } + + Future createRequest(String description, int? projectID, String? attachmentBase64) async { + String url = "${ApiConsts.cocRest}ETQAN_CreateIncident"; + Map postParams = { + "P_SELECTED_EMPLOYEE_NUMBER": AppState().memberInformationList?.eMPLOYEENUMBER, + "P_USER_NAME": AppState().memberInformationList?.eMPLOYEENUMBER, + "ETQAN_Emp_EmployeeNumber": AppState().memberInformationList?.eMPLOYEENUMBER, + "ETQAN_Description": description, + "ETQAN_ProjectId": projectID, + "ETQAN_FileInfoBase64": attachmentBase64, + "ETQAN_IsAnonymous": false, + }; + + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject( + (json) { + if (json["ETQAN_CreateIncident_Response"] != null) { + var response = json["ETQAN_CreateIncident_Response"]; + if (response["id"] != null && response["ticketNumber"] != null) { + return 1; + } + return null; + } + return null; + + // "ETQAN_CreateIncident_Response": { + // "id": "00adabe4-4a32-4b35-1f00-08de4d152e7c", + // "ticketNumber": "OVR/OLY/2026/224" + // }, + }, + url, + postParams, + ); + } +} diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index dbec87d..29d22d7 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -9,9 +9,9 @@ class ApiConsts { // static String baseUrl = "https://webservices.hmg.com"; // PreProd // static String baseUrl = "https://hmgwebservices.com"; // Live server - static String baseUrl = "https://mohemm.hmg.com"; // New Live server + // static String baseUrl = "https://mohemm.hmg.com"; // New Live server // - // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver + static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.20.200.111:1010/"; // static String baseUrl = "https://webservices.hmg.com"; // PreProd diff --git a/lib/config/routes.dart b/lib/config/routes.dart index 4653880..bf78671 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -10,6 +10,9 @@ import 'package:mohem_flutter_app/ui/chat/favorite_users_screen.dart'; import 'package:mohem_flutter_app/ui/chat/group_chat_detaied_screen.dart'; import 'package:mohem_flutter_app/ui/chat/group_members.dart'; import 'package:mohem_flutter_app/ui/chat/manage_group.dart'; +import 'package:mohem_flutter_app/ui/etqan_ovr/etqan_create_request.dart'; +import 'package:mohem_flutter_app/ui/etqan_ovr/etqan_ovr_home.dart'; +import 'package:mohem_flutter_app/ui/etqan_ovr/etqan_request_detailed.dart'; import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart'; import 'package:mohem_flutter_app/ui/landing/itg/change_itg_ad_password_screen.dart'; import 'package:mohem_flutter_app/ui/landing/itg/its_add_screen_video_image.dart'; @@ -211,6 +214,10 @@ class AppRoutes { static const String activityScreen = "/activityScreen"; + static const String etqanOvr = "/etqanOvr"; + static const String etqanCreateRequest = "/etqanCreateRequest"; + static const String etqanGetIncidientRequest = "/etqanGetIncidientRequest"; + static final Map routes = { login: (BuildContext context) => LoginScreen(), verifyLogin: (BuildContext context) => VerifyLoginScreen(), @@ -328,6 +335,11 @@ class AppRoutes { unsafeDeviceScreen: (BuildContext context) => const UnsafeDeviceScreen(), appUpdateScreen: (BuildContext context) => const AppUpdateScreen(), childEducation: (BuildContext context) => ChildEducationAssistance(), - activityScreen:(BuildContext context) => const EventActivityScreen() + activityScreen:(BuildContext context) => const EventActivityScreen(), + + //ETQAN OVR + etqanOvr: (BuildContext context) => EtqanOvrHome(), + etqanCreateRequest: (BuildContext context) => EtqanOvrCreateRequest(), + etqanGetIncidientRequest: (BuildContext context) => EtqanOvrRequestDetailed(), }; } diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index 6feb438..dc0c1b9 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -655,7 +655,11 @@ class CodegenLoader extends AssetLoader{ "yearsUsed": "سنوات الاستخدام", "faRequest": "طلب التخلص من FA", "showMore": "عرض المزيد", - "buyerDetails": "تفاصيل المشتري" + "buyerDetails": "تفاصيل المشتري", + "etqanOVR": "Etqan (OVR)", + "etqanRequest": "طلب إلكتروني", + "selectProject": "حدد المشروع", + "project": "مشروع" }; static const Map _en_US = { "mohemm": "Mohemm", @@ -1298,7 +1302,11 @@ static const Map _en_US = { "yearsUsed": "Years Used", "faRequest": "FA Disposal Request", "showMore": "Show More", - "buyerDetails": "Buyer Details" + "buyerDetails": "Buyer Details", + "etqanOVR": "Etqan (OVR)", + "etqanRequest": "Etqan Request", + "selectProject": "Select Project", + "project": "Project" }; static const Map> mapLocales = {"ar_SA": _ar_SA, "en_US": _en_US}; } diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 1a1cf95..c4efa13 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -628,5 +628,9 @@ abstract class LocaleKeys { static const faRequest = 'faRequest'; static const showMore = 'showMore'; static const buyerDetails = 'buyerDetails'; + static const etqanOVR = 'etqanOVR'; + static const etqanRequest = 'etqanRequest'; + static const selectProject = 'selectProject'; + static const project = 'project'; } diff --git a/lib/main.dart b/lib/main.dart index 263ed8e..022204d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -12,6 +12,7 @@ import 'package:mohem_flutter_app/models/post_params_model.dart'; import 'package:mohem_flutter_app/provider/chat_provider_model.dart'; import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; import 'package:mohem_flutter_app/provider/eit_provider_model.dart'; +import 'package:mohem_flutter_app/provider/etqan_ovr_provider.dart'; import 'package:mohem_flutter_app/theme/app_theme.dart'; import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart'; import 'package:month_year_picker/month_year_picker.dart'; @@ -53,6 +54,7 @@ Future main() async { ChangeNotifierProvider(create: (_) => EITProviderModel()), ChangeNotifierProvider(create: (_) => ChatProviderModel()), ChangeNotifierProvider(create: (_) => MarathonProvider()), + ChangeNotifierProvider(create: (_) => EtqanOvrProviderModel()), // ChangeNotifierProvider( // create: (_) => ChatCallProvider(), // ), diff --git a/lib/models/etqan_ovr/etqan_get_employee_incident_report.dart b/lib/models/etqan_ovr/etqan_get_employee_incident_report.dart new file mode 100644 index 0000000..3743cf3 --- /dev/null +++ b/lib/models/etqan_ovr/etqan_get_employee_incident_report.dart @@ -0,0 +1,45 @@ +import 'dart:convert'; + +class EtqanGetEmployeeIncidentRequestModel { + List? etqanGetIncidentRequestResponse; + + EtqanGetEmployeeIncidentRequestModel({ + this.etqanGetIncidentRequestResponse, + }); + + factory EtqanGetEmployeeIncidentRequestModel.fromRawJson(String str) => EtqanGetEmployeeIncidentRequestModel.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory EtqanGetEmployeeIncidentRequestModel.fromJson(Map json) => EtqanGetEmployeeIncidentRequestModel( + etqanGetIncidentRequestResponse: json["ETQAN_GetIncidentRequest_Response"] == null ? [] : List.from(json["ETQAN_GetIncidentRequest_Response"]!.map((x) => EtqanGetIncidentRequestResponse.fromJson(x))), + ); + + Map toJson() => { + "ETQAN_GetIncidentRequest_Response": etqanGetIncidentRequestResponse == null ? [] : List.from(etqanGetIncidentRequestResponse!.map((x) => x.toJson())), + }; +} + +class EtqanGetIncidentRequestResponse { + String? key; + String? value; + + EtqanGetIncidentRequestResponse({ + this.key, + this.value, + }); + + factory EtqanGetIncidentRequestResponse.fromRawJson(String str) => EtqanGetIncidentRequestResponse.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory EtqanGetIncidentRequestResponse.fromJson(Map json) => EtqanGetIncidentRequestResponse( + key: json["key"], + value: json["value"], + ); + + Map toJson() => { + "key": key, + "value": value, + }; +} diff --git a/lib/models/etqan_ovr/etqan_get_requests_model.dart b/lib/models/etqan_ovr/etqan_get_requests_model.dart new file mode 100644 index 0000000..c59e171 --- /dev/null +++ b/lib/models/etqan_ovr/etqan_get_requests_model.dart @@ -0,0 +1,53 @@ +import 'dart:convert'; + +class EtqanGetEmployeeRequestsModel { + List? etqanGetEmployeeOvrRequestsResponse; + + EtqanGetEmployeeRequestsModel({ + this.etqanGetEmployeeOvrRequestsResponse, + }); + + factory EtqanGetEmployeeRequestsModel.fromRawJson(String str) => EtqanGetEmployeeRequestsModel.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory EtqanGetEmployeeRequestsModel.fromJson(Map json) => EtqanGetEmployeeRequestsModel( + etqanGetEmployeeOvrRequestsResponse: json["ETQAN_GetEmployeeOVRRequests_Response"] == null ? [] : List.from(json["ETQAN_GetEmployeeOVRRequests_Response"]!.map((x) => EtqanGetEmployeeOvrRequestsResponse.fromJson(x))), + ); + + Map toJson() => { + "ETQAN_GetEmployeeOVRRequests_Response": etqanGetEmployeeOvrRequestsResponse == null ? [] : List.from(etqanGetEmployeeOvrRequestsResponse!.map((x) => x.toJson())), + }; +} + +class EtqanGetEmployeeOvrRequestsResponse { + String? createdDate; + String? description; + String? id; + String? ticketNumber; + + EtqanGetEmployeeOvrRequestsResponse({ + this.createdDate, + this.description, + this.id, + this.ticketNumber, + }); + + factory EtqanGetEmployeeOvrRequestsResponse.fromRawJson(String str) => EtqanGetEmployeeOvrRequestsResponse.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory EtqanGetEmployeeOvrRequestsResponse.fromJson(Map json) => EtqanGetEmployeeOvrRequestsResponse( + createdDate: json["createdDate"], + description: json["description"], + id: json["id"], + ticketNumber: json["ticketNumber"], + ); + + Map toJson() => { + "createdDate": createdDate, + "description": description, + "id": id, + "ticketNumber": ticketNumber, + }; +} diff --git a/lib/models/etqan_ovr/etqan_getprojects_model.dart b/lib/models/etqan_ovr/etqan_getprojects_model.dart new file mode 100644 index 0000000..5584faa --- /dev/null +++ b/lib/models/etqan_ovr/etqan_getprojects_model.dart @@ -0,0 +1,53 @@ +import 'dart:convert'; + +class EtqanGetProjectsModel { + List? etqanGetProjectsResponse; + + EtqanGetProjectsModel({ + this.etqanGetProjectsResponse, + }); + + factory EtqanGetProjectsModel.fromRawJson(String str) => EtqanGetProjectsModel.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory EtqanGetProjectsModel.fromJson(Map json) => EtqanGetProjectsModel( + etqanGetProjectsResponse: json["ETQAN_GetProjects_Response"] == null ? [] : List.from(json["ETQAN_GetProjects_Response"]!.map((x) => EtqanGetProjectsResponse.fromJson(x))), + ); + + Map toJson() => { + "ETQAN_GetProjects_Response": etqanGetProjectsResponse == null ? [] : List.from(etqanGetProjectsResponse!.map((x) => x.toJson())), + }; +} + +class EtqanGetProjectsResponse { + String? projectAr; + String? projectCode; + String? projectEn; + int? projectId; + + EtqanGetProjectsResponse({ + this.projectAr, + this.projectCode, + this.projectEn, + this.projectId, + }); + + factory EtqanGetProjectsResponse.fromRawJson(String str) => EtqanGetProjectsResponse.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory EtqanGetProjectsResponse.fromJson(Map json) => EtqanGetProjectsResponse( + projectAr: json["projectAr"], + projectCode: json["projectCode"], + projectEn: json["projectEn"], + projectId: json["projectId"], + ); + + Map toJson() => { + "projectAr": projectAr, + "projectCode": projectCode, + "projectEn": projectEn, + "projectId": projectId, + }; +} diff --git a/lib/provider/dashboard_provider_model.dart b/lib/provider/dashboard_provider_model.dart index 05c9ebb..55e16c3 100644 --- a/lib/provider/dashboard_provider_model.dart +++ b/lib/provider/dashboard_provider_model.dart @@ -120,6 +120,7 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { DrawerMenuItem("assets/images/drawer/my_profile.svg", LocaleKeys.myProfile.tr(), AppRoutes.profile), DrawerMenuItem("assets/images/drawer/performance_evaluation.svg", LocaleKeys.performanceEvaluation.tr(), AppRoutes.performanceEvaluation), DrawerMenuItem("assets/images/drawer/mowadhafi.svg", LocaleKeys.mowadhafhi.tr(), AppRoutes.mowadhafhi), + DrawerMenuItem("assets/images/drawer/mowadhafi.svg", LocaleKeys.etqanOVR.tr(), AppRoutes.etqanOvr), DrawerMenuItem("assets/images/drawer/pending_trasactions.svg", LocaleKeys.pendingTransactions.tr(), AppRoutes.pendingTransactions), // DrawerMenuItem("assets/images/drawer/drawer_marathon.svg", LocaleKeys.brainMarathon.tr(), AppRoutes.marathonIntroScreen), DrawerMenuItem("assets/images/drawer/change_password.svg", LocaleKeys.changePassword.tr(), AppRoutes.changePassword), diff --git a/lib/provider/etqan_ovr_provider.dart b/lib/provider/etqan_ovr_provider.dart new file mode 100644 index 0000000..a063463 --- /dev/null +++ b/lib/provider/etqan_ovr_provider.dart @@ -0,0 +1,181 @@ +import 'dart:io'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:mohem_flutter_app/api/etqan_ovr_api_client.dart'; +import 'package:mohem_flutter_app/classes/utils.dart'; +import 'package:mohem_flutter_app/models/etqan_ovr/etqan_get_employee_incident_report.dart'; +import 'package:mohem_flutter_app/models/etqan_ovr/etqan_get_requests_model.dart'; +import 'package:mohem_flutter_app/models/etqan_ovr/etqan_getprojects_model.dart'; +import 'package:speech_to_text/speech_recognition_result.dart'; +import 'package:speech_to_text/speech_to_text.dart'; + +class EtqanOvrProviderModel with ChangeNotifier, DiagnosticableTreeMixin { + // Home screen state + List? getEtqanProjectsList; + List? getEtqanEmployeeRequestsList; + List? getEtqanEmployeeIncidnetRequest; + bool isLoading = false; + String? _ticketId; + + // Speech to text state + final SpeechToText _speechToText = SpeechToText(); + bool _speechEnabled = false; + bool _isListening = false; + + // Getters for speech state + bool get speechEnabled => _speechEnabled; + + bool get isListening => _isListening; + + // Getter for ticketId + String get getTicketId => _ticketId ?? ''; + + // Setter for ticketId + void setTicketId(String ticketId) { + _ticketId = ticketId; + notifyListeners(); + } + + // Create request screen state + EtqanGetProjectsResponse? selectedProject; + String? selectedEmployeeNumber; + File? attachment; + String? attachmentBase64; + String description = ''; + + /// Initialize speech recognition - call this once when screen loads + Future initSpeech() async { + _speechEnabled = await _speechToText.initialize(); + notifyListeners(); + } + + /// Start listening for speech input + Future startListening(String localeId, TextEditingController controller) async { + await _speechToText.listen( + onResult: (SpeechRecognitionResult result) { + description = result.recognizedWords; + controller.text = result.recognizedWords; + controller.selection = TextSelection.fromPosition(TextPosition(offset: controller.text.length)); + notifyListeners(); + }, + localeId: localeId, + ); + _isListening = true; + notifyListeners(); + } + + /// Stop listening for speech input + Future stopListening() async { + await _speechToText.stop(); + _isListening = false; + notifyListeners(); + } + + /// Toggle listening state + Future toggleListening(String localeId, TextEditingController controller) async { + if (_isListening) { + await stopListening(); + } else { + await startListening(localeId, controller); + } + } + + // Fetch Etqan Projects + Future fetchEtqanProjects(BuildContext context) async { + isLoading = true; + notifyListeners(); + Utils.showLoading(context); + getEtqanProjectsList?.clear(); + getEtqanProjectsList = await EtqanApiClient().getEtqanProjects(); + Utils.hideLoading(context); + isLoading = false; + notifyListeners(); + } + + // Fetch Etqan Employee Requests + Future fetchEtqanEmployeeRequests(BuildContext context) async { + isLoading = true; + notifyListeners(); + Utils.showLoading(context); + getEtqanEmployeeRequestsList?.clear(); + getEtqanEmployeeRequestsList = await EtqanApiClient().getEmployeeEtqanRequests(); + Utils.hideLoading(context); + isLoading = false; + notifyListeners(); + } + + // Fetch Etqan Employee Incident Report + Future fetchEtqanEmployeeIncidentRequests(BuildContext context, String ticketNo) async { + isLoading = true; + notifyListeners(); + Utils.showLoading(context); + getEtqanEmployeeIncidnetRequest?.clear(); + getEtqanEmployeeIncidnetRequest = await EtqanApiClient().getEtqanIncidentRequests(ticketNo); + Utils.hideLoading(context); + isLoading = false; + notifyListeners(); + } + + // Set selected project + void setSelectedProject(EtqanGetProjectsResponse? project) { + selectedProject = project; + notifyListeners(); + } + + // Set selected employee number + void setSelectedEmployeeNumber(String? employeeNumber) { + selectedEmployeeNumber = employeeNumber; + notifyListeners(); + } + + // Set attachment with base64 + void setAttachment(File file, String base64) { + attachment = file; + attachmentBase64 = base64; + notifyListeners(); + } + + // Remove attachment + void removeAttachment() { + attachment = null; + attachmentBase64 = null; + notifyListeners(); + } + + // Set description + void setDescription(String value) { + description = value; + notifyListeners(); + } + + // Clear create request form + void clearCreateRequestForm() { + selectedProject = null; + selectedEmployeeNumber = null; + attachment = null; + attachmentBase64 = null; + description = ''; + notifyListeners(); + } + + // Submit request + Future submitRequest(BuildContext context) async { + try { + Utils.showLoading(context); + int? isSuccess = await EtqanApiClient().createRequest(description, selectedProject?.projectId, attachmentBase64); + Utils.hideLoading(context); + if (isSuccess == 1) { + getEtqanEmployeeRequestsList = await EtqanApiClient().getEmployeeEtqanRequests(); + notifyListeners(); + Navigator.of(context).pop(); + return true; + } + return false; + } catch (ex) { + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + return false; + } + } +} diff --git a/lib/ui/etqan_ovr/etqan_create_request.dart b/lib/ui/etqan_ovr/etqan_create_request.dart new file mode 100644 index 0000000..93925e0 --- /dev/null +++ b/lib/ui/etqan_ovr/etqan_create_request.dart @@ -0,0 +1,279 @@ +import 'dart:io'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:mohem_flutter_app/app_state/app_state.dart'; +import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/extensions/int_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/etqan_ovr/etqan_getprojects_model.dart'; +import 'package:mohem_flutter_app/provider/etqan_ovr_provider.dart'; +import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; +import 'package:mohem_flutter_app/widgets/bottom_sheet.dart'; +import 'package:mohem_flutter_app/widgets/button/default_button.dart'; +import 'package:mohem_flutter_app/widgets/image_picker.dart'; +import 'package:provider/provider.dart'; + +class EtqanOvrCreateRequest extends StatefulWidget { + const EtqanOvrCreateRequest({Key? key}) : super(key: key); + + @override + _EtqanOvrCreateRequestState createState() => _EtqanOvrCreateRequestState(); +} + +class _EtqanOvrCreateRequestState extends State { + final TextEditingController _descriptionController = TextEditingController(); + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) { + var provider = context.read(); + provider.initSpeech(); + provider.fetchEtqanProjects(context); + provider.clearCreateRequestForm(); + }); + } + + @override + void dispose() { + _descriptionController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBarWidget(context, title: LocaleKeys.createRequest.tr(), showHomeButton: false), + body: Consumer( + builder: (BuildContext context, EtqanOvrProviderModel provider, Widget? child) { + return Column( + children: [ + (ListView( + shrinkWrap: true, + physics: const BouncingScrollPhysics(), + padding: const EdgeInsets.all(21), + children: [ + _buildDropdownField( + label: LocaleKeys.project.tr(), + hint: LocaleKeys.selectProject.tr(), + value: _getProjectDisplayName(provider.selectedProject), + onTap: () => _showProjectSelectionSheet(context, provider), + ), + 16.height, + // _buildDropdownField( + // label: 'Employee Number', + // hint: 'Write a message', + // value: provider.selectedEmployeeNumber, + // onTap: () { + // // TODO: Show employee selection dialog + // }, + // ), + // 16.height, + _buildAttachmentSection(provider), + 16.height, + _buildDescriptionField(provider), + 24.height, + ], + )).expanded, + DefaultButton(LocaleKeys.submit.tr(), () async { + provider.setDescription(_descriptionController.text); + await provider.submitRequest(context); + }).insideContainer, + ], + ); + }, + ), + ); + } + + String? _getProjectDisplayName(EtqanGetProjectsResponse? project) { + if (project == null) return null; + return AppState().isArabic(context) ? project.projectAr : project.projectEn; + } + + void _showProjectSelectionSheet(BuildContext context, EtqanOvrProviderModel provider) { + if (provider.getEtqanProjectsList == null || provider.getEtqanProjectsList!.isEmpty) { + return; + } + showMyBottomSheet( + context, + callBackFunc: () {}, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + child: Text(LocaleKeys.selectProject.tr(), style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600, color: Color(0xff2B353E))), + ), + const Divider(), + ListView.separated( + shrinkWrap: true, + physics: const BouncingScrollPhysics(), + itemCount: provider.getEtqanProjectsList!.length, + separatorBuilder: (BuildContext context, int index) => const Divider(height: 1), + itemBuilder: (BuildContext context, int index) { + EtqanGetProjectsResponse project = provider.getEtqanProjectsList![index]; + bool isSelected = provider.selectedProject?.projectId == project.projectId; + return ListTile( + title: Text( + AppState().isArabic(context) ? (project.projectAr ?? '') : (project.projectEn ?? ''), + style: TextStyle(fontSize: 14, fontWeight: isSelected ? FontWeight.w600 : FontWeight.w400, color: isSelected ? MyColors.gradiantEndColor : const Color(0xff2B353E)), + ), + trailing: isSelected ? const Icon(Icons.check, color: MyColors.gradiantEndColor) : null, + onTap: () { + provider.setSelectedProject(project); + Navigator.pop(context); + }, + ); + }, + ), + 16.height, + ], + ), + ); + } + + Widget _buildDropdownField({required String label, required String hint, String? value, required VoidCallback onTap}) { + return InkWell( + onTap: onTap, + borderRadius: BorderRadius.circular(15), + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 15), + decoration: BoxDecoration(borderRadius: BorderRadius.circular(15), color: Colors.white, border: Border.all(color: const Color(0xffefefef), width: 1)), + child: Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(label, style: const TextStyle(fontSize: 11, fontWeight: FontWeight.w600, color: Color(0xff2B353E), letterSpacing: -0.44)), + const SizedBox(height: 4), + Text(value ?? hint, style: TextStyle(fontSize: 14, fontWeight: FontWeight.w400, color: value != null ? const Color(0xff2B353E) : const Color(0xff575757), letterSpacing: -0.56)), + ], + ), + ), + const Icon(Icons.keyboard_arrow_down, color: Color(0xff575757)), + ], + ), + ), + ); + } + + Widget _buildAttachmentSection(EtqanOvrProviderModel provider) { + return Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration(borderRadius: BorderRadius.circular(15), color: Colors.white, border: Border.all(color: const Color(0xffefefef), width: 1)), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(LocaleKeys.supportingDocument.tr(), style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Color(0xff2B353E))), + const SizedBox(height: 12), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text(LocaleKeys.attachments.tr(), style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: Color(0xff2B353E))), + if (provider.attachment == null) + InkWell( + onTap: () { + ImageOptions.showImageOptionsNew(context, true, (String base64, File file) { + provider.setAttachment(file, base64); + Navigator.of(context).pop(); + }); + }, + borderRadius: BorderRadius.circular(8), + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 8), + decoration: BoxDecoration(color: MyColors.gradiantEndColor, borderRadius: BorderRadius.circular(8)), + child: Text(LocaleKeys.add.tr(), style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w600, color: Colors.white)), + ), + ), + ], + ), + if (provider.attachment != null) ...[ + const SizedBox(height: 12), + Padding( + padding: const EdgeInsets.only(bottom: 8), + child: Row( + children: [ + const Icon(Icons.attach_file, size: 18, color: Color(0xff575757)), + const SizedBox(width: 8), + Expanded(child: Text(provider.attachment!.path.split('/').last, style: const TextStyle(fontSize: 12, color: Color(0xff575757)), overflow: TextOverflow.ellipsis)), + InkWell( + onTap: () { + provider.removeAttachment(); + }, + child: const Icon(Icons.close, size: 18, color: Colors.red), + ), + ], + ), + ), + ], + ], + ), + ); + } + + Widget _buildDescriptionField(EtqanOvrProviderModel provider) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 15), + decoration: BoxDecoration(borderRadius: BorderRadius.circular(15), color: Colors.white, border: Border.all(color: const Color(0xffefefef), width: 1)), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text(LocaleKeys.description.tr(), style: const TextStyle(fontSize: 11, fontWeight: FontWeight.w600, color: Color(0xff2B353E), letterSpacing: -0.44)), + GestureDetector( + onTap: + provider.speechEnabled + ? () { + String localeId = AppState().isArabic(context) ? 'ar_SA' : 'en_US'; + provider.toggleListening(localeId, _descriptionController); + } + : null, + child: Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration(color: provider.isListening ? MyColors.gradiantEndColor.withOpacity(0.1) : Colors.transparent, borderRadius: BorderRadius.circular(20)), + child: Icon( + provider.isListening ? Icons.mic : Icons.mic_none, + color: provider.isListening ? MyColors.gradiantEndColor : (provider.speechEnabled ? MyColors.grey57Color : Colors.grey.shade300), + size: 24, + ), + ), + ), + ], + ), + if (provider.isListening) + Padding( + padding: const EdgeInsets.only(bottom: 8), + child: Row( + children: [ + Container(width: 8, height: 8, decoration: BoxDecoration(color: Colors.red, borderRadius: BorderRadius.circular(4))), + const SizedBox(width: 8), + Text('Listening...', style: TextStyle(fontSize: 12, color: MyColors.gradiantEndColor, fontWeight: FontWeight.w500)), + ], + ), + ), + TextField( + controller: _descriptionController, + maxLines: 4, + onChanged: (String value) => provider.setDescription(value), + style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w400, color: Color(0xff2B353E), letterSpacing: -0.44), + decoration: InputDecoration( + isDense: true, + hintText: LocaleKeys.writeAMessage.tr(), + hintStyle: const TextStyle(fontSize: 14, fontWeight: FontWeight.w400, color: Color(0xff575757), letterSpacing: -0.56), + contentPadding: EdgeInsets.zero, + border: InputBorder.none, + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + ), + ), + ], + ), + ); + } +} diff --git a/lib/ui/etqan_ovr/etqan_ovr_home.dart b/lib/ui/etqan_ovr/etqan_ovr_home.dart new file mode 100644 index 0000000..0f549f0 --- /dev/null +++ b/lib/ui/etqan_ovr/etqan_ovr_home.dart @@ -0,0 +1,105 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:mohem_flutter_app/app_state/app_state.dart'; +import 'package:mohem_flutter_app/classes/colors.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/etqan_ovr/etqan_get_requests_model.dart'; +import 'package:mohem_flutter_app/provider/etqan_ovr_provider.dart'; +import 'package:mohem_flutter_app/classes/utils.dart'; +import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; +import 'package:mohem_flutter_app/widgets/button/default_button.dart'; +import 'package:provider/provider.dart'; + +class EtqanOvrHome extends StatefulWidget { + const EtqanOvrHome({Key? key}) : super(key: key); + + @override + _EtqanOvrHomeState createState() => _EtqanOvrHomeState(); +} + +class _EtqanOvrHomeState extends State { + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) { + context.read().fetchEtqanEmployeeRequests(context); + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBarWidget(context, title: LocaleKeys.etqanRequest.tr()), + body: Consumer( + builder: (BuildContext context, EtqanOvrProviderModel provider, Widget? child) { + return Column( + children: [ + (provider.getEtqanEmployeeRequestsList == null || provider.getEtqanEmployeeRequestsList!.isEmpty + ? Utils.getNoDataWidget(context) + : ListView.separated( + physics: const BouncingScrollPhysics(), + padding: const EdgeInsets.all(20), + itemBuilder: (BuildContext context, int index) { + EtqanGetEmployeeOvrRequestsResponse data = provider.getEtqanEmployeeRequestsList![index]; + return InkWell( + onTap: () { + context.read().setTicketId(data.ticketNumber ?? ''); + Navigator.pushNamed(context, AppRoutes.etqanGetIncidientRequest); + }, + child: Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(15), border: Border.all(color: const Color(0xffefefef), width: 1)), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + (data.ticketNumber ?? "").toText14(isBold: true, color: MyColors.darkTextColor), + (data.createdDate?.split(" ")[0] ?? "").toText12(color: MyColors.grey70Color), + ], + ), + 8.height, + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + (data.description ?? "").toText12(color: MyColors.grey57Color), + RotatedBox( + quarterTurns: AppState().isArabic(context) ? 2 : 0, + child: SvgPicture.asset("assets/images/arrow_next.svg", color: MyColors.grey70Color, width: 16, height: 16), + ), + ], + ), + ], + ), + ), + ], + ), + ), + ); + }, + separatorBuilder: (BuildContext context, int index) => 12.height, + itemCount: provider.getEtqanEmployeeRequestsList!.length, + )) + .expanded, + DefaultButton(LocaleKeys.createRequest.tr(), () async { + await Navigator.pushNamed(context, AppRoutes.etqanCreateRequest); + // getOpenTickets(); + }).insideContainer, + ], + ); + }, + ), + ); + } +} diff --git a/lib/ui/etqan_ovr/etqan_request_detailed.dart b/lib/ui/etqan_ovr/etqan_request_detailed.dart new file mode 100644 index 0000000..b1ed12a --- /dev/null +++ b/lib/ui/etqan_ovr/etqan_request_detailed.dart @@ -0,0 +1,110 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:mohem_flutter_app/classes/colors.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/etqan_ovr/etqan_get_employee_incident_report.dart'; +import 'package:mohem_flutter_app/provider/etqan_ovr_provider.dart'; +import 'package:mohem_flutter_app/classes/utils.dart'; +import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; +import 'package:provider/provider.dart'; + +class EtqanOvrRequestDetailed extends StatefulWidget { + const EtqanOvrRequestDetailed({Key? key}) : super(key: key); + + @override + _EtqanOvrRequestDetailedState createState() => _EtqanOvrRequestDetailedState(); +} + +class _EtqanOvrRequestDetailedState extends State { + List get fieldOrder => ['Project', 'Created', 'Occurrence Time', 'OVR Reference No', 'Involved Employee Number', 'Description']; + + List get hiddenFields => ['OVR Id', 'Is Anonymous']; + + List _getOrderedList(List list) { + List orderedList = []; + + List filteredList = list.where((EtqanGetIncidentRequestResponse item) => !hiddenFields.any((f) => f.toLowerCase() == item.key?.toLowerCase())).toList(); + + for (String fieldName in fieldOrder) { + var item = filteredList.firstWhere((e) => e.key?.toLowerCase() == fieldName.toLowerCase(), orElse: () => EtqanGetIncidentRequestResponse()); + if (item.key != null) { + orderedList.add(item); + } + } + + for (var item in filteredList) { + if (!fieldOrder.any((f) => f.toLowerCase() == item.key?.toLowerCase())) { + orderedList.add(item); + } + } + + return orderedList; + } + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) { + var provider = context.read(); + provider.fetchEtqanEmployeeIncidentRequests(context, provider.getTicketId); + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBarWidget(context, title: LocaleKeys.etqanRequest.tr()), + body: Consumer( + builder: (BuildContext context, EtqanOvrProviderModel provider, Widget? child) { + if (provider.getEtqanEmployeeIncidnetRequest == null || provider.getEtqanEmployeeIncidnetRequest!.isEmpty) { + return Utils.getNoDataWidget(context); + } + + List orderedList = _getOrderedList(provider.getEtqanEmployeeIncidnetRequest!); + + return SingleChildScrollView( + physics: const BouncingScrollPhysics(), + padding: const EdgeInsets.all(16), + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(15), + border: Border.all(color: const Color(0xffefefef), width: 1), + boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10, offset: const Offset(0, 2))], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: + orderedList.asMap().entries.map((MapEntry entry) { + int index = entry.key; + EtqanGetIncidentRequestResponse data = entry.value; + bool isLast = index == orderedList.length - 1; + return Column( + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded(flex: 2, child: (data.key ?? "").toText12(isBold: true, color: MyColors.grey57Color)), + 8.width, + Expanded(flex: 3, child: (data.value ?? "-").toText14(color: MyColors.darkTextColor)), + ], + ), + ), + if (!isLast) const Padding(padding: EdgeInsets.only(left: 14, right: 14), child: Divider(height: 1, thickness: 1, color: Color(0xffefefef))), + ], + ); + }).toList(), + ), + ), + ); + }, + ), + ); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 6abe6fc..8852c2d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -102,6 +102,9 @@ dependencies: audio_waveforms: ^1.3.0 rxdart: ^0.27.7 + #Speech to Text + speech_to_text: ^7.0.0 + #Encryption flutter_des: ^2.1.0 -- 2.30.2 From 74bcf3e1b7163baf1233afc7387c1f97a8d14000 Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Thu, 8 Jan 2026 14:38:32 +0300 Subject: [PATCH 107/135] translation --- assets/langs/ar-SA.json | 4 ++-- assets/langs/en-US.json | 4 ++-- lib/generated/codegen_loader.g.dart | 8 ++++---- lib/ui/etqan_ovr/etqan_ovr_home.dart | 7 ++++--- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index ea64f78..84c9b46 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -643,8 +643,8 @@ "faRequest": "طلب التخلص من FA", "showMore": "عرض المزيد", "buyerDetails": "تفاصيل المشتري", - "etqanOVR": "إتقان (OVR)", - "etqanRequest": "طلب إلكتروني", + "etqanOVR": "الإبلاغ عن حادثة", + "etqanRequest": "طلبات الحوادث", "selectProject": "حدد المشروع", "project": "مشروع" } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 630e0ad..8f95e9a 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -641,8 +641,8 @@ "faRequest":"FA Disposal Request", "showMore": "Show More", "buyerDetails": "Buyer Details", - "etqanOVR": "Etqan (OVR)", - "etqanRequest": "Etqan Request", + "etqanOVR": "Report An Incident", + "etqanRequest": "Incident Requests", "selectProject": "Select Project", "project": "Project" } \ No newline at end of file diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index dc0c1b9..4cb2359 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -656,8 +656,8 @@ class CodegenLoader extends AssetLoader{ "faRequest": "طلب التخلص من FA", "showMore": "عرض المزيد", "buyerDetails": "تفاصيل المشتري", - "etqanOVR": "Etqan (OVR)", - "etqanRequest": "طلب إلكتروني", + "etqanOVR": "الإبلاغ عن حادثة", + "etqanRequest": "طلبات الحوادث", "selectProject": "حدد المشروع", "project": "مشروع" }; @@ -1303,8 +1303,8 @@ static const Map _en_US = { "faRequest": "FA Disposal Request", "showMore": "Show More", "buyerDetails": "Buyer Details", - "etqanOVR": "Etqan (OVR)", - "etqanRequest": "Etqan Request", + "etqanOVR": "Report An Incident", + "etqanRequest": "Incident Requests", "selectProject": "Select Project", "project": "Project" }; diff --git a/lib/ui/etqan_ovr/etqan_ovr_home.dart b/lib/ui/etqan_ovr/etqan_ovr_home.dart index 0f549f0..7a48a51 100644 --- a/lib/ui/etqan_ovr/etqan_ovr_home.dart +++ b/lib/ui/etqan_ovr/etqan_ovr_home.dart @@ -1,10 +1,10 @@ -import 'package:easy_localization/easy_localization.dart'; +import 'package:easy_localization/easy_localization.dart' as lclize; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; import 'package:mohem_flutter_app/config/routes.dart'; -import 'package:mohem_flutter_app/extensions/int_extensions.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'; @@ -14,6 +14,7 @@ import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; import 'package:mohem_flutter_app/widgets/button/default_button.dart'; import 'package:provider/provider.dart'; +import 'package:intl/src/intl/text_direction.dart' as intl; class EtqanOvrHome extends StatefulWidget { const EtqanOvrHome({Key? key}) : super(key: key); @@ -66,7 +67,7 @@ class _EtqanOvrHomeState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ (data.ticketNumber ?? "").toText14(isBold: true, color: MyColors.darkTextColor), - (data.createdDate?.split(" ")[0] ?? "").toText12(color: MyColors.grey70Color), + Directionality(textDirection: TextDirection.ltr, child: (data.createdDate ?? "").toText12(color: MyColors.grey70Color)), ], ), 8.height, -- 2.30.2 From d021c95def20a4dc2754d2644d6d5ba167714e14 Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Wed, 14 Jan 2026 16:20:01 +0300 Subject: [PATCH 108/135] Parking Qr Solution --- assets/images/drawer/car_parking_icon.svg | 4 + assets/langs/ar-SA.json | 3 +- assets/langs/en-US.json | 3 +- lib/api/dashboard_api_client.dart | 21 +++- lib/classes/consts.dart | 4 +- lib/config/routes.dart | 10 +- lib/generated/codegen_loader.g.dart | 6 +- lib/generated/locale_keys.g.dart | 1 + .../get_employee_parking_details_model.dart | 61 ++++++++++ lib/provider/dashboard_provider_model.dart | 14 +-- lib/ui/parking_qr/parking_qr.dart | 106 ++++++++++++++++++ 11 files changed, 212 insertions(+), 21 deletions(-) create mode 100644 assets/images/drawer/car_parking_icon.svg create mode 100644 lib/models/get_employee_parking_details_model.dart create mode 100644 lib/ui/parking_qr/parking_qr.dart diff --git a/assets/images/drawer/car_parking_icon.svg b/assets/images/drawer/car_parking_icon.svg new file mode 100644 index 0000000..f77afa0 --- /dev/null +++ b/assets/images/drawer/car_parking_icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 916e8fb..a78c83f 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -642,5 +642,6 @@ "yearsUsed": "سنوات الاستخدام", "faRequest": "طلب التخلص من FA", "showMore": "عرض المزيد", - "buyerDetails": "تفاصيل المشتري" + "buyerDetails": "تفاصيل المشتري", + "parkingQr": "وقوف السيارات QR" } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 5fcb35c..5b49d24 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -640,5 +640,6 @@ "yearsUsed": "Years Used", "faRequest":"FA Disposal Request", "showMore": "Show More", - "buyerDetails": "Buyer Details" + "buyerDetails": "Buyer Details", + "parkingQr": "Parking QR" } \ No newline at end of file diff --git a/lib/api/dashboard_api_client.dart b/lib/api/dashboard_api_client.dart index 2bddb42..6f7288c 100644 --- a/lib/api/dashboard_api_client.dart +++ b/lib/api/dashboard_api_client.dart @@ -16,6 +16,7 @@ import 'package:mohem_flutter_app/models/dashboard/get_attendance_tracking_list_ import 'package:mohem_flutter_app/models/dashboard/itg_forms_model.dart'; import 'package:mohem_flutter_app/models/dashboard/list_menu.dart'; import 'package:mohem_flutter_app/models/generic_response_model.dart'; +import 'package:mohem_flutter_app/models/get_employee_parking_details_model.dart'; import 'package:mohem_flutter_app/models/itg/itg_main_response.dart'; import 'package:mohem_flutter_app/models/itg/itg_response_model.dart'; import 'package:mohem_flutter_app/models/sso_auth_model.dart'; @@ -226,9 +227,9 @@ class DashboardApiClient { } Future getBookingSSOFinalRedirection({required String token}) async { - token = - "eyJhbGciOiJSUzI1NiIsImtpZCI6IjhjZTE2OWM0YjIwYjQ2ZWM5YTQyOTU3Y2ZhODUzNzQ1IiwidHlwIjoiSldUIn0.eyJ0ZW5hbnRfaWQiOiJhOWY0ZDFhMDU5NmQ0YWVhOGY4MzA5OTJlYzRiZGFjMSIsImVpZCI6IjExNzkzMCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL3NpZCI6Ijk2MDI0OGM1NzA3YzQ3MmFhYTEzM2I1N2ZhODE1ZmVhIiwibGFuZ3VhZ2UiOiJVUyIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL2VtYWlsYWRkcmVzcyI6IjExNzkzMEBobWcuY29tIiwiZXhwIjoxNzgyNDc1NzY5LCJpc3MiOiJodHRwczovL3Nzby11YXQuaG1nLmNvbSIsImF1ZCI6ImE5ZjRkMWEwNTk2ZDRhZWE4ZjgzMDk5MmVjNGJkYWMxIn0.rJcLVsG8D0XECyLERCTD2uqGeWyvp-OBVGE9uL2qKrX4etFUHgdFt_5kYF6edFTtGy-0PIZadHDmv7e-IOhVWHm5HVMClaukiXoRXR8cDN8XA1wfme3Kd-U5PXN-IRh49AyRTzLO0rYNPvH81ScosWGlsFSkOvA-0hJNa2adHdtvgNvB8wJshSU5p7sAmF8mjdDY6aInG19etu2iEuUDwHHA4ZY_ts4hboHo8fE392hFaYGonExoD7bpW5RMx5xKWeRCmWpG_PK8Aw_z1jGzdB9PANus4pteRGuln1J-kmo2lQC9pVrSyZATAKp1HfgfyZ_vUhaHEfM69cMWaCslJQ"; - // var request = http.MultipartRequest('POST', Uri.parse('https://ek.techmaster.in/SSO/HMG')); + // token = + // "eyJhbGciOiJSUzI1NiIsImtpZCI6IjhjZTE2OWM0YjIwYjQ2ZWM5YTQyOTU3Y2ZhODUzNzQ1IiwidHlwIjoiSldUIn0.eyJ0ZW5hbnRfaWQiOiJhOWY0ZDFhMDU5NmQ0YWVhOGY4MzA5OTJlYzRiZGFjMSIsImVpZCI6IjExNzkzMCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL3NpZCI6Ijk2MDI0OGM1NzA3YzQ3MmFhYTEzM2I1N2ZhODE1ZmVhIiwibGFuZ3VhZ2UiOiJVUyIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL2VtYWlsYWRkcmVzcyI6IjExNzkzMEBobWcuY29tIiwiZXhwIjoxNzgyNDc1NzY5LCJpc3MiOiJodHRwczovL3Nzby11YXQuaG1nLmNvbSIsImF1ZCI6ImE5ZjRkMWEwNTk2ZDRhZWE4ZjgzMDk5MmVjNGJkYWMxIn0.rJcLVsG8D0XECyLERCTD2uqGeWyvp-OBVGE9uL2qKrX4etFUHgdFt_5kYF6edFTtGy-0PIZadHDmv7e-IOhVWHm5HVMClaukiXoRXR8cDN8XA1wfme3Kd-U5PXN-IRh49AyRTzLO0rYNPvH81ScosWGlsFSkOvA-0hJNa2adHdtvgNvB8wJshSU5p7sAmF8mjdDY6aInG19etu2iEuUDwHHA4ZY_ts4hboHo8fE392hFaYGonExoD7bpW5RMx5xKWeRCmWpG_PK8Aw_z1jGzdB9PANus4pteRGuln1J-kmo2lQC9pVrSyZATAKp1HfgfyZ_vUhaHEfM69cMWaCslJQ"; + // // var request = http.MultipartRequest('POST', Uri.parse('https://ek.techmaster.in/SSO/HMG')); var request = http.MultipartRequest('POST', Uri.parse('https://Paxes-release.techmaster.in/SSO/HMG')); request.fields.addAll({'JWTToken': token}); @@ -414,4 +415,18 @@ class DashboardApiClient { // postParams, // ); // } + + Future getEmployeeParkingQrCode() async { + String url = "${ApiConsts.erpRest}GET_Employee_Parking"; + Map postParams = {}; + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject( + (json) { + GetEmployeeParking responseData = GetEmployeeParking.fromJson(json); + return responseData; + }, + url, + postParams, + ); + } } diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index dbec87d..a6b7173 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -4,12 +4,12 @@ class ApiConsts { // static String baseUrl = "http://10.200.204.11"; // Local server // static String baseUrl = "https://erptstapp.srca.org.sa"; // SRCA server - // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver + static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.201.204.101:2024"; // static String baseUrl = "https://webservices.hmg.com"; // PreProd // static String baseUrl = "https://hmgwebservices.com"; // Live server - static String baseUrl = "https://mohemm.hmg.com"; // New Live server + // static String baseUrl = "https://mohemm.hmg.com"; // New Live server // // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.20.200.111:1010/"; diff --git a/lib/config/routes.dart b/lib/config/routes.dart index 4653880..0afc22c 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -40,6 +40,7 @@ import 'package:mohem_flutter_app/ui/my_team/profile_details.dart'; import 'package:mohem_flutter_app/ui/my_team/subordinate_leave.dart'; import 'package:mohem_flutter_app/ui/my_team/team_members.dart'; import 'package:mohem_flutter_app/ui/my_team/view_attendance.dart'; +import 'package:mohem_flutter_app/ui/parking_qr/parking_qr.dart'; import 'package:mohem_flutter_app/ui/payslip/monthly_pay_slip_screen.dart'; import 'package:mohem_flutter_app/ui/performance/performance_appraisal_screen.dart'; import 'package:mohem_flutter_app/ui/profile/add_update_family_member.dart'; @@ -211,6 +212,9 @@ class AppRoutes { static const String activityScreen = "/activityScreen"; + //Parking QR + static const String parkingQr = "/parkingQrScreen"; + static final Map routes = { login: (BuildContext context) => LoginScreen(), verifyLogin: (BuildContext context) => VerifyLoginScreen(), @@ -328,6 +332,10 @@ class AppRoutes { unsafeDeviceScreen: (BuildContext context) => const UnsafeDeviceScreen(), appUpdateScreen: (BuildContext context) => const AppUpdateScreen(), childEducation: (BuildContext context) => ChildEducationAssistance(), - activityScreen:(BuildContext context) => const EventActivityScreen() + activityScreen:(BuildContext context) => const EventActivityScreen(), + + //Parking QR + parkingQr: (BuildContext context) => const ParkingQrScreen(), + }; } diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index 6feb438..62bbce6 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -655,7 +655,8 @@ class CodegenLoader extends AssetLoader{ "yearsUsed": "سنوات الاستخدام", "faRequest": "طلب التخلص من FA", "showMore": "عرض المزيد", - "buyerDetails": "تفاصيل المشتري" + "buyerDetails": "تفاصيل المشتري", + "parkingQr": "وقوف السيارات QR" }; static const Map _en_US = { "mohemm": "Mohemm", @@ -1298,7 +1299,8 @@ static const Map _en_US = { "yearsUsed": "Years Used", "faRequest": "FA Disposal Request", "showMore": "Show More", - "buyerDetails": "Buyer Details" + "buyerDetails": "Buyer Details", + "parkingQr": "Parking QR" }; static const Map> mapLocales = {"ar_SA": _ar_SA, "en_US": _en_US}; } diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 1a1cf95..683c8c4 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -628,5 +628,6 @@ abstract class LocaleKeys { static const faRequest = 'faRequest'; static const showMore = 'showMore'; static const buyerDetails = 'buyerDetails'; + static const parkingQr = 'parkingQr'; } diff --git a/lib/models/get_employee_parking_details_model.dart b/lib/models/get_employee_parking_details_model.dart new file mode 100644 index 0000000..4a385c8 --- /dev/null +++ b/lib/models/get_employee_parking_details_model.dart @@ -0,0 +1,61 @@ +import 'dart:convert'; + +class GetEmployeeParking { + GetEmployeeParkingClass? getEmployeeParking; + + GetEmployeeParking({ + this.getEmployeeParking, + }); + + factory GetEmployeeParking.fromRawJson(String str) => GetEmployeeParking.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory GetEmployeeParking.fromJson(Map json) => GetEmployeeParking( + getEmployeeParking: json["GET_Employee_Parking"] == null ? null : GetEmployeeParkingClass.fromJson(json["GET_Employee_Parking"]), + ); + + Map toJson() => { + "GET_Employee_Parking": getEmployeeParking?.toJson(), + }; +} + +class GetEmployeeParkingClass { + DateTime? createdAt; + String? employeeCode; + String? isNewQrCode; + String? qrCode; + String? qrCodeImageBase64; + bool? success; + + GetEmployeeParkingClass({ + this.createdAt, + this.employeeCode, + this.isNewQrCode, + this.qrCode, + this.qrCodeImageBase64, + this.success, + }); + + factory GetEmployeeParkingClass.fromRawJson(String str) => GetEmployeeParkingClass.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory GetEmployeeParkingClass.fromJson(Map json) => GetEmployeeParkingClass( + createdAt: json["createdAt"] == null ? null : DateTime.parse(json["createdAt"]), + employeeCode: json["employeeCode"], + isNewQrCode: json["isNewQRCode"], + qrCode: json["qrCode"], + qrCodeImageBase64: json["qrCodeImageBase64"], + success: json["success"], + ); + + Map toJson() => { + "createdAt": createdAt?.toIso8601String(), + "employeeCode": employeeCode, + "isNewQRCode": isNewQrCode, + "qrCode": qrCode, + "qrCodeImageBase64": qrCodeImageBase64, + "success": success, + }; +} diff --git a/lib/provider/dashboard_provider_model.dart b/lib/provider/dashboard_provider_model.dart index 05c9ebb..dd1472b 100644 --- a/lib/provider/dashboard_provider_model.dart +++ b/lib/provider/dashboard_provider_model.dart @@ -120,6 +120,7 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { DrawerMenuItem("assets/images/drawer/my_profile.svg", LocaleKeys.myProfile.tr(), AppRoutes.profile), DrawerMenuItem("assets/images/drawer/performance_evaluation.svg", LocaleKeys.performanceEvaluation.tr(), AppRoutes.performanceEvaluation), DrawerMenuItem("assets/images/drawer/mowadhafi.svg", LocaleKeys.mowadhafhi.tr(), AppRoutes.mowadhafhi), + DrawerMenuItem("assets/images/drawer/car_parking_icon.svg", LocaleKeys.parkingQr.tr(), AppRoutes.parkingQr), DrawerMenuItem("assets/images/drawer/pending_trasactions.svg", LocaleKeys.pendingTransactions.tr(), AppRoutes.pendingTransactions), // DrawerMenuItem("assets/images/drawer/drawer_marathon.svg", LocaleKeys.brainMarathon.tr(), AppRoutes.marathonIntroScreen), DrawerMenuItem("assets/images/drawer/change_password.svg", LocaleKeys.changePassword.tr(), AppRoutes.changePassword), @@ -326,8 +327,6 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { void fetchTicketBalance() async { try { GenericResponseModel? ticketResponse = await DashboardApiClient().getTicketBalance(); - logger.d("Ticket Balance Response: ${ticketResponse?.toJson()}"); - print(" ========= Ticket Balance Response ======= "); } catch (ex) { logger.wtf(ex); isEventLoadingLoading = false; @@ -340,8 +339,7 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { Future fetchSSOAuthRedirection({String? clientID}) async { try { SSOAuthModel? ssoResponse = await DashboardApiClient().getBookingSSOAuthRedirection(clientID: clientID!); - logger.d("SSO Response: ${ssoResponse!.toJson()}"); - if (ssoResponse.status == "Success") { + if (ssoResponse!.status == "Success") { return ssoResponse; } else { Utils.showToast(ssoResponse.message!.first ?? "Failed to fetch SSO Auth Token"); @@ -361,18 +359,12 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { dynamic res = await DashboardApiClient().getBookingSSOFinalRedirection(token: token); logger.d("SSO URL: $res"); return res; - // if (ssoResponse.status == "Success") { - // return ssoResponse; - // } else { - // Utils.showToast(ssoResponse.message!.first ?? "Failed to fetch SSO Auth Token"); - // return null; - // } } catch (ex) { logger.wtf(ex); isEventLoadingLoading = false; notifyListeners(); Utils.handleException(ex, null, null); - return null; // Ensure a return value in case of an exception + return null; } } diff --git a/lib/ui/parking_qr/parking_qr.dart b/lib/ui/parking_qr/parking_qr.dart new file mode 100644 index 0000000..641f84a --- /dev/null +++ b/lib/ui/parking_qr/parking_qr.dart @@ -0,0 +1,106 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:mohem_flutter_app/api/dashboard_api_client.dart'; +import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/classes/utils.dart'; +import 'package:mohem_flutter_app/extensions/int_extensions.dart'; +import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; +import 'package:mohem_flutter_app/models/get_employee_parking_details_model.dart'; +import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; + +class ParkingQrScreen extends StatefulWidget { + const ParkingQrScreen({Key? key}) : super(key: key); + + @override + _RequestDetailsState createState() => _RequestDetailsState(); +} + +class _RequestDetailsState extends State { + GetEmployeeParking? qrData; + + @override + void initState() { + super.initState(); + getTicketDetails(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBarWidget(context, title: LocaleKeys.parkingQr.tr()), + body: + qrData?.getEmployeeParking == null + ? Center(child: Text(LocaleKeys.noDataAvailable.tr())) + : SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(20.0), + child: Center( + child: Container( + padding: const EdgeInsets.all(20.0), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + boxShadow: [BoxShadow(color: Colors.grey.withValues(alpha: 0.2), spreadRadius: 5, blurRadius: 10, offset: const Offset(0, 3))], + ), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + // QR Code Image + if (qrData!.getEmployeeParking!.qrCodeImageBase64 != null && qrData!.getEmployeeParking!.qrCodeImageBase64!.isNotEmpty) + Image.memory(Utils.dataFromBase64String(qrData!.getEmployeeParking!.qrCodeImageBase64!), width: 300, height: 300, fit: BoxFit.contain) + else + Container( + width: 300, + height: 300, + color: MyColors.lightGreyEFColor, + child: Center(child: Text(LocaleKeys.noDataAvailable.tr(), style: const TextStyle(color: MyColors.grey67Color))), + ), + 10.height, + Container(height: 1, color: MyColors.lightGreyE3Color, margin: const EdgeInsets.symmetric(vertical: 10)), + 20.height, + SizedBox( + width: double.infinity, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Employee Code + if (qrData!.getEmployeeParking!.employeeCode != null && qrData!.getEmployeeParking!.employeeCode!.isNotEmpty) ...[ + Text(LocaleKeys.employeeNumber.tr(), style: const TextStyle(fontSize: 14, color: MyColors.grey67Color, fontWeight: FontWeight.w400)), + 8.height, + Text(qrData!.getEmployeeParking!.employeeCode!, style: const TextStyle(fontSize: 18, color: MyColors.darkTextColor, fontWeight: FontWeight.w600)), + 8.height, + ], + if (qrData!.getEmployeeParking!.createdAt != null) ...[ + Text(LocaleKeys.creationDate.tr(), style: const TextStyle(fontSize: 14, color: MyColors.grey67Color, fontWeight: FontWeight.w400)), + 8.height, + Text( + DateFormat('dd MMM yyyy, hh:mm a').format(qrData!.getEmployeeParking!.createdAt!), + style: const TextStyle(fontSize: 16, color: MyColors.darkTextColor, fontWeight: FontWeight.w500), + ), + ], + ], + ), + ), + ], + ), + ), + ), + ), + ), + ); + } + + void getTicketDetails() async { + try { + Utils.showLoading(context); + qrData = await DashboardApiClient().getEmployeeParkingQrCode(); + Utils.hideLoading(context); + setState(() {}); + } catch (ex) { + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + } + } +} -- 2.30.2 From e3fcc992df46734eafaf00b66a9aff77c80d7f41 Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Sun, 25 Jan 2026 15:10:35 +0300 Subject: [PATCH 109/135] approval level commented Code for filter . --- lib/ui/work_list/itg_fragments/approval_level_fragment.dart | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/ui/work_list/itg_fragments/approval_level_fragment.dart b/lib/ui/work_list/itg_fragments/approval_level_fragment.dart index d7d9c7e..61681eb 100644 --- a/lib/ui/work_list/itg_fragments/approval_level_fragment.dart +++ b/lib/ui/work_list/itg_fragments/approval_level_fragment.dart @@ -21,7 +21,11 @@ class ApprovalLevelfragment extends StatelessWidget { @override Widget build(BuildContext context) { - if (wFHistory.isNotEmpty) wFHistory = wFHistory.reversed.toList(); + if (wFHistory.isNotEmpty) { + //TODO: This COde is Written For Future. If Needed Enable to Filter The Empty Action Requests. + // wFHistory = wFHistory.where((item) => item.action != null && item.action!.isNotEmpty).toList(); + wFHistory = wFHistory.reversed.toList(); + } return Container( width: double.infinity, height: double.infinity, -- 2.30.2 From 9112b269874f7a0c317dde02488ce86c5a2a5dfb Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Tue, 27 Jan 2026 18:06:36 +0300 Subject: [PATCH 110/135] updates --- assets/langs/ar-SA.json | 3 ++- assets/langs/en-US.json | 3 ++- lib/classes/consts.dart | 4 ++-- lib/generated/locale_keys.g.dart | 1 + lib/provider/dashboard_provider_model.dart | 3 ++- 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 84c9b46..acd9660 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -646,5 +646,6 @@ "etqanOVR": "الإبلاغ عن حادثة", "etqanRequest": "طلبات الحوادث", "selectProject": "حدد المشروع", - "project": "مشروع" + "project": "مشروع", + "keen": "حريص" } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 8f95e9a..aa51e3e 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -644,5 +644,6 @@ "etqanOVR": "Report An Incident", "etqanRequest": "Incident Requests", "selectProject": "Select Project", - "project": "Project" + "project": "Project", + "keen": "Keen" } \ No newline at end of file diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 29d22d7..dbec87d 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -9,9 +9,9 @@ class ApiConsts { // static String baseUrl = "https://webservices.hmg.com"; // PreProd // static String baseUrl = "https://hmgwebservices.com"; // Live server - // static String baseUrl = "https://mohemm.hmg.com"; // New Live server + static String baseUrl = "https://mohemm.hmg.com"; // New Live server // - static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver + // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.20.200.111:1010/"; // static String baseUrl = "https://webservices.hmg.com"; // PreProd diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index c4efa13..b7e7295 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -632,5 +632,6 @@ abstract class LocaleKeys { static const etqanRequest = 'etqanRequest'; static const selectProject = 'selectProject'; static const project = 'project'; + static const keen = 'keen'; } diff --git a/lib/provider/dashboard_provider_model.dart b/lib/provider/dashboard_provider_model.dart index 55e16c3..2d1c50b 100644 --- a/lib/provider/dashboard_provider_model.dart +++ b/lib/provider/dashboard_provider_model.dart @@ -120,7 +120,8 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { DrawerMenuItem("assets/images/drawer/my_profile.svg", LocaleKeys.myProfile.tr(), AppRoutes.profile), DrawerMenuItem("assets/images/drawer/performance_evaluation.svg", LocaleKeys.performanceEvaluation.tr(), AppRoutes.performanceEvaluation), DrawerMenuItem("assets/images/drawer/mowadhafi.svg", LocaleKeys.mowadhafhi.tr(), AppRoutes.mowadhafhi), - DrawerMenuItem("assets/images/drawer/mowadhafi.svg", LocaleKeys.etqanOVR.tr(), AppRoutes.etqanOvr), + // DrawerMenuItem("assets/images/drawer/mowadhafi.svg", LocaleKeys.etqanOVR.tr(), AppRoutes.etqanOvr), + DrawerMenuItem("assets/images/drawer/mowadhafi.svg", LocaleKeys.keen.tr(), AppRoutes.etqanOvr), DrawerMenuItem("assets/images/drawer/pending_trasactions.svg", LocaleKeys.pendingTransactions.tr(), AppRoutes.pendingTransactions), // DrawerMenuItem("assets/images/drawer/drawer_marathon.svg", LocaleKeys.brainMarathon.tr(), AppRoutes.marathonIntroScreen), DrawerMenuItem("assets/images/drawer/change_password.svg", LocaleKeys.changePassword.tr(), AppRoutes.changePassword), -- 2.30.2 From dfa7d9a713f023cc985da56bb421b4cfda573d35 Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Wed, 28 Jan 2026 10:05:36 +0300 Subject: [PATCH 111/135] approval level commented Code for filter . --- assets/langs/ar-SA.json | 1 + assets/langs/en-US.json | 1 + lib/api/etqan_ovr_api_client.dart | 4 +-- lib/generated/codegen_loader.g.dart | 2 ++ lib/generated/locale_keys.g.dart | 1 + lib/provider/etqan_ovr_provider.dart | 10 +++++- lib/ui/etqan_ovr/etqan_create_request.dart | 39 ++++++++++++++++++++++ 7 files changed, 55 insertions(+), 3 deletions(-) diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 84c9b46..da79f14 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -258,6 +258,7 @@ "fullName": "الأسم الكامل", "remove": "حذف", "submit": "ارسال", + "submitAsAnonymous": "إرسال كمجهول", "areYouSureYouWantToSubmit": "هل أنت متأكد أنك تريد أن تقدم؟", "comments": "تعليقات", "writeComment": "أكتب تعليقا", diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 8f95e9a..f1600be 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -256,6 +256,7 @@ "remove": "Remove", "Attendance": "Attendance", "submit": "Submit", + "submitAsAnonymous": "Submit as Anonymous", "areYouSureYouWantToSubmit": "Are you sure you want to submit?", "comments": "Comments", "writeComment": "Write a comment", diff --git a/lib/api/etqan_ovr_api_client.dart b/lib/api/etqan_ovr_api_client.dart index f9d97bd..3f595a4 100644 --- a/lib/api/etqan_ovr_api_client.dart +++ b/lib/api/etqan_ovr_api_client.dart @@ -93,7 +93,7 @@ class EtqanApiClient { ); } - Future createRequest(String description, int? projectID, String? attachmentBase64) async { + Future createRequest(String description, int? projectID, String? attachmentBase64, bool? isAnonymous) async { String url = "${ApiConsts.cocRest}ETQAN_CreateIncident"; Map postParams = { "P_SELECTED_EMPLOYEE_NUMBER": AppState().memberInformationList?.eMPLOYEENUMBER, @@ -102,7 +102,7 @@ class EtqanApiClient { "ETQAN_Description": description, "ETQAN_ProjectId": projectID, "ETQAN_FileInfoBase64": attachmentBase64, - "ETQAN_IsAnonymous": false, + "ETQAN_IsAnonymous": isAnonymous ?? false, }; postParams.addAll(AppState().postParamsJson); diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index 4cb2359..3eef24e 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -274,6 +274,7 @@ class CodegenLoader extends AssetLoader{ "fullName": "الأسم الكامل", "remove": "حذف", "submit": "ارسال", + "submitAsAnonymous": "إرسال كمجهول", "areYouSureYouWantToSubmit": "هل أنت متأكد أنك تريد أن تقدم؟", "comments": "تعليقات", "writeComment": "أكتب تعليقا", @@ -919,6 +920,7 @@ static const Map _en_US = { "remove": "Remove", "Attendance": "Attendance", "submit": "Submit", + "submitAsAnonymous": "Submit as Anonymous", "areYouSureYouWantToSubmit": "Are you sure you want to submit?", "comments": "Comments", "writeComment": "Write a comment", diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index c4efa13..8402214 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -261,6 +261,7 @@ abstract class LocaleKeys { static const fullName = 'fullName'; static const remove = 'remove'; static const submit = 'submit'; + static const submitAsAnonymous = 'submitAsAnonymous'; static const areYouSureYouWantToSubmit = 'areYouSureYouWantToSubmit'; static const comments = 'comments'; static const writeComment = 'writeComment'; diff --git a/lib/provider/etqan_ovr_provider.dart b/lib/provider/etqan_ovr_provider.dart index a063463..83e4c9b 100644 --- a/lib/provider/etqan_ovr_provider.dart +++ b/lib/provider/etqan_ovr_provider.dart @@ -43,6 +43,7 @@ class EtqanOvrProviderModel with ChangeNotifier, DiagnosticableTreeMixin { File? attachment; String? attachmentBase64; String description = ''; + bool isAnonymous = false; /// Initialize speech recognition - call this once when screen loads Future initSpeech() async { @@ -149,6 +150,12 @@ class EtqanOvrProviderModel with ChangeNotifier, DiagnosticableTreeMixin { notifyListeners(); } + // Set isAnonymous + void setIsAnonymous(bool value) { + isAnonymous = value; + notifyListeners(); + } + // Clear create request form void clearCreateRequestForm() { selectedProject = null; @@ -156,6 +163,7 @@ class EtqanOvrProviderModel with ChangeNotifier, DiagnosticableTreeMixin { attachment = null; attachmentBase64 = null; description = ''; + isAnonymous = false; notifyListeners(); } @@ -163,7 +171,7 @@ class EtqanOvrProviderModel with ChangeNotifier, DiagnosticableTreeMixin { Future submitRequest(BuildContext context) async { try { Utils.showLoading(context); - int? isSuccess = await EtqanApiClient().createRequest(description, selectedProject?.projectId, attachmentBase64); + int? isSuccess = await EtqanApiClient().createRequest(description, selectedProject?.projectId, attachmentBase64, isAnonymous); Utils.hideLoading(context); if (isSuccess == 1) { getEtqanEmployeeRequestsList = await EtqanApiClient().getEmployeeEtqanRequests(); diff --git a/lib/ui/etqan_ovr/etqan_create_request.dart b/lib/ui/etqan_ovr/etqan_create_request.dart index 93925e0..8bc320e 100644 --- a/lib/ui/etqan_ovr/etqan_create_request.dart +++ b/lib/ui/etqan_ovr/etqan_create_request.dart @@ -74,6 +74,8 @@ class _EtqanOvrCreateRequestState extends State { _buildAttachmentSection(provider), 16.height, _buildDescriptionField(provider), + 16.height, + _buildAnonymousCheckbox(provider), 24.height, ], )).expanded, @@ -276,4 +278,41 @@ class _EtqanOvrCreateRequestState extends State { ), ); } + + Widget _buildAnonymousCheckbox(EtqanOvrProviderModel provider) { + return InkWell( + onTap: () { + provider.setIsAnonymous(!provider.isAnonymous); + }, + borderRadius: BorderRadius.circular(15), + child: Row( + children: [ + Checkbox( + value: provider.isAnonymous, + onChanged: (bool? value) { + if (value != null) { + provider.setIsAnonymous(value); + } + }, + activeColor: MyColors.gradiantEndColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(4), + ), + ), + const SizedBox(width: 8), + Expanded( + child: Text( + LocaleKeys.submitAsAnonymous.tr(), + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Color(0xff2B353E), + letterSpacing: -0.44, + ), + ), + ), + ], + ), + ); + } } -- 2.30.2 From eebaafcf7c6b6bdcd3443a0acf1f8c88ead3c1fe Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Wed, 28 Jan 2026 10:21:55 +0300 Subject: [PATCH 112/135] approval level commented Code for filter . --- lib/classes/consts.dart | 4 ++-- lib/ui/etqan_ovr/etqan_create_request.dart | 19 +++---------------- 2 files changed, 5 insertions(+), 18 deletions(-) diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index dbec87d..a6b7173 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -4,12 +4,12 @@ class ApiConsts { // static String baseUrl = "http://10.200.204.11"; // Local server // static String baseUrl = "https://erptstapp.srca.org.sa"; // SRCA server - // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver + static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.201.204.101:2024"; // static String baseUrl = "https://webservices.hmg.com"; // PreProd // static String baseUrl = "https://hmgwebservices.com"; // Live server - static String baseUrl = "https://mohemm.hmg.com"; // New Live server + // static String baseUrl = "https://mohemm.hmg.com"; // New Live server // // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.20.200.111:1010/"; diff --git a/lib/ui/etqan_ovr/etqan_create_request.dart b/lib/ui/etqan_ovr/etqan_create_request.dart index 8bc320e..2e546bb 100644 --- a/lib/ui/etqan_ovr/etqan_create_request.dart +++ b/lib/ui/etqan_ovr/etqan_create_request.dart @@ -74,7 +74,7 @@ class _EtqanOvrCreateRequestState extends State { _buildAttachmentSection(provider), 16.height, _buildDescriptionField(provider), - 16.height, + 8.height, _buildAnonymousCheckbox(provider), 24.height, ], @@ -284,7 +284,6 @@ class _EtqanOvrCreateRequestState extends State { onTap: () { provider.setIsAnonymous(!provider.isAnonymous); }, - borderRadius: BorderRadius.circular(15), child: Row( children: [ Checkbox( @@ -295,22 +294,10 @@ class _EtqanOvrCreateRequestState extends State { } }, activeColor: MyColors.gradiantEndColor, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(4), - ), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)), ), const SizedBox(width: 8), - Expanded( - child: Text( - LocaleKeys.submitAsAnonymous.tr(), - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: Color(0xff2B353E), - letterSpacing: -0.44, - ), - ), - ), + Expanded(child: Text(LocaleKeys.submitAsAnonymous.tr(), style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: Color(0xff2B353E), letterSpacing: -0.44))), ], ), ); -- 2.30.2 From 12d8fd95badd40da6702525359fb939150b2fa25 Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Wed, 28 Jan 2026 10:27:08 +0300 Subject: [PATCH 113/135] approval level commented Code for filter . --- lib/ui/etqan_ovr/etqan_create_request.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ui/etqan_ovr/etqan_create_request.dart b/lib/ui/etqan_ovr/etqan_create_request.dart index 2e546bb..3a253d9 100644 --- a/lib/ui/etqan_ovr/etqan_create_request.dart +++ b/lib/ui/etqan_ovr/etqan_create_request.dart @@ -296,7 +296,7 @@ class _EtqanOvrCreateRequestState extends State { activeColor: MyColors.gradiantEndColor, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)), ), - const SizedBox(width: 8), + Expanded(child: Text(LocaleKeys.submitAsAnonymous.tr(), style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: Color(0xff2B353E), letterSpacing: -0.44))), ], ), -- 2.30.2 From a426bc332efe453cdcaa3e9cb1aa6fce0c1520b3 Mon Sep 17 00:00:00 2001 From: Sultan khan Date: Thu, 29 Jan 2026 11:04:59 +0300 Subject: [PATCH 114/135] E-learning Mandatory Courses - CR# 7150 --- assets/langs/ar-SA.json | 18 +- assets/langs/en-US.json | 15 +- lib/api/dashboard_api_client.dart | 26 ++ lib/config/routes.dart | 7 + lib/generated/codegen_loader.g.dart | 30 +- lib/generated/locale_keys.g.dart | 12 + .../dashboard/courses_response_model.dart | 91 +++++ lib/models/itg/advertisement.dart | 19 +- lib/provider/dashboard_provider_model.dart | 31 ++ .../itg/its_add_screen_video_image.dart | 43 ++- lib/ui/screens/courses/courses_screen.dart | 328 ++++++++++++++++++ .../ticket/ticket_detailed_screen.dart | 9 +- 12 files changed, 601 insertions(+), 28 deletions(-) create mode 100644 lib/models/dashboard/courses_response_model.dart create mode 100644 lib/ui/screens/courses/courses_screen.dart diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 916e8fb..fd27267 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -642,5 +642,19 @@ "yearsUsed": "سنوات الاستخدام", "faRequest": "طلب التخلص من FA", "showMore": "عرض المزيد", - "buyerDetails": "تفاصيل المشتري" -} \ No newline at end of file + "buyerDetails": "تفاصيل المشتري", + "ticketDetails": "تفاصيل التذكرة", + "currentTicketBalance": "رصيد التذكرة الحالي", + "ticketHistory": "تاريخ التذكرة", + "proceedBooking": "المتابعة للحجز", + "courses": "الدورات التدريبية", + "course": "دورة", + "status": "الحالة", + "deadline": "الموعد النهائي", + "overdue": "متأخر", + "open": "فتح", + "noCoursesAvailable": "لا توجد دورات متاحة", + "pullToRefresh": "اسحب للتحديث", + "courseUrlNotAvailable": "رابط الدورة غير متوفر" +} + diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 5fcb35c..9cb0be2 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -640,5 +640,18 @@ "yearsUsed": "Years Used", "faRequest":"FA Disposal Request", "showMore": "Show More", - "buyerDetails": "Buyer Details" + "buyerDetails": "Buyer Details", + "ticketDetails": "Ticket Details", + "currentTicketBalance": "Current Ticket Balance", + "ticketHistory": "Ticket History", + "proceedBooking": "Proceed For Booking", + "courses": "Courses", + "course": "Course", + "status": "Status", + "deadline": "Deadline", + "overdue": "Overdue", + "open": "Open", + "noCoursesAvailable": "No Courses Available", + "pullToRefresh": "Pull to refresh", + "courseUrlNotAvailable": "Course URL not available" } \ No newline at end of file diff --git a/lib/api/dashboard_api_client.dart b/lib/api/dashboard_api_client.dart index ae5fda8..20fdf93 100644 --- a/lib/api/dashboard_api_client.dart +++ b/lib/api/dashboard_api_client.dart @@ -14,6 +14,7 @@ import 'package:mohem_flutter_app/models/dashboard/get_accural_ticket_balance_mo import 'package:mohem_flutter_app/models/dashboard/get_attendance_tracking_list_model.dart'; import 'package:mohem_flutter_app/models/dashboard/itg_forms_model.dart'; import 'package:mohem_flutter_app/models/dashboard/list_menu.dart'; +import 'package:mohem_flutter_app/models/dashboard/courses_response_model.dart'; import 'package:mohem_flutter_app/models/generic_response_model.dart'; import 'package:mohem_flutter_app/models/itg/itg_main_response.dart'; import 'package:mohem_flutter_app/models/itg/itg_response_model.dart'; @@ -411,4 +412,29 @@ class DashboardApiClient { // postParams, // ); // } + + //Fetch All Courses Status + Future fetchAllCoursesStatus() async { + String url = "https://elearning.hmg.com/moodle_dev/api/Fetch_All_Courses_Status.php"; + + Map headers = { + 'x-api-key': 'bLi@mbXJeXTHd/)h&LFh%25+%25(Nbnaq6hBg%7d%5dyQbthY%7bv6ew6-5UT\$NASwucn%7d,_PSJpuwNCCen2%7djj%7b00HR2T-%5b,k7W%7d-0yepK?%258', + 'Content-Type': 'application/x-www-form-urlencoded', + }; + + Map postParams = { + "username": AppState().memberInformationList?.eMPLOYEENUMBER ?? "", + }; + + return await ApiClient().postJsonForObject( + (json) { + CoursesResponseModel responseData = CoursesResponseModel.fromJson(json); + return responseData; + }, + url, + postParams, + headers: headers, + isFormData: false, + ); + } } diff --git a/lib/config/routes.dart b/lib/config/routes.dart index 4653880..ca4d30f 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -54,6 +54,7 @@ import 'package:mohem_flutter_app/ui/profile/profile_screen.dart'; import 'package:mohem_flutter_app/ui/screens/announcements/announcement_details.dart'; import 'package:mohem_flutter_app/ui/screens/announcements/announcements.dart'; import 'package:mohem_flutter_app/ui/screens/child_education/child_education_assistance.dart'; +import 'package:mohem_flutter_app/ui/screens/courses/courses_screen.dart'; // import 'package:mohem_flutter_app/ui/my_attendance/work_from_home_screen.dart'; import 'package:mohem_flutter_app/ui/screens/eit/add_eit.dart'; import 'package:mohem_flutter_app/ui/screens/event_activity/event_activity.dart'; @@ -166,6 +167,9 @@ class AppRoutes { static const String offersAndDiscounts = "/offersAndDiscounts"; static const String offersAndDiscountsDetails = "/offersAndDiscountsDetails"; + // Courses + static const String courses = "/courses"; + //Pay slip static const String monthlyPaySlip = "/monthlyPaySlip"; @@ -291,6 +295,9 @@ class AppRoutes { offersAndDiscounts: (BuildContext context) => OffersAndDiscountsHome(), offersAndDiscountsDetails: (BuildContext context) => OffersAndDiscountsDetails(), + // Courses + courses: (BuildContext context) => const CoursesScreen(), + //pay slip monthlyPaySlip: (BuildContext context) => MonthlyPaySlipScreen(), performanceEvaluation: (BuildContext context) => PerformanceAppraisal(), diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index 6feb438..ee1ed0e 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -563,7 +563,7 @@ class CodegenLoader extends AssetLoader{ "addAtLeastOneAttachment": "الرجاء إضافة مرفق واحد على الأقل.", "pleaseClickButtonToJoinMarathon": "الرجاء الضغط على الزر أدناه للانضمام إلى الماراثون", "youCannotJoinTheMarathon": "لا يمكنك الانضمام إلى الماراثون لأنك تجاوزت الحد الزمني", - "open": "يفتح", + "open": "فتح", "paymentRequest": "طلب الدفع", "paymentDetails": "تفاصيل الدفع", "requestNo": "رقم الطلب", @@ -655,7 +655,18 @@ class CodegenLoader extends AssetLoader{ "yearsUsed": "سنوات الاستخدام", "faRequest": "طلب التخلص من FA", "showMore": "عرض المزيد", - "buyerDetails": "تفاصيل المشتري" + "buyerDetails": "تفاصيل المشتري", + "ticketDetails": "تفاصيل التذكرة", + "currentTicketBalance": "رصيد التذكرة الحالي", + "ticketHistory": "تاريخ التذكرة", + "proceedBooking": "المتابعة للحجز", + "courses": "الدورات التدريبية", + "course": "دورة", + "status": "الحالة", + "deadline": "الموعد النهائي", + "noCoursesAvailable": "لا توجد دورات متاحة", + "pullToRefresh": "اسحب للتحديث", + "courseUrlNotAvailable": "رابط الدورة غير متوفر" }; static const Map _en_US = { "mohemm": "Mohemm", @@ -1220,7 +1231,7 @@ static const Map _en_US = { "userSearch": "User Search", "userName": "User Name", "userId": "UserID", - "open": "open", + "open": "Open", "addAtLeastOneAttachment": "Please add at least one attachment.", "pleaseClickButtonToJoinMarathon": "Press the button below to join the Marathon.", "youCannotJoinTheMarathon": "You cannot join the Marathon because you have exceeded the time limit.", @@ -1298,7 +1309,18 @@ static const Map _en_US = { "yearsUsed": "Years Used", "faRequest": "FA Disposal Request", "showMore": "Show More", - "buyerDetails": "Buyer Details" + "buyerDetails": "Buyer Details", + "ticketDetails": "Ticket Details", + "currentTicketBalance": "Current Ticket Balance", + "ticketHistory": "Ticket History", + "proceedBooking": "Proceed For Booking", + "courses": "Courses", + "course": "Course", + "status": "Status", + "deadline": "Deadline", + "noCoursesAvailable": "No Courses Available", + "pullToRefresh": "Pull to refresh", + "courseUrlNotAvailable": "Course URL not available" }; static const Map> mapLocales = {"ar_SA": _ar_SA, "en_US": _en_US}; } diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 1a1cf95..b9a3cfc 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -628,5 +628,17 @@ abstract class LocaleKeys { static const faRequest = 'faRequest'; static const showMore = 'showMore'; static const buyerDetails = 'buyerDetails'; + static const ticketDetails = 'ticketDetails'; + static const currentTicketBalance = 'currentTicketBalance'; + static const ticketHistory = 'ticketHistory'; + static const proceedBooking = 'proceedBooking'; + static const courses = 'courses'; + static const course = 'course'; + static const status = 'status'; + static const deadline = 'deadline'; + static const overdue = 'overdue'; + static const noCoursesAvailable = 'noCoursesAvailable'; + static const pullToRefresh = 'pullToRefresh'; + static const courseUrlNotAvailable = 'courseUrlNotAvailable'; } diff --git a/lib/models/dashboard/courses_response_model.dart b/lib/models/dashboard/courses_response_model.dart new file mode 100644 index 0000000..63a98fc --- /dev/null +++ b/lib/models/dashboard/courses_response_model.dart @@ -0,0 +1,91 @@ +class CoursesResponseModel { + bool? success; + int? status; + String? username; + List? coursesStatus; + int? totalCourses; + + CoursesResponseModel({ + this.success, + this.status, + this.username, + this.coursesStatus, + this.totalCourses, + }); + + CoursesResponseModel.fromJson(Map json) { + success = json['success']; + status = json['status']; + username = json['username']; + if (json['courses_status'] != null) { + coursesStatus = []; + json['courses_status'].forEach((v) { + coursesStatus!.add(CourseStatus.fromJson(v)); + }); + } + totalCourses = json['total_courses']; + } + + Map toJson() { + Map data = {}; + data['success'] = success; + data['status'] = status; + data['username'] = username; + if (coursesStatus != null) { + data['courses_status'] = coursesStatus!.map((v) => v.toJson()).toList(); + } + data['total_courses'] = totalCourses; + return data; + } +} + +class CourseStatus { + String? cId; + String? cFullname; + String? cNameAr; + String? cShortname; + String? cStatus; + String? cIsMohemmAffective; + String? cStartdate; + String? cEnddate; + String? cUrl; + + CourseStatus({ + this.cId, + this.cFullname, + this.cNameAr, + this.cShortname, + this.cStatus, + this.cIsMohemmAffective, + this.cStartdate, + this.cEnddate, + this.cUrl, + }); + + CourseStatus.fromJson(Map json) { + cId = json['c_id']; + cFullname = json['c_fullname']; + cNameAr = json['c_name_ar']; + cShortname = json['c_shortname']; + cStatus = json['c_status']; + cIsMohemmAffective = json['c_is_mohemm_affective']; + cStartdate = json['c_startdate']; + cEnddate = json['c_enddate']; + cUrl = json['c_url']; + } + + Map toJson() { + Map data = {}; + data['c_id'] = cId; + data['c_fullname'] = cFullname; + data['c_name_ar'] = cNameAr; + data['c_shortname'] = cShortname; + data['c_status'] = cStatus; + data['c_is_mohemm_affective'] = cIsMohemmAffective; + data['c_startdate'] = cStartdate; + data['c_enddate'] = cEnddate; + data['c_url'] = cUrl; + return data; + } +} + diff --git a/lib/models/itg/advertisement.dart b/lib/models/itg/advertisement.dart index 002f73d..2379d37 100644 --- a/lib/models/itg/advertisement.dart +++ b/lib/models/itg/advertisement.dart @@ -136,10 +136,21 @@ class ActionButtonsColl { late String btnTextEn; late String btnTextAr; late String actionValue; - late dynamic iconOrImage; + dynamic iconOrImage; + String? actionType; late int orderNo; + String? url; - ActionButtonsColl({required this.actionButtonId, required this.btnTextEn, required this.btnTextAr, required this.actionValue, required this.iconOrImage, required this.orderNo}); + ActionButtonsColl({ + required this.actionButtonId, + required this.btnTextEn, + required this.btnTextAr, + required this.actionValue, + this.iconOrImage, + this.actionType, + required this.orderNo, + this.url, + }); ActionButtonsColl.fromJson(Map json) { actionButtonId = json['actionButtonId']; @@ -147,7 +158,9 @@ class ActionButtonsColl { btnTextAr = json['btnTextAr']; actionValue = json['actionValue']; iconOrImage = json['iconOrImage']; + actionType = json['actionType']; orderNo = json['orderNo']; + url = json['url']; } Map toJson() { @@ -157,7 +170,9 @@ class ActionButtonsColl { data['btnTextAr'] = this.btnTextAr; data['actionValue'] = this.actionValue; data['iconOrImage'] = this.iconOrImage; + data['actionType'] = this.actionType; data['orderNo'] = this.orderNo; + data['url'] = this.url; return data; } } diff --git a/lib/provider/dashboard_provider_model.dart b/lib/provider/dashboard_provider_model.dart index 05c9ebb..00f339d 100644 --- a/lib/provider/dashboard_provider_model.dart +++ b/lib/provider/dashboard_provider_model.dart @@ -19,6 +19,7 @@ import 'package:mohem_flutter_app/models/dashboard/list_menu.dart'; import 'package:mohem_flutter_app/models/dashboard/menu_entries.dart'; import 'package:mohem_flutter_app/models/dashboard/menus.dart'; import 'package:mohem_flutter_app/models/dashboard/mohemm_itg_pending_task_responseitem.dart'; +import 'package:mohem_flutter_app/models/dashboard/courses_response_model.dart'; import 'package:mohem_flutter_app/models/eit/get_eit_transaction_model.dart'; import 'package:mohem_flutter_app/models/generic_response_model.dart'; import 'package:mohem_flutter_app/models/itg/itg_response_model.dart'; @@ -67,6 +68,11 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { bool isOffersLoading = true; List getOffersList = []; + //Courses + bool isCoursesLoading = true; + CoursesResponseModel? coursesResponse; + List coursesList = []; + //Attendance Tracking API's & Methods Future fetchAttendanceTracking(context) async { try { @@ -121,6 +127,7 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { DrawerMenuItem("assets/images/drawer/performance_evaluation.svg", LocaleKeys.performanceEvaluation.tr(), AppRoutes.performanceEvaluation), DrawerMenuItem("assets/images/drawer/mowadhafi.svg", LocaleKeys.mowadhafhi.tr(), AppRoutes.mowadhafhi), DrawerMenuItem("assets/images/drawer/pending_trasactions.svg", LocaleKeys.pendingTransactions.tr(), AppRoutes.pendingTransactions), + DrawerMenuItem("assets/images/drawer/courses.svg", "courses".tr(), AppRoutes.courses), // DrawerMenuItem("assets/images/drawer/drawer_marathon.svg", LocaleKeys.brainMarathon.tr(), AppRoutes.marathonIntroScreen), DrawerMenuItem("assets/images/drawer/change_password.svg", LocaleKeys.changePassword.tr(), AppRoutes.changePassword), ]; @@ -409,6 +416,30 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { return res; } + //Courses API's & Methods + Future fetchCourses(BuildContext context) async { + try { + isCoursesLoading = true; + notifyListeners(); + + coursesResponse = await DashboardApiClient().fetchAllCoursesStatus(); + + if (coursesResponse != null && coursesResponse!.success == true) { + coursesList = coursesResponse!.coursesStatus ?? []; + } else { + coursesList = []; + } + + isCoursesLoading = false; + notifyListeners(); + } catch (ex) { + isCoursesLoading = false; + coursesList = []; + notifyListeners(); + Utils.handleException(ex, context, null); + } + } + void notify() { notifyListeners(); } 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 2076d7c..ab0d39f 100644 --- a/lib/ui/landing/itg/its_add_screen_video_image.dart +++ b/lib/ui/landing/itg/its_add_screen_video_image.dart @@ -26,7 +26,7 @@ class ITGAdsScreen extends StatefulWidget { class _ITGAdsScreenState extends State { late Future _futureController; - late VideoPlayerController _controller; + VideoPlayerController? _controller; bool skip = false; bool isVideo = false; bool isImage = false; @@ -125,7 +125,7 @@ class _ITGAdsScreenState extends State { @override void dispose() { - if (_controller != null) _controller.dispose(); + _controller?.dispose(); super.dispose(); } @@ -166,11 +166,11 @@ class _ITGAdsScreenState extends State { child: isAudio ? Lottie.asset(MyLottieConsts.audioPlaybackLottie) : AspectRatio( - aspectRatio: _controller.value.aspectRatio, + aspectRatio: _controller!.value.aspectRatio, child: Stack( alignment: Alignment.bottomCenter, children: [ - VideoPlayer(_controller), + VideoPlayer(_controller!), if (advertisementData?.isOptional ?? false) Positioned( top: 4, @@ -230,7 +230,7 @@ class _ITGAdsScreenState extends State { alignment: Alignment.center, children: [ MyVideoProgressIndicator( - _controller, + _controller!, allowScrubbing: false, //padding: EdgeInsets.only(left: 60, right: 60), ), @@ -386,16 +386,29 @@ class _ITGAdsScreenState extends State { if (advertisementData!.actionButtonsColl![index].actionValue.toLowerCase() == "skip") { Navigator.pop(context); } else { - Uri uri = Uri.parse(advertisementData!.actionButtonsColl![index].iconOrImage); - // if (await canLaunchUrl(uri)) { - await launchUrl(uri, mode: LaunchMode.externalApplication).catchError((err) { - // print(err); - Utils.showToast('Could not launch'); - }); - Navigator.pop(context); - // } else { - // Utils.showToast('Could not launch'); - // } + if (advertisementData!.actionButtonsColl![index].actionType!.toLowerCase() == 'redirect' && advertisementData!.actionButtonsColl![index].actionValue!.toLowerCase() == + 'external') { + Uri uri = Uri.parse(advertisementData!.actionButtonsColl![index].url!); + await launchUrl(uri, mode: LaunchMode.externalApplication).catchError((err) { + // print(err); + Utils.showToast('Could not launch'); + }); + Navigator.pop(context); + } else if (advertisementData!.actionButtonsColl![index].actionType!.toLowerCase() == 'redirect' && advertisementData!.actionButtonsColl![index].actionValue!.toLowerCase() == + 'internal') { + await Navigator.pushNamed(context, advertisementData!.actionButtonsColl![index].url!); + } else { + Uri uri = Uri.parse(advertisementData!.actionButtonsColl![index].iconOrImage); + // if (await canLaunchUrl(uri)) { + await launchUrl(uri, mode: LaunchMode.externalApplication).catchError((err) { + // print(err); + Utils.showToast('Could not launch'); + }); + Navigator.pop(context); + // } else { + // Utils.showToast('Could not launch'); + // } + } } }, ), diff --git a/lib/ui/screens/courses/courses_screen.dart b/lib/ui/screens/courses/courses_screen.dart new file mode 100644 index 0000000..dc00ea1 --- /dev/null +++ b/lib/ui/screens/courses/courses_screen.dart @@ -0,0 +1,328 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_inappwebview/flutter_inappwebview.dart'; +import 'package:flutter_svg/flutter_svg.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/inAppWebView.dart'; +import 'package:mohem_flutter_app/classes/utils.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/dashboard/courses_response_model.dart'; +import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; +import 'package:mohem_flutter_app/theme/colors.dart' as theme_colors; +import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; +import 'package:provider/provider.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; + +class CoursesScreen extends StatefulWidget { + const CoursesScreen({Key? key}) : super(key: key); + + @override + _CoursesScreenState createState() => _CoursesScreenState(); +} + +class _CoursesScreenState extends State { + late DashboardProviderModel data; + final RefreshController _refreshController = RefreshController(initialRefresh: false); + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) { + data = Provider.of(context, listen: false); + _onRefresh(); + }); + } + + void _onRefresh() async { + await data.fetchCourses(context); + _refreshController.refreshCompleted(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBarWidget( + context, + title: LocaleKeys.courses.tr(), + ), + body: Consumer( + builder: (context, provider, child) { + return SmartRefresher( + enablePullDown: true, + enablePullUp: false, + controller: _refreshController, + onRefresh: _onRefresh, + child: provider.isCoursesLoading + ? _buildShimmerLoading() + : provider.coursesList.isEmpty + ? _buildEmptyState() + : _buildCoursesList(provider.coursesList), + ); + }, + ), + ); + } + + Widget _buildShimmerLoading() { + return ListView.builder( + padding: const EdgeInsets.all(21), + itemCount: 5, + itemBuilder: (context, index) { + return Container( + margin: const EdgeInsets.only(bottom: 12), + height: 150, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(15), + boxShadow: [ + BoxShadow( + color: const Color(0xff000000).withOpacity(.05), + blurRadius: 26, + offset: const Offset(0, -3), + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + height: 20, + width: 200, + decoration: BoxDecoration( + color: Colors.grey[300], + borderRadius: BorderRadius.circular(4), + ), + ).toShimmer(), + 12.height, + Container( + height: 14, + width: 100, + decoration: BoxDecoration( + color: Colors.grey[300], + borderRadius: BorderRadius.circular(4), + ), + ).toShimmer(), + const Spacer(), + Container( + height: 40, + decoration: BoxDecoration( + color: Colors.grey[300], + borderRadius: BorderRadius.circular(6), + ), + ).toShimmer(), + ], + ).paddingAll(14), + ); + }, + ); + } + + Widget _buildEmptyState() { + return Utils.getNoDataWidget(context); + } + + Widget _buildCoursesList(List courses) { + return ListView.separated( + physics: const BouncingScrollPhysics(), + shrinkWrap: true, + padding: const EdgeInsets.all(21), + itemBuilder: (BuildContext context, int index) { + return _buildCourseCard(courses[index]); + }, + separatorBuilder: (BuildContext context, int index) => 12.height, + itemCount: courses.length, + ); + } + + Widget _buildCourseCard(CourseStatus course) { + bool isArabic = AppState().isArabic(context); + String courseName = isArabic && course.cNameAr != null && course.cNameAr!.isNotEmpty + ? course.cNameAr! + : course.cFullname ?? ''; + + String status = course.cStatus ?? 'Unknown'; + Color statusColor = _getStatusColor(status); + + return InkWell( + onTap: () => _openCourse(course.cUrl ?? ''), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Course Title + Row( + children: [ + Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: MyColors.lightGreyEFColor, + borderRadius: BorderRadius.circular(8), + ), + child: const Icon( + Icons.school_rounded, + color: MyColors.gradiantStartColor, + size: 20, + ), + ), + 12.width, + Expanded( + child: courseName.toText14(isBold: true, color: MyColors.darkTextColor), + ), + ], + ), + 12.height, + // Status Badge + Row( + children: [ + Icon( + _getStatusIcon(status), + size: 16, + color: statusColor, + ), + 6.width, + LocaleKeys.status.tr().toText11(color: MyColors.grey98Color), + 8.width, + Container( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), + decoration: BoxDecoration( + color: statusColor.withOpacity(0.1), + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: statusColor.withOpacity(0.3), + width: 1, + ), + ), + child: status.toText10(color: statusColor, isBold: true), + ), + ], + ), + 10.height, + // Start Date + if (course.cStartdate != null && course.cStartdate!.isNotEmpty) + Row( + children: [ + const Icon( + Icons.calendar_month_rounded, + size: 16, + color: MyColors.darkIconColor, + ), + 6.width, + LocaleKeys.startDateT.tr().toText11(color: MyColors.grey98Color), + 8.width, + Expanded( + child: _formatDate(course.cStartdate!).toText11( + color: MyColors.darkTextColor, + isBold: true, + ), + ), + ], + ), + if (course.cStartdate != null && course.cStartdate!.isNotEmpty) 14.height, + // Open Button + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + LocaleKeys.open.tr().toText12(color: MyColors.gradiantStartColor, isUnderLine: true), + 6.width, + RotatedBox( + quarterTurns: AppState().isArabic(context) ? 2 : 4, + child: SvgPicture.asset( + "assets/images/arrow_next.svg", + color: MyColors.gradiantStartColor, + width: 16, + height: 16, + ), + ), + ], + ), + ], + ).objectContainerView(), + ); + } + + + IconData _getStatusIcon(String status) { + if (status.toLowerCase().contains('passed')) { + return Icons.check_circle_rounded; + } else if (status.toLowerCase().contains('not passed') || status.toLowerCase().contains('failed')) { + return Icons.cancel_rounded; + } else if (status.toLowerCase().contains('in progress')) { + return Icons.pending_rounded; + } else { + return Icons.info_rounded; + } + } + + Color _getStatusColor(String status) { + if (status.toLowerCase().contains('passed') && !status.toLowerCase().contains('not passed')) { + return Colors.green; + } else if (status.toLowerCase().contains('not passed') || status.toLowerCase().contains('failed')) { + return Colors.red; + } else if (status.toLowerCase().contains('in progress')) { + return Colors.yellow[700]!; + } else { + return MyColors.grey98Color; + } + } + + DateTime? _parseDate(String? date) { + if (date == null || date.isEmpty) return null; + try { + return DateTime.parse(date.replaceAll(' ', 'T')); + } catch (e) { + try { + DateFormat format = DateFormat('yyyy-MM-dd HH:mm:ss'); + return format.parse(date); + } catch (e) { + return null; + } + } + } + + String _formatDate(String date) { + DateTime? dateTime = _parseDate(date); + if (dateTime == null) return date; + + bool isArabic = AppState().isArabic(context); + DateFormat format = DateFormat('dd MMM yyyy, hh:mm a', isArabic ? 'ar' : 'en'); + return format.format(dateTime); + } + + void _openCourse(String url) { + if (url.isEmpty) { + Utils.showToast(LocaleKeys.courseUrlNotAvailable.tr()); + return; + } + + MyInAppBrowser browser = MyInAppBrowser( + onExitCallback: () {}, + onLoadStartCallback: (String url) {}, + ); + + var settings = InAppBrowserClassSettings( + webViewSettings: InAppWebViewSettings( + useShouldOverrideUrlLoading: false, + transparentBackground: false, + ), + browserSettings: InAppBrowserSettings( + hideUrlBar: true, + hideTitleBar: false, + toolbarTopBackgroundColor: theme_colors.primaryColor, + ), + ); + + browser.openUrlRequest( + urlRequest: URLRequest(url: WebUri(url)), + settings: settings, + ); + } + + @override + void dispose() { + _refreshController.dispose(); + super.dispose(); + } +} diff --git a/lib/ui/screens/ticket/ticket_detailed_screen.dart b/lib/ui/screens/ticket/ticket_detailed_screen.dart index d406153..c4d232f 100644 --- a/lib/ui/screens/ticket/ticket_detailed_screen.dart +++ b/lib/ui/screens/ticket/ticket_detailed_screen.dart @@ -9,6 +9,7 @@ import 'package:mohem_flutter_app/classes/utils.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/dashboard/get_accural_ticket_balance_model.dart'; import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; @@ -55,7 +56,7 @@ class _TicketDetailedScreenState extends State { Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, - appBar: AppBarWidget(context, title: "Ticket Details"), + appBar: AppBarWidget(context, title:LocaleKeys.ticketDetails.tr()), body: Column( children: [ ListView( @@ -74,7 +75,7 @@ class _TicketDetailedScreenState extends State { children: [ Row( children: [ - "Current Ticket Balance".toText20().expanded, + LocaleKeys.currentTicketBalance.tr().toText20().expanded, Row( children: [ const Icon(Icons.calendar_month_rounded, color: MyColors.darkIconColor, size: 16), @@ -118,7 +119,7 @@ class _TicketDetailedScreenState extends State { shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), children: [ - "Tickets History".toText20().expanded, + LocaleKeys.ticketHistory.tr().toText20().expanded, 12.height, ListView.separated( physics: const NeverScrollableScrollPhysics(), @@ -175,7 +176,7 @@ class _TicketDetailedScreenState extends State { ], ], ).expanded, - DefaultButton("Proceed For Booking", () { + DefaultButton(LocaleKeys.proceedBooking.tr(), () { if (widget.url != null && widget.jwtToken != null) { Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => SsoLoginWebView(url: widget.url, jwtToken: widget.jwtToken))); } -- 2.30.2 From 5705619ce4f93b766e26c0185b28c90646a245fc Mon Sep 17 00:00:00 2001 From: Sultan khan Date: Thu, 29 Jan 2026 11:11:56 +0300 Subject: [PATCH 115/135] untracked icon added --- assets/images/drawer/courses.svg | 8 ++++++++ assets/images/ticket_bal.svg | 6 ++++++ assets/images/vacation_rule.svg | 16 ++++++++++++++++ assets/images/worklist/approve.svg | 1 + assets/images/worklist/reject.svg | 1 + 5 files changed, 32 insertions(+) create mode 100644 assets/images/drawer/courses.svg create mode 100644 assets/images/ticket_bal.svg create mode 100644 assets/images/vacation_rule.svg create mode 100644 assets/images/worklist/approve.svg create mode 100644 assets/images/worklist/reject.svg diff --git a/assets/images/drawer/courses.svg b/assets/images/drawer/courses.svg new file mode 100644 index 0000000..d15e742 --- /dev/null +++ b/assets/images/drawer/courses.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/assets/images/ticket_bal.svg b/assets/images/ticket_bal.svg new file mode 100644 index 0000000..8fadde8 --- /dev/null +++ b/assets/images/ticket_bal.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/assets/images/vacation_rule.svg b/assets/images/vacation_rule.svg new file mode 100644 index 0000000..0a536f7 --- /dev/null +++ b/assets/images/vacation_rule.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/assets/images/worklist/approve.svg b/assets/images/worklist/approve.svg new file mode 100644 index 0000000..8d62ae9 --- /dev/null +++ b/assets/images/worklist/approve.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/images/worklist/reject.svg b/assets/images/worklist/reject.svg new file mode 100644 index 0000000..cb5da34 --- /dev/null +++ b/assets/images/worklist/reject.svg @@ -0,0 +1 @@ + \ No newline at end of file -- 2.30.2 From 19ccee6a208127fc4c9d40b338ef80de197c56bf Mon Sep 17 00:00:00 2001 From: Sultan khan Date: Thu, 29 Jan 2026 11:23:29 +0300 Subject: [PATCH 116/135] updates --- assets/langs/ar-SA.json | 2 +- lib/generated/codegen_loader.g.dart | 10 ++++++---- lib/generated/locale_keys.g.dart | 2 +- lib/ui/screens/courses/courses_screen.dart | 6 +++--- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index aded425..5eb2c59 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -653,7 +653,7 @@ "overdue": "متأخر", "noCoursesAvailable": "لا توجد دورات متاحة", "pullToRefresh": "اسحب للتحديث", - "courseUrlNotAvailable": "رابط الدورة غير متوفر" + "courseUrlNotAvailable": "رابط الدورة غير متوفر", "buyerDetails": "تفاصيل المشتري", "parkingQr": "وقوف السيارات QR" } diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index e2de580..4a92eef 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -655,7 +655,6 @@ class CodegenLoader extends AssetLoader{ "yearsUsed": "سنوات الاستخدام", "faRequest": "طلب التخلص من FA", "showMore": "عرض المزيد", - "buyerDetails": "تفاصيل المشتري", "ticketDetails": "تفاصيل التذكرة", "currentTicketBalance": "رصيد التذكرة الحالي", "ticketHistory": "تاريخ التذكرة", @@ -664,9 +663,11 @@ class CodegenLoader extends AssetLoader{ "course": "دورة", "status": "الحالة", "deadline": "الموعد النهائي", + "overdue": "متأخر", "noCoursesAvailable": "لا توجد دورات متاحة", "pullToRefresh": "اسحب للتحديث", "courseUrlNotAvailable": "رابط الدورة غير متوفر", + "buyerDetails": "تفاصيل المشتري", "parkingQr": "وقوف السيارات QR" }; static const Map _en_US = { @@ -1310,8 +1311,6 @@ static const Map _en_US = { "yearsUsed": "Years Used", "faRequest": "FA Disposal Request", "showMore": "Show More", - "buyerDetails": "Buyer Details", - "parkingQr": "Parking QR", "ticketDetails": "Ticket Details", "currentTicketBalance": "Current Ticket Balance", "ticketHistory": "Ticket History", @@ -1320,9 +1319,12 @@ static const Map _en_US = { "course": "Course", "status": "Status", "deadline": "Deadline", + "overdue": "Overdue", "noCoursesAvailable": "No Courses Available", "pullToRefresh": "Pull to refresh", - "courseUrlNotAvailable": "Course URL not available" + "courseUrlNotAvailable": "Course URL not available", + "buyerDetails": "Buyer Details", + "parkingQr": "Parking QR" }; static const Map> mapLocales = {"ar_SA": _ar_SA, "en_US": _en_US}; } diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 37d0b60..57aad94 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -627,7 +627,6 @@ abstract class LocaleKeys { static const yearsUsed = 'yearsUsed'; static const faRequest = 'faRequest'; static const showMore = 'showMore'; - static const buyerDetails = 'buyerDetails'; static const ticketDetails = 'ticketDetails'; static const currentTicketBalance = 'currentTicketBalance'; static const ticketHistory = 'ticketHistory'; @@ -640,6 +639,7 @@ abstract class LocaleKeys { static const noCoursesAvailable = 'noCoursesAvailable'; static const pullToRefresh = 'pullToRefresh'; static const courseUrlNotAvailable = 'courseUrlNotAvailable'; + static const buyerDetails = 'buyerDetails'; static const parkingQr = 'parkingQr'; } diff --git a/lib/ui/screens/courses/courses_screen.dart b/lib/ui/screens/courses/courses_screen.dart index dc00ea1..7c995a2 100644 --- a/lib/ui/screens/courses/courses_screen.dart +++ b/lib/ui/screens/courses/courses_screen.dart @@ -201,7 +201,7 @@ class _CoursesScreenState extends State { ), 10.height, // Start Date - if (course.cStartdate != null && course.cStartdate!.isNotEmpty) + if (course.cEnddate != null && course.cEnddate!.isNotEmpty) Row( children: [ const Icon( @@ -210,10 +210,10 @@ class _CoursesScreenState extends State { color: MyColors.darkIconColor, ), 6.width, - LocaleKeys.startDateT.tr().toText11(color: MyColors.grey98Color), + LocaleKeys.endDateT.tr().toText11(color: MyColors.grey98Color), 8.width, Expanded( - child: _formatDate(course.cStartdate!).toText11( + child: _formatDate(course.cEnddate!).toText11( color: MyColors.darkTextColor, isBold: true, ), -- 2.30.2 From eea35e4d77a4373f9582a93fed0b2de32e23557e Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Sun, 15 Feb 2026 15:09:38 +0300 Subject: [PATCH 117/135] approval level commented Code for filter . --- ios/Runner/Info.plist | 2 ++ lib/api/dashboard_api_client.dart | 2 +- lib/api/etqan_ovr_api_client.dart | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 01197de..595a98f 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -61,6 +61,8 @@ This app requires photo library access to select image as document & upload it. UIApplicationSupportsIndirectInputEvents +keen ovr NSSpeechRecognitionUsageDescription + This app requires speech recognition access to access voice command features. UIBackgroundModes fetch diff --git a/lib/api/dashboard_api_client.dart b/lib/api/dashboard_api_client.dart index 2bddb42..5256084 100644 --- a/lib/api/dashboard_api_client.dart +++ b/lib/api/dashboard_api_client.dart @@ -226,7 +226,7 @@ class DashboardApiClient { } Future getBookingSSOFinalRedirection({required String token}) async { - token = + // token = "eyJhbGciOiJSUzI1NiIsImtpZCI6IjhjZTE2OWM0YjIwYjQ2ZWM5YTQyOTU3Y2ZhODUzNzQ1IiwidHlwIjoiSldUIn0.eyJ0ZW5hbnRfaWQiOiJhOWY0ZDFhMDU5NmQ0YWVhOGY4MzA5OTJlYzRiZGFjMSIsImVpZCI6IjExNzkzMCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL3NpZCI6Ijk2MDI0OGM1NzA3YzQ3MmFhYTEzM2I1N2ZhODE1ZmVhIiwibGFuZ3VhZ2UiOiJVUyIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL2VtYWlsYWRkcmVzcyI6IjExNzkzMEBobWcuY29tIiwiZXhwIjoxNzgyNDc1NzY5LCJpc3MiOiJodHRwczovL3Nzby11YXQuaG1nLmNvbSIsImF1ZCI6ImE5ZjRkMWEwNTk2ZDRhZWE4ZjgzMDk5MmVjNGJkYWMxIn0.rJcLVsG8D0XECyLERCTD2uqGeWyvp-OBVGE9uL2qKrX4etFUHgdFt_5kYF6edFTtGy-0PIZadHDmv7e-IOhVWHm5HVMClaukiXoRXR8cDN8XA1wfme3Kd-U5PXN-IRh49AyRTzLO0rYNPvH81ScosWGlsFSkOvA-0hJNa2adHdtvgNvB8wJshSU5p7sAmF8mjdDY6aInG19etu2iEuUDwHHA4ZY_ts4hboHo8fE392hFaYGonExoD7bpW5RMx5xKWeRCmWpG_PK8Aw_z1jGzdB9PANus4pteRGuln1J-kmo2lQC9pVrSyZATAKp1HfgfyZ_vUhaHEfM69cMWaCslJQ"; // var request = http.MultipartRequest('POST', Uri.parse('https://ek.techmaster.in/SSO/HMG')); var request = http.MultipartRequest('POST', Uri.parse('https://Paxes-release.techmaster.in/SSO/HMG')); diff --git a/lib/api/etqan_ovr_api_client.dart b/lib/api/etqan_ovr_api_client.dart index 3f595a4..e4b4e61 100644 --- a/lib/api/etqan_ovr_api_client.dart +++ b/lib/api/etqan_ovr_api_client.dart @@ -55,7 +55,7 @@ class EtqanApiClient { (json) { List responseData = []; if (json["ETQAN_GetEmployeeOVRRequests_Response"] != null && json["ETQAN_GetEmployeeOVRRequests_Response"].isNotEmpty) { - json["ETQAN_GetEmployeeOVRRequests_Response"].forEach((element) { + json["ETQAN_GetEmployeeOVRRequests_Response"].forEach((Map element) { responseData.add(EtqanGetEmployeeOvrRequestsResponse.fromJson(element)); }); } -- 2.30.2 From 048c9b395f57fbafdce4fa0b085f09cc3ed53781 Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Wed, 18 Feb 2026 13:13:23 +0300 Subject: [PATCH 118/135] approval level commented Code for filter . --- ios/Runner/Info.plist | 2 +- lib/api/etqan_ovr_api_client.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 595a98f..51a5801 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -61,7 +61,7 @@ This app requires photo library access to select image as document & upload it. UIApplicationSupportsIndirectInputEvents -keen ovr NSSpeechRecognitionUsageDescription + NSSpeechRecognitionUsageDescription This app requires speech recognition access to access voice command features. UIBackgroundModes diff --git a/lib/api/etqan_ovr_api_client.dart b/lib/api/etqan_ovr_api_client.dart index e4b4e61..3f595a4 100644 --- a/lib/api/etqan_ovr_api_client.dart +++ b/lib/api/etqan_ovr_api_client.dart @@ -55,7 +55,7 @@ class EtqanApiClient { (json) { List responseData = []; if (json["ETQAN_GetEmployeeOVRRequests_Response"] != null && json["ETQAN_GetEmployeeOVRRequests_Response"].isNotEmpty) { - json["ETQAN_GetEmployeeOVRRequests_Response"].forEach((Map element) { + json["ETQAN_GetEmployeeOVRRequests_Response"].forEach((element) { responseData.add(EtqanGetEmployeeOvrRequestsResponse.fromJson(element)); }); } -- 2.30.2 From 82c9aa8a2f34e8d14c6f1f4cb3bd15e46dcf5d39 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Tue, 27 Jan 2026 17:33:38 +0300 Subject: [PATCH 119/135] updates --- lib/api/dashboard_api_client.dart | 3 ++- lib/classes/consts.dart | 4 ++-- lib/ui/work_list/itg_fragments/approval_level_fragment.dart | 4 ++-- pubspec.yaml | 4 ++-- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/api/dashboard_api_client.dart b/lib/api/dashboard_api_client.dart index 6f7288c..0b8247f 100644 --- a/lib/api/dashboard_api_client.dart +++ b/lib/api/dashboard_api_client.dart @@ -230,7 +230,8 @@ class DashboardApiClient { // token = // "eyJhbGciOiJSUzI1NiIsImtpZCI6IjhjZTE2OWM0YjIwYjQ2ZWM5YTQyOTU3Y2ZhODUzNzQ1IiwidHlwIjoiSldUIn0.eyJ0ZW5hbnRfaWQiOiJhOWY0ZDFhMDU5NmQ0YWVhOGY4MzA5OTJlYzRiZGFjMSIsImVpZCI6IjExNzkzMCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL3NpZCI6Ijk2MDI0OGM1NzA3YzQ3MmFhYTEzM2I1N2ZhODE1ZmVhIiwibGFuZ3VhZ2UiOiJVUyIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL2VtYWlsYWRkcmVzcyI6IjExNzkzMEBobWcuY29tIiwiZXhwIjoxNzgyNDc1NzY5LCJpc3MiOiJodHRwczovL3Nzby11YXQuaG1nLmNvbSIsImF1ZCI6ImE5ZjRkMWEwNTk2ZDRhZWE4ZjgzMDk5MmVjNGJkYWMxIn0.rJcLVsG8D0XECyLERCTD2uqGeWyvp-OBVGE9uL2qKrX4etFUHgdFt_5kYF6edFTtGy-0PIZadHDmv7e-IOhVWHm5HVMClaukiXoRXR8cDN8XA1wfme3Kd-U5PXN-IRh49AyRTzLO0rYNPvH81ScosWGlsFSkOvA-0hJNa2adHdtvgNvB8wJshSU5p7sAmF8mjdDY6aInG19etu2iEuUDwHHA4ZY_ts4hboHo8fE392hFaYGonExoD7bpW5RMx5xKWeRCmWpG_PK8Aw_z1jGzdB9PANus4pteRGuln1J-kmo2lQC9pVrSyZATAKp1HfgfyZ_vUhaHEfM69cMWaCslJQ"; // // var request = http.MultipartRequest('POST', Uri.parse('https://ek.techmaster.in/SSO/HMG')); - var request = http.MultipartRequest('POST', Uri.parse('https://Paxes-release.techmaster.in/SSO/HMG')); + var request = http.MultipartRequest('POST', Uri.parse('https://Paxes-release.techmaster.in/SSO/HMG')); // UAT + // var request = http.MultipartRequest('POST', Uri.parse('https://paxes.com/sso/hmg')); // Prod request.fields.addAll({'JWTToken': token}); // request.headers.addAll(headers); diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index a6b7173..2f60326 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -11,7 +11,6 @@ class ApiConsts { // static String baseUrl = "https://mohemm.hmg.com"; // New Live server // - // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.20.200.111:1010/"; // static String baseUrl = "https://webservices.hmg.com"; // PreProd @@ -27,7 +26,8 @@ class ApiConsts { static String user = baseUrlServices + "api/User/"; static String cocRest = baseUrlServices + "COCWS.svc/REST/"; - static String ssoAuthRedirection = "https://sso-uat.hmg.com/api/auth/connect"; + // static String ssoAuthRedirection = "https://sso-uat.hmg.com/api/auth/connect"; // UAT + static String ssoAuthRedirection = "https://sso.hmg.com/api/auth/connect"; // Prod //Chat static String chatServerBaseUrl = "https://apiderichat.hmg.com/"; diff --git a/lib/ui/work_list/itg_fragments/approval_level_fragment.dart b/lib/ui/work_list/itg_fragments/approval_level_fragment.dart index 61681eb..9d7e94a 100644 --- a/lib/ui/work_list/itg_fragments/approval_level_fragment.dart +++ b/lib/ui/work_list/itg_fragments/approval_level_fragment.dart @@ -168,8 +168,8 @@ class ApprovalLevelfragment extends StatelessWidget { if (wFHistory[index].date!.isEmpty || wFHistory[index].action!.toLowerCase() == "NO ACTION" || wFHistory[index + 1].date! == "") { return ""; } else { - DateTime dateTimeTo = DateUtil.convertSimpleStringDateToDate(wFHistory[index].date!); - DateTime dateTimeFrom = DateUtil.convertSimpleStringDateToDate(wFHistory[index + 1].date!); + DateTime dateTimeTo = DateUtil.convertSimpleStringDateToDate(wFHistory[index].date!, isITG: true); + DateTime dateTimeFrom = DateUtil.convertSimpleStringDateToDate(wFHistory[index + 1].date!, isITG: true); Duration duration = dateTimeTo.difference(dateTimeFrom); return "Action duration: " + DateUtil.formatDuration(duration); } diff --git a/pubspec.yaml b/pubspec.yaml index 6abe6fc..fde2c08 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,8 +17,8 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -#version: 3.7.1+300081 -version: 3.9.3+1 +version: 3.7.1+300081 +#version: 3.9.3+1 environment: sdk: ^3.7.0 -- 2.30.2 From 31d1804f7a6bc1ee3268e846043e42b65eff1830 Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Thu, 19 Feb 2026 11:40:23 +0300 Subject: [PATCH 120/135] QIPS-1175,QIPS-1179,QIPS-1180 --- assets/langs/ar-SA.json | 6 ++- assets/langs/en-US.json | 6 ++- lib/api/etqan_ovr_api_client.dart | 4 +- lib/generated/codegen_loader.g.dart | 14 +++++- lib/generated/locale_keys.g.dart | 4 ++ lib/provider/etqan_ovr_provider.dart | 18 +++++--- lib/ui/etqan_ovr/etqan_create_request.dart | 52 ++++++++++++++++++++-- 7 files changed, 87 insertions(+), 17 deletions(-) diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 49e2d82..64708d4 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -164,6 +164,7 @@ "quotationAnalysis": "تحليل الاقتباس", "subject": "موضوعات", "description": "وصف", + "pleaseEnterDescription": "الرجاء إدخال الوصف", "supplier": "المورد", "site": "موقع", "buyer": "مشتر", @@ -648,5 +649,8 @@ "etqanRequest": "طلبات الحوادث", "selectProject": "حدد المشروع", "project": "مشروع", - "keen": "حريص" + "keen": "حريص", + "ticketNumber": "رقم التذكرة", + "ticketId": "معرف التذكرة", + "pleaseSelectProject": "الرجاء اختيار مشروع" } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 1e69102..b130204 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -158,6 +158,7 @@ "subject": "Subject", "quotationAnalysis": "Quotation Analysis", "description": "Description", + "pleaseEnterDescription": "Please enter description", "supplier": "Supplier", "site": "Site", "buyer": "Buyer", @@ -646,5 +647,8 @@ "etqanRequest": "Incident Requests", "selectProject": "Select Project", "project": "Project", - "keen": "Keen" + "keen": "Keen", + "ticketNumber": "Ticket Number", + "ticketId": "Ticket ID", + "pleaseSelectProject": "Please select a project" } \ No newline at end of file diff --git a/lib/api/etqan_ovr_api_client.dart b/lib/api/etqan_ovr_api_client.dart index 3f595a4..1018177 100644 --- a/lib/api/etqan_ovr_api_client.dart +++ b/lib/api/etqan_ovr_api_client.dart @@ -93,7 +93,7 @@ class EtqanApiClient { ); } - Future createRequest(String description, int? projectID, String? attachmentBase64, bool? isAnonymous) async { + Future?> createRequest(String description, int? projectID, String? attachmentBase64, bool? isAnonymous) async { String url = "${ApiConsts.cocRest}ETQAN_CreateIncident"; Map postParams = { "P_SELECTED_EMPLOYEE_NUMBER": AppState().memberInformationList?.eMPLOYEENUMBER, @@ -111,7 +111,7 @@ class EtqanApiClient { if (json["ETQAN_CreateIncident_Response"] != null) { var response = json["ETQAN_CreateIncident_Response"]; if (response["id"] != null && response["ticketNumber"] != null) { - return 1; + return {"id": response["id"], "ticketNumber": response["ticketNumber"]}; } return null; } diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index 3eef24e..9f72052 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -180,6 +180,7 @@ class CodegenLoader extends AssetLoader{ "quotationAnalysis": "تحليل الاقتباس", "subject": "موضوعات", "description": "وصف", + "pleaseEnterDescription": "الرجاء إدخال الوصف", "supplier": "المورد", "site": "موقع", "buyer": "مشتر", @@ -660,7 +661,11 @@ class CodegenLoader extends AssetLoader{ "etqanOVR": "الإبلاغ عن حادثة", "etqanRequest": "طلبات الحوادث", "selectProject": "حدد المشروع", - "project": "مشروع" + "project": "مشروع", + "keen": "حريص", + "ticketNumber": "رقم التذكرة", + "ticketId": "معرف التذكرة", + "pleaseSelectProject": "الرجاء اختيار مشروع" }; static const Map _en_US = { "mohemm": "Mohemm", @@ -822,6 +827,7 @@ static const Map _en_US = { "subject": "Subject", "quotationAnalysis": "Quotation Analysis", "description": "Description", + "pleaseEnterDescription": "Please enter description", "supplier": "Supplier", "site": "Site", "buyer": "Buyer", @@ -1308,7 +1314,11 @@ static const Map _en_US = { "etqanOVR": "Report An Incident", "etqanRequest": "Incident Requests", "selectProject": "Select Project", - "project": "Project" + "project": "Project", + "keen": "Keen", + "ticketNumber": "Ticket Number", + "ticketId": "Ticket ID", + "pleaseSelectProject": "Please select a project" }; static const Map> mapLocales = {"ar_SA": _ar_SA, "en_US": _en_US}; } diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 7c74caa..6bcc80b 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -167,6 +167,7 @@ abstract class LocaleKeys { static const quotationAnalysis = 'quotationAnalysis'; static const subject = 'subject'; static const description = 'description'; + static const pleaseEnterDescription = 'pleaseEnterDescription'; static const supplier = 'supplier'; static const site = 'site'; static const buyer = 'buyer'; @@ -634,5 +635,8 @@ abstract class LocaleKeys { static const selectProject = 'selectProject'; static const project = 'project'; static const keen = 'keen'; + static const ticketNumber = 'ticketNumber'; + static const ticketId = 'ticketId'; + static const pleaseSelectProject = 'pleaseSelectProject'; } diff --git a/lib/provider/etqan_ovr_provider.dart b/lib/provider/etqan_ovr_provider.dart index 83e4c9b..b717b0f 100644 --- a/lib/provider/etqan_ovr_provider.dart +++ b/lib/provider/etqan_ovr_provider.dart @@ -150,6 +150,11 @@ class EtqanOvrProviderModel with ChangeNotifier, DiagnosticableTreeMixin { notifyListeners(); } + // Validate description + bool isDescriptionValid() { + return description.trim().isNotEmpty; + } + // Set isAnonymous void setIsAnonymous(bool value) { isAnonymous = value; @@ -168,22 +173,21 @@ class EtqanOvrProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } // Submit request - Future submitRequest(BuildContext context) async { + Future?> submitRequest(BuildContext context) async { try { Utils.showLoading(context); - int? isSuccess = await EtqanApiClient().createRequest(description, selectedProject?.projectId, attachmentBase64, isAnonymous); + Map? response = await EtqanApiClient().createRequest(description, selectedProject?.projectId, attachmentBase64, isAnonymous); Utils.hideLoading(context); - if (isSuccess == 1) { + if (response != null) { getEtqanEmployeeRequestsList = await EtqanApiClient().getEmployeeEtqanRequests(); notifyListeners(); - Navigator.of(context).pop(); - return true; + return response; } - return false; + return null; } catch (ex) { Utils.hideLoading(context); Utils.handleException(ex, context, null); - return false; + return null; } } } diff --git a/lib/ui/etqan_ovr/etqan_create_request.dart b/lib/ui/etqan_ovr/etqan_create_request.dart index 3a253d9..1618711 100644 --- a/lib/ui/etqan_ovr/etqan_create_request.dart +++ b/lib/ui/etqan_ovr/etqan_create_request.dart @@ -3,6 +3,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.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/utils.dart'; import 'package:mohem_flutter_app/extensions/int_extensions.dart'; import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; @@ -60,6 +61,7 @@ class _EtqanOvrCreateRequestState extends State { hint: LocaleKeys.selectProject.tr(), value: _getProjectDisplayName(provider.selectedProject), onTap: () => _showProjectSelectionSheet(context, provider), + isMandatory: true, ), 16.height, // _buildDropdownField( @@ -81,7 +83,39 @@ class _EtqanOvrCreateRequestState extends State { )).expanded, DefaultButton(LocaleKeys.submit.tr(), () async { provider.setDescription(_descriptionController.text); - await provider.submitRequest(context); + if (provider.selectedProject == null) { + Utils.showErrorDialog( + context: context, + message: LocaleKeys.pleaseSelectProject.tr(), + onOkTapped: () { + Navigator.of(context).pop(); + }, + ); + return; + } + if (!provider.isDescriptionValid()) { + Utils.showErrorDialog( + context: context, + message: LocaleKeys.pleaseEnterDescription.tr(), + onOkTapped: () { + Navigator.of(context).pop(); + }, + ); + return; + } + Map? ticketInfo = await provider.submitRequest(context); + if (ticketInfo != null) { + String ticketNumber = ticketInfo['ticketNumber'] ?? ''; + String ticketId = ticketInfo['id'] ?? ''; + String successMessage = '${LocaleKeys.requestCreatedSuccessfully.tr()}\n\n${LocaleKeys.ticketNumber.tr()}: $ticketNumber\n${LocaleKeys.ticketId.tr()}: $ticketId'; + Utils.showErrorDialog( + context: context, + message: successMessage, + onOkTapped: () { + Navigator.of(context).pop(); + }, + ); + } }).insideContainer, ], ); @@ -137,7 +171,7 @@ class _EtqanOvrCreateRequestState extends State { ); } - Widget _buildDropdownField({required String label, required String hint, String? value, required VoidCallback onTap}) { + Widget _buildDropdownField({required String label, required String hint, String? value, required VoidCallback onTap, bool isMandatory = false}) { return InkWell( onTap: onTap, borderRadius: BorderRadius.circular(15), @@ -150,7 +184,12 @@ class _EtqanOvrCreateRequestState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(label, style: const TextStyle(fontSize: 11, fontWeight: FontWeight.w600, color: Color(0xff2B353E), letterSpacing: -0.44)), + Row( + children: [ + Text(label, style: const TextStyle(fontSize: 11, fontWeight: FontWeight.w600, color: Color(0xff2B353E), letterSpacing: -0.44)), + if (isMandatory) const Text(' *', style: TextStyle(fontSize: 11, fontWeight: FontWeight.w600, color: Colors.red, letterSpacing: -0.44)), + ], + ), const SizedBox(height: 4), Text(value ?? hint, style: TextStyle(fontSize: 14, fontWeight: FontWeight.w400, color: value != null ? const Color(0xff2B353E) : const Color(0xff575757), letterSpacing: -0.56)), ], @@ -227,7 +266,12 @@ class _EtqanOvrCreateRequestState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text(LocaleKeys.description.tr(), style: const TextStyle(fontSize: 11, fontWeight: FontWeight.w600, color: Color(0xff2B353E), letterSpacing: -0.44)), + Row( + children: [ + Text(LocaleKeys.description.tr(), style: const TextStyle(fontSize: 11, fontWeight: FontWeight.w600, color: Color(0xff2B353E), letterSpacing: -0.44)), + const Text(' *', style: TextStyle(fontSize: 11, fontWeight: FontWeight.w600, color: Colors.red, letterSpacing: -0.44)), + ], + ), GestureDetector( onTap: provider.speechEnabled -- 2.30.2 From 2c7d3bf963546404b1766da9632e0a66174ea723 Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Thu, 26 Feb 2026 14:51:56 +0300 Subject: [PATCH 121/135] QIPS-1175,QIPS-1179,QIPS-1180 --- assets/langs/ar-SA.json | 6 +- assets/langs/en-US.json | 6 +- lib/classes/utils.dart | 4 +- lib/generated/codegen_loader.g.dart | 12 ++- lib/generated/locale_keys.g.dart | 4 + .../etqan_get_employee_incident_report.dart | 12 +++ lib/provider/etqan_ovr_provider.dart | 13 ++- lib/ui/etqan_ovr/etqan_create_request.dart | 8 +- lib/ui/etqan_ovr/etqan_ovr_home.dart | 6 +- lib/ui/etqan_ovr/etqan_request_detailed.dart | 97 +++++++++++++++++-- 10 files changed, 150 insertions(+), 18 deletions(-) diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 64708d4..88a3891 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -650,7 +650,11 @@ "selectProject": "حدد المشروع", "project": "مشروع", "keen": "حريص", + "reportIncident": "الإبلاغ عن الحادث", + "myIncidents": "حوادثي", + "incidentDetails": "تفاصيل الحادث", "ticketNumber": "رقم التذكرة", "ticketId": "معرف التذكرة", - "pleaseSelectProject": "الرجاء اختيار مشروع" + "pleaseSelectProject": "الرجاء اختيار مشروع", + "viewAttachment" : "عرض المرفق" } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index b130204..4e29cbc 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -648,7 +648,11 @@ "selectProject": "Select Project", "project": "Project", "keen": "Keen", + "reportIncident": "Report Incident", + "myIncidents": "My Incidents", + "incidentDetails": "Incident Details", "ticketNumber": "Ticket Number", "ticketId": "Ticket ID", - "pleaseSelectProject": "Please select a project" + "pleaseSelectProject": "Please select a project", + "viewAttachment" : "View Attachment" } \ No newline at end of file diff --git a/lib/classes/utils.dart b/lib/classes/utils.dart index 6a9b16b..2ae4fe3 100644 --- a/lib/classes/utils.dart +++ b/lib/classes/utils.dart @@ -135,8 +135,8 @@ class Utils { } } - static Future showErrorDialog({required BuildContext context, required VoidCallback onOkTapped, required String message}) async { - return showDialog(context: context, builder: (BuildContext context) => ConfirmDialog(message: message, onTap: onOkTapped)); + static Future showErrorDialog({required BuildContext context, required VoidCallback onOkTapped, required String message, VoidCallback? onCloseTap}) async { + return showDialog(context: context, builder: (BuildContext context) => ConfirmDialog(message: message, onTap: onOkTapped, onCloseTap: onCloseTap)); } static void confirmDialog(cxt, String message, {VoidCallback? onTap}) { diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index 9f72052..1a3ec71 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -663,9 +663,13 @@ class CodegenLoader extends AssetLoader{ "selectProject": "حدد المشروع", "project": "مشروع", "keen": "حريص", + "reportIncident": "الإبلاغ عن الحادث", + "myIncidents": "حوادثي", + "incidentDetails": "تفاصيل الحادث", "ticketNumber": "رقم التذكرة", "ticketId": "معرف التذكرة", - "pleaseSelectProject": "الرجاء اختيار مشروع" + "pleaseSelectProject": "الرجاء اختيار مشروع", + "viewAttachment": "عرض المرفق" }; static const Map _en_US = { "mohemm": "Mohemm", @@ -1316,9 +1320,13 @@ static const Map _en_US = { "selectProject": "Select Project", "project": "Project", "keen": "Keen", + "reportIncident": "Report Incident", + "myIncidents": "My Incidents", + "incidentDetails": "Incident Details", "ticketNumber": "Ticket Number", "ticketId": "Ticket ID", - "pleaseSelectProject": "Please select a project" + "pleaseSelectProject": "Please select a project", + "viewAttachment": "View Attachment" }; static const Map> mapLocales = {"ar_SA": _ar_SA, "en_US": _en_US}; } diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 6bcc80b..d060682 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -635,8 +635,12 @@ abstract class LocaleKeys { static const selectProject = 'selectProject'; static const project = 'project'; static const keen = 'keen'; + static const reportIncident = 'reportIncident'; + static const myIncidents = 'myIncidents'; + static const incidentDetails = 'incidentDetails'; static const ticketNumber = 'ticketNumber'; static const ticketId = 'ticketId'; static const pleaseSelectProject = 'pleaseSelectProject'; + static const viewAttachment = 'viewAttachment'; } diff --git a/lib/models/etqan_ovr/etqan_get_employee_incident_report.dart b/lib/models/etqan_ovr/etqan_get_employee_incident_report.dart index 3743cf3..e4a57fd 100644 --- a/lib/models/etqan_ovr/etqan_get_employee_incident_report.dart +++ b/lib/models/etqan_ovr/etqan_get_employee_incident_report.dart @@ -22,11 +22,17 @@ class EtqanGetEmployeeIncidentRequestModel { class EtqanGetIncidentRequestResponse { String? key; + String? keyAr; String? value; + String? valueAr; + List? subValues; EtqanGetIncidentRequestResponse({ this.key, + this.keyAr, this.value, + this.valueAr, + this.subValues, }); factory EtqanGetIncidentRequestResponse.fromRawJson(String str) => EtqanGetIncidentRequestResponse.fromJson(json.decode(str)); @@ -35,11 +41,17 @@ class EtqanGetIncidentRequestResponse { factory EtqanGetIncidentRequestResponse.fromJson(Map json) => EtqanGetIncidentRequestResponse( key: json["key"], + keyAr: json["keyAr"], value: json["value"], + valueAr: json["valueAr"], + subValues: json["subValues"] == null ? [] : List.from(json["subValues"]!.map((x) => x)), ); Map toJson() => { "key": key, + "keyAr": keyAr, "value": value, + "valueAr": valueAr, + "subValues": subValues == null ? [] : List.from(subValues!.map((x) => x)), }; } diff --git a/lib/provider/etqan_ovr_provider.dart b/lib/provider/etqan_ovr_provider.dart index b717b0f..1f6ab80 100644 --- a/lib/provider/etqan_ovr_provider.dart +++ b/lib/provider/etqan_ovr_provider.dart @@ -47,7 +47,15 @@ class EtqanOvrProviderModel with ChangeNotifier, DiagnosticableTreeMixin { /// Initialize speech recognition - call this once when screen loads Future initSpeech() async { - _speechEnabled = await _speechToText.initialize(); + _speechEnabled = await _speechToText.initialize( + onStatus: (String status) { + // Update listening state when speech recognition status changes + if (status == 'done' || status == 'notListening') { + _isListening = false; + notifyListeners(); + } + }, + ); notifyListeners(); } @@ -61,6 +69,9 @@ class EtqanOvrProviderModel with ChangeNotifier, DiagnosticableTreeMixin { notifyListeners(); }, localeId: localeId, + listenFor: const Duration(seconds: 30), + pauseFor: const Duration(seconds: 3), + listenMode: ListenMode.confirmation, ); _isListening = true; notifyListeners(); diff --git a/lib/ui/etqan_ovr/etqan_create_request.dart b/lib/ui/etqan_ovr/etqan_create_request.dart index 1618711..ce636ff 100644 --- a/lib/ui/etqan_ovr/etqan_create_request.dart +++ b/lib/ui/etqan_ovr/etqan_create_request.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.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/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/widget_extensions.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; @@ -46,7 +47,7 @@ class _EtqanOvrCreateRequestState extends State { Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, - appBar: AppBarWidget(context, title: LocaleKeys.createRequest.tr(), showHomeButton: false), + appBar: AppBarWidget(context, title: LocaleKeys.reportIncident.tr(), showHomeButton: false), body: Consumer( builder: (BuildContext context, EtqanOvrProviderModel provider, Widget? child) { return Column( @@ -112,7 +113,10 @@ class _EtqanOvrCreateRequestState extends State { context: context, message: successMessage, onOkTapped: () { - Navigator.of(context).pop(); + Navigator.popAndPushNamed(context, AppRoutes.etqanOvr); + }, + onCloseTap: () { + Navigator.popAndPushNamed(context, AppRoutes.etqanOvr); }, ); } diff --git a/lib/ui/etqan_ovr/etqan_ovr_home.dart b/lib/ui/etqan_ovr/etqan_ovr_home.dart index 7a48a51..c4174a1 100644 --- a/lib/ui/etqan_ovr/etqan_ovr_home.dart +++ b/lib/ui/etqan_ovr/etqan_ovr_home.dart @@ -4,7 +4,7 @@ import 'package:flutter_svg/svg.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; import 'package:mohem_flutter_app/config/routes.dart'; -import 'package:mohem_flutter_app/extensions/int_extensions.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'; @@ -36,7 +36,7 @@ class _EtqanOvrHomeState extends State { Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, - appBar: AppBarWidget(context, title: LocaleKeys.etqanRequest.tr()), + appBar: AppBarWidget(context, title: LocaleKeys.myIncidents.tr()), body: Consumer( builder: (BuildContext context, EtqanOvrProviderModel provider, Widget? child) { return Column( @@ -93,7 +93,7 @@ class _EtqanOvrHomeState extends State { itemCount: provider.getEtqanEmployeeRequestsList!.length, )) .expanded, - DefaultButton(LocaleKeys.createRequest.tr(), () async { + DefaultButton(LocaleKeys.reportIncident.tr(), () async { await Navigator.pushNamed(context, AppRoutes.etqanCreateRequest); // getOpenTickets(); }).insideContainer, diff --git a/lib/ui/etqan_ovr/etqan_request_detailed.dart b/lib/ui/etqan_ovr/etqan_request_detailed.dart index b1ed12a..6f9aebc 100644 --- a/lib/ui/etqan_ovr/etqan_request_detailed.dart +++ b/lib/ui/etqan_ovr/etqan_request_detailed.dart @@ -1,3 +1,7 @@ +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; + import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; @@ -10,6 +14,8 @@ import 'package:mohem_flutter_app/provider/etqan_ovr_provider.dart'; import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; import 'package:provider/provider.dart'; +import 'package:open_filex/open_filex.dart'; +import 'package:path_provider/path_provider.dart'; class EtqanOvrRequestDetailed extends StatefulWidget { const EtqanOvrRequestDetailed({Key? key}) : super(key: key); @@ -23,6 +29,24 @@ class _EtqanOvrRequestDetailedState extends State { List get hiddenFields => ['OVR Id', 'Is Anonymous']; + Future _viewAttachment(BuildContext context, String base64Data) async { + try { + Uint8List bytes = base64.decode(base64Data); + String dir = (await getApplicationDocumentsDirectory()).path; + String ext = 'pdf'; + if (base64Data.startsWith('/9j/')) { + ext = 'jpg'; + } else if (base64Data.startsWith('iVBORw0KGgo')) { + ext = 'png'; + } + File file = File("$dir/${DateTime.now().millisecondsSinceEpoch}.$ext"); + await file.writeAsBytes(bytes); + OpenFilex.open(file.path); + } catch (e) { + Utils.showToast("Cannot open attachment."); + } + } + List _getOrderedList(List list) { List orderedList = []; @@ -48,7 +72,7 @@ class _EtqanOvrRequestDetailedState extends State { void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { - var provider = context.read(); + EtqanOvrProviderModel provider = context.read(); provider.fetchEtqanEmployeeIncidentRequests(context, provider.getTicketId); }); } @@ -57,7 +81,7 @@ class _EtqanOvrRequestDetailedState extends State { Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, - appBar: AppBarWidget(context, title: LocaleKeys.etqanRequest.tr()), + appBar: AppBarWidget(context, title: LocaleKeys.incidentDetails.tr()), body: Consumer( builder: (BuildContext context, EtqanOvrProviderModel provider, Widget? child) { if (provider.getEtqanEmployeeIncidnetRequest == null || provider.getEtqanEmployeeIncidnetRequest!.isEmpty) { @@ -74,7 +98,7 @@ class _EtqanOvrRequestDetailedState extends State { color: Colors.white, borderRadius: BorderRadius.circular(15), border: Border.all(color: const Color(0xffefefef), width: 1), - boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10, offset: const Offset(0, 2))], + boxShadow: [BoxShadow(color: Colors.black.withValues(alpha: 0.05), blurRadius: 10, offset: const Offset(0, 2))], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -83,6 +107,13 @@ class _EtqanOvrRequestDetailedState extends State { int index = entry.key; EtqanGetIncidentRequestResponse data = entry.value; bool isLast = index == orderedList.length - 1; + bool isAttachment = data.key?.toLowerCase() == 'attachment'; + + String displayKey = context.locale.languageCode == "ar" ? (data.keyAr ?? data.key ?? "") : (data.key ?? ""); + String displayValue = context.locale.languageCode == "ar" ? (data.valueAr ?? data.value ?? "") : (data.value ?? ""); + + bool hasSubValues = data.subValues != null && data.subValues!.isNotEmpty; + return Column( children: [ Padding( @@ -90,9 +121,63 @@ class _EtqanOvrRequestDetailedState extends State { child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Expanded(flex: 2, child: (data.key ?? "").toText12(isBold: true, color: MyColors.grey57Color)), + Expanded(flex: 2, child: displayKey.toText12(isBold: true, color: MyColors.grey57Color)), 8.width, - Expanded(flex: 3, child: (data.value ?? "-").toText14(color: MyColors.darkTextColor)), + Expanded( + flex: 3, + child: + isAttachment && hasSubValues + ? Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: + data.subValues!.asMap().entries.map((entry) { + int subIndex = entry.key; + String base64Data = entry.value; + return Padding( + padding: EdgeInsets.only(bottom: subIndex < data.subValues!.length - 1 ? 8.0 : 0), + child: GestureDetector( + onTap: () => _viewAttachment(context, base64Data), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: context.locale.languageCode == "ar" ? MainAxisAlignment.end : MainAxisAlignment.start, + children: [ + Text( + data.subValues!.length > 1 ? '${LocaleKeys.viewAttachment.tr()} ${subIndex + 1}' : LocaleKeys.viewAttachment.tr(), + // textAlign: context.locale.languageCode == "ar" ? TextAlign.start : TextAlign.start, + style: const TextStyle( + fontSize: 14, + color: MyColors.green9CColor, + decoration: TextDecoration.underline, + decorationColor: MyColors.green9CColor, + ), + ), + ], + ), + ), + ); + }).toList(), + ) + : hasSubValues + ? Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (displayValue.isNotEmpty) displayValue.toText14(color: MyColors.darkTextColor), + if (displayValue.isNotEmpty) 8.height, + ...data.subValues! + .map( + (subValue) => Padding( + padding: const EdgeInsets.only(bottom: 4), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [const Text("• ", style: TextStyle(fontSize: 14)), Expanded(child: subValue.toText14(color: MyColors.darkTextColor))], + ), + ), + ) + .toList(), + ], + ) + : (displayValue.isNotEmpty ? displayValue : "-").toText14(color: MyColors.darkTextColor), + ), ], ), ), @@ -104,7 +189,7 @@ class _EtqanOvrRequestDetailedState extends State { ), ); }, - ), + ).paddingOnly(bottom: 20), ); } } -- 2.30.2 From a8f390d49f85e5422783bfb9242c7a67bfe0765c Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Sun, 1 Mar 2026 10:09:39 +0300 Subject: [PATCH 122/135] QIPS-1175,QIPS-1179,QIPS-1180 --- lib/provider/etqan_ovr_provider.dart | 22 ++++++++++++++++++++++ lib/ui/etqan_ovr/etqan_ovr_home.dart | 5 ++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/lib/provider/etqan_ovr_provider.dart b/lib/provider/etqan_ovr_provider.dart index 1f6ab80..deba5ba 100644 --- a/lib/provider/etqan_ovr_provider.dart +++ b/lib/provider/etqan_ovr_provider.dart @@ -112,6 +112,17 @@ class EtqanOvrProviderModel with ChangeNotifier, DiagnosticableTreeMixin { Utils.showLoading(context); getEtqanEmployeeRequestsList?.clear(); getEtqanEmployeeRequestsList = await EtqanApiClient().getEmployeeEtqanRequests(); + + // Sort by createdDate in descending order (newest first) + if (getEtqanEmployeeRequestsList != null && getEtqanEmployeeRequestsList!.isNotEmpty) { + getEtqanEmployeeRequestsList!.sort((a, b) { + if (a.createdDate == null && b.createdDate == null) return 0; + if (a.createdDate == null) return 1; + if (b.createdDate == null) return -1; + return b.createdDate!.compareTo(a.createdDate!); + }); + } + Utils.hideLoading(context); isLoading = false; notifyListeners(); @@ -191,6 +202,17 @@ class EtqanOvrProviderModel with ChangeNotifier, DiagnosticableTreeMixin { Utils.hideLoading(context); if (response != null) { getEtqanEmployeeRequestsList = await EtqanApiClient().getEmployeeEtqanRequests(); + + // Sort by ticketNumber in descending order (newest first) + if (getEtqanEmployeeRequestsList != null && getEtqanEmployeeRequestsList!.isNotEmpty) { + getEtqanEmployeeRequestsList!.sort((a, b) { + if (a.ticketNumber == null && b.ticketNumber == null) return 0; + if (a.ticketNumber == null) return 1; + if (b.ticketNumber == null) return -1; + return b.ticketNumber!.compareTo(a.ticketNumber!); + }); + } + notifyListeners(); return response; } diff --git a/lib/ui/etqan_ovr/etqan_ovr_home.dart b/lib/ui/etqan_ovr/etqan_ovr_home.dart index c4174a1..978f894 100644 --- a/lib/ui/etqan_ovr/etqan_ovr_home.dart +++ b/lib/ui/etqan_ovr/etqan_ovr_home.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:easy_localization/easy_localization.dart' as lclize; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; @@ -74,7 +76,8 @@ class _EtqanOvrHomeState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - (data.description ?? "").toText12(color: MyColors.grey57Color), + (data.description ?? "").toText12(color: MyColors.grey57Color).expanded, + const SizedBox(width: 5,), RotatedBox( quarterTurns: AppState().isArabic(context) ? 2 : 0, child: SvgPicture.asset("assets/images/arrow_next.svg", color: MyColors.grey70Color, width: 16, height: 16), -- 2.30.2 From ba8908d4eb187703b7bdfbe45fae01e01674c275 Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Sun, 1 Mar 2026 12:01:46 +0300 Subject: [PATCH 123/135] Greeting Card --- lib/api/dashboard_api_client.dart | 15 + lib/models/greetings/greeting_card_model.dart | 105 ++ lib/provider/dashboard_provider_model.dart | 25 + lib/ui/landing/dashboard_screen.dart | 1280 +++++++++-------- 4 files changed, 851 insertions(+), 574 deletions(-) create mode 100644 lib/models/greetings/greeting_card_model.dart diff --git a/lib/api/dashboard_api_client.dart b/lib/api/dashboard_api_client.dart index 6f7288c..3265774 100644 --- a/lib/api/dashboard_api_client.dart +++ b/lib/api/dashboard_api_client.dart @@ -17,6 +17,7 @@ import 'package:mohem_flutter_app/models/dashboard/itg_forms_model.dart'; import 'package:mohem_flutter_app/models/dashboard/list_menu.dart'; import 'package:mohem_flutter_app/models/generic_response_model.dart'; import 'package:mohem_flutter_app/models/get_employee_parking_details_model.dart'; +import 'package:mohem_flutter_app/models/greetings/greeting_card_model.dart'; import 'package:mohem_flutter_app/models/itg/itg_main_response.dart'; import 'package:mohem_flutter_app/models/itg/itg_response_model.dart'; import 'package:mohem_flutter_app/models/sso_auth_model.dart'; @@ -429,4 +430,18 @@ class DashboardApiClient { postParams, ); } + + Future getGreetingCards() async { + String url = "${ApiConsts.erpRest}Get_GreetingCards"; + Map postParams = {}; + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject( + (json) { + GetGreetingCardsModelResponse responseData = GetGreetingCardsModelResponse.fromJson(json); + return responseData; + }, + url, + postParams, + ); + } } diff --git a/lib/models/greetings/greeting_card_model.dart b/lib/models/greetings/greeting_card_model.dart new file mode 100644 index 0000000..99b93ed --- /dev/null +++ b/lib/models/greetings/greeting_card_model.dart @@ -0,0 +1,105 @@ +import 'dart:convert'; + +class GetGreetingCardsModelResponse { + List? getGreetingCardsModelResponse; + + GetGreetingCardsModelResponse({ + this.getGreetingCardsModelResponse, + }); + + factory GetGreetingCardsModelResponse.fromRawJson(String str) => GetGreetingCardsModelResponse.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory GetGreetingCardsModelResponse.fromJson(Map json) => GetGreetingCardsModelResponse( + getGreetingCardsModelResponse: json["Get_GreetingCardsModel_Response"] == null ? [] : List.from(json["Get_GreetingCardsModel_Response"]!.map((x) => GetGreetingCardsModelResponseElement.fromJson(x))), + ); + + Map toJson() => { + "Get_GreetingCardsModel_Response": getGreetingCardsModelResponse == null ? [] : List.from(getGreetingCardsModelResponse!.map((x) => x.toJson())), + }; +} + +class GetGreetingCardsModelResponseElement { + int? id; + dynamic titleEn; + String? titleAr; + String? descriptionEn; + String? descriptionAr; + String? startDate; + String? endDate; + String? urlEn; + String? urlAr; + String? backgroundImageUrlEn; + String? backgroundImageUrlAr; + int? channel; + int? categoryId; + String? categoryNameAr; + String? categoryNameEn; + String? createdOn; + bool? isActive; + + GetGreetingCardsModelResponseElement({ + this.id, + this.titleEn, + this.titleAr, + this.descriptionEn, + this.descriptionAr, + this.startDate, + this.endDate, + this.urlEn, + this.urlAr, + this.backgroundImageUrlEn, + this.backgroundImageUrlAr, + this.channel, + this.categoryId, + this.categoryNameAr, + this.categoryNameEn, + this.createdOn, + this.isActive, + }); + + factory GetGreetingCardsModelResponseElement.fromRawJson(String str) => GetGreetingCardsModelResponseElement.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory GetGreetingCardsModelResponseElement.fromJson(Map json) => GetGreetingCardsModelResponseElement( + id: json["ID"], + titleEn: json["TitleEn"], + titleAr: json["TitleAr"], + descriptionEn: json["DescriptionEn"], + descriptionAr: json["DescriptionAr"], + startDate: json["StartDate"], + endDate: json["EndDate"], + urlEn: json["UrlEn"], + urlAr: json["UrlAr"], + backgroundImageUrlEn: json["BackgroundImageUrlEn"], + backgroundImageUrlAr: json["BackgroundImageUrlAr"], + channel: json["Channel"], + categoryId: json["CategoryID"], + categoryNameAr: json["CategoryNameAr"], + categoryNameEn: json["CategoryNameEn"], + createdOn: json["CreatedOn"], + isActive: json["IsActive"], + ); + + Map toJson() => { + "ID": id, + "TitleEn": titleEn, + "TitleAr": titleAr, + "DescriptionEn": descriptionEn, + "DescriptionAr": descriptionAr, + "StartDate": startDate, + "EndDate": endDate, + "UrlEn": urlEn, + "UrlAr": urlAr, + "BackgroundImageUrlEn": backgroundImageUrlEn, + "BackgroundImageUrlAr": backgroundImageUrlAr, + "Channel": channel, + "CategoryID": categoryId, + "CategoryNameAr": categoryNameAr, + "CategoryNameEn": categoryNameEn, + "CreatedOn": createdOn, + "IsActive": isActive, + }; +} diff --git a/lib/provider/dashboard_provider_model.dart b/lib/provider/dashboard_provider_model.dart index dd1472b..09c347e 100644 --- a/lib/provider/dashboard_provider_model.dart +++ b/lib/provider/dashboard_provider_model.dart @@ -21,6 +21,7 @@ import 'package:mohem_flutter_app/models/dashboard/menus.dart'; import 'package:mohem_flutter_app/models/dashboard/mohemm_itg_pending_task_responseitem.dart'; import 'package:mohem_flutter_app/models/eit/get_eit_transaction_model.dart'; import 'package:mohem_flutter_app/models/generic_response_model.dart'; +import 'package:mohem_flutter_app/models/greetings/greeting_card_model.dart'; import 'package:mohem_flutter_app/models/itg/itg_response_model.dart'; import 'package:mohem_flutter_app/models/offers_and_discounts/get_offers_list.dart'; import 'package:mohem_flutter_app/models/sso_auth_model.dart'; @@ -67,6 +68,9 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { bool isOffersLoading = true; List getOffersList = []; + bool isDisplayEidGreetings = false; + List? greetingCardsList; + //Attendance Tracking API's & Methods Future fetchAttendanceTracking(context) async { try { @@ -307,6 +311,27 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } } + void fetchGreetingCards() async { + try { + GetGreetingCardsModelResponse? response = await DashboardApiClient().getGreetingCards(); + greetingCardsList = response?.getGreetingCardsModelResponse ?? []; + + // Check if there are any active greeting cards + if (greetingCardsList != null && greetingCardsList!.isNotEmpty) { + isDisplayEidGreetings = greetingCardsList!.any((card) => card.isActive == true); + } else { + isDisplayEidGreetings = false; + } + + notifyListeners(); + } catch (ex) { + logger.wtf(ex); + isDisplayEidGreetings = false; + greetingCardsList = []; + notifyListeners(); + } + } + Future fetchTicketBooking() async { try { GenericResponseModel? genericResponseModel = await DashboardApiClient().getTicketBookingRedirection(); diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index 3122d17..aca7aba 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -155,6 +155,7 @@ class _DashboardScreenState extends State with WidgetsBindingOb data.fetchLeaveTicketBalance(context, DateTime.now()); data.fetchMenuEntries(); data.fetchEventActivity(); + data.fetchGreetingCards(); data.getCategoryOffersListAPI(context); marathonProvider.getMarathonDetailsFromApi(); marathonProvider.getMarathonTutorial(); @@ -253,585 +254,716 @@ class _DashboardScreenState extends State with WidgetsBindingOb child: Scaffold( key: _scaffoldState, body: Column( - children: [ - Row( - children: [ - Builder( - builder: (BuildContext context) { - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - Image.memory( - Utils.dataFromBase64String(AppState().memberInformationList!.eMPLOYEEIMAGE ?? ""), - errorBuilder: (BuildContext context, Object error, StackTrace? stackTrace) { - return SvgPicture.asset("assets/images/user.svg", height: 34, width: 34); - }, - width: 34, - height: 34, - fit: BoxFit.cover, - ).circle(50), - // CircularAvatar( - // width: 34, - // height: 34, - // url: "https://cdn4.iconfinder.com/data/icons/professions-2-2/151/89-512.png", - // ), - 8.width, - SvgPicture.asset("assets/images/side_nav.svg"), - ], - ).onPress(() { - _scaffoldState.currentState!.openDrawer(); - }); - }, - ), - Image.asset("assets/images/logos/main_mohemm_logo.png", width: 134, height: 28).expanded, - SvgPicture.asset("assets/images/announcements.svg", matchTextDirection: true).onPress(() async { - await Navigator.pushNamed(context, AppRoutes.announcements); - }), - ], - ).paddingOnly(left: 21, right: 21, top: 48, bottom: 7), - Expanded( - child: SmartRefresher( - enablePullDown: true, - enablePullUp: false, - header: const MaterialClassicHeader(color: MyColors.gradiantEndColor), - controller: _refreshController, - onRefresh: () { - _onRefresh(false); - }, - child: SingleChildScrollView( - child: Column( - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - LocaleKeys.welcomeBack.tr().toText14(color: MyColors.grey77Color), - (AppState().memberInformationList!.eMPLOYEENAME ?? "").toText24(isBold: true), - 16.height, - Row( - children: [ - Expanded( - child: AspectRatio( - aspectRatio: 159 / 159, - child: Consumer( - builder: (BuildContext context, DashboardProviderModel model, Widget? child) { - return (model.isAttendanceTrackingLoading - ? GetAttendanceTrackingShimmer() - : Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(15), - gradient: const LinearGradient( - transform: GradientRotation(.46), - begin: Alignment.topRight, - end: Alignment.bottomLeft, - colors: [MyColors.gradiantEndColor, MyColors.gradiantStartColor], - ), - ), - child: Stack( - alignment: Alignment.center, - children: [ - if (model.isTimeRemainingInSeconds == 0) SvgPicture.asset("assets/images/thumb.svg"), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - LocaleKeys.markAttendance.tr().toText14(color: Colors.white, isBold: true), - if (model.isTimeRemainingInSeconds == 0) DateTime.now().toString().split(" ")[0].toText12(color: Colors.white), - if (model.isTimeRemainingInSeconds != 0) - Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - 9.height, - Directionality( - textDirection: ui.TextDirection.ltr, - child: CountdownTimer( - endTime: model.endTime, - onEnd: null, - endWidget: "00:00:00".toText14(color: Colors.white, isBold: true), - textStyle: const TextStyle(color: Colors.white, fontSize: 14, letterSpacing: -0.48, fontWeight: FontWeight.bold), - ), - ), - LocaleKeys.timeLeftToday.tr().toText12(color: Colors.white), - 9.height, - ClipRRect( - borderRadius: const BorderRadius.all(Radius.circular(20)), - child: LinearProgressIndicator( - value: model.progress, - minHeight: 8, - valueColor: const AlwaysStoppedAnimation(Colors.white), - backgroundColor: const Color(0xff196D73), - ), - ), - ], - ), - ], - ).paddingOnly(top: 12, right: 15, left: 12), - ), - Row( - children: [ - Expanded( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - LocaleKeys.checkIn.tr().toText12(color: Colors.white), - (model.attendanceTracking!.pSwipeIn == null ? "--:--" : model.attendanceTracking!.pSwipeIn).toString().toText14( - color: Colors.white, - isBold: true, - ), - 4.height, - ], - ).paddingOnly(left: 12, right: 12), - ), - Container( - margin: EdgeInsets.only(top: AppState().isArabic(context) ? 6 : 0), - width: 45, - height: 45, - padding: const EdgeInsets.only(left: 10, right: 10), - decoration: BoxDecoration( - color: const Color(0xff259EA4), - borderRadius: BorderRadius.only( - bottomRight: AppState().isArabic(context) ? const Radius.circular(0) : const Radius.circular(15), - bottomLeft: AppState().isArabic(context) ? const Radius.circular(15) : const Radius.circular(0), - ), - ), - child: SvgPicture.asset(model.isTimeRemainingInSeconds == 0 ? "assets/images/biometrics.svg" : "assets/images/biometrics.svg"), - ).onPress(() { - showMyBottomSheet(context, callBackFunc: () {}, child: MarkAttendanceWidget(model, isFromDashboard: true)); - }), - ], - ), - ], - ), - ], - ), - ).onPress(() { - Navigator.pushNamed(context, AppRoutes.todayAttendance); - })) - .animatedSwither(); - }, - ), - ), - ), - 9.width, - Expanded(child: MenusWidget()), - ], - ), - ], - ).paddingOnly(left: 21, right: 21, top: 7, bottom: 21), - eventActivityWidget(context), - - if (isDisplayMazaya) ...[ - Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Directionality( - textDirection: AppState().isArabic(context) ? ui.TextDirection.rtl : ui.TextDirection.ltr, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - gradient: const LinearGradient(colors: [Color(0xFF91C481), Color(0xFF7CCED7)], begin: Alignment.centerLeft, end: Alignment.centerRight), - ), - child: Padding( - padding: const EdgeInsets.all(3.0), // This creates the border width - child: Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(17), // Slightly less than outer radius - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - flex: 4, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Row( - children: [ - Expanded( - flex: 2, - child: RichText( - text: - AppState().isArabic(context) - ? TextSpan( - children: [ - TextSpan( - text: 'اطلع على مميزات', - style: TextStyle( - fontSize: 16, - letterSpacing: -0.2, - fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins', - fontWeight: FontWeight.w700, - height: 24 / 16, - color: Color(0xFF5D5E5E), - ), - ), - TextSpan( - text: ' مزايا', - style: TextStyle( - fontSize: 16, - fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins', - fontWeight: FontWeight.w700, - letterSpacing: -0.2, - height: 24 / 16, - color: MyColors.mazayaRedColor, // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed - ), - ), - ], - ) - : TextSpan( - children: [ - TextSpan( - text: LocaleKeys.explore.tr() + ' ', - style: const TextStyle( - fontSize: 16, - letterSpacing: -0.2, - fontFamily: 'Poppins', - fontWeight: FontWeight.w700, - height: 24 / 16, - color: Color(0xFF5D5E5E), - ), - ), - TextSpan( - text: LocaleKeys.mazaya.tr(), - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w700, - fontFamily: 'Poppins', - letterSpacing: -0.2, - height: 24 / 16, - color: MyColors.mazayaRedColor, // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed - ), - ), - TextSpan( - text: ' ' + LocaleKeys.benefits.tr(), - style: const TextStyle( - fontSize: 16, - letterSpacing: -0.2, - fontFamily: 'Poppins', - fontWeight: FontWeight.w700, - height: 24 / 16, - color: Color(0xFF5D5E5E), - ), - ), - ], - ), - ), - ), - const Expanded(flex: 1, child: SizedBox()), - ], - ), - const SizedBox(height: 8), - LocaleKeys.mazayaDesc.tr().toText11(color: const Color(0xFF5D5E5E)), - ], - ), - ), - Expanded( - flex: 2, - child: Column( - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisAlignment: MainAxisAlignment.end, - children: [ - SvgPicture.asset("assets/icons/mazaya_brand.svg", width: 90, height: 47), - const SizedBox(height: 28), - LocaleKeys.viewallofferMazaya.tr().toText12(isUnderLine: true, color: const Color(0xFF3B3D4A)).onPress(() { - Navigator.pushNamed(context, AppRoutes.offersAndDiscounts); - }), - ], - ), - ), - ], - ).paddingOnly(left: 21, right: 21, top: 14, bottom: 14), - ), - ), - ).paddingOnly(left: 21, right: 21, top: 0, bottom: 21), - ), - ], - ), - ], + children: [ + Row( + children: [ + Builder( + builder: (BuildContext context) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + Image.memory( + Utils.dataFromBase64String(AppState().memberInformationList!.eMPLOYEEIMAGE ?? ""), + errorBuilder: (BuildContext context, Object error, StackTrace? stackTrace) { + return SvgPicture.asset("assets/images/user.svg", height: 34, width: 34); + }, + width: 34, + height: 34, + fit: BoxFit.cover, + ).circle(50), + // CircularAvatar( + // width: 34, + // height: 34, + // url: "https://cdn4.iconfinder.com/data/icons/professions-2-2/151/89-512.png", + // ), + 8.width, + SvgPicture.asset("assets/images/side_nav.svg"), + ], + ).onPress(() { + _scaffoldState.currentState!.openDrawer(); + }); + }, + ), + Image + .asset("assets/images/logos/main_mohemm_logo.png", width: 134, height: 28) + .expanded, + SvgPicture.asset("assets/images/announcements.svg", matchTextDirection: true).onPress(() async { + await Navigator.pushNamed(context, AppRoutes.announcements); + }), + ], + ).paddingOnly(left: 21, right: 21, top: 48, bottom: 7), + Expanded( + child: SmartRefresher( + enablePullDown: true, + enablePullUp: false, + header: const MaterialClassicHeader(color: MyColors.gradiantEndColor), + controller: _refreshController, + onRefresh: () { + _onRefresh(false); + }, + child: SingleChildScrollView( + child: Column( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.welcomeBack.tr().toText14(color: MyColors.grey77Color), + (AppState().memberInformationList!.eMPLOYEENAME ?? "").toText24(isBold: true), + 16.height, + Row( + children: [ + Expanded( + child: AspectRatio( + aspectRatio: 159 / 159, + child: Consumer( + builder: (BuildContext context, DashboardProviderModel model, Widget? child) { + return (model.isAttendanceTrackingLoading + ? GetAttendanceTrackingShimmer() + : Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(15), + gradient: const LinearGradient( + transform: GradientRotation(.46), + begin: Alignment.topRight, + end: Alignment.bottomLeft, + colors: [MyColors.gradiantEndColor, MyColors.gradiantStartColor], + ), + ), + child: Stack( + alignment: Alignment.center, + children: [ + if (model.isTimeRemainingInSeconds == 0) SvgPicture.asset("assets/images/thumb.svg"), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.markAttendance.tr().toText14(color: Colors.white, isBold: true), + if (model.isTimeRemainingInSeconds == 0) DateTime.now().toString().split(" ")[0].toText12(color: Colors.white), + if (model.isTimeRemainingInSeconds != 0) + Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + 9.height, + Directionality( + textDirection: ui.TextDirection.ltr, + child: CountdownTimer( + endTime: model.endTime, + onEnd: null, + endWidget: "00:00:00".toText14(color: Colors.white, isBold: true), + textStyle: const TextStyle(color: Colors.white, fontSize: 14, letterSpacing: -0.48, fontWeight: FontWeight.bold), + ), + ), + LocaleKeys.timeLeftToday.tr().toText12(color: Colors.white), + 9.height, + ClipRRect( + borderRadius: const BorderRadius.all(Radius.circular(20)), + child: LinearProgressIndicator( + value: model.progress, + minHeight: 8, + valueColor: const AlwaysStoppedAnimation(Colors.white), + backgroundColor: const Color(0xff196D73), + ), + ), + ], + ), + ], + ).paddingOnly(top: 12, right: 15, left: 12), + ), + Row( + children: [ + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.checkIn.tr().toText12(color: Colors.white), + (model.attendanceTracking!.pSwipeIn == null ? "--:--" : model.attendanceTracking!.pSwipeIn).toString().toText14( + color: Colors.white, + isBold: true, + ), + 4.height, + ], + ).paddingOnly(left: 12, right: 12), + ), + Container( + margin: EdgeInsets.only(top: AppState().isArabic(context) ? 6 : 0), + width: 45, + height: 45, + padding: const EdgeInsets.only(left: 10, right: 10), + decoration: BoxDecoration( + color: const Color(0xff259EA4), + borderRadius: BorderRadius.only( + bottomRight: AppState().isArabic(context) ? const Radius.circular(0) : const Radius.circular(15), + bottomLeft: AppState().isArabic(context) ? const Radius.circular(15) : const Radius.circular(0), + ), + ), + child: SvgPicture.asset(model.isTimeRemainingInSeconds == 0 ? "assets/images/biometrics.svg" : "assets/images/biometrics.svg"), + ).onPress(() { + showMyBottomSheet(context, callBackFunc: () {}, child: MarkAttendanceWidget(model, isFromDashboard: true)); + }), + ], + ), + ], + ), + ], + ), + ).onPress(() { + Navigator.pushNamed(context, AppRoutes.todayAttendance); + })) + .animatedSwither(); + }, + ), + ), + ), + 9.width, + Expanded(child: MenusWidget()), + ], + ), + ], + ).paddingOnly(left: 21, right: 21, top: 7, bottom: 21), + if (data.isDisplayEidGreetings) ...[ + Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Directionality( + textDirection: AppState().isArabic(context) ? ui.TextDirection.rtl : ui.TextDirection.ltr, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + gradient: const LinearGradient(colors: [Color(0xFFE7E7E7), Color(0xFFE7E7E7)], begin: Alignment.centerLeft, end: Alignment.centerRight), + ), + child: Padding( + padding: const EdgeInsets.all(3.0), + child: Container( + height: 120, + decoration: BoxDecoration(color: const Color(0xFFFAF4E7),borderRadius: BorderRadius.circular(17), image: DecorationImage(image: NetworkImage(AppState().isArabic(context) ? data.greetingCardsList!.first.backgroundImageUrlAr ?? "" : data.greetingCardsList!.first.backgroundImageUrlEn ?? ""), fit: BoxFit.cover)), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Expanded( + // flex: 4, + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // mainAxisAlignment: MainAxisAlignment.start, + // children: [ + // Row( + // children: [ + // Expanded( + // flex: 2, + // child: RichText( + // text: + // AppState().isArabic(context) + // ? TextSpan( + // children: [ + // TextSpan( + // text: 'اطلع على مميزات', + // style: TextStyle( + // fontSize: 16, + // letterSpacing: -0.2, + // fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins', + // fontWeight: FontWeight.w700, + // height: 24 / 16, + // color: const Color(0xFF5D5E5E), + // ), + // ), + // TextSpan( + // text: ' مزايا', + // style: TextStyle( + // fontSize: 16, + // fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins', + // fontWeight: FontWeight.w700, + // letterSpacing: -0.2, + // height: 24 / 16, + // color: MyColors.mazayaRedColor, // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed + // ), + // ), + // ], + // ) + // : TextSpan( + // children: [ + // TextSpan( + // text: LocaleKeys.explore.tr() + ' ', + // style: const TextStyle( + // fontSize: 16, + // letterSpacing: -0.2, + // fontFamily: 'Poppins', + // fontWeight: FontWeight.w700, + // height: 24 / 16, + // color: Color(0xFF5D5E5E), + // ), + // ), + // TextSpan( + // text: LocaleKeys.mazaya.tr(), + // style: const TextStyle( + // fontSize: 16, + // fontWeight: FontWeight.w700, + // fontFamily: 'Poppins', + // letterSpacing: -0.2, + // height: 24 / 16, + // color: MyColors.mazayaRedColor, // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed + // ), + // ), + // TextSpan( + // text: ' ' + LocaleKeys.benefits.tr(), + // style: const TextStyle( + // fontSize: 16, + // letterSpacing: -0.2, + // fontFamily: 'Poppins', + // fontWeight: FontWeight.w700, + // height: 24 / 16, + // color: Color(0xFF5D5E5E), + // ), + // ), + // ], + // ), + // ), + // ), + // const Expanded(flex: 1, child: SizedBox()), + // ], + // ), + // const SizedBox(height: 8), + // LocaleKeys.mazayaDesc.tr().toText11(color: const Color(0xFF5D5E5E)), + // ], + // ), + // ), + // Expanded( + // flex: 2, + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.end, + // mainAxisAlignment: MainAxisAlignment.end, + // children: [ + // SvgPicture.asset("assets/icons/mazaya_brand.svg", width: 90, height: 47), + // const SizedBox(height: 28), + // LocaleKeys.viewallofferMazaya.tr().toText12(isUnderLine: true, color: const Color(0xFF3B3D4A)).onPress(() { + // Navigator.pushNamed(context, AppRoutes.offersAndDiscounts); + // }), + // ], + // ), + // ), + ], + ).paddingOnly(left: 21, right: 21, top: 14, bottom: 14), + ), + ), + ).paddingOnly(left: 21, right: 21, top: 0, bottom: 21), + ), + ], + ), + ], + eventActivityWidget(context), + if (isDisplayMazaya) ...[ + Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Directionality( + textDirection: AppState().isArabic(context) ? ui.TextDirection.rtl : ui.TextDirection.ltr, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + gradient: const LinearGradient(colors: [Color(0xFF91C481), Color(0xFF7CCED7)], begin: Alignment.centerLeft, end: Alignment.centerRight), + ), + child: Padding( + padding: const EdgeInsets.all(3.0), // This creates the border width + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(17), // Slightly less than outer radius + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + flex: 4, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Row( + children: [ + Expanded( + flex: 2, + child: RichText( + text: + AppState().isArabic(context) + ? TextSpan( + children: [ + TextSpan( + text: 'اطلع على مميزات', + style: TextStyle( + fontSize: 16, + letterSpacing: -0.2, + fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins', + fontWeight: FontWeight.w700, + height: 24 / 16, + color: const Color(0xFF5D5E5E), + ), + ), + TextSpan( + text: ' مزايا', + style: TextStyle( + fontSize: 16, + fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins', + fontWeight: FontWeight.w700, + letterSpacing: -0.2, + height: 24 / 16, + color: MyColors.mazayaRedColor, // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed + ), + ), + ], + ) + : TextSpan( + children: [ + TextSpan( + text: LocaleKeys.explore.tr() + ' ', + style: const TextStyle( + fontSize: 16, + letterSpacing: -0.2, + fontFamily: 'Poppins', + fontWeight: FontWeight.w700, + height: 24 / 16, + color: Color(0xFF5D5E5E), + ), + ), + TextSpan( + text: LocaleKeys.mazaya.tr(), + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.w700, + fontFamily: 'Poppins', + letterSpacing: -0.2, + height: 24 / 16, + color: MyColors.mazayaRedColor, // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed + ), + ), + TextSpan( + text: ' ' + LocaleKeys.benefits.tr(), + style: const TextStyle( + fontSize: 16, + letterSpacing: -0.2, + fontFamily: 'Poppins', + fontWeight: FontWeight.w700, + height: 24 / 16, + color: Color(0xFF5D5E5E), + ), + ), + ], + ), + ), + ), + const Expanded(flex: 1, child: SizedBox()), + ], + ), + const SizedBox(height: 8), + LocaleKeys.mazayaDesc.tr().toText11(color: const Color(0xFF5D5E5E)), + ], + ), + ), + Expanded( + flex: 2, + child: Column( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + SvgPicture.asset("assets/icons/mazaya_brand.svg", width: 90, height: 47), + const SizedBox(height: 28), + LocaleKeys.viewallofferMazaya.tr().toText12(isUnderLine: true, color: const Color(0xFF3B3D4A)).onPress(() { + Navigator.pushNamed(context, AppRoutes.offersAndDiscounts); + }), + ], + ), + ), + ], + ).paddingOnly(left: 21, right: 21, top: 14, bottom: 14), + ), + ), + ).paddingOnly(left: 21, right: 21, top: 0, bottom: 21), + ), + ], + ), + ], - Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - LocaleKeys.offers.tr().toText12(), - Row( - children: [ - LocaleKeys.discounts.tr().toText24(isBold: true), - 6.width, - Container( - padding: const EdgeInsets.only(left: 8, right: 8), - decoration: BoxDecoration( - color: MyColors.yellowColor, - borderRadius: BorderRadius.circular(10), - ), - child: LocaleKeys.newString.tr().toText10(isBold: true)), - ], - ), - ], - ), - ), - LocaleKeys.viewAllOffers.tr().toText12(isUnderLine: true).onPress(() { - Navigator.pushNamed(context, AppRoutes.offersAndDiscounts); - }) - ], - ).paddingOnly(left: 21, right: 21), - Consumer( - builder: (BuildContext context, DashboardProviderModel model, Widget? child) { - return SizedBox( - height: 103 + 33, - child: ListView.separated( - shrinkWrap: true, - physics: const BouncingScrollPhysics(), - padding: const EdgeInsets.only(left: 21, right: 21, top: 13), - scrollDirection: Axis.horizontal, - itemBuilder: (BuildContext cxt, int index) { - return model.isOffersLoading - ? const OffersShimmerWidget() - : InkWell( - onTap: () { - navigateToDetails(data.getOffersList[index]); - }, - child: SizedBox( - width: 73, - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Container( - width: 73, - height: 73, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: const BorderRadius.all( - Radius.circular(100), - ), - border: Border.all(color: MyColors.lightGreyE3Color, width: 1), - ), - child: ClipRRect( - borderRadius: const BorderRadius.all( - Radius.circular(50), - ), - child: Hero( - tag: "ItemImage" + data.getOffersList[index].offersDiscountId.toString()!, - transitionOnUserGestures: true, - child: Image.network( - data.getOffersList[index].logo ?? "", - fit: BoxFit.contain, - ), - ), - ), - ), - 4.height, - Expanded( - child: AppState().isArabic(context) - ? data.getOffersList[index].titleAr!.toText12(isCenter: true, maxLine: 1) - : data.getOffersList[index].titleEn!.toText12(isCenter: true, maxLine: 1), - ), - ], - ), - ), - ); - }, - separatorBuilder: (BuildContext cxt, int index) => 8.width, - itemCount: 9), - ); - }, - ), - ], - ), + Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + LocaleKeys.offers.tr().toText12(), + Row( + children: [ + LocaleKeys.discounts.tr().toText24(isBold: true), + 6.width, + Container( + padding: const EdgeInsets.only(left: 8, right: 8), + decoration: BoxDecoration(color: MyColors.yellowColor, borderRadius: BorderRadius.circular(10)), + child: LocaleKeys.newString.tr().toText10(isBold: true), + ), + ], + ), + ], + ), + ), + LocaleKeys.viewAllOffers.tr().toText12(isUnderLine: true).onPress(() { + Navigator.pushNamed(context, AppRoutes.offersAndDiscounts); + }), + ], + ).paddingOnly(left: 21, right: 21), + Consumer( + builder: (BuildContext context, DashboardProviderModel model, Widget? child) { + return SizedBox( + height: 103 + 33, + child: ListView.separated( + shrinkWrap: true, + physics: const BouncingScrollPhysics(), + padding: const EdgeInsets.only(left: 21, right: 21, top: 13), + scrollDirection: Axis.horizontal, + itemBuilder: (BuildContext cxt, int index) { + return model.isOffersLoading + ? const OffersShimmerWidget() + : InkWell( + onTap: () { + navigateToDetails(data.getOffersList[index]); + }, + child: SizedBox( + width: 73, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + width: 73, + height: 73, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: const BorderRadius.all(Radius.circular(100)), + border: Border.all(color: MyColors.lightGreyE3Color, width: 1), + ), + child: ClipRRect( + borderRadius: const BorderRadius.all(Radius.circular(50)), + child: Hero( + tag: "ItemImage" + data.getOffersList[index].offersDiscountId.toString()!, + transitionOnUserGestures: true, + child: Image.network(data.getOffersList[index].logo ?? "", fit: BoxFit.contain), + ), + ), + ), + 4.height, + Expanded( + child: + AppState().isArabic(context) + ? data.getOffersList[index].titleAr!.toText12(isCenter: true, maxLine: 1) + : data.getOffersList[index].titleEn!.toText12(isCenter: true, maxLine: 1), + ), + ], + ), + ), + ); + }, + separatorBuilder: (BuildContext cxt, int index) => 8.width, + itemCount: 9, + ), + ); + }, + ), + ], + ), - Container( - width: double.infinity, - padding: const EdgeInsets.only(top: 31), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: const BorderRadius.only(topRight: Radius.circular(50), topLeft: Radius.circular(50)), - border: Border.all(color: MyColors.lightGreyEDColor, width: 1), - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - ServicesWidget(), - context.watch().isLoading ? const MarathonBannerShimmer().paddingAll(20) : const MarathonBanner().paddingOnly(left: 21, right: 21, bottom: 8, top: 8), - // context.watch().isTutorialLoading - // ? const MarathonBannerShimmer().paddingAll(20) - // : Container( - // padding: EdgeInsets.only(bottom: 12, top: 12), - // margin: EdgeInsets.only(left: 21, right: 21, bottom: 21, top: 8), - // width: double.infinity, - // alignment: Alignment.center, - // decoration: BoxDecoration( - // color: MyColors.backgroundBlackColor, - // borderRadius: BorderRadius.circular(20), - // border: Border.all(color: MyColors.lightGreyEDColor, width: 1), - // ), - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // mainAxisSize: MainAxisSize.min, - // children: [ - // Text( - // "Tutorial:", - // style: TextStyle( - // fontSize: 11, - // fontStyle: FontStyle.italic, - // fontWeight: FontWeight.w600, - // color: MyColors.white.withOpacity(0.83), - // letterSpacing: -0.4, - // ), - // ), - // Text( - // context.read().tutorial?.tutorialName ?? "", - // overflow: TextOverflow.ellipsis, - // style: TextStyle( - // fontStyle: FontStyle.italic, - // fontSize: 19, - // fontWeight: FontWeight.bold, - // color: MyColors.white, - // height: 32 / 22, - // ), - // ), - // ], - // ), - // ).onPress(() { - // checkERMChannel(); - // // Navigator.pushNamed(context, AppRoutes.marathonTutorialScreen); - // }), - ], - ), - ), - ], - ), - ), - ), - ), - ], - ), - drawer: AppDrawer(onLanguageChange: _onRefresh), - bottomNavigationBar: SizedBox( - height: Platform.isAndroid ? 70 : 100, - child: BottomNavigationBar( - items: [ - BottomNavigationBarItem( - icon: SvgPicture.asset("assets/icons/home.svg", color: currentIndex == 0 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4), - label: LocaleKeys.home.tr(), - ), - BottomNavigationBarItem( - icon: SvgPicture.asset("assets/icons/create_req.svg", color: currentIndex == 1 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4), - label: LocaleKeys.mowadhafhiRequest.tr(), - ), - BottomNavigationBarItem( - icon: Stack( - alignment: Alignment.centerLeft, - children: [ - SvgPicture.asset("assets/icons/work_list.svg", color: currentIndex == 2 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4), - Consumer( - builder: (BuildContext cxt, DashboardProviderModel data, Widget? child) { - if (data.workListCounter == 0) { - return const SizedBox(); - } - return Positioned( - right: 0, - top: 0, - child: Container( - padding: const EdgeInsets.only(left: 4, right: 4), - alignment: Alignment.center, - decoration: BoxDecoration(color: MyColors.redColor, borderRadius: BorderRadius.circular(17)), - child: data.workListCounter.toString().toText10(color: Colors.white), - ), - ); - }, - ), - ], - ), - label: LocaleKeys.workList.tr(), - ), - BottomNavigationBarItem( - icon: SvgPicture.asset("assets/icons/item_for_sale.svg", color: currentIndex == 3 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4), - label: LocaleKeys.itemsForSale.tr(), - ), - BottomNavigationBarItem( - icon: Stack( - alignment: Alignment.centerLeft, - children: [ - SvgPicture.asset( - "assets/icons/chat/chat.svg", - color: - !checkIfPrivilegedForChat() - ? MyColors.lightGreyE3Color - : currentIndex == 4 - ? MyColors.grey3AColor - : cProvider.disbaleChatForThisUser - ? MyColors.lightGreyE3Color - : MyColors.grey98Color, - ).paddingAll(4), - Consumer( - builder: (BuildContext cxt, ChatProviderModel data, Widget? child) { - return !checkIfPrivilegedForChat() - ? const SizedBox() - : Positioned( - right: 0, - top: 0, - child: Container( - padding: const EdgeInsets.only(left: 4, right: 4), - alignment: Alignment.center, - decoration: BoxDecoration(color: cProvider.disbaleChatForThisUser ? MyColors.pinkDarkColor : MyColors.redColor, borderRadius: BorderRadius.circular(17)), - child: data.chatUConvCounter.toString().toText10(color: Colors.white), - ), - ); - }, - ), - ], - ), - label: LocaleKeys.chat.tr(), - ), - ], - currentIndex: currentIndex, - selectedLabelStyle: const TextStyle(fontSize: 10, color: MyColors.grey3AColor, fontWeight: FontWeight.w600), - unselectedLabelStyle: const TextStyle(fontSize: 10, color: MyColors.grey98Color, fontWeight: FontWeight.w600), - type: BottomNavigationBarType.fixed, - selectedItemColor: MyColors.grey3AColor, - backgroundColor: MyColors.backgroundColor, - selectedIconTheme: const IconThemeData(color: MyColors.grey3AColor, size: 28), - unselectedIconTheme: const IconThemeData(color: MyColors.grey98Color, size: 28), - onTap: (int index) { - if (index == 1) { - Navigator.pushNamed(context, AppRoutes.mowadhafhi); - } else if (index == 2) { - Navigator.pushNamed(context, AppRoutes.workList); - } else if (index == 3) { - Navigator.pushNamed(context, AppRoutes.itemsForSale); - } else if (index == 4) { - if (!cProvider.disbaleChatForThisUser && checkIfPrivilegedForChat()) { - Navigator.pushNamed(context, AppRoutes.chat); - } - } - }, - ), - ), - ), + Container( + width: double.infinity, + padding: const EdgeInsets.only(top: 31), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: const BorderRadius.only(topRight: Radius.circular(50), topLeft: Radius.circular(50)), + border: Border.all(color: MyColors.lightGreyEDColor, width: 1), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + ServicesWidget(), + context.watch().isLoading ? const MarathonBannerShimmer().paddingAll(20) : const MarathonBanner().paddingOnly(left: 21, right: 21, bottom: 8, top: 8), + // context.watch().isTutorialLoading + // ? const MarathonBannerShimmer().paddingAll(20) + // : Container( + // padding: EdgeInsets.only(bottom: 12, top: 12), + // margin: EdgeInsets.only(left: 21, right: 21, bottom: 21, top: 8), + // width: double.infinity, + // alignment: Alignment.center, + // decoration: BoxDecoration( + // color: MyColors.backgroundBlackColor, + // borderRadius: BorderRadius.circular(20), + // border: Border.all(color: MyColors.lightGreyEDColor, width: 1), + // ), + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // mainAxisSize: MainAxisSize.min, + // children: [ + // Text( + // "Tutorial:", + // style: TextStyle( + // fontSize: 11, + // fontStyle: FontStyle.italic, + // fontWeight: FontWeight.w600, + // color: MyColors.white.withOpacity(0.83), + // letterSpacing: -0.4, + // ), + // ), + // Text( + // context.read().tutorial?.tutorialName ?? "", + // overflow: TextOverflow.ellipsis, + // style: TextStyle( + // fontStyle: FontStyle.italic, + // fontSize: 19, + // fontWeight: FontWeight.bold, + // color: MyColors.white, + // height: 32 / 22, + // ), + // ), + // ], + // ), + // ).onPress(() { + // checkERMChannel(); + // // Navigator.pushNamed(context, AppRoutes.marathonTutorialScreen); + // }), + ], + ), + ), + ], + ), + ), + ), + ), + ], + ), + drawer: AppDrawer(onLanguageChange: _onRefresh), + bottomNavigationBar: SizedBox( + height: Platform.isAndroid ? 70 : 100, + child: BottomNavigationBar( + items: [ + BottomNavigationBarItem( + icon: SvgPicture.asset("assets/icons/home.svg", color: currentIndex == 0 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4), + label: LocaleKeys.home.tr(), + ), + BottomNavigationBarItem( + icon: SvgPicture.asset("assets/icons/create_req.svg", color: currentIndex == 1 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4), + label: LocaleKeys.mowadhafhiRequest.tr(), + ), + BottomNavigationBarItem( + icon: Stack( + alignment: Alignment.centerLeft, + children: [ + SvgPicture.asset("assets/icons/work_list.svg", color: currentIndex == 2 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4), + Consumer( + builder: (BuildContext cxt, DashboardProviderModel data, Widget? child) { + if (data.workListCounter == 0) { + return const SizedBox(); + } + return Positioned( + right: 0, + top: 0, + child: Container( + padding: const EdgeInsets.only(left: 4, right: 4), + alignment: Alignment.center, + decoration: BoxDecoration(color: MyColors.redColor, borderRadius: BorderRadius.circular(17)), + child: data.workListCounter.toString().toText10(color: Colors.white), + ), ); - } + }, + ), + ], + ), + label: LocaleKeys.workList.tr(), + ), + BottomNavigationBarItem( + icon: SvgPicture.asset("assets/icons/item_for_sale.svg", color: currentIndex == 3 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4), + label: LocaleKeys.itemsForSale.tr(), + ), + BottomNavigationBarItem( + icon: Stack( + alignment: Alignment.centerLeft, + children: [ + SvgPicture.asset( + "assets/icons/chat/chat.svg", + color: + !checkIfPrivilegedForChat() + ? MyColors.lightGreyE3Color + : currentIndex == 4 + ? MyColors.grey3AColor + : cProvider.disbaleChatForThisUser + ? MyColors.lightGreyE3Color + : MyColors.grey98Color, + ).paddingAll(4), + Consumer( + builder: (BuildContext cxt, ChatProviderModel data, Widget? child) { + return !checkIfPrivilegedForChat() + ? const SizedBox() + : Positioned( + right: 0, + top: 0, + child: Container( + padding: const EdgeInsets.only(left: 4, right: 4), + alignment: Alignment.center, + decoration: BoxDecoration(color: cProvider.disbaleChatForThisUser ? MyColors.pinkDarkColor : MyColors.redColor, borderRadius: BorderRadius.circular(17)), + child: data.chatUConvCounter.toString().toText10(color: Colors.white), + ), + ); + }, + ), + ], + ), + label: LocaleKeys.chat.tr(), + ), + ], + currentIndex: currentIndex, + selectedLabelStyle: const TextStyle(fontSize: 10, color: MyColors.grey3AColor, fontWeight: FontWeight.w600), + unselectedLabelStyle: const TextStyle(fontSize: 10, color: MyColors.grey98Color, fontWeight: FontWeight.w600), + type: BottomNavigationBarType.fixed, + selectedItemColor: MyColors.grey3AColor, + backgroundColor: MyColors.backgroundColor, + selectedIconTheme: const IconThemeData(color: MyColors.grey3AColor, size: 28), + unselectedIconTheme: const IconThemeData(color: MyColors.grey98Color, size: 28), + onTap: (int index) { + if (index == 1) { + Navigator.pushNamed(context, AppRoutes.mowadhafhi); + } else if (index == 2) { + Navigator.pushNamed(context, AppRoutes.workList); + } else if (index == 3) { + Navigator.pushNamed(context, AppRoutes.itemsForSale); + } else if (index == 4) { + if (!cProvider.disbaleChatForThisUser && checkIfPrivilegedForChat()) { + Navigator.pushNamed(context, AppRoutes.chat); + } + } + }, + ), + ), + ), + ); + } Widget eventActivityWidget(BuildContext context) { - return (context.watch().isEventLoadingLoading) + return (context + .watch() + .isEventLoadingLoading) ? const MarathonBannerShimmer().paddingOnly(left: 21, right: 21, bottom: 21, top: 0) - : (context.watch().eventActivity != null && context.watch().eventActivity!.isActive == true) + : (context + .watch() + .eventActivity != null && context + .watch() + .eventActivity! + .isActive == true) ? const EventActivityBanner().paddingOnly(left: 21, right: 21, bottom: 21, top: 0) : const SizedBox(); } @@ -864,4 +996,4 @@ class _DashboardScreenState extends State with WidgetsBindingOb } return false; } -} \ No newline at end of file +} -- 2.30.2 From 9f663df3cce393a4941613b664201f0b81aa8849 Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Sun, 1 Mar 2026 13:48:29 +0300 Subject: [PATCH 124/135] QIPS-1205 --- lib/api/etqan_ovr_api_client.dart | 20 ++++++++++++++++---- lib/provider/etqan_ovr_provider.dart | 21 --------------------- lib/ui/etqan_ovr/etqan_ovr_home.dart | 2 +- lib/widgets/image_picker.dart | 4 ++-- 4 files changed, 19 insertions(+), 28 deletions(-) diff --git a/lib/api/etqan_ovr_api_client.dart b/lib/api/etqan_ovr_api_client.dart index 1018177..4435ec7 100644 --- a/lib/api/etqan_ovr_api_client.dart +++ b/lib/api/etqan_ovr_api_client.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'package:flutter/foundation.dart'; +import 'package:intl/intl.dart'; import 'package:mohem_flutter_app/api/api_client.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/consts.dart'; @@ -61,10 +62,21 @@ class EtqanApiClient { } if (responseData.isNotEmpty) { - for (EtqanGetEmployeeOvrRequestsResponse action in responseData) { - action.createdDate = action.createdDate?.split(" ")[0]; - } - responseData.sort((EtqanGetEmployeeOvrRequestsResponse a, EtqanGetEmployeeOvrRequestsResponse b) => (b.createdDate ?? '').compareTo(a.createdDate ?? '')); + responseData.sort((EtqanGetEmployeeOvrRequestsResponse a, EtqanGetEmployeeOvrRequestsResponse b) { + if (a.createdDate == null && b.createdDate == null) return 0; + if (a.createdDate == null) return 1; + if (b.createdDate == null) return -1; + + try { + // Parse dates in format "15-Feb-2026 05:24 PM" + DateFormat dateFormat = DateFormat("dd-MMM-yyyy hh:mm a"); + DateTime dateA = dateFormat.parse(a.createdDate!); + DateTime dateB = dateFormat.parse(b.createdDate!); + return dateB.compareTo(dateA); + } catch (e) { + return (b.createdDate ?? '').compareTo(a.createdDate ?? ''); + } + }); } return responseData; diff --git a/lib/provider/etqan_ovr_provider.dart b/lib/provider/etqan_ovr_provider.dart index deba5ba..6ac8cf7 100644 --- a/lib/provider/etqan_ovr_provider.dart +++ b/lib/provider/etqan_ovr_provider.dart @@ -112,17 +112,6 @@ class EtqanOvrProviderModel with ChangeNotifier, DiagnosticableTreeMixin { Utils.showLoading(context); getEtqanEmployeeRequestsList?.clear(); getEtqanEmployeeRequestsList = await EtqanApiClient().getEmployeeEtqanRequests(); - - // Sort by createdDate in descending order (newest first) - if (getEtqanEmployeeRequestsList != null && getEtqanEmployeeRequestsList!.isNotEmpty) { - getEtqanEmployeeRequestsList!.sort((a, b) { - if (a.createdDate == null && b.createdDate == null) return 0; - if (a.createdDate == null) return 1; - if (b.createdDate == null) return -1; - return b.createdDate!.compareTo(a.createdDate!); - }); - } - Utils.hideLoading(context); isLoading = false; notifyListeners(); @@ -203,16 +192,6 @@ class EtqanOvrProviderModel with ChangeNotifier, DiagnosticableTreeMixin { if (response != null) { getEtqanEmployeeRequestsList = await EtqanApiClient().getEmployeeEtqanRequests(); - // Sort by ticketNumber in descending order (newest first) - if (getEtqanEmployeeRequestsList != null && getEtqanEmployeeRequestsList!.isNotEmpty) { - getEtqanEmployeeRequestsList!.sort((a, b) { - if (a.ticketNumber == null && b.ticketNumber == null) return 0; - if (a.ticketNumber == null) return 1; - if (b.ticketNumber == null) return -1; - return b.ticketNumber!.compareTo(a.ticketNumber!); - }); - } - notifyListeners(); return response; } diff --git a/lib/ui/etqan_ovr/etqan_ovr_home.dart b/lib/ui/etqan_ovr/etqan_ovr_home.dart index 978f894..10c1306 100644 --- a/lib/ui/etqan_ovr/etqan_ovr_home.dart +++ b/lib/ui/etqan_ovr/etqan_ovr_home.dart @@ -69,7 +69,7 @@ class _EtqanOvrHomeState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ (data.ticketNumber ?? "").toText14(isBold: true, color: MyColors.darkTextColor), - Directionality(textDirection: TextDirection.ltr, child: (data.createdDate ?? "").toText12(color: MyColors.grey70Color)), + Directionality(textDirection: TextDirection.ltr, child: (data.createdDate!.split(" ").first ?? "").toText12(color: MyColors.grey70Color)), ], ), 8.height, diff --git a/lib/widgets/image_picker.dart b/lib/widgets/image_picker.dart index a5d346f..984d6ad 100644 --- a/lib/widgets/image_picker.dart +++ b/lib/widgets/image_picker.dart @@ -141,7 +141,7 @@ void galleryImageAndroid(Function(String, File) image) async { } void cameraImageAndroid(Function(String, File) image) async { - File _image = File(( await picker.pickMedia())?.path ?? ""); + File _image = File((await picker.pickImage(source: ImageSource.camera, imageQuality: 20))?.path ?? ""); String fileName = _image.path; var bytes = File(fileName).readAsBytesSync(); String base64Encode = base64.encode(bytes); @@ -159,7 +159,7 @@ class _BottomSheet extends StatelessWidget { Widget build(BuildContext context) { return Container( padding: const EdgeInsets.symmetric(vertical: 12.0), - decoration: BoxDecoration( borderRadius: const BorderRadius.only(topLeft: Radius.circular(16.0), topRight: Radius.circular(16.0))), + decoration: const BoxDecoration( borderRadius: BorderRadius.only(topLeft: Radius.circular(16.0), topRight: Radius.circular(16.0))), child: SafeArea( top: false, child: Column( -- 2.30.2 From 71d03ba66467e4304cd4a141df18dfde79ffa74e Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Sun, 1 Mar 2026 15:09:32 +0300 Subject: [PATCH 125/135] QIPS-1205 --- lib/api/etqan_ovr_api_client.dart | 3 +-- lib/provider/etqan_ovr_provider.dart | 19 +++++++++++++++++-- lib/ui/etqan_ovr/etqan_create_request.dart | 2 +- lib/ui/etqan_ovr/etqan_ovr_home.dart | 2 +- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/lib/api/etqan_ovr_api_client.dart b/lib/api/etqan_ovr_api_client.dart index 4435ec7..bc68160 100644 --- a/lib/api/etqan_ovr_api_client.dart +++ b/lib/api/etqan_ovr_api_client.dart @@ -72,13 +72,12 @@ class EtqanApiClient { DateFormat dateFormat = DateFormat("dd-MMM-yyyy hh:mm a"); DateTime dateA = dateFormat.parse(a.createdDate!); DateTime dateB = dateFormat.parse(b.createdDate!); - return dateB.compareTo(dateA); + return dateA.compareTo(dateB); } catch (e) { return (b.createdDate ?? '').compareTo(a.createdDate ?? ''); } }); } - return responseData; }, url, diff --git a/lib/provider/etqan_ovr_provider.dart b/lib/provider/etqan_ovr_provider.dart index 6ac8cf7..a8128fe 100644 --- a/lib/provider/etqan_ovr_provider.dart +++ b/lib/provider/etqan_ovr_provider.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:mohem_flutter_app/api/etqan_ovr_api_client.dart'; @@ -71,6 +72,7 @@ class EtqanOvrProviderModel with ChangeNotifier, DiagnosticableTreeMixin { localeId: localeId, listenFor: const Duration(seconds: 30), pauseFor: const Duration(seconds: 3), + partialResults: true, listenMode: ListenMode.confirmation, ); _isListening = true; @@ -191,8 +193,21 @@ class EtqanOvrProviderModel with ChangeNotifier, DiagnosticableTreeMixin { Utils.hideLoading(context); if (response != null) { getEtqanEmployeeRequestsList = await EtqanApiClient().getEmployeeEtqanRequests(); - - notifyListeners(); + if (getEtqanEmployeeRequestsList != null) { + getEtqanEmployeeRequestsList!.sort((EtqanGetEmployeeOvrRequestsResponse a, EtqanGetEmployeeOvrRequestsResponse b) { + if (a.createdDate == null && b.createdDate == null) return 0; + if (a.createdDate == null) return 1; + if (b.createdDate == null) return -1; + try { + DateFormat dateFormat = DateFormat("dd-MMM-yyyy hh:mm a"); + DateTime dateA = dateFormat.parse(a.createdDate!); + DateTime dateB = dateFormat.parse(b.createdDate!); + return dateA.compareTo(dateB); + } catch (e) { + return (b.createdDate ?? '').compareTo(a.createdDate ?? ''); + } + }); + } return response; } return null; diff --git a/lib/ui/etqan_ovr/etqan_create_request.dart b/lib/ui/etqan_ovr/etqan_create_request.dart index ce636ff..8ade990 100644 --- a/lib/ui/etqan_ovr/etqan_create_request.dart +++ b/lib/ui/etqan_ovr/etqan_create_request.dart @@ -303,7 +303,7 @@ class _EtqanOvrCreateRequestState extends State { children: [ Container(width: 8, height: 8, decoration: BoxDecoration(color: Colors.red, borderRadius: BorderRadius.circular(4))), const SizedBox(width: 8), - Text('Listening...', style: TextStyle(fontSize: 12, color: MyColors.gradiantEndColor, fontWeight: FontWeight.w500)), + const Text('Listening...', style: TextStyle(fontSize: 12, color: MyColors.gradiantEndColor, fontWeight: FontWeight.w500)), ], ), ), diff --git a/lib/ui/etqan_ovr/etqan_ovr_home.dart b/lib/ui/etqan_ovr/etqan_ovr_home.dart index 10c1306..e2493e6 100644 --- a/lib/ui/etqan_ovr/etqan_ovr_home.dart +++ b/lib/ui/etqan_ovr/etqan_ovr_home.dart @@ -69,7 +69,7 @@ class _EtqanOvrHomeState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ (data.ticketNumber ?? "").toText14(isBold: true, color: MyColors.darkTextColor), - Directionality(textDirection: TextDirection.ltr, child: (data.createdDate!.split(" ").first ?? "").toText12(color: MyColors.grey70Color)), + Directionality(textDirection: TextDirection.ltr, child: (data.createdDate! ?? "").toText12(color: MyColors.grey70Color)), ], ), 8.height, -- 2.30.2 From facb3bf4e60abc839f0bbad814e0f127deb01336 Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Sun, 1 Mar 2026 15:20:54 +0300 Subject: [PATCH 126/135] QIPS-1205 --- lib/api/etqan_ovr_api_client.dart | 6 +- lib/provider/etqan_ovr_provider.dart | 68 +++++++++++++--------- lib/ui/etqan_ovr/etqan_create_request.dart | 2 + lib/ui/etqan_ovr/etqan_ovr_home.dart | 3 +- 4 files changed, 47 insertions(+), 32 deletions(-) diff --git a/lib/api/etqan_ovr_api_client.dart b/lib/api/etqan_ovr_api_client.dart index bc68160..f7512cc 100644 --- a/lib/api/etqan_ovr_api_client.dart +++ b/lib/api/etqan_ovr_api_client.dart @@ -68,11 +68,11 @@ class EtqanApiClient { if (b.createdDate == null) return -1; try { - // Parse dates in format "15-Feb-2026 05:24 PM" - DateFormat dateFormat = DateFormat("dd-MMM-yyyy hh:mm a"); + // Parse dates in format "26-Feb-2026 12:54 PM" or "01-Mar-2026 02:45 PM" + DateFormat dateFormat = DateFormat("dd-MMM-yyyy hh:mm a", "en_US"); DateTime dateA = dateFormat.parse(a.createdDate!); DateTime dateB = dateFormat.parse(b.createdDate!); - return dateA.compareTo(dateB); + return dateB.compareTo(dateA); // Descending order (newest first) } catch (e) { return (b.createdDate ?? '').compareTo(a.createdDate ?? ''); } diff --git a/lib/provider/etqan_ovr_provider.dart b/lib/provider/etqan_ovr_provider.dart index a8128fe..4f2fe0f 100644 --- a/lib/provider/etqan_ovr_provider.dart +++ b/lib/provider/etqan_ovr_provider.dart @@ -1,6 +1,5 @@ import 'dart:io'; -import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:mohem_flutter_app/api/etqan_ovr_api_client.dart'; @@ -23,6 +22,8 @@ class EtqanOvrProviderModel with ChangeNotifier, DiagnosticableTreeMixin { final SpeechToText _speechToText = SpeechToText(); bool _speechEnabled = false; bool _isListening = false; + String _currentLocaleId = ''; + TextEditingController? _currentController; // Getters for speech state bool get speechEnabled => _speechEnabled; @@ -50,18 +51,25 @@ class EtqanOvrProviderModel with ChangeNotifier, DiagnosticableTreeMixin { Future initSpeech() async { _speechEnabled = await _speechToText.initialize( onStatus: (String status) { - // Update listening state when speech recognition status changes - if (status == 'done' || status == 'notListening') { - _isListening = false; - notifyListeners(); + print('Speech status: $status, isListening: $_isListening'); + // If user wants to keep listening but speech stopped, restart it + if ((status == 'done' || status == 'notListening') && _isListening && _currentController != null) { + // Automatically restart listening after a brief pause + Future.delayed(const Duration(milliseconds: 200), () { + if (_isListening && _currentController != null) { + _startListeningInternal(_currentLocaleId, _currentController!); + } + }); } }, ); notifyListeners(); } - /// Start listening for speech input - Future startListening(String localeId, TextEditingController controller) async { + /// Internal method to start listening + Future _startListeningInternal(String localeId, TextEditingController controller) async { + if (!_speechEnabled) return; + await _speechToText.listen( onResult: (SpeechRecognitionResult result) { description = result.recognizedWords; @@ -70,19 +78,31 @@ class EtqanOvrProviderModel with ChangeNotifier, DiagnosticableTreeMixin { notifyListeners(); }, localeId: localeId, - listenFor: const Duration(seconds: 30), - pauseFor: const Duration(seconds: 3), - partialResults: true, - listenMode: ListenMode.confirmation, + listenFor: const Duration(seconds: 60), + pauseFor: const Duration(seconds: 10), + listenOptions: SpeechListenOptions( + partialResults: true, + listenMode: ListenMode.confirmation, + cancelOnError: false, + ), ); + } + + /// Start listening for speech input + Future startListening(String localeId, TextEditingController controller) async { _isListening = true; + _currentLocaleId = localeId; + _currentController = controller; notifyListeners(); + await _startListeningInternal(localeId, controller); } /// Stop listening for speech input Future stopListening() async { - await _speechToText.stop(); _isListening = false; + _currentLocaleId = ''; + _currentController = null; + await _speechToText.stop(); notifyListeners(); } @@ -193,21 +213,7 @@ class EtqanOvrProviderModel with ChangeNotifier, DiagnosticableTreeMixin { Utils.hideLoading(context); if (response != null) { getEtqanEmployeeRequestsList = await EtqanApiClient().getEmployeeEtqanRequests(); - if (getEtqanEmployeeRequestsList != null) { - getEtqanEmployeeRequestsList!.sort((EtqanGetEmployeeOvrRequestsResponse a, EtqanGetEmployeeOvrRequestsResponse b) { - if (a.createdDate == null && b.createdDate == null) return 0; - if (a.createdDate == null) return 1; - if (b.createdDate == null) return -1; - try { - DateFormat dateFormat = DateFormat("dd-MMM-yyyy hh:mm a"); - DateTime dateA = dateFormat.parse(a.createdDate!); - DateTime dateB = dateFormat.parse(b.createdDate!); - return dateA.compareTo(dateB); - } catch (e) { - return (b.createdDate ?? '').compareTo(a.createdDate ?? ''); - } - }); - } + notifyListeners(); return response; } return null; @@ -217,4 +223,12 @@ class EtqanOvrProviderModel with ChangeNotifier, DiagnosticableTreeMixin { return null; } } + + @override + void dispose() { + if (_isListening) { + _speechToText.stop(); + } + super.dispose(); + } } diff --git a/lib/ui/etqan_ovr/etqan_create_request.dart b/lib/ui/etqan_ovr/etqan_create_request.dart index 8ade990..a1d64af 100644 --- a/lib/ui/etqan_ovr/etqan_create_request.dart +++ b/lib/ui/etqan_ovr/etqan_create_request.dart @@ -39,6 +39,8 @@ class _EtqanOvrCreateRequestState extends State { @override void dispose() { + // Stop listening if active + context.read().stopListening(); _descriptionController.dispose(); super.dispose(); } diff --git a/lib/ui/etqan_ovr/etqan_ovr_home.dart b/lib/ui/etqan_ovr/etqan_ovr_home.dart index e2493e6..80a27c6 100644 --- a/lib/ui/etqan_ovr/etqan_ovr_home.dart +++ b/lib/ui/etqan_ovr/etqan_ovr_home.dart @@ -1,4 +1,3 @@ -import 'dart:convert'; import 'package:easy_localization/easy_localization.dart' as lclize; import 'package:flutter/material.dart'; @@ -69,7 +68,7 @@ class _EtqanOvrHomeState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ (data.ticketNumber ?? "").toText14(isBold: true, color: MyColors.darkTextColor), - Directionality(textDirection: TextDirection.ltr, child: (data.createdDate! ?? "").toText12(color: MyColors.grey70Color)), + Directionality(textDirection: TextDirection.ltr, child: (data.createdDate!.split(" ").first ?? "").toText12(color: MyColors.grey70Color)), ], ), 8.height, -- 2.30.2 From dae746587f5f539b130121db73d5e90fb9868a25 Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Sun, 1 Mar 2026 15:26:09 +0300 Subject: [PATCH 127/135] QIPS-1205 --- lib/provider/etqan_ovr_provider.dart | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/lib/provider/etqan_ovr_provider.dart b/lib/provider/etqan_ovr_provider.dart index 4f2fe0f..a7cb842 100644 --- a/lib/provider/etqan_ovr_provider.dart +++ b/lib/provider/etqan_ovr_provider.dart @@ -24,6 +24,8 @@ class EtqanOvrProviderModel with ChangeNotifier, DiagnosticableTreeMixin { bool _isListening = false; String _currentLocaleId = ''; TextEditingController? _currentController; + String _baseText = ''; // Text that was there when we started listening + String _currentSessionText = ''; // Text captured in current listening session // Getters for speech state bool get speechEnabled => _speechEnabled; @@ -54,8 +56,14 @@ class EtqanOvrProviderModel with ChangeNotifier, DiagnosticableTreeMixin { print('Speech status: $status, isListening: $_isListening'); // If user wants to keep listening but speech stopped, restart it if ((status == 'done' || status == 'notListening') && _isListening && _currentController != null) { + // Save the finalized text before restarting + if (_currentSessionText.isNotEmpty) { + _baseText = _currentController!.text.trim(); + _currentSessionText = ''; + } + // Automatically restart listening after a brief pause - Future.delayed(const Duration(milliseconds: 200), () { + Future.delayed(const Duration(milliseconds: 300), () { if (_isListening && _currentController != null) { _startListeningInternal(_currentLocaleId, _currentController!); } @@ -72,8 +80,15 @@ class EtqanOvrProviderModel with ChangeNotifier, DiagnosticableTreeMixin { await _speechToText.listen( onResult: (SpeechRecognitionResult result) { - description = result.recognizedWords; - controller.text = result.recognizedWords; + _currentSessionText = result.recognizedWords; + + // Combine base text with current session text + String combinedText = _baseText.isEmpty + ? _currentSessionText + : _baseText + (_baseText.endsWith(' ') ? '' : ' ') + _currentSessionText; + + description = combinedText; + controller.text = combinedText; controller.selection = TextSelection.fromPosition(TextPosition(offset: controller.text.length)); notifyListeners(); }, @@ -93,6 +108,8 @@ class EtqanOvrProviderModel with ChangeNotifier, DiagnosticableTreeMixin { _isListening = true; _currentLocaleId = localeId; _currentController = controller; + _baseText = controller.text.trim(); // Save existing text + _currentSessionText = ''; notifyListeners(); await _startListeningInternal(localeId, controller); } @@ -102,6 +119,8 @@ class EtqanOvrProviderModel with ChangeNotifier, DiagnosticableTreeMixin { _isListening = false; _currentLocaleId = ''; _currentController = null; + _baseText = ''; + _currentSessionText = ''; await _speechToText.stop(); notifyListeners(); } -- 2.30.2 From a958257ce93ef35dd4757bf311b5c536e1ba0f07 Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Mon, 2 Mar 2026 14:20:11 +0300 Subject: [PATCH 128/135] Greeting --- assets/images/greeting.svg | 605 ++++++++ assets/langs/ar-SA.json | 43 +- assets/langs/en-US.json | 45 +- lib/generated/codegen_loader.g.dart | 6 +- lib/generated/locale_keys.g.dart | 1 + lib/provider/dashboard_provider_model.dart | 10 +- lib/ui/landing/dashboard_screen.dart | 1363 ++++++++--------- lib/ui/landing/widget/services_widget.dart | 5 +- .../shimmer/dashboard_shimmer_widget.dart | 78 + 9 files changed, 1400 insertions(+), 756 deletions(-) create mode 100644 assets/images/greeting.svg diff --git a/assets/images/greeting.svg b/assets/images/greeting.svg new file mode 100644 index 0000000..0682c60 --- /dev/null +++ b/assets/images/greeting.svg @@ -0,0 +1,605 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index a78c83f..c34661b 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -531,7 +531,7 @@ "noWinner": "حزين! لم يفز أحد اليوم.", "myTeam": "فريقي", "youCanPlayDemo": "لكن يمكنك لعب العرض", - "group" : "مجموعة", + "group": "مجموعة", "searchGroup": "مجموعة البحث", "connectHmgWifi": "قم بتوصيل HMG WIFI", "connectedHmgWifi": "اتصال HMG WIFI", @@ -575,20 +575,20 @@ "versionStatus": "حالة الإصدار", "supplierNo": "رقم المورد", "general": "عام", - "requesterOperatingUnit":"وحدة تشغيل مقدم الطلب", - "prepareEmpNum":"إعداد رقم الموظف", - "supplierInfo" : "معلومات المورد", + "requesterOperatingUnit": "وحدة تشغيل مقدم الطلب", + "prepareEmpNum": "إعداد رقم الموظف", + "supplierInfo": "معلومات المورد", "supplierAcNo": "رقم حساب المورد", "supplierAcName": "اسم حساب المورد", - "supplierIBAN" : "رقم IBAN للمورد", - "supplierCRNo" :"رقم السجل التجاري", - "suppliedAcNo" : "رقم الحساب المقدم", - "patientRefundInvoice" : "فاتورة استرداد الأموال للمريض", - "patientNumber" : "رقم المريض", - "patientName" : "اسم المريض", - "invoiceDate" : "تاريخ الفاتورة", - "refundInvoice" :"فاتورة الاسترجاع", - "hospitalClinic" : "عيادة المستشفى", + "supplierIBAN": "رقم IBAN للمورد", + "supplierCRNo": "رقم السجل التجاري", + "suppliedAcNo": "رقم الحساب المقدم", + "patientRefundInvoice": "فاتورة استرداد الأموال للمريض", + "patientNumber": "رقم المريض", + "patientName": "اسم المريض", + "invoiceDate": "تاريخ الفاتورة", + "refundInvoice": "فاتورة الاسترجاع", + "hospitalClinic": "عيادة المستشفى", "graphicalAnalysis": "التحليل الرسومي", "itemHistoryAnalysis": "تحليل تاريخ العنصر", "pOno": "امر شراء #", @@ -614,23 +614,23 @@ "members": "الأعضاء", "searchByUserName": "البحث بواسطة اسم المستخدم", "shareScreen": "مشاركة الشاشة", - "start":"يبدأ", - "about":"عن", + "start": "يبدأ", + "about": "عن", "explore": "يستكشف", "mazaya": "مازيا", "benefits": "فوائد", "mazayaDesc": "اكتشف الخصومات والعروض الخاصة المتاحة للموظفين", - "viewallofferMazaya" : "أعرض كل المزايا", + "viewallofferMazaya": "أعرض كل المزايا", "buyerName": "اسم المشتري", "buyerNumber": "رقم المشتري", "highestBidder": "أعلى مزايد", "remarks": "ملاحظات", "faHeader": "تفاصيل رأس الصفحة FA", - "bookTypeCode": "رمز نوع الكتاب", + "bookTypeCode": "رمز نوع الكتاب", "categoryCode": "رمز الفئة", "categoryGroup": "مجموعة الفئات", - "faLINES": "تفاصيل الأصول", - "assetNumber": "رقم الأصول", + "faLINES": "تفاصيل الأصول", + "assetNumber": "رقم الأصول", "assetDescription": "وصف الأصول", "barCodeNumber": "رقم الباركود", "datePlaceInService": "تاريخ وضعه في الخدمة", @@ -638,10 +638,11 @@ "disposedDate": "تاريخ التخلص", "netBookValue": "القيمة الدفترية الصافية", "purchasedPrice": "سعر الشراء", - "usefulLife": "العمر الإنتاجي", + "usefulLife": "العمر الإنتاجي", "yearsUsed": "سنوات الاستخدام", "faRequest": "طلب التخلص من FA", "showMore": "عرض المزيد", "buyerDetails": "تفاصيل المشتري", - "parkingQr": "وقوف السيارات QR" + "parkingQr": "وقوف السيارات QR", + "startNow": "ابدأ الآن" } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 5b49d24..af3251e 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -565,7 +565,7 @@ "addAtLeastOneAttachment": "Please add at least one attachment.", "pleaseClickButtonToJoinMarathon": "Press the button below to join the Marathon.", "youCannotJoinTheMarathon": "You cannot join the Marathon because you have exceeded the time limit.", - "requesterOperatingUnit":"Requester Operating Unit", + "requesterOperatingUnit": "Requester Operating Unit", "generate": "Generate", "paymentRequest": "Pay Request", "paymentDetails": "Payment Details", @@ -591,19 +591,19 @@ "versionStatus": "Version Status", "supplierNo": "Supplier No", "general": "General", - "prepareEmpNum":"Prepare Employee Num", - "supplierInfo" : "Supplier Information", + "prepareEmpNum": "Prepare Employee Num", + "supplierInfo": "Supplier Information", "supplierAcNo": "Supplier Account No", - "supplierAcName":"Supplier Account Name", - "supplierIBAN" : "Supplier IBAN", - "supplierCRNo" : "CR Number", - "suppliedAcNo" : "Supplied Account No.", - "patientRefundInvoice" : "Patient Refund Invoice", - "patientNumber" : "Patient Number", - "patientName" : "Patient Name", - "invoiceDate" : "Invoice Date", - "refundInvoice" :"Refund Invoice", - "hospitalClinic" : "Hospital Clinic", + "supplierAcName": "Supplier Account Name", + "supplierIBAN": "Supplier IBAN", + "supplierCRNo": "CR Number", + "suppliedAcNo": "Supplied Account No.", + "patientRefundInvoice": "Patient Refund Invoice", + "patientNumber": "Patient Number", + "patientName": "Patient Name", + "invoiceDate": "Invoice Date", + "refundInvoice": "Refund Invoice", + "hospitalClinic": "Hospital Clinic", "graphicalAnalysis": "Graphical Analysis", "itemHistoryAnalysis": "Item History Analysis", "pOno": "P.O #", @@ -612,23 +612,23 @@ "qtyReceived": "Qty. Received", "bonusQty": "Bonus Qty.", "balQty": "Bal. Qty.", - "start":"Start", - "about":"About", + "start": "Start", + "about": "About", "explore": "Explore", "mazaya": "MAZAYA", "benefits": "Benefits", "mazayaDesc": "Discover special Discounts and offers available to Employees", - "viewallofferMazaya" : "View All Offers", + "viewallofferMazaya": "View All Offers", "buyerName": "Buyer Name", "buyerNumber": "Buyer Number", "highestBidder": "Highest Bidder", "remarks": "Remarks", "faHeader": "FA Header Details", - "bookTypeCode": "Book Type Code", + "bookTypeCode": "Book Type Code", "categoryCode": "Category Code", "categoryGroup": "Category Group", - "faLINES": "Asset Details", - "assetNumber": "Asset Number", + "faLINES": "Asset Details", + "assetNumber": "Asset Number", "assetDescription": "Asset Description", "barCodeNumber": "BarCode Number", "datePlaceInService": "Date place In Service", @@ -636,10 +636,11 @@ "disposedDate": "Disposed Date", "netBookValue": "Net Book Value", "purchasedPrice": "Purchased Price", - "usefulLife": "Useful Life", + "usefulLife": "Useful Life", "yearsUsed": "Years Used", - "faRequest":"FA Disposal Request", + "faRequest": "FA Disposal Request", "showMore": "Show More", "buyerDetails": "Buyer Details", - "parkingQr": "Parking QR" + "parkingQr": "Parking QR", + "startNow": "Start Now" } \ No newline at end of file diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index 62bbce6..3b24423 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -656,7 +656,8 @@ class CodegenLoader extends AssetLoader{ "faRequest": "طلب التخلص من FA", "showMore": "عرض المزيد", "buyerDetails": "تفاصيل المشتري", - "parkingQr": "وقوف السيارات QR" + "parkingQr": "وقوف السيارات QR", + "startNow": "ابدأ الآن" }; static const Map _en_US = { "mohemm": "Mohemm", @@ -1300,7 +1301,8 @@ static const Map _en_US = { "faRequest": "FA Disposal Request", "showMore": "Show More", "buyerDetails": "Buyer Details", - "parkingQr": "Parking QR" + "parkingQr": "Parking QR", + "startNow": "Start Now" }; static const Map> mapLocales = {"ar_SA": _ar_SA, "en_US": _en_US}; } diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 683c8c4..9cf563a 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -629,5 +629,6 @@ abstract class LocaleKeys { static const showMore = 'showMore'; static const buyerDetails = 'buyerDetails'; static const parkingQr = 'parkingQr'; + static const startNow = 'startNow'; } diff --git a/lib/provider/dashboard_provider_model.dart b/lib/provider/dashboard_provider_model.dart index 09c347e..169eb28 100644 --- a/lib/provider/dashboard_provider_model.dart +++ b/lib/provider/dashboard_provider_model.dart @@ -68,6 +68,7 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { bool isOffersLoading = true; List getOffersList = []; + bool isGreetingCardsLoading = true; bool isDisplayEidGreetings = false; List? greetingCardsList; @@ -119,6 +120,8 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { getMenuEntriesList = null; isOffersLoading = true; getOffersList = []; + isGreetingCardsLoading = true; + isDisplayEidGreetings = false; drawerMenuItemList = [ DrawerMenuItem("assets/images/drawer/my_profile.svg", LocaleKeys.myProfile.tr(), AppRoutes.profile), @@ -312,22 +315,23 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } void fetchGreetingCards() async { + isGreetingCardsLoading = true; + notifyListeners(); try { GetGreetingCardsModelResponse? response = await DashboardApiClient().getGreetingCards(); greetingCardsList = response?.getGreetingCardsModelResponse ?? []; - - // Check if there are any active greeting cards if (greetingCardsList != null && greetingCardsList!.isNotEmpty) { isDisplayEidGreetings = greetingCardsList!.any((card) => card.isActive == true); } else { isDisplayEidGreetings = false; } - + isGreetingCardsLoading = false; notifyListeners(); } catch (ex) { logger.wtf(ex); isDisplayEidGreetings = false; greetingCardsList = []; + isGreetingCardsLoading = false; notifyListeners(); } } diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index aca7aba..e067666 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'dart:io'; import 'dart:ui' as ui; - import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_countdown_timer/flutter_countdown_timer.dart'; @@ -254,716 +253,670 @@ class _DashboardScreenState extends State with WidgetsBindingOb child: Scaffold( key: _scaffoldState, body: Column( - children: [ - Row( - children: [ - Builder( - builder: (BuildContext context) { - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - Image.memory( - Utils.dataFromBase64String(AppState().memberInformationList!.eMPLOYEEIMAGE ?? ""), - errorBuilder: (BuildContext context, Object error, StackTrace? stackTrace) { - return SvgPicture.asset("assets/images/user.svg", height: 34, width: 34); - }, - width: 34, - height: 34, - fit: BoxFit.cover, - ).circle(50), - // CircularAvatar( - // width: 34, - // height: 34, - // url: "https://cdn4.iconfinder.com/data/icons/professions-2-2/151/89-512.png", - // ), - 8.width, - SvgPicture.asset("assets/images/side_nav.svg"), - ], - ).onPress(() { - _scaffoldState.currentState!.openDrawer(); - }); - }, - ), - Image - .asset("assets/images/logos/main_mohemm_logo.png", width: 134, height: 28) - .expanded, - SvgPicture.asset("assets/images/announcements.svg", matchTextDirection: true).onPress(() async { - await Navigator.pushNamed(context, AppRoutes.announcements); - }), - ], - ).paddingOnly(left: 21, right: 21, top: 48, bottom: 7), - Expanded( - child: SmartRefresher( - enablePullDown: true, - enablePullUp: false, - header: const MaterialClassicHeader(color: MyColors.gradiantEndColor), - controller: _refreshController, - onRefresh: () { - _onRefresh(false); - }, - child: SingleChildScrollView( - child: Column( - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - LocaleKeys.welcomeBack.tr().toText14(color: MyColors.grey77Color), - (AppState().memberInformationList!.eMPLOYEENAME ?? "").toText24(isBold: true), - 16.height, - Row( - children: [ - Expanded( - child: AspectRatio( - aspectRatio: 159 / 159, - child: Consumer( - builder: (BuildContext context, DashboardProviderModel model, Widget? child) { - return (model.isAttendanceTrackingLoading - ? GetAttendanceTrackingShimmer() - : Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(15), - gradient: const LinearGradient( - transform: GradientRotation(.46), - begin: Alignment.topRight, - end: Alignment.bottomLeft, - colors: [MyColors.gradiantEndColor, MyColors.gradiantStartColor], - ), - ), - child: Stack( - alignment: Alignment.center, - children: [ - if (model.isTimeRemainingInSeconds == 0) SvgPicture.asset("assets/images/thumb.svg"), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - LocaleKeys.markAttendance.tr().toText14(color: Colors.white, isBold: true), - if (model.isTimeRemainingInSeconds == 0) DateTime.now().toString().split(" ")[0].toText12(color: Colors.white), - if (model.isTimeRemainingInSeconds != 0) - Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - 9.height, - Directionality( - textDirection: ui.TextDirection.ltr, - child: CountdownTimer( - endTime: model.endTime, - onEnd: null, - endWidget: "00:00:00".toText14(color: Colors.white, isBold: true), - textStyle: const TextStyle(color: Colors.white, fontSize: 14, letterSpacing: -0.48, fontWeight: FontWeight.bold), - ), - ), - LocaleKeys.timeLeftToday.tr().toText12(color: Colors.white), - 9.height, - ClipRRect( - borderRadius: const BorderRadius.all(Radius.circular(20)), - child: LinearProgressIndicator( - value: model.progress, - minHeight: 8, - valueColor: const AlwaysStoppedAnimation(Colors.white), - backgroundColor: const Color(0xff196D73), - ), - ), - ], - ), - ], - ).paddingOnly(top: 12, right: 15, left: 12), - ), - Row( - children: [ - Expanded( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - LocaleKeys.checkIn.tr().toText12(color: Colors.white), - (model.attendanceTracking!.pSwipeIn == null ? "--:--" : model.attendanceTracking!.pSwipeIn).toString().toText14( - color: Colors.white, - isBold: true, - ), - 4.height, - ], - ).paddingOnly(left: 12, right: 12), - ), - Container( - margin: EdgeInsets.only(top: AppState().isArabic(context) ? 6 : 0), - width: 45, - height: 45, - padding: const EdgeInsets.only(left: 10, right: 10), - decoration: BoxDecoration( - color: const Color(0xff259EA4), - borderRadius: BorderRadius.only( - bottomRight: AppState().isArabic(context) ? const Radius.circular(0) : const Radius.circular(15), - bottomLeft: AppState().isArabic(context) ? const Radius.circular(15) : const Radius.circular(0), - ), - ), - child: SvgPicture.asset(model.isTimeRemainingInSeconds == 0 ? "assets/images/biometrics.svg" : "assets/images/biometrics.svg"), - ).onPress(() { - showMyBottomSheet(context, callBackFunc: () {}, child: MarkAttendanceWidget(model, isFromDashboard: true)); - }), - ], - ), - ], - ), - ], - ), - ).onPress(() { - Navigator.pushNamed(context, AppRoutes.todayAttendance); - })) - .animatedSwither(); - }, - ), - ), - ), - 9.width, - Expanded(child: MenusWidget()), - ], - ), - ], - ).paddingOnly(left: 21, right: 21, top: 7, bottom: 21), - if (data.isDisplayEidGreetings) ...[ - Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Directionality( - textDirection: AppState().isArabic(context) ? ui.TextDirection.rtl : ui.TextDirection.ltr, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - gradient: const LinearGradient(colors: [Color(0xFFE7E7E7), Color(0xFFE7E7E7)], begin: Alignment.centerLeft, end: Alignment.centerRight), - ), - child: Padding( - padding: const EdgeInsets.all(3.0), - child: Container( - height: 120, - decoration: BoxDecoration(color: const Color(0xFFFAF4E7),borderRadius: BorderRadius.circular(17), image: DecorationImage(image: NetworkImage(AppState().isArabic(context) ? data.greetingCardsList!.first.backgroundImageUrlAr ?? "" : data.greetingCardsList!.first.backgroundImageUrlEn ?? ""), fit: BoxFit.cover)), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Expanded( - // flex: 4, - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // mainAxisAlignment: MainAxisAlignment.start, - // children: [ - // Row( - // children: [ - // Expanded( - // flex: 2, - // child: RichText( - // text: - // AppState().isArabic(context) - // ? TextSpan( - // children: [ - // TextSpan( - // text: 'اطلع على مميزات', - // style: TextStyle( - // fontSize: 16, - // letterSpacing: -0.2, - // fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins', - // fontWeight: FontWeight.w700, - // height: 24 / 16, - // color: const Color(0xFF5D5E5E), - // ), - // ), - // TextSpan( - // text: ' مزايا', - // style: TextStyle( - // fontSize: 16, - // fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins', - // fontWeight: FontWeight.w700, - // letterSpacing: -0.2, - // height: 24 / 16, - // color: MyColors.mazayaRedColor, // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed - // ), - // ), - // ], - // ) - // : TextSpan( - // children: [ - // TextSpan( - // text: LocaleKeys.explore.tr() + ' ', - // style: const TextStyle( - // fontSize: 16, - // letterSpacing: -0.2, - // fontFamily: 'Poppins', - // fontWeight: FontWeight.w700, - // height: 24 / 16, - // color: Color(0xFF5D5E5E), - // ), - // ), - // TextSpan( - // text: LocaleKeys.mazaya.tr(), - // style: const TextStyle( - // fontSize: 16, - // fontWeight: FontWeight.w700, - // fontFamily: 'Poppins', - // letterSpacing: -0.2, - // height: 24 / 16, - // color: MyColors.mazayaRedColor, // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed - // ), - // ), - // TextSpan( - // text: ' ' + LocaleKeys.benefits.tr(), - // style: const TextStyle( - // fontSize: 16, - // letterSpacing: -0.2, - // fontFamily: 'Poppins', - // fontWeight: FontWeight.w700, - // height: 24 / 16, - // color: Color(0xFF5D5E5E), - // ), - // ), - // ], - // ), - // ), - // ), - // const Expanded(flex: 1, child: SizedBox()), - // ], - // ), - // const SizedBox(height: 8), - // LocaleKeys.mazayaDesc.tr().toText11(color: const Color(0xFF5D5E5E)), - // ], - // ), - // ), - // Expanded( - // flex: 2, - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.end, - // mainAxisAlignment: MainAxisAlignment.end, - // children: [ - // SvgPicture.asset("assets/icons/mazaya_brand.svg", width: 90, height: 47), - // const SizedBox(height: 28), - // LocaleKeys.viewallofferMazaya.tr().toText12(isUnderLine: true, color: const Color(0xFF3B3D4A)).onPress(() { - // Navigator.pushNamed(context, AppRoutes.offersAndDiscounts); - // }), - // ], - // ), - // ), - ], - ).paddingOnly(left: 21, right: 21, top: 14, bottom: 14), - ), - ), - ).paddingOnly(left: 21, right: 21, top: 0, bottom: 21), - ), - ], - ), - ], - eventActivityWidget(context), - if (isDisplayMazaya) ...[ - Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Directionality( - textDirection: AppState().isArabic(context) ? ui.TextDirection.rtl : ui.TextDirection.ltr, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - gradient: const LinearGradient(colors: [Color(0xFF91C481), Color(0xFF7CCED7)], begin: Alignment.centerLeft, end: Alignment.centerRight), - ), - child: Padding( - padding: const EdgeInsets.all(3.0), // This creates the border width - child: Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(17), // Slightly less than outer radius - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - flex: 4, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Row( - children: [ - Expanded( - flex: 2, - child: RichText( - text: - AppState().isArabic(context) - ? TextSpan( - children: [ - TextSpan( - text: 'اطلع على مميزات', - style: TextStyle( - fontSize: 16, - letterSpacing: -0.2, - fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins', - fontWeight: FontWeight.w700, - height: 24 / 16, - color: const Color(0xFF5D5E5E), - ), - ), - TextSpan( - text: ' مزايا', - style: TextStyle( - fontSize: 16, - fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins', - fontWeight: FontWeight.w700, - letterSpacing: -0.2, - height: 24 / 16, - color: MyColors.mazayaRedColor, // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed - ), - ), - ], - ) - : TextSpan( - children: [ - TextSpan( - text: LocaleKeys.explore.tr() + ' ', - style: const TextStyle( - fontSize: 16, - letterSpacing: -0.2, - fontFamily: 'Poppins', - fontWeight: FontWeight.w700, - height: 24 / 16, - color: Color(0xFF5D5E5E), - ), - ), - TextSpan( - text: LocaleKeys.mazaya.tr(), - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w700, - fontFamily: 'Poppins', - letterSpacing: -0.2, - height: 24 / 16, - color: MyColors.mazayaRedColor, // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed - ), - ), - TextSpan( - text: ' ' + LocaleKeys.benefits.tr(), - style: const TextStyle( - fontSize: 16, - letterSpacing: -0.2, - fontFamily: 'Poppins', - fontWeight: FontWeight.w700, - height: 24 / 16, - color: Color(0xFF5D5E5E), - ), - ), - ], - ), - ), - ), - const Expanded(flex: 1, child: SizedBox()), - ], - ), - const SizedBox(height: 8), - LocaleKeys.mazayaDesc.tr().toText11(color: const Color(0xFF5D5E5E)), - ], - ), - ), - Expanded( - flex: 2, - child: Column( - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisAlignment: MainAxisAlignment.end, - children: [ - SvgPicture.asset("assets/icons/mazaya_brand.svg", width: 90, height: 47), - const SizedBox(height: 28), - LocaleKeys.viewallofferMazaya.tr().toText12(isUnderLine: true, color: const Color(0xFF3B3D4A)).onPress(() { - Navigator.pushNamed(context, AppRoutes.offersAndDiscounts); - }), - ], - ), - ), - ], - ).paddingOnly(left: 21, right: 21, top: 14, bottom: 14), - ), - ), - ).paddingOnly(left: 21, right: 21, top: 0, bottom: 21), - ), - ], - ), - ], + children: [ + Row( + children: [ + Builder( + builder: (BuildContext context) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + Image.memory( + Utils.dataFromBase64String(AppState().memberInformationList!.eMPLOYEEIMAGE ?? ""), + errorBuilder: (BuildContext context, Object error, StackTrace? stackTrace) { + return SvgPicture.asset("assets/images/user.svg", height: 34, width: 34); + }, + width: 34, + height: 34, + fit: BoxFit.cover, + ).circle(50), + // CircularAvatar( + // width: 34, + // height: 34, + // url: "https://cdn4.iconfinder.com/data/icons/professions-2-2/151/89-512.png", + // ), + 8.width, + SvgPicture.asset("assets/images/side_nav.svg"), + ], + ).onPress(() { + _scaffoldState.currentState!.openDrawer(); + }); + }, + ), + Image.asset("assets/images/logos/main_mohemm_logo.png", width: 134, height: 28).expanded, + SvgPicture.asset("assets/images/announcements.svg", matchTextDirection: true).onPress(() async { + await Navigator.pushNamed(context, AppRoutes.announcements); + }), + ], + ).paddingOnly(left: 21, right: 21, top: 48, bottom: 7), + Expanded( + child: SmartRefresher( + enablePullDown: true, + enablePullUp: false, + header: const MaterialClassicHeader(color: MyColors.gradiantEndColor), + controller: _refreshController, + onRefresh: () { + _onRefresh(false); + }, + child: SingleChildScrollView( + child: Column( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.welcomeBack.tr().toText14(color: MyColors.grey77Color), + (AppState().memberInformationList!.eMPLOYEENAME ?? "").toText24(isBold: true), + 16.height, + Row( + children: [ + Expanded( + child: AspectRatio( + aspectRatio: 159 / 159, + child: Consumer( + builder: (BuildContext context, DashboardProviderModel model, Widget? child) { + return (model.isAttendanceTrackingLoading + ? GetAttendanceTrackingShimmer() + : Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(15), + gradient: const LinearGradient( + transform: GradientRotation(.46), + begin: Alignment.topRight, + end: Alignment.bottomLeft, + colors: [MyColors.gradiantEndColor, MyColors.gradiantStartColor], + ), + ), + child: Stack( + alignment: Alignment.center, + children: [ + if (model.isTimeRemainingInSeconds == 0) SvgPicture.asset("assets/images/thumb.svg"), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.markAttendance.tr().toText14(color: Colors.white, isBold: true), + if (model.isTimeRemainingInSeconds == 0) DateTime.now().toString().split(" ")[0].toText12(color: Colors.white), + if (model.isTimeRemainingInSeconds != 0) + Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + 9.height, + Directionality( + textDirection: ui.TextDirection.ltr, + child: CountdownTimer( + endTime: model.endTime, + onEnd: null, + endWidget: "00:00:00".toText14(color: Colors.white, isBold: true), + textStyle: const TextStyle(color: Colors.white, fontSize: 14, letterSpacing: -0.48, fontWeight: FontWeight.bold), + ), + ), + LocaleKeys.timeLeftToday.tr().toText12(color: Colors.white), + 9.height, + ClipRRect( + borderRadius: const BorderRadius.all(Radius.circular(20)), + child: LinearProgressIndicator( + value: model.progress, + minHeight: 8, + valueColor: const AlwaysStoppedAnimation(Colors.white), + backgroundColor: const Color(0xff196D73), + ), + ), + ], + ), + ], + ).paddingOnly(top: 12, right: 15, left: 12), + ), + Row( + children: [ + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.checkIn.tr().toText12(color: Colors.white), + (model.attendanceTracking!.pSwipeIn == null ? "--:--" : model.attendanceTracking!.pSwipeIn).toString().toText14( + color: Colors.white, + isBold: true, + ), + 4.height, + ], + ).paddingOnly(left: 12, right: 12), + ), + Container( + margin: EdgeInsets.only(top: AppState().isArabic(context) ? 6 : 0), + width: 45, + height: 45, + padding: const EdgeInsets.only(left: 10, right: 10), + decoration: BoxDecoration( + color: const Color(0xff259EA4), + borderRadius: BorderRadius.only( + bottomRight: AppState().isArabic(context) ? const Radius.circular(0) : const Radius.circular(15), + bottomLeft: AppState().isArabic(context) ? const Radius.circular(15) : const Radius.circular(0), + ), + ), + child: SvgPicture.asset(model.isTimeRemainingInSeconds == 0 ? "assets/images/biometrics.svg" : "assets/images/biometrics.svg"), + ).onPress(() { + showMyBottomSheet(context, callBackFunc: () {}, child: MarkAttendanceWidget(model, isFromDashboard: true)); + }), + ], + ), + ], + ), + ], + ), + ).onPress(() { + Navigator.pushNamed(context, AppRoutes.todayAttendance); + })) + .animatedSwither(); + }, + ), + ), + ), + 9.width, + Expanded(child: MenusWidget()), + ], + ), + ], + ).paddingOnly(left: 21, right: 21, top: 7, bottom: 21), + Consumer( + builder: (BuildContext context, DashboardProviderModel model, Widget? child) { + if (model.isGreetingCardsLoading) { + return const GreetingCardShimmer(); + } else if (model.isDisplayEidGreetings) { + return Column( + children: [ + Directionality( + textDirection: AppState().isArabic(context) ? ui.TextDirection.rtl : ui.TextDirection.ltr, + child: Container( + height: 100, + decoration: BoxDecoration( + color: const Color(0xFFFAF4E7), + border: Border.all(width: 2, color: const Color(0xFFE7E7E7)), + borderRadius: BorderRadius.circular(20), + image: const DecorationImage( + image: NetworkImage( + "https://dummyimage.com/1200X600/faf4e7/faf4e7.jpg&text=0", + // AppState().isArabic(context) ? model.greetingCardsList!.first.backgroundImageUrlAr ?? "" : model.greetingCardsList!.first.backgroundImageUrlEn ?? "", + ), + fit: BoxFit.cover, + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SvgPicture.asset("assets/images/greeting.svg", width: 65, height: 81), + const SizedBox(width: 10), + Row( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Row( + children: [ + Text( + AppState().isArabic(context) ? model.greetingCardsList!.first.descriptionAr ?? '' : model.greetingCardsList!.first.descriptionEn ?? '', + style: TextStyle( + fontSize: AppState().isArabic(context) ? 18 : 16, + letterSpacing: -0.2, + fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins', + fontWeight: FontWeight.w700, + height: 24 / 16, + color: const Color(0xFF3B3E4F), + ), + ), + ], + ), + Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + AppState().isArabic(context) ? model.greetingCardsList!.first.titleAr ?? '' : model.greetingCardsList!.first.titleEn ?? '', + style: TextStyle( + fontSize: AppState().isArabic(context) ? 18 : 16, + letterSpacing: -0.2, + fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins', + fontWeight: FontWeight.w700, + height: 24 / 16, + color: const Color(0xFF3B3E4F), + ), + ), + ], + ), + ], + ), + ], + ).paddingOnly(top: 10, bottom: 10).expanded, + Column( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + LocaleKeys.startNow.tr().toText12(isUnderLine: true, color: const Color(0xFF3B3D4A)).onPress(() { + Navigator.pushNamed(context, AppRoutes.offersAndDiscounts); + }), + ], + ), + ], + ).paddingOnly(left: 8, right: 8, top: 6, bottom: 12), + ).paddingOnly(left: 21, right: 21, top: 14, bottom: 14), + ), + ], + ); + } else { + return const SizedBox(); + } + }, + ), - Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - LocaleKeys.offers.tr().toText12(), - Row( - children: [ - LocaleKeys.discounts.tr().toText24(isBold: true), - 6.width, - Container( - padding: const EdgeInsets.only(left: 8, right: 8), - decoration: BoxDecoration(color: MyColors.yellowColor, borderRadius: BorderRadius.circular(10)), - child: LocaleKeys.newString.tr().toText10(isBold: true), - ), - ], - ), - ], - ), - ), - LocaleKeys.viewAllOffers.tr().toText12(isUnderLine: true).onPress(() { - Navigator.pushNamed(context, AppRoutes.offersAndDiscounts); - }), - ], - ).paddingOnly(left: 21, right: 21), - Consumer( - builder: (BuildContext context, DashboardProviderModel model, Widget? child) { - return SizedBox( - height: 103 + 33, - child: ListView.separated( - shrinkWrap: true, - physics: const BouncingScrollPhysics(), - padding: const EdgeInsets.only(left: 21, right: 21, top: 13), - scrollDirection: Axis.horizontal, - itemBuilder: (BuildContext cxt, int index) { - return model.isOffersLoading - ? const OffersShimmerWidget() - : InkWell( - onTap: () { - navigateToDetails(data.getOffersList[index]); - }, - child: SizedBox( - width: 73, - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Container( - width: 73, - height: 73, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: const BorderRadius.all(Radius.circular(100)), - border: Border.all(color: MyColors.lightGreyE3Color, width: 1), - ), - child: ClipRRect( - borderRadius: const BorderRadius.all(Radius.circular(50)), - child: Hero( - tag: "ItemImage" + data.getOffersList[index].offersDiscountId.toString()!, - transitionOnUserGestures: true, - child: Image.network(data.getOffersList[index].logo ?? "", fit: BoxFit.contain), - ), - ), - ), - 4.height, - Expanded( - child: - AppState().isArabic(context) - ? data.getOffersList[index].titleAr!.toText12(isCenter: true, maxLine: 1) - : data.getOffersList[index].titleEn!.toText12(isCenter: true, maxLine: 1), - ), - ], - ), - ), - ); - }, - separatorBuilder: (BuildContext cxt, int index) => 8.width, - itemCount: 9, - ), - ); - }, - ), - ], - ), + eventActivityWidget(context), + if (isDisplayMazaya) ...[ + Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Directionality( + textDirection: AppState().isArabic(context) ? ui.TextDirection.rtl : ui.TextDirection.ltr, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + gradient: const LinearGradient(colors: [Color(0xFF91C481), Color(0xFF7CCED7)], begin: Alignment.centerLeft, end: Alignment.centerRight), + ), + child: Padding( + padding: const EdgeInsets.all(3.0), // This creates the border width + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(17), // Slightly less than outer radius + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + flex: 4, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Row( + children: [ + Expanded( + flex: 2, + child: RichText( + text: + AppState().isArabic(context) + ? TextSpan( + children: [ + TextSpan( + text: 'اطلع على مميزات', + style: TextStyle( + fontSize: 16, + letterSpacing: -0.2, + fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins', + fontWeight: FontWeight.w700, + height: 24 / 16, + color: const Color(0xFF5D5E5E), + ), + ), + TextSpan( + text: ' مزايا', + style: TextStyle( + fontSize: 16, + fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins', + fontWeight: FontWeight.w700, + letterSpacing: -0.2, + height: 24 / 16, + color: MyColors.mazayaRedColor, // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed + ), + ), + ], + ) + : TextSpan( + children: [ + TextSpan( + text: LocaleKeys.explore.tr() + ' ', + style: const TextStyle( + fontSize: 16, + letterSpacing: -0.2, + fontFamily: 'Poppins', + fontWeight: FontWeight.w700, + height: 24 / 16, + color: Color(0xFF5D5E5E), + ), + ), + TextSpan( + text: LocaleKeys.mazaya.tr(), + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.w700, + fontFamily: 'Poppins', + letterSpacing: -0.2, + height: 24 / 16, + color: MyColors.mazayaRedColor, // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed + ), + ), + TextSpan( + text: ' ' + LocaleKeys.benefits.tr(), + style: const TextStyle( + fontSize: 16, + letterSpacing: -0.2, + fontFamily: 'Poppins', + fontWeight: FontWeight.w700, + height: 24 / 16, + color: Color(0xFF5D5E5E), + ), + ), + ], + ), + ), + ), + const Expanded(flex: 1, child: SizedBox()), + ], + ), + const SizedBox(height: 8), + LocaleKeys.mazayaDesc.tr().toText11(color: const Color(0xFF5D5E5E)), + ], + ), + ), + Expanded( + flex: 2, + child: Column( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + SvgPicture.asset("assets/icons/mazaya_brand.svg", width: 90, height: 47), + const SizedBox(height: 28), + LocaleKeys.viewallofferMazaya.tr().toText12(isUnderLine: true, color: const Color(0xFF3B3D4A)).onPress(() { + Navigator.pushNamed(context, AppRoutes.offersAndDiscounts); + }), + ], + ), + ), + ], + ).paddingOnly(left: 21, right: 21, top: 14, bottom: 14), + ), + ), + ).paddingOnly(left: 21, right: 21, top: 0, bottom: 21), + ), + ], + ), + ], - Container( - width: double.infinity, - padding: const EdgeInsets.only(top: 31), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: const BorderRadius.only(topRight: Radius.circular(50), topLeft: Radius.circular(50)), - border: Border.all(color: MyColors.lightGreyEDColor, width: 1), - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - ServicesWidget(), - context.watch().isLoading ? const MarathonBannerShimmer().paddingAll(20) : const MarathonBanner().paddingOnly(left: 21, right: 21, bottom: 8, top: 8), - // context.watch().isTutorialLoading - // ? const MarathonBannerShimmer().paddingAll(20) - // : Container( - // padding: EdgeInsets.only(bottom: 12, top: 12), - // margin: EdgeInsets.only(left: 21, right: 21, bottom: 21, top: 8), - // width: double.infinity, - // alignment: Alignment.center, - // decoration: BoxDecoration( - // color: MyColors.backgroundBlackColor, - // borderRadius: BorderRadius.circular(20), - // border: Border.all(color: MyColors.lightGreyEDColor, width: 1), - // ), - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // mainAxisSize: MainAxisSize.min, - // children: [ - // Text( - // "Tutorial:", - // style: TextStyle( - // fontSize: 11, - // fontStyle: FontStyle.italic, - // fontWeight: FontWeight.w600, - // color: MyColors.white.withOpacity(0.83), - // letterSpacing: -0.4, - // ), - // ), - // Text( - // context.read().tutorial?.tutorialName ?? "", - // overflow: TextOverflow.ellipsis, - // style: TextStyle( - // fontStyle: FontStyle.italic, - // fontSize: 19, - // fontWeight: FontWeight.bold, - // color: MyColors.white, - // height: 32 / 22, - // ), - // ), - // ], - // ), - // ).onPress(() { - // checkERMChannel(); - // // Navigator.pushNamed(context, AppRoutes.marathonTutorialScreen); - // }), - ], - ), - ), - ], - ), - ), - ), - ), - ], - ), - drawer: AppDrawer(onLanguageChange: _onRefresh), - bottomNavigationBar: SizedBox( - height: Platform.isAndroid ? 70 : 100, - child: BottomNavigationBar( - items: [ - BottomNavigationBarItem( - icon: SvgPicture.asset("assets/icons/home.svg", color: currentIndex == 0 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4), - label: LocaleKeys.home.tr(), - ), - BottomNavigationBarItem( - icon: SvgPicture.asset("assets/icons/create_req.svg", color: currentIndex == 1 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4), - label: LocaleKeys.mowadhafhiRequest.tr(), - ), - BottomNavigationBarItem( - icon: Stack( - alignment: Alignment.centerLeft, - children: [ - SvgPicture.asset("assets/icons/work_list.svg", color: currentIndex == 2 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4), - Consumer( - builder: (BuildContext cxt, DashboardProviderModel data, Widget? child) { - if (data.workListCounter == 0) { - return const SizedBox(); - } - return Positioned( - right: 0, - top: 0, - child: Container( - padding: const EdgeInsets.only(left: 4, right: 4), - alignment: Alignment.center, - decoration: BoxDecoration(color: MyColors.redColor, borderRadius: BorderRadius.circular(17)), - child: data.workListCounter.toString().toText10(color: Colors.white), - ), - ); - }, - ), - ], - ), - label: LocaleKeys.workList.tr(), - ), - BottomNavigationBarItem( - icon: SvgPicture.asset("assets/icons/item_for_sale.svg", color: currentIndex == 3 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4), - label: LocaleKeys.itemsForSale.tr(), - ), - BottomNavigationBarItem( - icon: Stack( - alignment: Alignment.centerLeft, - children: [ - SvgPicture.asset( - "assets/icons/chat/chat.svg", - color: - !checkIfPrivilegedForChat() - ? MyColors.lightGreyE3Color - : currentIndex == 4 - ? MyColors.grey3AColor - : cProvider.disbaleChatForThisUser - ? MyColors.lightGreyE3Color - : MyColors.grey98Color, - ).paddingAll(4), - Consumer( - builder: (BuildContext cxt, ChatProviderModel data, Widget? child) { - return !checkIfPrivilegedForChat() - ? const SizedBox() - : Positioned( - right: 0, - top: 0, - child: Container( - padding: const EdgeInsets.only(left: 4, right: 4), - alignment: Alignment.center, - decoration: BoxDecoration(color: cProvider.disbaleChatForThisUser ? MyColors.pinkDarkColor : MyColors.redColor, borderRadius: BorderRadius.circular(17)), - child: data.chatUConvCounter.toString().toText10(color: Colors.white), - ), - ); - }, - ), - ], - ), - label: LocaleKeys.chat.tr(), - ), - ], - currentIndex: currentIndex, - selectedLabelStyle: const TextStyle(fontSize: 10, color: MyColors.grey3AColor, fontWeight: FontWeight.w600), - unselectedLabelStyle: const TextStyle(fontSize: 10, color: MyColors.grey98Color, fontWeight: FontWeight.w600), - type: BottomNavigationBarType.fixed, - selectedItemColor: MyColors.grey3AColor, - backgroundColor: MyColors.backgroundColor, - selectedIconTheme: const IconThemeData(color: MyColors.grey3AColor, size: 28), - unselectedIconTheme: const IconThemeData(color: MyColors.grey98Color, size: 28), - onTap: (int index) { - if (index == 1) { - Navigator.pushNamed(context, AppRoutes.mowadhafhi); - } else if (index == 2) { - Navigator.pushNamed(context, AppRoutes.workList); - } else if (index == 3) { - Navigator.pushNamed(context, AppRoutes.itemsForSale); - } else if (index == 4) { - if (!cProvider.disbaleChatForThisUser && checkIfPrivilegedForChat()) { - Navigator.pushNamed(context, AppRoutes.chat); - } - } - }, - ), - ), - ), + Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + LocaleKeys.offers.tr().toText12(), + Row( + children: [ + LocaleKeys.discounts.tr().toText24(isBold: true), + 6.width, + Container( + padding: const EdgeInsets.only(left: 8, right: 8), + decoration: BoxDecoration(color: MyColors.yellowColor, borderRadius: BorderRadius.circular(10)), + child: LocaleKeys.newString.tr().toText10(isBold: true), + ), + ], + ), + ], + ), + ), + LocaleKeys.viewAllOffers.tr().toText12(isUnderLine: true).onPress(() { + Navigator.pushNamed(context, AppRoutes.offersAndDiscounts); + }), + ], + ).paddingOnly(left: 21, right: 21), + Consumer( + builder: (BuildContext context, DashboardProviderModel model, Widget? child) { + return SizedBox( + height: 103 + 33, + child: ListView.separated( + shrinkWrap: true, + physics: const BouncingScrollPhysics(), + padding: const EdgeInsets.only(left: 21, right: 21, top: 13), + scrollDirection: Axis.horizontal, + itemBuilder: (BuildContext cxt, int index) { + return model.isOffersLoading + ? const OffersShimmerWidget() + : InkWell( + onTap: () { + navigateToDetails(data.getOffersList[index]); + }, + child: SizedBox( + width: 73, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + width: 73, + height: 73, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: const BorderRadius.all(Radius.circular(100)), + border: Border.all(color: MyColors.lightGreyE3Color, width: 1), + ), + child: ClipRRect( + borderRadius: const BorderRadius.all(Radius.circular(50)), + child: Hero( + tag: "ItemImage" + data.getOffersList[index].offersDiscountId.toString()!, + transitionOnUserGestures: true, + child: Image.network(data.getOffersList[index].logo ?? "", fit: BoxFit.contain), + ), + ), + ), + 4.height, + Expanded( + child: + AppState().isArabic(context) + ? data.getOffersList[index].titleAr!.toText12(isCenter: true, maxLine: 1) + : data.getOffersList[index].titleEn!.toText12(isCenter: true, maxLine: 1), + ), + ], + ), + ), + ); + }, + separatorBuilder: (BuildContext cxt, int index) => 8.width, + itemCount: 9, + ), + ); + }, + ), + ], + ), + + Container( + width: double.infinity, + padding: const EdgeInsets.only(top: 31), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: const BorderRadius.only(topRight: Radius.circular(50), topLeft: Radius.circular(50)), + border: Border.all(color: MyColors.lightGreyEDColor, width: 1), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + ServicesWidget(), + context.watch().isLoading ? const MarathonBannerShimmer().paddingAll(20) : const MarathonBanner().paddingOnly(left: 21, right: 21, bottom: 8, top: 8), + // context.watch().isTutorialLoading + // ? const MarathonBannerShimmer().paddingAll(20) + // : Container( + // padding: EdgeInsets.only(bottom: 12, top: 12), + // margin: EdgeInsets.only(left: 21, right: 21, bottom: 21, top: 8), + // width: double.infinity, + // alignment: Alignment.center, + // decoration: BoxDecoration( + // color: MyColors.backgroundBlackColor, + // borderRadius: BorderRadius.circular(20), + // border: Border.all(color: MyColors.lightGreyEDColor, width: 1), + // ), + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // mainAxisSize: MainAxisSize.min, + // children: [ + // Text( + // "Tutorial:", + // style: TextStyle( + // fontSize: 11, + // fontStyle: FontStyle.italic, + // fontWeight: FontWeight.w600, + // color: MyColors.white.withOpacity(0.83), + // letterSpacing: -0.4, + // ), + // ), + // Text( + // context.read().tutorial?.tutorialName ?? "", + // overflow: TextOverflow.ellipsis, + // style: TextStyle( + // fontStyle: FontStyle.italic, + // fontSize: 19, + // fontWeight: FontWeight.bold, + // color: MyColors.white, + // height: 32 / 22, + // ), + // ), + // ], + // ), + // ).onPress(() { + // checkERMChannel(); + // // Navigator.pushNamed(context, AppRoutes.marathonTutorialScreen); + // }), + ], + ), + ), + ], + ), + ), + ), + ), + ], + ), + drawer: AppDrawer(onLanguageChange: _onRefresh), + bottomNavigationBar: SizedBox( + height: Platform.isAndroid ? 70 : 100, + child: BottomNavigationBar( + items: [ + BottomNavigationBarItem( + icon: SvgPicture.asset("assets/icons/home.svg", color: currentIndex == 0 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4), + label: LocaleKeys.home.tr(), + ), + BottomNavigationBarItem( + icon: SvgPicture.asset("assets/icons/create_req.svg", color: currentIndex == 1 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4), + label: LocaleKeys.mowadhafhiRequest.tr(), + ), + BottomNavigationBarItem( + icon: Stack( + alignment: Alignment.centerLeft, + children: [ + SvgPicture.asset("assets/icons/work_list.svg", color: currentIndex == 2 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4), + Consumer( + builder: (BuildContext cxt, DashboardProviderModel data, Widget? child) { + if (data.workListCounter == 0) { + return const SizedBox(); + } + return Positioned( + right: 0, + top: 0, + child: Container( + padding: const EdgeInsets.only(left: 4, right: 4), + alignment: Alignment.center, + decoration: BoxDecoration(color: MyColors.redColor, borderRadius: BorderRadius.circular(17)), + child: data.workListCounter.toString().toText10(color: Colors.white), + ), + ); + }, + ), + ], + ), + label: LocaleKeys.workList.tr(), + ), + BottomNavigationBarItem( + icon: SvgPicture.asset("assets/icons/item_for_sale.svg", color: currentIndex == 3 ? MyColors.grey3AColor : MyColors.grey98Color).paddingAll(4), + label: LocaleKeys.itemsForSale.tr(), + ), + BottomNavigationBarItem( + icon: Stack( + alignment: Alignment.centerLeft, + children: [ + SvgPicture.asset( + "assets/icons/chat/chat.svg", + color: + !checkIfPrivilegedForChat() + ? MyColors.lightGreyE3Color + : currentIndex == 4 + ? MyColors.grey3AColor + : cProvider.disbaleChatForThisUser + ? MyColors.lightGreyE3Color + : MyColors.grey98Color, + ).paddingAll(4), + Consumer( + builder: (BuildContext cxt, ChatProviderModel data, Widget? child) { + return !checkIfPrivilegedForChat() + ? const SizedBox() + : Positioned( + right: 0, + top: 0, + child: Container( + padding: const EdgeInsets.only(left: 4, right: 4), + alignment: Alignment.center, + decoration: BoxDecoration(color: cProvider.disbaleChatForThisUser ? MyColors.pinkDarkColor : MyColors.redColor, borderRadius: BorderRadius.circular(17)), + child: data.chatUConvCounter.toString().toText10(color: Colors.white), + ), + ); + }, + ), + ], + ), + label: LocaleKeys.chat.tr(), + ), + ], + currentIndex: currentIndex, + selectedLabelStyle: const TextStyle(fontSize: 10, color: MyColors.grey3AColor, fontWeight: FontWeight.w600), + unselectedLabelStyle: const TextStyle(fontSize: 10, color: MyColors.grey98Color, fontWeight: FontWeight.w600), + type: BottomNavigationBarType.fixed, + selectedItemColor: MyColors.grey3AColor, + backgroundColor: MyColors.backgroundColor, + selectedIconTheme: const IconThemeData(color: MyColors.grey3AColor, size: 28), + unselectedIconTheme: const IconThemeData(color: MyColors.grey98Color, size: 28), + onTap: (int index) { + if (index == 1) { + Navigator.pushNamed(context, AppRoutes.mowadhafhi); + } else if (index == 2) { + Navigator.pushNamed(context, AppRoutes.workList); + } else if (index == 3) { + Navigator.pushNamed(context, AppRoutes.itemsForSale); + } else if (index == 4) { + if (!cProvider.disbaleChatForThisUser && checkIfPrivilegedForChat()) { + Navigator.pushNamed(context, AppRoutes.chat); + } + } + }, + ), + ), + ), ); - } + } Widget eventActivityWidget(BuildContext context) { - return (context - .watch() - .isEventLoadingLoading) + return (context.watch().isEventLoadingLoading) ? const MarathonBannerShimmer().paddingOnly(left: 21, right: 21, bottom: 21, top: 0) - : (context - .watch() - .eventActivity != null && context - .watch() - .eventActivity! - .isActive == true) + : (context.watch().eventActivity != null && context.watch().eventActivity!.isActive == true) ? const EventActivityBanner().paddingOnly(left: 21, right: 21, bottom: 21, top: 0) : const SizedBox(); } diff --git a/lib/ui/landing/widget/services_widget.dart b/lib/ui/landing/widget/services_widget.dart index 879173b..0a30857 100644 --- a/lib/ui/landing/widget/services_widget.dart +++ b/lib/ui/landing/widget/services_widget.dart @@ -92,7 +92,7 @@ class ServicesWidget extends StatelessWidget { aspectRatio: 105 / 105, child: data.isServicesMenusLoading - ? ServicesMenuShimmer() + ? const ServicesMenuShimmer() : Container( decoration: BoxDecoration( color: Colors.white, @@ -266,7 +266,6 @@ class ServicesWidget extends StatelessWidget { await pro.fetchTicketAccuralBalance(context, DateTime.now()); pro.ticketHistoryTransactionList = await EITApiClient().getEITTransactions("HMG_TICKET_ITENARY_HR_EIT_SS", isCompleteList: true); - Utils.hideLoading(context); // Here Need Work Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => TicketDetailedScreen(url: url, jwtToken: ssoToken.data!.accessToken))); @@ -311,7 +310,7 @@ class ServicesWidget extends StatelessWidget { padding: const EdgeInsets.only(left: 21, right: 21, top: 13, bottom: 13), scrollDirection: Axis.horizontal, itemBuilder: (cxt, index) { - return AspectRatio(aspectRatio: 105 / 105, child: ServicesMenuShimmer()); + return AspectRatio(aspectRatio: 105 / 105, child: const ServicesMenuShimmer()); }, separatorBuilder: (cxt, index) => 9.width, itemCount: 4, diff --git a/lib/widgets/shimmer/dashboard_shimmer_widget.dart b/lib/widgets/shimmer/dashboard_shimmer_widget.dart index c11cf16..7d59899 100644 --- a/lib/widgets/shimmer/dashboard_shimmer_widget.dart +++ b/lib/widgets/shimmer/dashboard_shimmer_widget.dart @@ -8,6 +8,8 @@ import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; import 'package:shimmer/shimmer.dart'; class GetAttendanceTrackingShimmer extends StatelessWidget { + const GetAttendanceTrackingShimmer({Key? key}) : super(key: key); + @override Widget build(BuildContext context) { return Container( @@ -85,6 +87,8 @@ class GetAttendanceTrackingShimmer extends StatelessWidget { } class MenuShimmer extends StatelessWidget { + const MenuShimmer({Key? key}) : super(key: key); + @override Widget build(BuildContext context) { return Container( @@ -122,6 +126,8 @@ class MenuShimmer extends StatelessWidget { } class ServicesHeaderShimmer extends StatelessWidget { + const ServicesHeaderShimmer({Key? key}) : super(key: key); + @override Widget build(BuildContext context) { return Row( @@ -145,6 +151,8 @@ class ServicesHeaderShimmer extends StatelessWidget { } class ServicesMenuShimmer extends StatelessWidget { + const ServicesMenuShimmer({Key? key}) : super(key: key); + @override Widget build(BuildContext context) { return Container( @@ -188,6 +196,75 @@ class ServicesMenuShimmer extends StatelessWidget { } } +class GreetingCardShimmer extends StatelessWidget { + const GreetingCardShimmer({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + height: 100, + decoration: BoxDecoration( + color: const Color(0xFFFAF4E7), + border: Border.all(width: 2, color: const Color(0xFFE7E7E7)), + borderRadius: BorderRadius.circular(20), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + width: 65, + height: 81, + decoration: BoxDecoration( + color: Colors.grey[300], + borderRadius: BorderRadius.circular(10), + ), + ).toShimmer(), + const SizedBox(width: 10), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: 150, + height: 16, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(4), + ), + ).toShimmer(), + const SizedBox(height: 8), + Container( + width: 120, + height: 16, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(4), + ), + ).toShimmer(), + ], + ).expanded, + Column( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Container( + width: 60, + height: 12, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(4), + ), + ).toShimmer(), + ], + ), + ], + ).paddingOnly(left: 8, right: 8, top: 6, bottom: 12), + ).paddingOnly(left: 21, right: 21, top: 14, bottom: 14); + } +} + + class MarathonBannerShimmer extends StatelessWidget { const MarathonBannerShimmer({Key? key}) : super(key: key); @@ -305,3 +382,4 @@ class ChatHomeShimmer extends StatelessWidget { )); } } + -- 2.30.2 From 257b803cce78c5791fac4443167fb29d3838e915 Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Mon, 2 Mar 2026 15:01:29 +0300 Subject: [PATCH 129/135] QIPS-1205 --- .../etqan_ovr/etqan_get_requests_model.dart | 12 ++ lib/provider/etqan_ovr_provider.dart | 13 +- lib/ui/etqan_ovr/etqan_ovr_home.dart | 67 +++++++- lib/ui/etqan_ovr/etqan_request_detailed.dart | 156 +++++++++++------- 4 files changed, 183 insertions(+), 65 deletions(-) diff --git a/lib/models/etqan_ovr/etqan_get_requests_model.dart b/lib/models/etqan_ovr/etqan_get_requests_model.dart index c59e171..ac4911b 100644 --- a/lib/models/etqan_ovr/etqan_get_requests_model.dart +++ b/lib/models/etqan_ovr/etqan_get_requests_model.dart @@ -24,12 +24,18 @@ class EtqanGetEmployeeOvrRequestsResponse { String? createdDate; String? description; String? id; + bool? isAnonymous; + String? status; + String? statusAr; String? ticketNumber; EtqanGetEmployeeOvrRequestsResponse({ this.createdDate, this.description, this.id, + this.isAnonymous, + this.status, + this.statusAr, this.ticketNumber, }); @@ -41,6 +47,9 @@ class EtqanGetEmployeeOvrRequestsResponse { createdDate: json["createdDate"], description: json["description"], id: json["id"], + isAnonymous: json["isAnonymous"], + status: json["status"], + statusAr: json["statusAr"], ticketNumber: json["ticketNumber"], ); @@ -48,6 +57,9 @@ class EtqanGetEmployeeOvrRequestsResponse { "createdDate": createdDate, "description": description, "id": id, + "isAnonymous": isAnonymous, + "status": status, + "statusAr": statusAr, "ticketNumber": ticketNumber, }; } diff --git a/lib/provider/etqan_ovr_provider.dart b/lib/provider/etqan_ovr_provider.dart index a7cb842..b4f2eb1 100644 --- a/lib/provider/etqan_ovr_provider.dart +++ b/lib/provider/etqan_ovr_provider.dart @@ -17,6 +17,9 @@ class EtqanOvrProviderModel with ChangeNotifier, DiagnosticableTreeMixin { List? getEtqanEmployeeIncidnetRequest; bool isLoading = false; String? _ticketId; + String? _currentStatus; + String? _currentStatusAr; + bool? _currentIsAnonymous; // Speech to text state final SpeechToText _speechToText = SpeechToText(); @@ -34,10 +37,16 @@ class EtqanOvrProviderModel with ChangeNotifier, DiagnosticableTreeMixin { // Getter for ticketId String get getTicketId => _ticketId ?? ''; + String get getCurrentStatus => _currentStatus ?? ''; + String get getCurrentStatusAr => _currentStatusAr ?? ''; + bool get getCurrentIsAnonymous => _currentIsAnonymous ?? false; - // Setter for ticketId - void setTicketId(String ticketId) { + // Setter for ticketId with status and isAnonymous + void setTicketId(String ticketId, {String? status, String? statusAr, bool? isAnonymous}) { _ticketId = ticketId; + _currentStatus = status; + _currentStatusAr = statusAr; + _currentIsAnonymous = isAnonymous; notifyListeners(); } diff --git a/lib/ui/etqan_ovr/etqan_ovr_home.dart b/lib/ui/etqan_ovr/etqan_ovr_home.dart index 80a27c6..b55b4c0 100644 --- a/lib/ui/etqan_ovr/etqan_ovr_home.dart +++ b/lib/ui/etqan_ovr/etqan_ovr_home.dart @@ -1,4 +1,3 @@ - import 'package:easy_localization/easy_localization.dart' as lclize; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; @@ -16,6 +15,7 @@ import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; import 'package:mohem_flutter_app/widgets/button/default_button.dart'; import 'package:provider/provider.dart'; import 'package:intl/src/intl/text_direction.dart' as intl; +import 'package:sizer/sizer.dart'; class EtqanOvrHome extends StatefulWidget { const EtqanOvrHome({Key? key}) : super(key: key); @@ -33,6 +33,18 @@ class _EtqanOvrHomeState extends State { }); } + Color _getStatusColor(String status) { + String statusLower = status.toLowerCase(); + if (statusLower.contains('open') || statusLower.contains('مفتوح')) { + return const Color(0xff2196F3); // Blue for open + } else if (statusLower.contains('progress') || statusLower.contains('قيد التنفيذ')) { + return const Color(0xffFF9800); // Orange for in progress + } else if (statusLower.contains('closed') || statusLower.contains('مغلق')) { + return const Color(0xff4CAF50); // Green for closed + } + return MyColors.grey70Color; // Default gray + } + @override Widget build(BuildContext context) { return Scaffold( @@ -51,7 +63,7 @@ class _EtqanOvrHomeState extends State { EtqanGetEmployeeOvrRequestsResponse data = provider.getEtqanEmployeeRequestsList![index]; return InkWell( onTap: () { - context.read().setTicketId(data.ticketNumber ?? ''); + context.read().setTicketId(data.ticketNumber ?? '', status: data.status, statusAr: data.statusAr, isAnonymous: data.isAnonymous); Navigator.pushNamed(context, AppRoutes.etqanGetIncidientRequest); }, child: Container( @@ -64,6 +76,50 @@ class _EtqanOvrHomeState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ + Row( + children: [ + Expanded( + child: Wrap( + spacing: 8, + runSpacing: 8, + children: [ + if (data.status != null && data.status!.isNotEmpty) + Container( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: _getStatusColor(data.status ?? "").withOpacity(0.1), + borderRadius: BorderRadius.circular(6), + border: Border.all(color: _getStatusColor(data.status ?? "").withOpacity(0.3), width: 1), + ), + child: (AppState().isArabic(context) ? (data.statusAr ?? "") : (data.status ?? "")).toText11( + color: _getStatusColor(data.status ?? ""), + isBold: true, + ), + ), + if (data.isAnonymous == true) + Container( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: MyColors.grey70Color.withOpacity(0.15), + borderRadius: BorderRadius.circular(6), + border: Border.all(color: MyColors.grey70Color.withOpacity(0.3), width: 1), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(Icons.visibility_off, size: 12, color: MyColors.grey70Color), + const SizedBox(width: 4), + (AppState().isArabic(context) ? "مجهول" : "Anonymous").toText11(color: MyColors.grey70Color, isBold: true), + ], + ), + ), + ], + ), + ), + const SizedBox(width: 8), + ], + ), + 8.height, Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -72,11 +128,12 @@ class _EtqanOvrHomeState extends State { ], ), 8.height, + Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [(data.description ?? "").toText12(color: MyColors.grey57Color).expanded]), + 3.height, Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.end, children: [ - (data.description ?? "").toText12(color: MyColors.grey57Color).expanded, - const SizedBox(width: 5,), RotatedBox( quarterTurns: AppState().isArabic(context) ? 2 : 0, child: SvgPicture.asset("assets/images/arrow_next.svg", color: MyColors.grey70Color, width: 16, height: 16), diff --git a/lib/ui/etqan_ovr/etqan_request_detailed.dart b/lib/ui/etqan_ovr/etqan_request_detailed.dart index 6f9aebc..41d11c6 100644 --- a/lib/ui/etqan_ovr/etqan_request_detailed.dart +++ b/lib/ui/etqan_ovr/etqan_request_detailed.dart @@ -4,6 +4,7 @@ import 'dart:typed_data'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; +import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; import 'package:mohem_flutter_app/extensions/int_extensions.dart'; import 'package:mohem_flutter_app/extensions/string_extensions.dart'; @@ -25,9 +26,21 @@ class EtqanOvrRequestDetailed extends StatefulWidget { } class _EtqanOvrRequestDetailedState extends State { - List get fieldOrder => ['Project', 'Created', 'Occurrence Time', 'OVR Reference No', 'Involved Employee Number', 'Description']; - - List get hiddenFields => ['OVR Id', 'Is Anonymous']; + List get fieldOrder => ['Status', 'Project', 'Created', 'Is Anonymous', 'Occurrence Time', 'OVR Reference No', 'Involved Employee Number', 'Description']; + + List get hiddenFields => ['OVR Id']; + + Color _getStatusColor(String status) { + String statusLower = status.toLowerCase(); + if (statusLower.contains('open') || statusLower.contains('مفتوح')) { + return const Color(0xff2196F3); // Blue for open + } else if (statusLower.contains('progress') || statusLower.contains('قيد التنفيذ')) { + return const Color(0xffFF9800); // Orange for in progress + } else if (statusLower.contains('closed') || statusLower.contains('مغلق')) { + return const Color(0xff4CAF50); // Green for closed + } + return MyColors.grey70Color; // Default gray + } Future _viewAttachment(BuildContext context, String base64Data) async { try { @@ -47,15 +60,33 @@ class _EtqanOvrRequestDetailedState extends State { } } - List _getOrderedList(List list) { + List _getOrderedList(List list, EtqanOvrProviderModel provider) { List orderedList = []; List filteredList = list.where((EtqanGetIncidentRequestResponse item) => !hiddenFields.any((f) => f.toLowerCase() == item.key?.toLowerCase())).toList(); for (String fieldName in fieldOrder) { - var item = filteredList.firstWhere((e) => e.key?.toLowerCase() == fieldName.toLowerCase(), orElse: () => EtqanGetIncidentRequestResponse()); - if (item.key != null) { - orderedList.add(item); + // Check if this is Status or Is Anonymous - inject from provider + if (fieldName.toLowerCase() == 'status' && provider.getCurrentStatus.isNotEmpty) { + orderedList.add(EtqanGetIncidentRequestResponse( + key: 'Status', + keyAr: 'الحالة', + value: provider.getCurrentStatus, + valueAr: provider.getCurrentStatusAr.isNotEmpty ? provider.getCurrentStatusAr : provider.getCurrentStatus, + )); + } else if (fieldName.toLowerCase() == 'is anonymous') { + orderedList.add(EtqanGetIncidentRequestResponse( + key: 'Is Anonymous', + keyAr: 'مجهول', + value: provider.getCurrentIsAnonymous.toString(), + valueAr: provider.getCurrentIsAnonymous.toString(), + )); + } else { + // Regular field from API + var item = filteredList.firstWhere((e) => e.key?.toLowerCase() == fieldName.toLowerCase(), orElse: () => EtqanGetIncidentRequestResponse()); + if (item.key != null) { + orderedList.add(item); + } } } @@ -88,7 +119,7 @@ class _EtqanOvrRequestDetailedState extends State { return Utils.getNoDataWidget(context); } - List orderedList = _getOrderedList(provider.getEtqanEmployeeIncidnetRequest!); + List orderedList = _getOrderedList(provider.getEtqanEmployeeIncidnetRequest!, provider); return SingleChildScrollView( physics: const BouncingScrollPhysics(), @@ -108,6 +139,8 @@ class _EtqanOvrRequestDetailedState extends State { EtqanGetIncidentRequestResponse data = entry.value; bool isLast = index == orderedList.length - 1; bool isAttachment = data.key?.toLowerCase() == 'attachment'; + bool isStatus = data.key?.toLowerCase() == 'status'; + bool isAnonymous = data.key?.toLowerCase() == 'is anonymous'; String displayKey = context.locale.languageCode == "ar" ? (data.keyAr ?? data.key ?? "") : (data.key ?? ""); String displayValue = context.locale.languageCode == "ar" ? (data.valueAr ?? data.value ?? "") : (data.value ?? ""); @@ -125,58 +158,65 @@ class _EtqanOvrRequestDetailedState extends State { 8.width, Expanded( flex: 3, - child: - isAttachment && hasSubValues - ? Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: - data.subValues!.asMap().entries.map((entry) { - int subIndex = entry.key; - String base64Data = entry.value; - return Padding( - padding: EdgeInsets.only(bottom: subIndex < data.subValues!.length - 1 ? 8.0 : 0), - child: GestureDetector( - onTap: () => _viewAttachment(context, base64Data), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: context.locale.languageCode == "ar" ? MainAxisAlignment.end : MainAxisAlignment.start, - children: [ - Text( - data.subValues!.length > 1 ? '${LocaleKeys.viewAttachment.tr()} ${subIndex + 1}' : LocaleKeys.viewAttachment.tr(), - // textAlign: context.locale.languageCode == "ar" ? TextAlign.start : TextAlign.start, - style: const TextStyle( - fontSize: 14, - color: MyColors.green9CColor, - decoration: TextDecoration.underline, - decorationColor: MyColors.green9CColor, + child: isStatus + ? displayValue.toText14( + color: _getStatusColor(displayValue), + isBold: true, + ) + : isAnonymous + ? (displayValue.toLowerCase() == 'true' || displayValue.toLowerCase() == 'yes' || displayValue == '1' + ? (context.locale.languageCode == "ar" ? "نعم" : "Yes") + : (context.locale.languageCode == "ar" ? "لا" : "No") + ).toText14(color: MyColors.darkTextColor) + : isAttachment && hasSubValues + ? Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: data.subValues!.asMap().entries.map((entry) { + int subIndex = entry.key; + String base64Data = entry.value; + return Padding( + padding: EdgeInsets.only(bottom: subIndex < data.subValues!.length - 1 ? 8.0 : 0), + child: GestureDetector( + onTap: () => _viewAttachment(context, base64Data), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: context.locale.languageCode == "ar" ? MainAxisAlignment.end : MainAxisAlignment.start, + children: [ + Text( + data.subValues!.length > 1 ? '${LocaleKeys.viewAttachment.tr()} ${subIndex + 1}' : LocaleKeys.viewAttachment.tr(), + style: const TextStyle( + fontSize: 14, + color: MyColors.green9CColor, + decoration: TextDecoration.underline, + decorationColor: MyColors.green9CColor, + ), ), - ), - ], - ), - ), - ); - }).toList(), - ) - : hasSubValues - ? Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (displayValue.isNotEmpty) displayValue.toText14(color: MyColors.darkTextColor), - if (displayValue.isNotEmpty) 8.height, - ...data.subValues! - .map( - (subValue) => Padding( - padding: const EdgeInsets.only(bottom: 4), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [const Text("• ", style: TextStyle(fontSize: 14)), Expanded(child: subValue.toText14(color: MyColors.darkTextColor))], + ], + ), ), - ), - ) - .toList(), - ], - ) - : (displayValue.isNotEmpty ? displayValue : "-").toText14(color: MyColors.darkTextColor), + ); + }).toList(), + ) + : hasSubValues + ? Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (displayValue.isNotEmpty) displayValue.toText14(color: MyColors.darkTextColor), + if (displayValue.isNotEmpty) 8.height, + ...data.subValues! + .map( + (subValue) => Padding( + padding: const EdgeInsets.only(bottom: 4), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [const Text("• ", style: TextStyle(fontSize: 14)), Expanded(child: subValue.toText14(color: MyColors.darkTextColor))], + ), + ), + ) + .toList(), + ], + ) + : (displayValue.isNotEmpty ? displayValue : "-").toText14(color: MyColors.darkTextColor), ), ], ), -- 2.30.2 From eb3eb1d10275762096c32cbb1c1b67aa6ce16fe5 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Sun, 15 Mar 2026 12:34:04 +0300 Subject: [PATCH 130/135] updates --- lib/classes/consts.dart | 9 +++++---- lib/ui/landing/dashboard_screen.dart | 3 ++- lib/ui/landing/widget/menus_widget.dart | 27 ++++++++++++++++++++++++- 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 2f60326..88ebf73 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -4,13 +4,14 @@ class ApiConsts { // static String baseUrl = "http://10.200.204.11"; // Local server // static String baseUrl = "https://erptstapp.srca.org.sa"; // SRCA server - static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver + // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.201.204.101:2024"; // static String baseUrl = "https://webservices.hmg.com"; // PreProd // static String baseUrl = "https://hmgwebservices.com"; // Live server - // static String baseUrl = "https://mohemm.hmg.com"; // New Live server + static String baseUrl = "https://mohemm.hmg.com"; // New Live server // + // static String baseUrl = "http://10.20.200.111:1010/"; // static String baseUrl = "https://webservices.hmg.com"; // PreProd @@ -26,8 +27,8 @@ class ApiConsts { static String user = baseUrlServices + "api/User/"; static String cocRest = baseUrlServices + "COCWS.svc/REST/"; - // static String ssoAuthRedirection = "https://sso-uat.hmg.com/api/auth/connect"; // UAT - static String ssoAuthRedirection = "https://sso.hmg.com/api/auth/connect"; // Prod + static String ssoAuthRedirection = "https://sso-uat.hmg.com/api/auth/connect"; // UAT + // static String ssoAuthRedirection = "https://sso.hmg.com/api/auth/connect"; // Prod //Chat static String chatServerBaseUrl = "https://apiderichat.hmg.com/"; diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index 3122d17..deb3131 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -167,8 +167,9 @@ class _DashboardScreenState extends State with WidgetsBindingOb // await data.fetchTicketBooking(); // if (data.ticketBookingResponse != null && !data.ticketBookingResponse!.success) { - // // data.fetchTicketBalance(); + // data.fetchTicketBalance(); // } + //continue here } diff --git a/lib/ui/landing/widget/menus_widget.dart b/lib/ui/landing/widget/menus_widget.dart index bc5dceb..e764dca 100644 --- a/lib/ui/landing/widget/menus_widget.dart +++ b/lib/ui/landing/widget/menus_widget.dart @@ -1,13 +1,17 @@ import 'package:easy_localization/src/public_ext.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:mohem_flutter_app/api/eit_api_client.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; +import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/config/routes.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/sso_auth_model.dart'; import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; import 'package:mohem_flutter_app/ui/my_attendance/dynamic_screens/dynamic_listview_screen.dart'; +import 'package:mohem_flutter_app/ui/screens/ticket/ticket_detailed_screen.dart'; import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart'; import 'package:provider/provider.dart'; @@ -117,8 +121,29 @@ class MenusWidget extends StatelessWidget { ), ], ).paddingOnly(left: 10, right: 10, bottom: 6, top: 6), - ).onPress(() { + ).onPress(() async { Navigator.pushNamed(context, AppRoutes.dynamicScreen, arguments: DynamicListViewParams(LocaleKeys.ticketBalance.tr(), "HMG_TKT_NEW_EIT_SS")); + + // var pro = Provider.of(context, listen: false); + // + // // if (menuEntry.menuName == "HMG_TICKET_REQUESTS") { + // Utils.showLoading(context); + // //Ticket Work + // if (pro.ticketBookingResponse != null && pro.ticketBookingResponse!.success) { + // SSOAuthModel? ssoToken = await pro.fetchSSOAuthRedirection(clientID: pro.ticketBookingResponse!.clientId); + // if (ssoToken != null) { + // dynamic url = await pro.fetchURLRedirection(token: ssoToken.data!.accessToken!); + // await pro.fetchTicketAccuralBalance(context, DateTime.now()); + // pro.ticketHistoryTransactionList = await EITApiClient().getEITTransactions("HMG_TICKET_ITENARY_HR_EIT_SS", isCompleteList: true); + // + // Utils.hideLoading(context); + // // Here Need Work + // Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => TicketDetailedScreen(url: url, jwtToken: ssoToken.data!.accessToken))); + // } + // //} + // } else { + // Navigator.pushNamed(context, AppRoutes.dynamicScreen, arguments: DynamicListViewParams(LocaleKeys.ticketBalance.tr(), "HMG_TKT_NEW_EIT_SS")); + // } }), ], ); -- 2.30.2 From 3343e4fe109494b60fe436fa1135ae5bf9c5095d Mon Sep 17 00:00:00 2001 From: Sultan khan Date: Sun, 15 Mar 2026 12:46:43 +0300 Subject: [PATCH 131/135] sso and courses in app browser updated --- .../dashboard/courses_response_model.dart | 5 +- .../itg/its_add_screen_video_image.dart | 19 ++++++- lib/ui/screens/courses/courses_screen.dart | 55 ++++++++++--------- lib/widgets/sso_webview_widget.dart | 9 ++- 4 files changed, 57 insertions(+), 31 deletions(-) diff --git a/lib/models/dashboard/courses_response_model.dart b/lib/models/dashboard/courses_response_model.dart index 63a98fc..730d4a4 100644 --- a/lib/models/dashboard/courses_response_model.dart +++ b/lib/models/dashboard/courses_response_model.dart @@ -49,7 +49,7 @@ class CourseStatus { String? cStartdate; String? cEnddate; String? cUrl; - + String? token; CourseStatus({ this.cId, this.cFullname, @@ -60,6 +60,7 @@ class CourseStatus { this.cStartdate, this.cEnddate, this.cUrl, + this.token }); CourseStatus.fromJson(Map json) { @@ -72,6 +73,7 @@ class CourseStatus { cStartdate = json['c_startdate']; cEnddate = json['c_enddate']; cUrl = json['c_url']; + token =json['c_token']; } Map toJson() { @@ -85,6 +87,7 @@ class CourseStatus { data['c_startdate'] = cStartdate; data['c_enddate'] = cEnddate; data['c_url'] = cUrl; + data['c_token'] = token; return data; } } 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 ab0d39f..23bfc66 100644 --- a/lib/ui/landing/itg/its_add_screen_video_image.dart +++ b/lib/ui/landing/itg/its_add_screen_video_image.dart @@ -6,14 +6,19 @@ 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'; +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/main.dart'; +import 'package:mohem_flutter_app/models/dashboard/menu_entries.dart'; import 'package:mohem_flutter_app/models/itg/advertisement.dart' as ads; +import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; +import 'package:mohem_flutter_app/ui/my_attendance/services_menu_list_screen.dart'; import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; import 'package:mohem_flutter_app/widgets/button/default_button.dart'; import 'package:mohem_flutter_app/widgets/my_video_progress_indicator.dart'; +import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:video_player/video_player.dart'; @@ -396,8 +401,18 @@ class _ITGAdsScreenState extends State { Navigator.pop(context); } else if (advertisementData!.actionButtonsColl![index].actionType!.toLowerCase() == 'redirect' && advertisementData!.actionButtonsColl![index].actionValue!.toLowerCase() == 'internal') { - await Navigator.pushNamed(context, advertisementData!.actionButtonsColl![index].url!); - } else { + + await Navigator.pushNamed(context, advertisementData!.actionButtonsColl![index].url!); + + } else if(advertisementData!.actionButtonsColl![index].actionType!.toLowerCase() == 'eit' && advertisementData!.actionButtonsColl![index].actionValue!.toLowerCase() == + 'internal'){ + var pro = Provider.of(context, listen: false); + List _menuList = + pro.getMenuEntriesList?.where((element) => element.parentMenuName == advertisementData!.actionButtonsColl![index].url && (element.menuEntryType == "FUNCTION" || element.menuEntryType == "MENU")).toList() ?? []; + Navigator.pushNamed(context, AppRoutes.servicesMenuListScreen, arguments: ServicesMenuListScreenParams(advertisementData!.advertisementTitle!, _menuList)); + + } + else{ Uri uri = Uri.parse(advertisementData!.actionButtonsColl![index].iconOrImage); // if (await canLaunchUrl(uri)) { await launchUrl(uri, mode: LaunchMode.externalApplication).catchError((err) { diff --git a/lib/ui/screens/courses/courses_screen.dart b/lib/ui/screens/courses/courses_screen.dart index 7c995a2..598b6cf 100644 --- a/lib/ui/screens/courses/courses_screen.dart +++ b/lib/ui/screens/courses/courses_screen.dart @@ -14,6 +14,7 @@ import 'package:mohem_flutter_app/models/dashboard/courses_response_model.dart'; import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; import 'package:mohem_flutter_app/theme/colors.dart' as theme_colors; import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; +import 'package:mohem_flutter_app/widgets/sso_webview_widget.dart'; import 'package:provider/provider.dart'; import 'package:pull_to_refresh/pull_to_refresh.dart'; @@ -148,7 +149,7 @@ class _CoursesScreenState extends State { Color statusColor = _getStatusColor(status); return InkWell( - onTap: () => _openCourse(course.cUrl ?? ''), + onTap: () => _openCourse(course.cUrl, course.token), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -291,33 +292,37 @@ class _CoursesScreenState extends State { return format.format(dateTime); } - void _openCourse(String url) { - if (url.isEmpty) { - Utils.showToast(LocaleKeys.courseUrlNotAvailable.tr()); - return; - } + void _openCourse(String? url, String? jwtToken) { - MyInAppBrowser browser = MyInAppBrowser( - onExitCallback: () {}, - onLoadStartCallback: (String url) {}, - ); - var settings = InAppBrowserClassSettings( - webViewSettings: InAppWebViewSettings( - useShouldOverrideUrlLoading: false, - transparentBackground: false, - ), - browserSettings: InAppBrowserSettings( - hideUrlBar: true, - hideTitleBar: false, - toolbarTopBackgroundColor: theme_colors.primaryColor, - ), - ); + Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => SsoLoginWebView(url: url, jwtToken: jwtToken))); + //Utils.showToast(LocaleKeys.courseUrlNotAvailable.tr()); - browser.openUrlRequest( - urlRequest: URLRequest(url: WebUri(url)), - settings: settings, - ); + + // return; + // } + // + // MyInAppBrowser browser = MyInAppBrowser( + // onExitCallback: () {}, + // onLoadStartCallback: (String url) {}, + // ); + // + // var settings = InAppBrowserClassSettings( + // webViewSettings: InAppWebViewSettings( + // useShouldOverrideUrlLoading: false, + // transparentBackground: false, + // ), + // browserSettings: InAppBrowserSettings( + // hideUrlBar: true, + // hideTitleBar: false, + // toolbarTopBackgroundColor: theme_colors.primaryColor, + // ), + // ); + // + // browser.openUrlRequest( + // urlRequest: URLRequest(url: WebUri(url)), + // settings: settings, + // ); } @override diff --git a/lib/widgets/sso_webview_widget.dart b/lib/widgets/sso_webview_widget.dart index 5877a63..ee4ed7a 100644 --- a/lib/widgets/sso_webview_widget.dart +++ b/lib/widgets/sso_webview_widget.dart @@ -15,10 +15,13 @@ class SsoLoginWebView extends StatefulWidget { class _SsoLoginWebViewState extends State { late final WebViewController _controller; - + String? url; @override void initState() { // TODO: implement initState + + url = widget.url ?? "https://Paxes-release.techmaster.in/SSO/HMG"; + super.initState(); _controller = WebViewController() @@ -46,7 +49,7 @@ class _SsoLoginWebViewState extends State { -
+

Redirecting...

@@ -56,6 +59,6 @@ class _SsoLoginWebViewState extends State { @override Widget build(BuildContext context) { - return Scaffold(appBar: AppBar(title: Text('Logging in...')), body: WebViewWidget(controller: _controller)); + return Scaffold(appBar: null, body:SafeArea(child: WebViewWidget(controller: _controller))); } } -- 2.30.2 From bdaccf133c2273324b5f5c398ebc2712658e9dfd Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Sun, 15 Mar 2026 16:04:06 +0300 Subject: [PATCH 132/135] updates --- assets/images/eid_banner.svg | 606 +++++++++++++++++++++ lib/provider/dashboard_provider_model.dart | 2 +- lib/ui/landing/dashboard_screen.dart | 6 +- 3 files changed, 610 insertions(+), 4 deletions(-) create mode 100644 assets/images/eid_banner.svg diff --git a/assets/images/eid_banner.svg b/assets/images/eid_banner.svg new file mode 100644 index 0000000..f8e4adb --- /dev/null +++ b/assets/images/eid_banner.svg @@ -0,0 +1,606 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/provider/dashboard_provider_model.dart b/lib/provider/dashboard_provider_model.dart index e9c6678..2b7a2bb 100644 --- a/lib/provider/dashboard_provider_model.dart +++ b/lib/provider/dashboard_provider_model.dart @@ -137,7 +137,7 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { DrawerMenuItem("assets/images/drawer/mowadhafi.svg", LocaleKeys.keen.tr(), AppRoutes.etqanOvr), // DrawerMenuItem("assets/images/drawer/car_parking_icon.svg", LocaleKeys.parkingQr.tr(), AppRoutes.parkingQr), DrawerMenuItem("assets/images/drawer/pending_trasactions.svg", LocaleKeys.pendingTransactions.tr(), AppRoutes.pendingTransactions), - DrawerMenuItem("assets/images/drawer/courses.svg", "courses".tr(), AppRoutes.courses), + // DrawerMenuItem("assets/images/drawer/courses.svg", "courses".tr(), AppRoutes.courses), // DrawerMenuItem("assets/images/drawer/drawer_marathon.svg", LocaleKeys.brainMarathon.tr(), AppRoutes.marathonIntroScreen), DrawerMenuItem("assets/images/drawer/change_password.svg", LocaleKeys.changePassword.tr(), AppRoutes.changePassword), ]; diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index 0ff22ae..eac7890 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -450,8 +450,8 @@ class _DashboardScreenState extends State with WidgetsBindingOb flipX: !AppState().isArabic(context), child: SvgPicture.network( AppState().isArabic(context) - ? (card.backgroundImageUrlAr ?? "http://meena-health-care-1.s3.eu-north-1.amazonaws.com/eid_banner.svg") - : (card.backgroundImageUrlEn ?? "http://meena-health-care-1.s3.eu-north-1.amazonaws.com/eid_banner.svg"), + ? (card.backgroundImageUrlAr ?? "https://www.hmg.com/Lists/CS_Greeting_Cards/Attachments/5/CS_Ramadan_26.jpg") + : (card.backgroundImageUrlEn ?? "https://www.hmg.com/Lists/CS_Greeting_Cards/Attachments/5/CS_Ramadan_26.jpg"), fit: BoxFit.contain, placeholderBuilder: (context) => ClipRRect(borderRadius: BorderRadius.circular(18), child: Container(height: 80, color: Colors.white).toShimmer()), ), @@ -460,7 +460,7 @@ class _DashboardScreenState extends State with WidgetsBindingOb mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ - SizedBox(width: AppState().isArabic(context) ? 10 : 40), + SizedBox(width: AppState().isArabic(context) ? 20 : 50), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, -- 2.30.2 From 057e71e3c0fc811118fdd67cd4fdfec387bb3c85 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Mon, 16 Mar 2026 01:47:39 +0300 Subject: [PATCH 133/135] Etqan fixes, Update to Stores VersionID 9.6 --- lib/app_state/app_state.dart | 2 +- lib/classes/consts.dart | 4 ++-- lib/ui/etqan_ovr/etqan_create_request.dart | 11 ++++++++--- pubspec.yaml | 2 +- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/lib/app_state/app_state.dart b/lib/app_state/app_state.dart index 799bcb5..703a8b0 100644 --- a/lib/app_state/app_state.dart +++ b/lib/app_state/app_state.dart @@ -90,7 +90,7 @@ class AppState { String get getHuaweiPushToken => _huaweiPushToken; - final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 9.5, mobileType: Platform.isAndroid ? "android" : "ios"); + final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 9.6, mobileType: Platform.isAndroid ? "android" : "ios"); void setPostParamsInitConfig() { isAuthenticated = false; diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index d8efe5d..88ebf73 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -4,12 +4,12 @@ class ApiConsts { // static String baseUrl = "http://10.200.204.11"; // Local server // static String baseUrl = "https://erptstapp.srca.org.sa"; // SRCA server - static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver + // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver // static String baseUrl = "http://10.201.204.101:2024"; // static String baseUrl = "https://webservices.hmg.com"; // PreProd // static String baseUrl = "https://hmgwebservices.com"; // Live server - // static String baseUrl = "https://mohemm.hmg.com"; // New Live server + static String baseUrl = "https://mohemm.hmg.com"; // New Live server // // static String baseUrl = "http://10.20.200.111:1010/"; diff --git a/lib/ui/etqan_ovr/etqan_create_request.dart b/lib/ui/etqan_ovr/etqan_create_request.dart index a1d64af..ba3c504 100644 --- a/lib/ui/etqan_ovr/etqan_create_request.dart +++ b/lib/ui/etqan_ovr/etqan_create_request.dart @@ -110,15 +110,20 @@ class _EtqanOvrCreateRequestState extends State { if (ticketInfo != null) { String ticketNumber = ticketInfo['ticketNumber'] ?? ''; String ticketId = ticketInfo['id'] ?? ''; - String successMessage = '${LocaleKeys.requestCreatedSuccessfully.tr()}\n\n${LocaleKeys.ticketNumber.tr()}: $ticketNumber\n${LocaleKeys.ticketId.tr()}: $ticketId'; + // String successMessage = '${LocaleKeys.requestCreatedSuccessfully.tr()}\n\n${LocaleKeys.ticketNumber.tr()}: $ticketNumber\n${LocaleKeys.ticketId.tr()}: $ticketId'; + String successMessage = '${LocaleKeys.requestCreatedSuccessfully.tr()}\n\n${LocaleKeys.ticketNumber.tr()}: $ticketNumber'; Utils.showErrorDialog( context: context, message: successMessage, onOkTapped: () { - Navigator.popAndPushNamed(context, AppRoutes.etqanOvr); + Navigator.pop(context); + Navigator.pop(context); + // Navigator.popAndPushNamed(context, AppRoutes.etqanOvr); }, onCloseTap: () { - Navigator.popAndPushNamed(context, AppRoutes.etqanOvr); + Navigator.pop(context); + Navigator.pop(context); + // Navigator.popAndPushNamed(context, AppRoutes.etqanOvr); }, ); } diff --git a/pubspec.yaml b/pubspec.yaml index 49dec60..7e5a29a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 3.7.1+300081 +version: 3.7.2+300082 #version: 3.9.3+1 environment: -- 2.30.2 From 3391cf49ef304d3e5b6e6b7e5743a58f82197634 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Mon, 16 Mar 2026 14:56:04 +0300 Subject: [PATCH 134/135] updates --- lib/ui/landing/dashboard_screen.dart | 89 ++++------------------------ 1 file changed, 13 insertions(+), 76 deletions(-) diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index eac7890..793712c 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -431,86 +431,24 @@ class _DashboardScreenState extends State with WidgetsBindingOb return const GreetingCardShimmer(); } else if (model.isDisplayEidGreetings && model.greetingCardsList != null && model.greetingCardsList!.isNotEmpty) { return SizedBox( - height: 120, + height: 140, child: ListView.separated( shrinkWrap: true, scrollDirection: Axis.horizontal, - padding: const EdgeInsets.symmetric(horizontal: 21), + padding: const EdgeInsets.symmetric(horizontal: 24), itemCount: model.greetingCardsList!.length, - separatorBuilder: (context, index) => const SizedBox(width: 12), + separatorBuilder: (context, index) => const SizedBox(width: 24), itemBuilder: (context, index) { var card = model.greetingCardsList![index]; - return SizedBox( - width: MediaQuery.of(context).size.width - 42, - child: Directionality( - textDirection: AppState().isArabic(context) ? ui.TextDirection.rtl : ui.TextDirection.ltr, - child: Stack( - children: [ - Transform.flip( - flipX: !AppState().isArabic(context), - child: SvgPicture.network( - AppState().isArabic(context) - ? (card.backgroundImageUrlAr ?? "https://www.hmg.com/Lists/CS_Greeting_Cards/Attachments/5/CS_Ramadan_26.jpg") - : (card.backgroundImageUrlEn ?? "https://www.hmg.com/Lists/CS_Greeting_Cards/Attachments/5/CS_Ramadan_26.jpg"), - fit: BoxFit.contain, - placeholderBuilder: (context) => ClipRRect(borderRadius: BorderRadius.circular(18), child: Container(height: 80, color: Colors.white).toShimmer()), - ), - ), - Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox(width: AppState().isArabic(context) ? 20 : 50), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - AppState().isArabic(context) ? card.titleAr ?? '' : card.titleEn ?? '', - style: TextStyle( - fontSize: AppState().isArabic(context) ? 20 : 18, - letterSpacing: -0.2, - fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins', - fontWeight: FontWeight.w700, - height: 24 / 16, - color: const Color(0xFF3B3E4F), - ), - ), - const SizedBox(height: 4), - Text( - AppState().isArabic(context) ? card.descriptionAr ?? '' : card.descriptionEn ?? '', - style: TextStyle( - fontSize: AppState().isArabic(context) ? 16 : 14, - letterSpacing: -0.2, - fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins', - fontWeight: FontWeight.w500, - color: const Color(0xFF3B3E4F), - ), - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - ], - ), - ), - Column( - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisAlignment: MainAxisAlignment.end, - children: [ - (AppState().isArabic(context) - ? card.buttonTextN!.toText12(isUnderLine: true, color: const Color(0xFF3B3D4A)) - : card.buttonText!.toText12(isUnderLine: true, color: const Color(0xFF3B3D4A))) - .onPress(() { - launchUrl(Uri.parse(AppState().isArabic(context) ? card.urlAr! : card.urlEn!)); - }), - ], - ).paddingOnly(bottom: 10, right: 15, left: 15), - ], - ).paddingOnly(left: AppState().isArabic(context) ? 10 : 36, right: AppState().isArabic(context) ? 66 : 10, top: 6, bottom: 40), - ], - ), - ), - ); + return SvgPicture.network( + AppState().isArabic(context) + ? (card.backgroundImageUrlAr ?? "https://www.hmg.com/Lists/CS_Greeting_Cards/Attachments/5/CS_Ramadan_26.jpg") + : (card.backgroundImageUrlEn ?? "https://www.hmg.com/Lists/CS_Greeting_Cards/Attachments/5/CS_Ramadan_26.jpg"), + fit: BoxFit.fill, + placeholderBuilder: (context) => ClipRRect(borderRadius: BorderRadius.circular(18), child: Container(height: 80, color: Colors.white).toShimmer()), + ).onPress(() { + launchUrl(Uri.parse(AppState().isArabic(context) ? card.urlAr! : card.urlEn!)); + }); }, ), ).paddingOnly(bottom: 0); @@ -518,8 +456,7 @@ class _DashboardScreenState extends State with WidgetsBindingOb return const SizedBox(); } }, - ), - + ).paddingOnly(bottom: 24), // eventActivityWidget(context), if (isDisplayMazaya) ...[ Column( -- 2.30.2 From 5ad012d60245501c702ec4ef2e4912c53e2a9e69 Mon Sep 17 00:00:00 2001 From: Haroon Amjad <> Date: Thu, 19 Mar 2026 17:09:37 -0400 Subject: [PATCH 135/135] Banner updates, VersionID 9.7 sent to stores --- assets/images/EID_ARABIC_3.svg | 9 +++++++++ assets/images/EID_Englsih_04.svg | 4 ++++ assets/images/asddasd.svg | 14 ++++++++++++++ lib/app_state/app_state.dart | 2 +- lib/ui/landing/dashboard_screen.dart | 4 ++-- 5 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 assets/images/EID_ARABIC_3.svg create mode 100644 assets/images/EID_Englsih_04.svg create mode 100644 assets/images/asddasd.svg diff --git a/assets/images/EID_ARABIC_3.svg b/assets/images/EID_ARABIC_3.svg new file mode 100644 index 0000000..483a836 --- /dev/null +++ b/assets/images/EID_ARABIC_3.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/assets/images/EID_Englsih_04.svg b/assets/images/EID_Englsih_04.svg new file mode 100644 index 0000000..c2a75b5 --- /dev/null +++ b/assets/images/EID_Englsih_04.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/assets/images/asddasd.svg b/assets/images/asddasd.svg new file mode 100644 index 0000000..b91a675 --- /dev/null +++ b/assets/images/asddasd.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/lib/app_state/app_state.dart b/lib/app_state/app_state.dart index 703a8b0..5ce6861 100644 --- a/lib/app_state/app_state.dart +++ b/lib/app_state/app_state.dart @@ -90,7 +90,7 @@ class AppState { String get getHuaweiPushToken => _huaweiPushToken; - final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 9.6, mobileType: Platform.isAndroid ? "android" : "ios"); + final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 9.7, mobileType: Platform.isAndroid ? "android" : "ios"); void setPostParamsInitConfig() { isAuthenticated = false; diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index 793712c..a89c7f6 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -435,7 +435,7 @@ class _DashboardScreenState extends State with WidgetsBindingOb child: ListView.separated( shrinkWrap: true, scrollDirection: Axis.horizontal, - padding: const EdgeInsets.symmetric(horizontal: 24), + padding: const EdgeInsets.symmetric(horizontal: 0), itemCount: model.greetingCardsList!.length, separatorBuilder: (context, index) => const SizedBox(width: 24), itemBuilder: (context, index) { @@ -444,7 +444,7 @@ class _DashboardScreenState extends State with WidgetsBindingOb AppState().isArabic(context) ? (card.backgroundImageUrlAr ?? "https://www.hmg.com/Lists/CS_Greeting_Cards/Attachments/5/CS_Ramadan_26.jpg") : (card.backgroundImageUrlEn ?? "https://www.hmg.com/Lists/CS_Greeting_Cards/Attachments/5/CS_Ramadan_26.jpg"), - fit: BoxFit.fill, + fit: BoxFit.contain, placeholderBuilder: (context) => ClipRRect(borderRadius: BorderRadius.circular(18), child: Container(height: 80, color: Colors.white).toShimmer()), ).onPress(() { launchUrl(Uri.parse(AppState().isArabic(context) ? card.urlAr! : card.urlEn!)); -- 2.30.2

&C>(~AQ#-g6;6%8YtLe4k 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⪻AfjL%Et4`4%2VK;lSz@0{f#z?HF@pF( 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%0DJ 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 b`hadV4#7-Ub{h=ff*{SSdTKdWF#i7oPL9RD literal 0 HcmV?d00001 diff --git a/AppIcons/Assets.xcassets/AppIcon.appiconset/114.png b/AppIcons/Assets.xcassets/AppIcon.appiconset/114.png new file mode 100644 index 0000000000000000000000000000000000000000..ba1ac90b0e9699d2b591c0b938742c344dce78dc GIT binary patch literal 6676 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 literal 0 HcmV?d00001 diff --git a/AppIcons/Assets.xcassets/AppIcon.appiconset/120.png b/AppIcons/Assets.xcassets/AppIcon.appiconset/120.png new file mode 100644 index 0000000000000000000000000000000000000000..3adedb4f112312c8ade72b1bccc0d3b3db8d750a GIT binary patch literal 7122 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 Ds<6;G literal 0 HcmV?d00001 diff --git a/AppIcons/Assets.xcassets/AppIcon.appiconset/144.png b/AppIcons/Assets.xcassets/AppIcon.appiconset/144.png new file mode 100644 index 0000000000000000000000000000000000000000..2dd8969ab54c48f14d1a452d75a82029220a4e34 GIT binary patch literal 9016 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 literal 0 HcmV?d00001 diff --git a/AppIcons/Assets.xcassets/AppIcon.appiconset/152.png b/AppIcons/Assets.xcassets/AppIcon.appiconset/152.png new file mode 100644 index 0000000000000000000000000000000000000000..3e1f94eb69ffc2bdacde4d62a578bb1ab78ad014 GIT binary patch literal 9641 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 N8#z_kN@--s{{bc=FB|{> literal 0 HcmV?d00001 diff --git a/AppIcons/Assets.xcassets/AppIcon.appiconset/167.png b/AppIcons/Assets.xcassets/AppIcon.appiconset/167.png new file mode 100644 index 0000000000000000000000000000000000000000..7ee129e02a05ba5c47f4f9640af228c3bdb42439 GIT binary patch literal 10681 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 ZX#I_|{o-QdNpb-I%JN{jpRylA{tsA@;++5h literal 0 HcmV?d00001 diff --git a/AppIcons/Assets.xcassets/AppIcon.appiconset/180.png b/AppIcons/Assets.xcassets/AppIcon.appiconset/180.png new file mode 100644 index 0000000000000000000000000000000000000000..ad74bdcc11ad3d973ae174b0dcee6a58195a1f46 GIT binary patch literal 11974 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 Q5ljbYsOqTHDp^JR4`SN4d;kCd literal 0 HcmV?d00001 diff --git a/AppIcons/Assets.xcassets/AppIcon.appiconset/20.png b/AppIcons/Assets.xcassets/AppIcon.appiconset/20.png new file mode 100644 index 0000000000000000000000000000000000000000..1d84d69b6040a3b25762541727aa153780275837 GIT binary patch literal 859 zcmV-h1ElPx&6-h)vR5(w~lub+&XBfwSGqbaUyDT%iRzWJCT58a?CTg@P29rj#1QH}d4^?T? z9yRtrNP049d+}g29+cq0k5UtZ9;$6EN(dBe8WkIAn`&4JNV7!>4Z8yFI=k~WGaF!o z%Z)=PnZrEqGr#xwKkxJYB_V`h86W9?2NVb-q7~e6 z>3rK84NQ)pYaTS0mzH}MDbxk~Hhqjs){rbqh`11Za-)wQf=|fx$(*d%#;(Fw`MkTE zuA#@Q^hg}tUQSs-3Dj@^9oM<>&b5C=Pr*XLY#hYFL_xyvu2F1`@48N5#-ai_p?^d=0)NKox$(O literal 0 HcmV?d00001 diff --git a/AppIcons/Assets.xcassets/AppIcon.appiconset/29.png b/AppIcons/Assets.xcassets/AppIcon.appiconset/29.png new file mode 100644 index 0000000000000000000000000000000000000000..c9f036216bce32c5fb9fc9fe637d4f41ff5c3922 GIT binary patch literal 1287 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 BvaSFC literal 0 HcmV?d00001 diff --git a/AppIcons/Assets.xcassets/AppIcon.appiconset/50.png b/AppIcons/Assets.xcassets/AppIcon.appiconset/50.png new file mode 100644 index 0000000000000000000000000000000000000000..01ececaa4b49c7b5c799c66851439180fa081bb0 GIT binary patch literal 2485 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 literal 0 HcmV?d00001 diff --git a/AppIcons/Assets.xcassets/AppIcon.appiconset/57.png b/AppIcons/Assets.xcassets/AppIcon.appiconset/57.png new file mode 100644 index 0000000000000000000000000000000000000000..feda4568a2b6b7b608445eb0fe406506c184cf6e GIT binary patch literal 2898 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 literal 0 HcmV?d00001 diff --git a/AppIcons/Assets.xcassets/AppIcon.appiconset/58.png b/AppIcons/Assets.xcassets/AppIcon.appiconset/58.png new file mode 100644 index 0000000000000000000000000000000000000000..0f1dd24d434899481a209452c01bc737897451d6 GIT binary patch literal 2940 zcmV-?3xo8DP)Px=Hc3Q5RA@u(SqpGf5khUp77?|Ik7=s{t(~b@ z+fHX%$G)VtGmcK{bf#nLR8U|#3Qh^w7a$=-5fl>)CM3!u4-=9Q!fqb>ynFBMod4dt zdw1Dnv8*#ub2G4koqzxTJKuM{bI!k^b5xF1fyRtLNUSU1f!qR2uw)# zb4uK($DUwxg3)ml0cz9fhaQgpaQqifx&)Hr2;PM~8FQ3AP_xfB9KdrNi(sZlvqjv9 zI>**t$YW=Vtz~-}Yb}uNzAiNNeFz>QTwX96a|~M^Z~KXbhx_(uQpc0B}I@UsgU^quAgx;ZY;Sg9tbc>!+Qwm+zl5#dJPz%6I zN80h+!B+Sq5r~`yp3@=nI<6}&z%yT6gv%y*lE7LD4=M`&c<3PN+D}2#6$l(4a4KAq zfaP<_uzJCbuoN7ZqX}{-62NO8?m^3$6VUXiu_vdaC^sLgD<43<+lvnW89e*;tC%FK zaEc1tq5_YkLg4&ZQhFz@ELxHosH*D_I1Vp2cHr?{jkv@u!YOj#p@A2SO@|_3l;(M` zVPzGj=epxyjhqC2QL_*G+fSj$_{|%@**!@SYCx3S!Ts-{r-S#3?N3rRp@8s#8|7wX&aWKAs4@xA|C(mZXE6F!6aEUlwf1iTFY2sfePUM@*8o-m5VVP3F3GAHzOPiLE@UPX4Do+AtxGd|B(gIEk^!fKr;wQU~Vp@&_Nzjoi3+%vTNCeWz9b4XsfG-rl zJ!NxodUz0rKIz0{rv#Ts)=zC&f*n$VommQCOpD^4t8YT>sd}6X`QR2sI7ERtd?HX9 zM216!u17Jis0`&(uR(!(3Ow>8h&(B1^d||ZRaWXc&tm6CJ*+G=_50A=?}JC;7<>X6;H(+ZytQ%AU+!CLw{fhlO2+w3e!as`IpFf9Wj&@UJ9ouVkk0< zp5b0_h`}w9B#m4*9GLbuWK8mxc^)&pv#_%4JIqN(>)A54fK+b&b-Wu-?QcX>jlm(p zVAga|D+ft#foK@_%)0_VzWzEE+M!4UTbn6d*cABsc}a61hWJ*sDyEI$z^zYSru!;MBbPtUOI9JJ6b+Sa^l2i8090R1hHn} zH*nphW$ds5$0MRf@#1@1&^OY{jE(@=-PlM2BlqvC_yG#sMV}6+UFlTiVrGr}`QCbL zZ#{*4mjtA^u?4iMbOr-z)JNkXCH(N;TbZ-kRxff9HDr_Oa? zL;V)GL#X97>FZut0(m_eSJUG1Bb{dcU=YRneh67r)j^r1NMnFJ+ zYXYT#z{>kSy}J*!Z7rDWkk4~e#%L^vwF?tKsdN~7YxwiQ7vT#Hz#$~+YjSN?abGro zT8C}u8Nfq3YLO%HaW}Lam;qJ7s4AJ61e6X+GThX72-}apjPJ-m+plCwYwlfjcK{Dp*CI!zjI~-p#LT<*I3d`1#0Cs1&d@q7SN6Lo6+HGgIkip znLzEX%|pe#EJrWGb;ks1%ascQ`aZl)r`Z6QZ6!}-=t6;#^Cl~a0!4DZZ~i)Xvk7!{ z^*%$oDczC8>xOhoXJRx)t6LI4?R{*bj;7C1VzkrW2A3q6&5Fi`ii9diy6fO|Wr@)b z&-n0Qbq(ubt-_t;y3sI}jsoAD1TZRH9qvXvKW6#GYWH5z+9K(6dCYH-SYn>C=;MV6vz3~1NT5ZqKtZP7LIEDQqr zl+BDRBWpR^gZ2BW;gQTq$lh$&7)=NCt@ZAeOu^4~zXpGJn6-hH0HLKTModT5Bvgm4E%aYqG7OtWXbT8!2$f? zot+p6`Z38Nv-Zzu>H~Oq!ELy<*qC0drk;h!1l!Pk7`r~+0a@VTl%)8GMrL$(`J>rm z)MAI-#OgXW9c{t(mR9r!N7$x8C4^gMm*SaQZcTrSZyxwuXauh}zm224ClQH-7(>+S zKC&S}+n(08}<^2huGtm^>4h$HF!S&0000Px={YgYYRA@u(S$l94^&S80?(IEtmlqNeqaY<>BJxsjDgmu%n5ji2wLG*|Tm8$K z)@my{bvlmIsWZ;hna;G;R-rR}ik3$}p(@0I1T0FB2)Phrgpj0xye=l>-gkSuo$qh= zm)(2hVSAZDnuDE8a`)Z)eZHU1_ql?mX&U~IUcxls%be|LhA(r1G0pHa!g^(m6tRD6$BHc2F-w+8Th0DvyqCNIKBfjdY6x5|Apze zZ0XawIsU7+f}m z$yyczSbP0rD9$Z2!opNX8sLPgK@tUQY3#sLwN03v=b*H}E>X}JXuAXqN5WWMdIerv zdmG$#nH`*7B;#Y}FJSZj{ftpr(g2dANEg`QBk>4k=H%e{)$35=$!E5DrqvLM$MCBo z+t3#rK)%BTAOT5GVH1IPB7%ydd3fl?``LFL?{33u$7@iU>x9!5LynEWhLG=&uztyA zIBn^1oCKK5I1p3tjlX^XUntDj1t^B-qPQf7XmCit#b^YpW*6hPcijrRB!L(rz)!w+ z0H=C;kmr;EO+Tx_=?A1x7nep8vfMyPn_&Ii2^6!lA>_S3hpZZ4$5cUoW?GTY3ojlvM(i- z6FtMY=gkk{wu_8e9jNisI5>f@O9C!N!dO#wHD0P(#gy?yID$vtdK(cX#*`pJgGlUh zXBqdhivl7_7;_7*z_YhiBiG@gs)s)u+XHXk8F=h=2m(3FbQDvE5=8ZawYd4}_%p!s?ai z4FvG$TYH%lNrvPo&QOx$4BK!#jPjW!*u1hDF4>Nkj=YJE;q%CmZArGe!>MW{SX@7{ z><1`v7qJ>l2`nkg8}&I;LC(lVaiifbMcs8C~QH|d>?8ceFF1TfxIn8t!&mn-S#gON4 zW8H#vm|Hl{QYI;1kWKUpHwg17mVN+^-Va?-mQbCxM56LlaUHp z5)h1q@nY3#+&X6t`;M>@$Lmdvc)Rr!avdbol#FlO!zKv`$Ah@HVg>H4SjlW-i8%h% zc>)K{)Wac(Y097sZW9FtSWzRG<(Y*CmOlRFduhs+RFCz_2zFCd10LRU1Sfj>k>{|P z5*^LHde$C^hVWG7*HK+jfrOfXT_RNgFE<=U?b#OOJ4kZY?5jIXmMA1bs4BY=8yBu- zEZIce_Gs6~*!$^waNDUT&~2>_r(~vTQOxobp*{7; zl_|DUN)1b1z(_QVXI8C1b$K}wDsT4nn*GGP+o2@lta;(`TpqukNK^(00~FBLEWb{hu z`b-W~)mZib6Z0JOgS+d{)aOGU6=3FRGix)3GXUnT<0}nyIN08T0w(KZmWW{*64qS1 zY?NUu;8Q)#*zVnhT!%9$oLC+a4N1F+VT$2NmZkBc-3r*-=VM(BH33{!^pku*l1^oq z4-_wRz-+`!@1iJaRgD99hj$k|24J&u(*cvDi>3zfA$a=+kxOl7N*6_mhmzJaD=V?i zh+&d62dp!E8u?B=`Is@NXWQ`sd$Ge?lftmI8Hr++yBM3Y&G7ejA3{^#AZteS5@RMH zDog%o2v1J{xWMTcWtb-~o~756EyD&QX(dbAiyh51$hBJ~&2xa6r8h0fvZM(xlQgxR z24LO{n35i!VJl#6YXZIr8y4O;WYtShHZi{2N(mvC=*8?f_q0}5RZeKBAeB&e5W zWvOf#)@J~GcCa0P`{eJ)koQ9hy~^)E+WPQ)@|* zP6u4y(T3k0JHYl}`sim)PHcFfvXlatH!XvqFR-Oyi@Auf4iZKkrn0ng$&a&BhdJQG zT|M~WJBLw7>l@zJ8edL{#~%%+0XCO&7xA;&?fTF$+Ft5Ih_x)OzrmEWxd~OVwP7oK zp*}bzo6*|x9H3|EtODjw4`|1{apwW_2LfyxY4+4KEoBDGIyIxceDTO$czZk9xX2a@ zM&hE9Mv`U>rvT=ey1u<0huYsqz9WaVm*#wJc3K;<#V{S3@4RYS+wt7N4^iTAvPGMD zXan%dO5A&0#c1r3Ezbe1z8?ItZWlauTH(;nOP4k|izIz#+43~N{0TxJ7QohqR}oKy z*wRomIz5}9u`LLdr45U-Be~Y^4UNub~SHfdo3D0^>I<1I>7ovHA+{&Z;pL}oh_}ToKUzBxl6Eq zah5u*5<4V8ZR70*H9b6@r#Hj0!-4ImOPc6ES+hRvOZUet12!= zBJ80VJvY*~j$^;9wxk+=G>E7|&xRauvuGB@P0%|1JcXUD1cBmnxBVWKC;>8CMm zCw}gnHNcZ`%BAp`X~35P3sZT9X@;lLyO+Yfry0H!SeVK)Ofx){-n|s=JPx@Z%IT!RCr$Pnt5=PZT@(R6-4O&~K%e{8gqW&n5R;&2 znhHS>GlKe703y|pVxnpk?SXcPf`%ejDI`&X1`Ptzt7*W1XzZw}NyA40Y*z***7!!z zZt@G`Kj{W8b{)1#(m+&SC%zJgbGYRzY_F?ANa=(_Qc&W~!w<*J!<9wXWP~&zKv7MD zlp$tQ$v2g5v%N3d>*h5xy_Z8#H5H;D;z&y!-Z-=Y`8FWWCNMx2F$k*|#E&Nb9AgTn zB3-y;1;j6;S5~m2;R0$dbRi(iD00~_V?+^VjVWXMmF?#E>-6(bOEbP~Z$o#e4{nvW&J|9E@D0L6RgkfV~x7eX;U1O^M)6RGBO`r`0 z4iPp{hQp%3X`xN;#c)p<=1=(z3&Hrx@vX=Rh%0Af?RorpZ!Ma-dm%uBBvRaJut~sm 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 literal 0 HcmV?d00001 diff --git a/AppIcons/Assets.xcassets/AppIcon.appiconset/Contents.json b/AppIcons/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..65b74d7 --- /dev/null +++ b/AppIcons/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1 @@ +{"images":[{"size":"60x60","expected-size":"180","filename":"180.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"40x40","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"60x60","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"57x57","expected-size":"57","filename":"57.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"87","filename":"87.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"57x57","expected-size":"114","filename":"114.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"60","filename":"60.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"1024x1024","filename":"1024.png","expected-size":"1024","idiom":"ios-marketing","folder":"Assets.xcassets/AppIcon.appiconset/","scale":"1x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"72x72","expected-size":"72","filename":"72.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"76x76","expected-size":"152","filename":"152.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"50x50","expected-size":"100","filename":"100.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"76x76","expected-size":"76","filename":"76.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"50x50","expected-size":"50","filename":"50.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"72x72","expected-size":"144","filename":"144.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"40x40","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"83.5x83.5","expected-size":"167","filename":"167.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"20x20","expected-size":"20","filename":"20.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"}]} \ No newline at end of file diff --git a/AppIcons/appstore.png b/AppIcons/appstore.png new file mode 100644 index 0000000000000000000000000000000000000000..fffa7bfe28152a489f3edb1165d586de2ed7d1ff GIT binary patch literal 123080 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