* 'master' of http://34.17.182.140/Haroon6138/mohemm-flutter-app:
  ticket enable
  dashboard
  dashboard
  Ticket
  Ticket
  color coding changes on the monthly leave calendar and prod e-learning URL added.
  VHR-279
  VHR-279
  Alma
  Banner updates, VersionID 9.7 sent to stores
  updates
  Etqan fixes, Update to Stores VersionID 9.6
  updates
  Greeting
  Greeting Card
  Ticket Attachments
  Survey title key fix
coc-into-ensat
Sultan khan 2 weeks ago
commit 33829a2ab3

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 31 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 31 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 730 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 1.2 MiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 1.2 MiB

@ -533,7 +533,7 @@
"noWinner": "حزين! لم يفز أحد اليوم.", "noWinner": "حزين! لم يفز أحد اليوم.",
"myTeam": "فريقي", "myTeam": "فريقي",
"youCanPlayDemo": "لكن يمكنك لعب العرض", "youCanPlayDemo": "لكن يمكنك لعب العرض",
"group" : "مجموعة", "group": "مجموعة",
"searchGroup": "مجموعة البحث", "searchGroup": "مجموعة البحث",
"connectHmgWifi": "قم بتوصيل HMG WIFI", "connectHmgWifi": "قم بتوصيل HMG WIFI",
"connectedHmgWifi": "اتصال HMG WIFI", "connectedHmgWifi": "اتصال HMG WIFI",
@ -577,20 +577,20 @@
"versionStatus": "حالة الإصدار", "versionStatus": "حالة الإصدار",
"supplierNo": "رقم المورد", "supplierNo": "رقم المورد",
"general": "عام", "general": "عام",
"requesterOperatingUnit":"وحدة تشغيل مقدم الطلب", "requesterOperatingUnit": "وحدة تشغيل مقدم الطلب",
"prepareEmpNum":"إعداد رقم الموظف", "prepareEmpNum": "إعداد رقم الموظف",
"supplierInfo" : "معلومات المورد", "supplierInfo": "معلومات المورد",
"supplierAcNo": "رقم حساب المورد", "supplierAcNo": "رقم حساب المورد",
"supplierAcName": "اسم حساب المورد", "supplierAcName": "اسم حساب المورد",
"supplierIBAN" : "رقم IBAN للمورد", "supplierIBAN": "رقم IBAN للمورد",
"supplierCRNo" :"رقم السجل التجاري", "supplierCRNo": "رقم السجل التجاري",
"suppliedAcNo" : "رقم الحساب المقدم", "suppliedAcNo": "رقم الحساب المقدم",
"patientRefundInvoice" : "فاتورة استرداد الأموال للمريض", "patientRefundInvoice": "فاتورة استرداد الأموال للمريض",
"patientNumber" : "رقم المريض", "patientNumber": "رقم المريض",
"patientName" : "اسم المريض", "patientName": "اسم المريض",
"invoiceDate" : "تاريخ الفاتورة", "invoiceDate": "تاريخ الفاتورة",
"refundInvoice" :"فاتورة الاسترجاع", "refundInvoice": "فاتورة الاسترجاع",
"hospitalClinic" : "عيادة المستشفى", "hospitalClinic": "عيادة المستشفى",
"graphicalAnalysis": "التحليل الرسومي", "graphicalAnalysis": "التحليل الرسومي",
"itemHistoryAnalysis": "تحليل تاريخ العنصر", "itemHistoryAnalysis": "تحليل تاريخ العنصر",
"pOno": "امر شراء #", "pOno": "امر شراء #",
@ -616,23 +616,23 @@
"members": "الأعضاء", "members": "الأعضاء",
"searchByUserName": "البحث بواسطة اسم المستخدم", "searchByUserName": "البحث بواسطة اسم المستخدم",
"shareScreen": "مشاركة الشاشة", "shareScreen": "مشاركة الشاشة",
"start":"يبدأ", "start": "يبدأ",
"about":"عن", "about": "عن",
"explore": "يستكشف", "explore": "يستكشف",
"mazaya": "مازيا", "mazaya": "مازيا",
"benefits": "فوائد", "benefits": "فوائد",
"mazayaDesc": "اكتشف الخصومات والعروض الخاصة المتاحة للموظفين", "mazayaDesc": "اكتشف الخصومات والعروض الخاصة المتاحة للموظفين",
"viewallofferMazaya" : "أعرض كل المزايا", "viewallofferMazaya": "أعرض كل المزايا",
"buyerName": "اسم المشتري", "buyerName": "اسم المشتري",
"buyerNumber": "رقم المشتري", "buyerNumber": "رقم المشتري",
"highestBidder": "أعلى مزايد", "highestBidder": "أعلى مزايد",
"remarks": "ملاحظات", "remarks": "ملاحظات",
"faHeader": "تفاصيل رأس الصفحة FA", "faHeader": "تفاصيل رأس الصفحة FA",
"bookTypeCode": "رمز نوع الكتاب", "bookTypeCode": "رمز نوع الكتاب",
"categoryCode": "رمز الفئة", "categoryCode": "رمز الفئة",
"categoryGroup": "مجموعة الفئات", "categoryGroup": "مجموعة الفئات",
"faLINES": "تفاصيل الأصول", "faLINES": "تفاصيل الأصول",
"assetNumber": "رقم الأصول", "assetNumber": "رقم الأصول",
"assetDescription": "وصف الأصول", "assetDescription": "وصف الأصول",
"barCodeNumber": "رقم الباركود", "barCodeNumber": "رقم الباركود",
"datePlaceInService": "تاريخ وضعه في الخدمة", "datePlaceInService": "تاريخ وضعه في الخدمة",
@ -640,7 +640,7 @@
"disposedDate": "تاريخ التخلص", "disposedDate": "تاريخ التخلص",
"netBookValue": "القيمة الدفترية الصافية", "netBookValue": "القيمة الدفترية الصافية",
"purchasedPrice": "سعر الشراء", "purchasedPrice": "سعر الشراء",
"usefulLife": "العمر الإنتاجي", "usefulLife": "العمر الإنتاجي",
"yearsUsed": "سنوات الاستخدام", "yearsUsed": "سنوات الاستخدام",
"faRequest": "طلب التخلص من FA", "faRequest": "طلب التخلص من FA",
"showMore": "عرض المزيد", "showMore": "عرض المزيد",
@ -669,6 +669,7 @@
"ticketId": "معرف التذكرة", "ticketId": "معرف التذكرة",
"pleaseSelectProject": "الرجاء اختيار مشروع", "pleaseSelectProject": "الرجاء اختيار مشروع",
"viewAttachment" : "عرض المرفق", "viewAttachment" : "عرض المرفق",
"parkingQr": "وقوف السيارات QR" "parkingQr": "وقوف السيارات QR",
"startNow": "ابدأ الآن"
} }

@ -567,7 +567,7 @@
"addAtLeastOneAttachment": "Please add at least one attachment.", "addAtLeastOneAttachment": "Please add at least one attachment.",
"pleaseClickButtonToJoinMarathon": "Press the button below to join the Marathon.", "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", "requesterOperatingUnit": "Requester Operating Unit",
"generate": "Generate", "generate": "Generate",
"paymentRequest": "Pay Request", "paymentRequest": "Pay Request",
"paymentDetails": "Payment Details", "paymentDetails": "Payment Details",
@ -593,19 +593,19 @@
"versionStatus": "Version Status", "versionStatus": "Version Status",
"supplierNo": "Supplier No", "supplierNo": "Supplier No",
"general": "General", "general": "General",
"prepareEmpNum":"Prepare Employee Num", "prepareEmpNum": "Prepare Employee Num",
"supplierInfo" : "Supplier Information", "supplierInfo": "Supplier Information",
"supplierAcNo": "Supplier Account No", "supplierAcNo": "Supplier Account No",
"supplierAcName":"Supplier Account Name", "supplierAcName": "Supplier Account Name",
"supplierIBAN" : "Supplier IBAN", "supplierIBAN": "Supplier IBAN",
"supplierCRNo" : "CR Number", "supplierCRNo": "CR Number",
"suppliedAcNo" : "Supplied Account No.", "suppliedAcNo": "Supplied Account No.",
"patientRefundInvoice" : "Patient Refund Invoice", "patientRefundInvoice": "Patient Refund Invoice",
"patientNumber" : "Patient Number", "patientNumber": "Patient Number",
"patientName" : "Patient Name", "patientName": "Patient Name",
"invoiceDate" : "Invoice Date", "invoiceDate": "Invoice Date",
"refundInvoice" :"Refund Invoice", "refundInvoice": "Refund Invoice",
"hospitalClinic" : "Hospital Clinic", "hospitalClinic": "Hospital Clinic",
"graphicalAnalysis": "Graphical Analysis", "graphicalAnalysis": "Graphical Analysis",
"itemHistoryAnalysis": "Item History Analysis", "itemHistoryAnalysis": "Item History Analysis",
"pOno": "P.O #", "pOno": "P.O #",
@ -614,23 +614,23 @@
"qtyReceived": "Qty. Received", "qtyReceived": "Qty. Received",
"bonusQty": "Bonus Qty.", "bonusQty": "Bonus Qty.",
"balQty": "Bal. Qty.", "balQty": "Bal. Qty.",
"start":"Start", "start": "Start",
"about":"About", "about": "About",
"explore": "Explore", "explore": "Explore",
"mazaya": "MAZAYA", "mazaya": "MAZAYA",
"benefits": "Benefits", "benefits": "Benefits",
"mazayaDesc": "Discover special Discounts and offers available to Employees", "mazayaDesc": "Discover special Discounts and offers available to Employees",
"viewallofferMazaya" : "View All Offers", "viewallofferMazaya": "View All Offers",
"buyerName": "Buyer Name", "buyerName": "Buyer Name",
"buyerNumber": "Buyer Number", "buyerNumber": "Buyer Number",
"highestBidder": "Highest Bidder", "highestBidder": "Highest Bidder",
"remarks": "Remarks", "remarks": "Remarks",
"faHeader": "FA Header Details", "faHeader": "FA Header Details",
"bookTypeCode": "Book Type Code", "bookTypeCode": "Book Type Code",
"categoryCode": "Category Code", "categoryCode": "Category Code",
"categoryGroup": "Category Group", "categoryGroup": "Category Group",
"faLINES": "Asset Details", "faLINES": "Asset Details",
"assetNumber": "Asset Number", "assetNumber": "Asset Number",
"assetDescription": "Asset Description", "assetDescription": "Asset Description",
"barCodeNumber": "BarCode Number", "barCodeNumber": "BarCode Number",
"datePlaceInService": "Date place In Service", "datePlaceInService": "Date place In Service",
@ -638,9 +638,9 @@
"disposedDate": "Disposed Date", "disposedDate": "Disposed Date",
"netBookValue": "Net Book Value", "netBookValue": "Net Book Value",
"purchasedPrice": "Purchased Price", "purchasedPrice": "Purchased Price",
"usefulLife": "Useful Life", "usefulLife": "Useful Life",
"yearsUsed": "Years Used", "yearsUsed": "Years Used",
"faRequest":"FA Disposal Request", "faRequest": "FA Disposal Request",
"showMore": "Show More", "showMore": "Show More",
"ticketDetails": "Ticket Details", "ticketDetails": "Ticket Details",
"currentTicketBalance": "Current Ticket Balance", "currentTicketBalance": "Current Ticket Balance",
@ -667,5 +667,6 @@
"ticketId": "Ticket ID", "ticketId": "Ticket ID",
"pleaseSelectProject": "Please select a project", "pleaseSelectProject": "Please select a project",
"viewAttachment" : "View Attachment", "viewAttachment" : "View Attachment",
"parkingQr": "Parking QR" "parkingQr": "Parking QR",
"startNow": "Start Now"
} }

@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:http/http.dart'; import 'package:http/http.dart';
import 'package:http/io_client.dart'; import 'package:http/io_client.dart';
@ -18,15 +19,11 @@ class APIError {
dynamic errorCode; dynamic errorCode;
int? errorType; int? errorType;
String? errorMessage; String? errorMessage;
int? errorStatusCode; int? errorStatusCode;
APIError(this.errorCode, this.errorMessage, this.errorType, this.errorStatusCode); APIError(this.errorCode, this.errorMessage, this.errorType, this.errorStatusCode);
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {'errorCode': errorCode, 'errorMessage': errorMessage, 'errorType': errorType, 'ErrorStatusCode': errorStatusCode};
'errorCode': errorCode,
'errorMessage': errorMessage,
'errorType': errorType,
'ErrorStatusCode': errorStatusCode
};
@override @override
String toString() { String toString() {
@ -48,22 +45,22 @@ APIException _throwAPIException(Response response) {
APIError? apiError; APIError? apiError;
if (response.body != null && response.body.isNotEmpty) { if (response.body != null && response.body.isNotEmpty) {
var jsonError = jsonDecode(response.body); var jsonError = jsonDecode(response.body);
apiError = APIError(jsonError['ErrorCode'], jsonError['ErrorMessage'], jsonError['ErrorType'],jsonError['ErrorStatusCode']); apiError = APIError(jsonError['ErrorCode'], jsonError['ErrorMessage'], jsonError['ErrorType'], jsonError['ErrorStatusCode']);
} }
return APIException(APIException.BAD_REQUEST, error: apiError); return APIException(APIException.BAD_REQUEST, error: apiError);
case 401: case 401:
return APIException(APIException.UNAUTHORIZED); return const APIException(APIException.UNAUTHORIZED);
case 403: case 403:
return APIException(APIException.FORBIDDEN); return const APIException(APIException.FORBIDDEN);
case 404: case 404:
return APIException(APIException.NOT_FOUND); return const APIException(APIException.NOT_FOUND);
case 500: case 500:
return APIException(APIException.INTERNAL_SERVER_ERROR); return const APIException(APIException.INTERNAL_SERVER_ERROR);
case 444: case 444:
var downloadUrl = response.headers["location"]; var downloadUrl = response.headers["location"];
return APIException(APIException.UPGRADE_REQUIRED, arguments: downloadUrl); return APIException(APIException.UPGRADE_REQUIRED, arguments: downloadUrl);
default: default:
return APIException(APIException.OTHER); return const APIException(APIException.OTHER);
} }
} }
@ -74,8 +71,16 @@ class ApiClient {
factory ApiClient() => _instance; factory ApiClient() => _instance;
Future<U> postJsonForObject<T, U>(FactoryConstructor<U> factoryConstructor, String url, T jsonObject, Future<U> postJsonForObject<T, U>(
{String? token, Map<String, dynamic>? queryParameters, Map<String, String>? headers, int retryTimes = 0, bool isFormData = false}) async { FactoryConstructor<U> factoryConstructor,
String url,
T jsonObject, {
String? token,
Map<String, dynamic>? queryParameters,
Map<String, String>? headers,
int retryTimes = 0,
bool isFormData = false,
}) async {
var _headers = {'Accept': 'application/json'}; var _headers = {'Accept': 'application/json'};
if (headers != null && headers.isNotEmpty) { if (headers != null && headers.isNotEmpty) {
_headers.addAll(headers); _headers.addAll(headers);
@ -121,8 +126,15 @@ class ApiClient {
} }
} }
Future<Response> postJsonForResponse<T>(String url, T jsonObject, Future<Response> postJsonForResponse<T>(
{String? token, Map<String, dynamic>? queryParameters, Map<String, String>? headers, int retryTimes = 0, bool isFormData = false}) async { String url,
T jsonObject, {
String? token,
Map<String, dynamic>? queryParameters,
Map<String, String>? headers,
int retryTimes = 0,
bool isFormData = false,
}) async {
String? requestBody; String? requestBody;
late Map<String, String> stringObj; late Map<String, String> stringObj;
if (jsonObject != null) { if (jsonObject != null) {
@ -157,9 +169,9 @@ class ApiClient {
var queryString = new Uri(queryParameters: queryParameters).query; var queryString = new Uri(queryParameters: queryParameters).query;
url = url + '?' + queryString; url = url + '?' + queryString;
} }
var response = await _post(Uri.parse(url), body: requestBody, headers: _headers).timeout(Duration(seconds: 120)); var response = await _post(Uri.parse(url), body: requestBody, headers: _headers).timeout(const Duration(seconds: 120));
if (response. statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {
return response; return response;
} else { } else {
throw _throwAPIException(response); throw _throwAPIException(response);
@ -167,7 +179,7 @@ class ApiClient {
} on SocketException catch (e) { } on SocketException catch (e) {
if (retryTimes > 0) { if (retryTimes > 0) {
print('will retry after 3 seconds...'); print('will retry after 3 seconds...');
await Future.delayed(Duration(seconds: 3)); await Future.delayed(const Duration(seconds: 3));
return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1);
} else { } else {
throw APIException(APIException.OTHER, arguments: e); throw APIException(APIException.OTHER, arguments: e);
@ -175,7 +187,7 @@ class ApiClient {
} on HttpException catch (e) { } on HttpException catch (e) {
if (retryTimes > 0) { if (retryTimes > 0) {
print('will retry after 3 seconds...'); print('will retry after 3 seconds...');
await Future.delayed(Duration(seconds: 3)); await Future.delayed(const Duration(seconds: 3));
return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1);
} else { } else {
throw APIException(APIException.OTHER, arguments: e); throw APIException(APIException.OTHER, arguments: e);
@ -185,7 +197,7 @@ class ApiClient {
} on ClientException catch (e) { } on ClientException catch (e) {
if (retryTimes > 0) { if (retryTimes > 0) {
print('will retry after 3 seconds...'); print('will retry after 3 seconds...');
await Future.delayed(Duration(seconds: 3)); await Future.delayed(const Duration(seconds: 3));
return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1);
} else { } else {
throw APIException(APIException.OTHER, arguments: e); throw APIException(APIException.OTHER, arguments: e);
@ -224,7 +236,7 @@ class ApiClient {
var queryString = new Uri(queryParameters: queryParameters).query; var queryString = new Uri(queryParameters: queryParameters).query;
url = url + '?' + queryString; url = url + '?' + queryString;
} }
var response = await _get(Uri.parse(url), headers: _headers).timeout(Duration(seconds: 60)); var response = await _get(Uri.parse(url), headers: _headers).timeout(const Duration(seconds: 60));
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {
return response; return response;
@ -234,7 +246,7 @@ class ApiClient {
} on SocketException catch (e) { } on SocketException catch (e) {
if (retryTimes > 0) { if (retryTimes > 0) {
print('will retry after 3 seconds...'); print('will retry after 3 seconds...');
await Future.delayed(Duration(seconds: 3)); await Future.delayed(const Duration(seconds: 3));
return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1);
} else { } else {
throw APIException(APIException.OTHER, arguments: e); throw APIException(APIException.OTHER, arguments: e);
@ -242,7 +254,7 @@ class ApiClient {
} on HttpException catch (e) { } on HttpException catch (e) {
if (retryTimes > 0) { if (retryTimes > 0) {
print('will retry after 3 seconds...'); print('will retry after 3 seconds...');
await Future.delayed(Duration(seconds: 3)); await Future.delayed(const Duration(seconds: 3));
return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1);
} else { } else {
throw APIException(APIException.OTHER, arguments: e); throw APIException(APIException.OTHER, arguments: e);
@ -252,7 +264,7 @@ class ApiClient {
} on ClientException catch (e) { } on ClientException catch (e) {
if (retryTimes > 0) { if (retryTimes > 0) {
print('will retry after 3 seconds...'); print('will retry after 3 seconds...');
await Future.delayed(Duration(seconds: 3)); await Future.delayed(const Duration(seconds: 3));
return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1);
} else { } else {
throw APIException(APIException.OTHER, arguments: e); throw APIException(APIException.OTHER, arguments: e);

@ -15,12 +15,15 @@ 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/get_attendance_tracking_list_model.dart';
import 'package:mohem_flutter_app/models/dashboard/itg_forms_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/list_menu.dart';
import 'package:mohem_flutter_app/models/eit_attachment_ticket_model.dart';
import 'package:mohem_flutter_app/models/dashboard/courses_response_model.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/generic_response_model.dart';
import 'package:mohem_flutter_app/models/get_employee_parking_details_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_main_response.dart';
import 'package:mohem_flutter_app/models/itg/itg_response_model.dart'; import 'package:mohem_flutter_app/models/itg/itg_response_model.dart';
import 'package:mohem_flutter_app/models/sso_auth_model.dart'; import 'package:mohem_flutter_app/models/sso_auth_model.dart';
// import 'package:platform_device_id/platform_device_id.dart';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
@ -33,7 +36,7 @@ class DashboardApiClient {
Future<GetAttendanceTracking?> getAttendanceTracking() async { Future<GetAttendanceTracking?> getAttendanceTracking() async {
String url = "${ApiConsts.erpRest}GET_Attendance_Tracking"; String url = "${ApiConsts.erpRest}GET_Attendance_Tracking";
Map<String, dynamic> postParams = {}; Map<String, dynamic> postParams = <String, dynamic>{};
postParams.addAll(AppState().postParamsJson); postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject( return await ApiClient().postJsonForObject(
(json) { (json) {
@ -47,7 +50,7 @@ class DashboardApiClient {
Future<GenericResponseModel?> getOpenNotifications() async { Future<GenericResponseModel?> getOpenNotifications() async {
String url = "${ApiConsts.erpRest}GET_OPEN_NOTIFICATIONS"; String url = "${ApiConsts.erpRest}GET_OPEN_NOTIFICATIONS";
Map<String, dynamic> postParams = {}; Map<String, dynamic> postParams = <String, dynamic>{};
postParams.addAll(AppState().postParamsJson); postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject( return await ApiClient().postJsonForObject(
(json) { (json) {
@ -61,7 +64,7 @@ class DashboardApiClient {
Future<GenericResponseModel?> getCOCNotifications() async { Future<GenericResponseModel?> getCOCNotifications() async {
String url = "${ApiConsts.cocRest}Mohemm_ITG_ReviewerAdmin_Pending_Tasks"; String url = "${ApiConsts.cocRest}Mohemm_ITG_ReviewerAdmin_Pending_Tasks";
Map<String, dynamic> postParams = {"Date": DateUtil.getISODateFormat(DateTime.now()), "EmployeeNumber": AppState().memberInformationList?.eMPLOYEENUMBER}; Map<String, dynamic> postParams = <String, dynamic>{"Date": DateUtil.getISODateFormat(DateTime.now()), "EmployeeNumber": AppState().memberInformationList?.eMPLOYEENUMBER};
postParams.addAll(AppState().postParamsJson); postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject( return await ApiClient().postJsonForObject(
(json) { (json) {
@ -75,7 +78,7 @@ class DashboardApiClient {
Future<ItgFormsModel?> getItgFormsPendingTask() async { Future<ItgFormsModel?> getItgFormsPendingTask() async {
String url = "${ApiConsts.cocRest}ITGFormsPendingTasks"; String url = "${ApiConsts.cocRest}ITGFormsPendingTasks";
Map<String, dynamic> postParams = {}; Map<String, dynamic> postParams = <String, dynamic>{};
postParams.addAll(AppState().postParamsJson); postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject( return await ApiClient().postJsonForObject(
(json) { (json) {
@ -89,13 +92,13 @@ class DashboardApiClient {
Future<List<GetAccrualBalancesList>> getAccrualBalances(String effectiveDate, {String? empID}) async { Future<List<GetAccrualBalancesList>> getAccrualBalances(String effectiveDate, {String? empID}) async {
String url = "${ApiConsts.erpRest}GET_ACCRUAL_BALANCES"; String url = "${ApiConsts.erpRest}GET_ACCRUAL_BALANCES";
Map<String, dynamic> postParams = {"P_EFFECTIVE_DATE": effectiveDate}; Map<String, dynamic> postParams = <String, dynamic>{"P_EFFECTIVE_DATE": effectiveDate};
postParams.addAll(AppState().postParamsJson); postParams.addAll(AppState().postParamsJson);
if (empID != null) postParams["P_SELECTED_EMPLOYEE_NUMBER"] = empID; if (empID != null) postParams["P_SELECTED_EMPLOYEE_NUMBER"] = empID;
return await ApiClient().postJsonForObject( return await ApiClient().postJsonForObject(
(json) { (json) {
GenericResponseModel responseData = GenericResponseModel.fromJson(json); GenericResponseModel responseData = GenericResponseModel.fromJson(json);
return responseData.getAccrualBalancesList ?? []; return responseData.getAccrualBalancesList ?? <GetAccrualBalancesList>[];
}, },
url, url,
postParams, postParams,
@ -104,13 +107,13 @@ class DashboardApiClient {
Future<List<GetTicketAccuralBalanceModel>> getTicketAccuralBalance(String effectiveDate, {String? empID}) async { Future<List<GetTicketAccuralBalanceModel>> getTicketAccuralBalance(String effectiveDate, {String? empID}) async {
String url = "${ApiConsts.erpRest}GET_TICKET_ACCRUAL_BALANCES"; String url = "${ApiConsts.erpRest}GET_TICKET_ACCRUAL_BALANCES";
Map<String, dynamic> postParams = {"P_EFFECTIVE_DATE": effectiveDate}; Map<String, dynamic> postParams = <String, dynamic>{"P_EFFECTIVE_DATE": effectiveDate};
postParams.addAll(AppState().postParamsJson); postParams.addAll(AppState().postParamsJson);
if (empID != null) postParams["P_SELECTED_EMPLOYEE_NUMBER"] = empID; if (empID != null) postParams["P_SELECTED_EMPLOYEE_NUMBER"] = empID;
return await ApiClient().postJsonForObject( return await ApiClient().postJsonForObject(
(json) { (json) {
GenericResponseModel responseData = GenericResponseModel.fromJson(json); GenericResponseModel responseData = GenericResponseModel.fromJson(json);
return responseData.getAccrualBalancesTicketList ?? []; return responseData.getAccrualBalancesTicketList ?? <GetTicketAccuralBalanceModel>[];
}, },
url, url,
postParams, postParams,
@ -119,7 +122,7 @@ class DashboardApiClient {
Future<GenericResponseModel?> getOpenMissingSwipes() async { Future<GenericResponseModel?> getOpenMissingSwipes() async {
String url = "${ApiConsts.erpRest}GET_OPEN_MISSING_SWIPES"; String url = "${ApiConsts.erpRest}GET_OPEN_MISSING_SWIPES";
Map<String, dynamic> postParams = {}; Map<String, dynamic> postParams = <String, dynamic>{};
postParams.addAll(AppState().postParamsJson); postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject( return await ApiClient().postJsonForObject(
(json) { (json) {
@ -134,12 +137,12 @@ class DashboardApiClient {
//Menus List //Menus List
Future<List<ListMenu>> getListMenu() async { Future<List<ListMenu>> getListMenu() async {
String url = "${ApiConsts.erpRest}GET_MENU"; String url = "${ApiConsts.erpRest}GET_MENU";
Map<String, dynamic> postParams = {}; Map<String, dynamic> postParams = <String, dynamic>{};
postParams.addAll(AppState().postParamsJson); postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject( return await ApiClient().postJsonForObject(
(json) { (json) {
GenericResponseModel responseData = GenericResponseModel.fromJson(json); GenericResponseModel responseData = GenericResponseModel.fromJson(json);
return responseData.listMenu ?? []; return responseData.listMenu ?? <ListMenu>[];
}, },
url, url,
postParams, postParams,
@ -149,7 +152,7 @@ class DashboardApiClient {
//GET_MENU_ENTRIES //GET_MENU_ENTRIES
Future<GenericResponseModel?> getGetMenuEntries() async { Future<GenericResponseModel?> getGetMenuEntries() async {
String url = "${ApiConsts.erpRest}GET_MENU_ENTRIES"; String url = "${ApiConsts.erpRest}GET_MENU_ENTRIES";
Map<String, dynamic> postParams = {"P_SELECTED_RESP_ID": -999, "P_MENU_TYPE": "E"}; Map<String, dynamic> postParams = <String, dynamic>{"P_SELECTED_RESP_ID": -999, "P_MENU_TYPE": "E"};
postParams.addAll(AppState().postParamsJson); postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject( return await ApiClient().postJsonForObject(
(json) { (json) {
@ -163,7 +166,7 @@ class DashboardApiClient {
Future<GenericResponseModel?> getEventActivity() async { Future<GenericResponseModel?> getEventActivity() async {
String url = "${ApiConsts.erpRest}Get_EventActivity"; String url = "${ApiConsts.erpRest}Get_EventActivity";
Map<String, dynamic> postParams = {"P_SELECTED_RESP_ID": -999, "P_MENU_TYPE": "E"}; Map<String, dynamic> postParams = <String, dynamic>{"P_SELECTED_RESP_ID": -999, "P_MENU_TYPE": "E"};
postParams.addAll(AppState().postParamsJson); postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject( return await ApiClient().postJsonForObject(
(json) { (json) {
@ -177,7 +180,7 @@ class DashboardApiClient {
Future<GenericResponseModel?> getTicketBookingRedirection() async { Future<GenericResponseModel?> getTicketBookingRedirection() async {
String url = "${ApiConsts.erpRest}GET_PORTAL_REDIRECTION"; String url = "${ApiConsts.erpRest}GET_PORTAL_REDIRECTION";
Map<String, dynamic> postParams = {"P_USER_NAME": AppState().memberInformationList?.eMPLOYEENUMBER}; Map<String, dynamic> postParams = <String, dynamic>{"P_USER_NAME": AppState().memberInformationList?.eMPLOYEENUMBER};
postParams.addAll(AppState().postParamsJson); postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject( return await ApiClient().postJsonForObject(
(json) { (json) {
@ -191,7 +194,7 @@ class DashboardApiClient {
Future<GenericResponseModel?> getTicketBalance() async { Future<GenericResponseModel?> getTicketBalance() async {
String url = "${ApiConsts.erpRest}GET_TICKET_BALANCE"; String url = "${ApiConsts.erpRest}GET_TICKET_BALANCE";
Map<String, dynamic> postParams = {"P_USER_NAME": AppState().memberInformationList?.eMPLOYEENUMBER}; Map<String, dynamic> postParams = <String, dynamic>{"P_USER_NAME": AppState().memberInformationList?.eMPLOYEENUMBER};
postParams.addAll(AppState().postParamsJson); postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject( return await ApiClient().postJsonForObject(
@ -208,7 +211,7 @@ class DashboardApiClient {
String url = "${ApiConsts.ssoAuthRedirection}?grantType=mohemm"; String url = "${ApiConsts.ssoAuthRedirection}?grantType=mohemm";
//https://sso-uat.hmg.com/api/auth/connect?grantType=mohemm' //https://sso-uat.hmg.com/api/auth/connect?grantType=mohemm'
// Map<String, dynamic> postParams = {"P_USER_NAME": AppState().memberInformationList?.eMPLOYEENUMBER}; // Map<String, dynamic> postParams = {"P_USER_NAME": AppState().memberInformationList?.eMPLOYEENUMBER};
Map<String, dynamic> postParams = { Map<String, dynamic> postParams = <String, dynamic>{
"ClientId": clientID, "ClientId": clientID,
// "ClientId": "a9f4d1a0596d4aea8f830992ec4bdac1", // "ClientId": "a9f4d1a0596d4aea8f830992ec4bdac1",
"PersonId": AppState().memberInformationList?.eMPLOYEENUMBER, "PersonId": AppState().memberInformationList?.eMPLOYEENUMBER,
@ -227,20 +230,35 @@ class DashboardApiClient {
); );
} }
Future<GetEitAttachmentTicket?> getTicketEitPDFDownload({required String peiExtraInfoId}) async {
String url = "${ApiConsts.erpRest}GET_EIT_ATTACHMENTS";
Map<String, dynamic> postParams = <String, dynamic>{
"P_PERSON_EXTRA_INFO_ID": peiExtraInfoId,
"PersonId": AppState().memberInformationList?.eMPLOYEENUMBER,
"Username": AppState().memberInformationList?.eMPLOYEENUMBER,
"Language": "US",
"SessionId": AppState().postParamsObject?.pSessionId,
};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
GetEitAttachmentTicket responseData = GetEitAttachmentTicket.fromJson(json);
return responseData;
},
url,
postParams,
);
}
Future<dynamic> getBookingSSOFinalRedirection({required String token}) async { Future<dynamic> getBookingSSOFinalRedirection({required String token}) async {
// token = // token =
// "eyJhbGciOiJSUzI1NiIsImtpZCI6IjhjZTE2OWM0YjIwYjQ2ZWM5YTQyOTU3Y2ZhODUzNzQ1IiwidHlwIjoiSldUIn0.eyJ0ZW5hbnRfaWQiOiJhOWY0ZDFhMDU5NmQ0YWVhOGY4MzA5OTJlYzRiZGFjMSIsImVpZCI6IjExNzkzMCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL3NpZCI6Ijk2MDI0OGM1NzA3YzQ3MmFhYTEzM2I1N2ZhODE1ZmVhIiwibGFuZ3VhZ2UiOiJVUyIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL2VtYWlsYWRkcmVzcyI6IjExNzkzMEBobWcuY29tIiwiZXhwIjoxNzgyNDc1NzY5LCJpc3MiOiJodHRwczovL3Nzby11YXQuaG1nLmNvbSIsImF1ZCI6ImE5ZjRkMWEwNTk2ZDRhZWE4ZjgzMDk5MmVjNGJkYWMxIn0.rJcLVsG8D0XECyLERCTD2uqGeWyvp-OBVGE9uL2qKrX4etFUHgdFt_5kYF6edFTtGy-0PIZadHDmv7e-IOhVWHm5HVMClaukiXoRXR8cDN8XA1wfme3Kd-U5PXN-IRh49AyRTzLO0rYNPvH81ScosWGlsFSkOvA-0hJNa2adHdtvgNvB8wJshSU5p7sAmF8mjdDY6aInG19etu2iEuUDwHHA4ZY_ts4hboHo8fE392hFaYGonExoD7bpW5RMx5xKWeRCmWpG_PK8Aw_z1jGzdB9PANus4pteRGuln1J-kmo2lQC9pVrSyZATAKp1HfgfyZ_vUhaHEfM69cMWaCslJQ"; // "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')); http.MultipartRequest request = http.MultipartRequest('POST', Uri.parse('https://www.paxes.com/sso/hmg'));
var request = http.MultipartRequest('POST', Uri.parse('https://Paxes-release.techmaster.in/SSO/HMG')); // UAT // http.MultipartRequest request = http.MultipartRequest('POST', Uri.parse('https://ek.techmaster.in/SSO/HMG'));
// var request = http.MultipartRequest('POST', Uri.parse('https://paxes.com/sso/hmg')); // Prod request.fields.addAll(<String, String>{'JWTToken': token});
request.fields.addAll({'JWTToken': token});
// request.headers.addAll(headers);
http.StreamedResponse response = await request.send(); http.StreamedResponse response = await request.send();
if (response.statusCode == 302) { if (response.statusCode == 302) {
print("================== post =========="); String res = await response.stream.bytesToString();
var res = await response.stream.bytesToString();
return response.headers["location"]; return response.headers["location"];
} else { } else {
print(response.reasonPhrase); print(response.reasonPhrase);
@ -260,7 +278,7 @@ class DashboardApiClient {
var _mobileDeviceIdentifierPlugin = MobileDeviceIdentifier(); var _mobileDeviceIdentifierPlugin = MobileDeviceIdentifier();
Codec<String, String> stringToBase64 = utf8.fuse(base64); Codec<String, String> stringToBase64 = utf8.fuse(base64);
String url = "${ApiConsts.swpRest}AuthenticateAndSwipeUserSupportNFC"; String url = "${ApiConsts.swpRest}AuthenticateAndSwipeUserSupportNFC";
var uuid = Uuid(); Uuid uuid = Uuid();
String? deviceId = ""; String? deviceId = "";
// Generate a v4 (random) id // Generate a v4 (random) id
if (Platform.isAndroid) { if (Platform.isAndroid) {
@ -272,7 +290,7 @@ class DashboardApiClient {
IosDeviceInfo iosInfo = await DeviceInfoPlugin().iosInfo; IosDeviceInfo iosInfo = await DeviceInfoPlugin().iosInfo;
deviceId = iosInfo.identifierForVendor; deviceId = iosInfo.identifierForVendor;
} }
Map<String, dynamic> postParams = { Map<String, dynamic> postParams = <String, dynamic>{
"UID": deviceId, //uuid.v4(), //Mobile Id "UID": deviceId, //uuid.v4(), //Mobile Id
// "UID": uuid.v4(), //Mobile Id // "UID": uuid.v4(), //Mobile Id
"Latitude": lat, "Latitude": lat,
@ -298,10 +316,10 @@ class DashboardApiClient {
//Mark Fake Location //Mark Fake Location
Future<GenericResponseModel?> markFakeLocation({String lat = "0", String? long = "0", required String sourceName}) async { Future<GenericResponseModel?> markFakeLocation({String lat = "0", String? long = "0", required String sourceName}) async {
String url = "${ApiConsts.swpRest}CreateIssueInfo"; String url = "${ApiConsts.swpRest}CreateIssueInfo";
var uuid = Uuid(); Uuid uuid = Uuid();
// Generate a v4 (random) id // Generate a v4 (random) id
Map<String, dynamic> postParams = { Map<String, dynamic> postParams = <String, dynamic>{
"UID": uuid.v4(), //Mobile Id "UID": uuid.v4(), //Mobile Id
"Latitude": lat, "Latitude": lat,
"Longitude": long, "Longitude": long,
@ -325,7 +343,7 @@ class DashboardApiClient {
Future<MohemmItgResponseItem?> getITGPageNotification() async { Future<MohemmItgResponseItem?> getITGPageNotification() async {
String url = "${ApiConsts.cocRest}Mohemm_ITG_GetPageNotification"; String url = "${ApiConsts.cocRest}Mohemm_ITG_GetPageNotification";
Map<String, dynamic> postParams = { Map<String, dynamic> postParams = <String, dynamic>{
"EmployeeNumber": AppState().getUserName, "EmployeeNumber": AppState().getUserName,
"ItgEnableAt": "After Service Submission", //Mobile Id "ItgEnableAt": "After Service Submission", //Mobile Id
"ItgServiceName": "Login", "ItgServiceName": "Login",
@ -347,7 +365,7 @@ class DashboardApiClient {
Future<ItgMainRes?> submitItgForm({required String comment, required String masterId, required List<Map<String, dynamic>> itgList, required int serviceId}) async { Future<ItgMainRes?> submitItgForm({required String comment, required String masterId, required List<Map<String, dynamic>> itgList, required int serviceId}) async {
String url = "${ApiConsts.cocRest}Mohemm_ITG_Survey_Response"; String url = "${ApiConsts.cocRest}Mohemm_ITG_Survey_Response";
Map<String, dynamic> postParams = { Map<String, dynamic> postParams = <String, dynamic>{
"EmployeeNumber": AppState().getUserName, "EmployeeNumber": AppState().getUserName,
"ItgComments": comment, "ItgComments": comment,
"ItgNotificationMasterId": masterId, "ItgNotificationMasterId": masterId,
@ -368,7 +386,7 @@ class DashboardApiClient {
Future<ItgMainRes?> getAdvertisementDetail(String masterID) async { Future<ItgMainRes?> getAdvertisementDetail(String masterID) async {
String url = "${ApiConsts.cocRest}Mohemm_ITG_GetPageNotificationDetails"; String url = "${ApiConsts.cocRest}Mohemm_ITG_GetPageNotificationDetails";
Map<String, dynamic> postParams = { Map<String, dynamic> postParams = <String, dynamic>{
"EmployeeNumber": AppState().getUserName, "EmployeeNumber": AppState().getUserName,
"ItgNotificationMasterId": masterID, //Mobile Id "ItgNotificationMasterId": masterID, //Mobile Id
}; };
@ -386,7 +404,7 @@ class DashboardApiClient {
Future setAdvertisementViewed(String masterID, int advertisementId, String? ackValue) async { Future setAdvertisementViewed(String masterID, int advertisementId, String? ackValue) async {
String url = "${ApiConsts.cocRest}Mohemm_ITG_UpdateAdvertisementAsViewed"; String url = "${ApiConsts.cocRest}Mohemm_ITG_UpdateAdvertisementAsViewed";
Map<String, dynamic> postParams = { Map<String, dynamic> postParams = <String, dynamic>{
"ItgNotificationMasterId": masterID, "ItgNotificationMasterId": masterID,
"EmployeeNumber": AppState().memberInformationList!.eMPLOYEENUMBER.toString(), "EmployeeNumber": AppState().memberInformationList!.eMPLOYEENUMBER.toString(),
"ItgAdvertisementId": advertisementId, "ItgAdvertisementId": advertisementId,
@ -434,7 +452,7 @@ class DashboardApiClient {
//Fetch All Courses Status //Fetch All Courses Status
Future<CoursesResponseModel?> fetchAllCoursesStatus() async { Future<CoursesResponseModel?> fetchAllCoursesStatus() async {
String url = "https://elearning.hmg.com/moodle_dev/api/Fetch_All_Courses_Status.php"; String url = ApiConsts.eLearningBaseUrl +"Fetch_All_Courses_Status.php";
Map<String, String> headers = { Map<String, String> 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', 'x-api-key': 'bLi@mbXJeXTHd/)h&LFh%25+%25(Nbnaq6hBg%7d%5dyQbthY%7bv6ew6-5UT\$NASwucn%7d,_PSJpuwNCCen2%7djj%7b00HR2T-%5b,k7W%7d-0yepK?%258',
@ -456,4 +474,18 @@ class DashboardApiClient {
isFormData: false, isFormData: false,
); );
} }
Future<GetGreetingCardsModelResponse?> getGreetingCards() async {
String url = "${ApiConsts.erpRest}Get_GreetingCards";
Map<String, dynamic> postParams = {};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
GetGreetingCardsModelResponse responseData = GetGreetingCardsModelResponse.fromJson(json);
return responseData;
},
url,
postParams,
);
}
} }

@ -25,16 +25,23 @@ class EITApiClient {
postParams.addAll(AppState().postParamsJson); postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject( return await ApiClient().postJsonForObject(
(json) { (json) {
// Check if GetEITTransactionList exists and is not empty
if (json['GetEITTransactionList'] == null || (json['GetEITTransactionList'] is List && json['GetEITTransactionList'].isEmpty)) {
return isCompleteList ? <List<CollectionTransaction>>[] : <CollectionTransaction>[];
}
if (isCompleteList) { if (isCompleteList) {
List<List<CollectionTransaction>> responseData = []; List<List<CollectionTransaction>> responseData = [];
json['GetEITTransactionList'].forEach((element) { json['GetEITTransactionList'].forEach((element) {
var transactionList = GetEitTransactionsModel.fromJson(element).collectionTransaction; var transactionList = GetEitTransactionsModel.fromJson(element).collectionTransaction;
if (transactionList != null) responseData.add(transactionList); if (transactionList != null && transactionList.isNotEmpty) {
responseData.add(transactionList);
}
}); });
return responseData; return responseData;
} else { } else {
List<CollectionTransaction>? responseData = GetEitTransactionsModel.fromJson(json['GetEITTransactionList'][0]).collectionTransaction; List<CollectionTransaction>? responseData = GetEitTransactionsModel.fromJson(json['GetEITTransactionList'][0]).collectionTransaction;
return responseData; return responseData ?? <CollectionTransaction>[];
} }
}, },
url, url,

@ -90,7 +90,7 @@ class AppState {
String get getHuaweiPushToken => _huaweiPushToken; 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.7, mobileType: Platform.isAndroid ? "android" : "ios");
void setPostParamsInitConfig() { void setPostParamsInitConfig() {
isAuthenticated = false; isAuthenticated = false;

@ -4,13 +4,19 @@ class ApiConsts {
// static String baseUrl = "http://10.200.204.11"; // 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://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 = "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://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 ssoBaseUrl = "https://sso.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://mohemm.hmg.com"; // New Live server
//static String eLearningBaseUrl = "https://elearning.hmg.com/moodle_dev/api/"; // Elearning server UAT
static String eLearningBaseUrl = "https://elearning.hmg.com/moodle/api/"; // Elearning server live
// static String baseUrl = "http://10.20.200.111:1010/"; // static String baseUrl = "http://10.20.200.111:1010/";
@ -27,8 +33,8 @@ class ApiConsts {
static String user = baseUrlServices + "api/User/"; static String user = baseUrlServices + "api/User/";
static String cocRest = baseUrlServices + "COCWS.svc/REST/"; static String cocRest = baseUrlServices + "COCWS.svc/REST/";
static String ssoAuthRedirection = "https://sso-uat.hmg.com/api/auth/connect"; // UAT static String ssoAuthRedirection = ssoBaseUrl + "/api/auth/connect";
// static String ssoAuthRedirection = "https://sso.hmg.com/api/auth/connect"; // Prod
//Chat //Chat
static String chatServerBaseUrl = "https://apiderichat.hmg.com/"; static String chatServerBaseUrl = "https://apiderichat.hmg.com/";
@ -56,6 +62,7 @@ class ApiConsts {
static String marathonBaseUrlUAT = "https://marathoon.com/uatservice/api/"; static String marathonBaseUrlUAT = "https://marathoon.com/uatservice/api/";
static String marathonBaseUrl = marathonBaseUrlLive; static String marathonBaseUrl = marathonBaseUrlLive;
// static String marathonBaseUrl = marathonBaseUrlUAT; // static String marathonBaseUrl = marathonBaseUrlUAT;
static String marathonBaseUrlServices = "https://marathoon.com/service/"; static String marathonBaseUrlServices = "https://marathoon.com/service/";
static String marathonParticipantLoginUrl = marathonBaseUrl + "auth/participantlogin"; static String marathonParticipantLoginUrl = marathonBaseUrl + "auth/participantlogin";
@ -87,5 +94,3 @@ class SharedPrefsConsts {
static String mohemmWifiPassword = "mohemmWifiPassword"; static String mohemmWifiPassword = "mohemmWifiPassword";
static String editItemForSale = "editItemForSale"; static String editItemForSale = "editItemForSale";
} }

@ -682,7 +682,8 @@ class CodegenLoader extends AssetLoader{
"ticketId": "معرف التذكرة", "ticketId": "معرف التذكرة",
"pleaseSelectProject": "الرجاء اختيار مشروع", "pleaseSelectProject": "الرجاء اختيار مشروع",
"viewAttachment": "عرض المرفق", "viewAttachment": "عرض المرفق",
"parkingQr": "وقوف السيارات QR" "parkingQr": "وقوف السيارات QR",
"startNow": "ابدأ الآن"
}; };
static const Map<String,dynamic> _en_US = { static const Map<String,dynamic> _en_US = {
"mohemm": "Mohemm", "mohemm": "Mohemm",
@ -1352,7 +1353,8 @@ static const Map<String,dynamic> _en_US = {
"ticketId": "Ticket ID", "ticketId": "Ticket ID",
"pleaseSelectProject": "Please select a project", "pleaseSelectProject": "Please select a project",
"viewAttachment": "View Attachment", "viewAttachment": "View Attachment",
"parkingQr": "Parking QR" "parkingQr": "Parking QR",
"startNow": "Start Now"
}; };
static const Map<String, Map<String,dynamic>> mapLocales = {"ar_SA": _ar_SA, "en_US": _en_US}; static const Map<String, Map<String,dynamic>> mapLocales = {"ar_SA": _ar_SA, "en_US": _en_US};
} }

@ -655,5 +655,6 @@ abstract class LocaleKeys {
static const pleaseSelectProject = 'pleaseSelectProject'; static const pleaseSelectProject = 'pleaseSelectProject';
static const viewAttachment = 'viewAttachment'; static const viewAttachment = 'viewAttachment';
static const parkingQr = 'parkingQr'; static const parkingQr = 'parkingQr';
static const startNow = 'startNow';
} }

@ -30,7 +30,7 @@ class CollectionTransaction {
String? dISPLAYFLAG; String? dISPLAYFLAG;
int? fROMROWNUM; int? fROMROWNUM;
int? nOOFROWS; int? nOOFROWS;
dynamic? nUMBERVALUE; dynamic nUMBERVALUE;
int? rOWNUM; int? rOWNUM;
String? sEGMENTNAME; String? sEGMENTNAME;
String? sEGMENTPROMPT; String? sEGMENTPROMPT;
@ -80,7 +80,7 @@ class CollectionTransaction {
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
Map<String, dynamic> data = new Map<String, dynamic>(); Map<String, dynamic> data = Map<String, dynamic>();
data['APPLICATION_COLUMN_NAME'] = this.aPPLICATIONCOLUMNNAME; data['APPLICATION_COLUMN_NAME'] = this.aPPLICATIONCOLUMNNAME;
data['DATATYPE'] = this.dATATYPE; data['DATATYPE'] = this.dATATYPE;
data['DATE_VALUE'] = this.dATEVALUE; data['DATE_VALUE'] = this.dATEVALUE;

@ -0,0 +1,97 @@
import 'dart:convert';
class GetEitAttachmentTicket {
List<GetEitAttachmentList>? getEitAttachmentList;
GetEitAttachmentTicket({
this.getEitAttachmentList,
});
factory GetEitAttachmentTicket.fromRawJson(String str) => GetEitAttachmentTicket.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory GetEitAttachmentTicket.fromJson(Map<String, dynamic> json) => GetEitAttachmentTicket(
getEitAttachmentList: json["GetEITAttachmentList"] == null ? [] : List<GetEitAttachmentList>.from(json["GetEITAttachmentList"]!.map((x) => GetEitAttachmentList.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"GetEITAttachmentList": getEitAttachmentList == null ? [] : List<dynamic>.from(getEitAttachmentList!.map((x) => x.toJson())),
};
}
class GetEitAttachmentList {
int? attachedDocumentId;
int? categoryId;
int? datatypeId;
int? documentId;
String? entityName;
String? fileContentType;
String? fileData;
int? fileId;
String? fileName;
String? pk1Value;
String? pk2Value;
String? pk3Value;
String? pk4Value;
String? pk5Value;
int? seqNum;
GetEitAttachmentList({
this.attachedDocumentId,
this.categoryId,
this.datatypeId,
this.documentId,
this.entityName,
this.fileContentType,
this.fileData,
this.fileId,
this.fileName,
this.pk1Value,
this.pk2Value,
this.pk3Value,
this.pk4Value,
this.pk5Value,
this.seqNum,
});
factory GetEitAttachmentList.fromRawJson(String str) => GetEitAttachmentList.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory GetEitAttachmentList.fromJson(Map<String, dynamic> json) => GetEitAttachmentList(
attachedDocumentId: json["ATTACHED_DOCUMENT_ID"],
categoryId: json["CATEGORY_ID"],
datatypeId: json["DATATYPE_ID"],
documentId: json["DOCUMENT_ID"],
entityName: json["ENTITY_NAME"],
fileContentType: json["FILE_CONTENT_TYPE"],
fileData: json["FILE_DATA"],
fileId: json["FILE_ID"],
fileName: json["FILE_NAME"],
pk1Value: json["PK1_VALUE"],
pk2Value: json["PK2_VALUE"],
pk3Value: json["PK3_VALUE"],
pk4Value: json["PK4_VALUE"],
pk5Value: json["PK5_VALUE"],
seqNum: json["SEQ_NUM"],
);
Map<String, dynamic> toJson() => {
"ATTACHED_DOCUMENT_ID": attachedDocumentId,
"CATEGORY_ID": categoryId,
"DATATYPE_ID": datatypeId,
"DOCUMENT_ID": documentId,
"ENTITY_NAME": entityName,
"FILE_CONTENT_TYPE": fileContentType,
"FILE_DATA": fileData,
"FILE_ID": fileId,
"FILE_NAME": fileName,
"PK1_VALUE": pk1Value,
"PK2_VALUE": pk2Value,
"PK3_VALUE": pk3Value,
"PK4_VALUE": pk4Value,
"PK5_VALUE": pk5Value,
"SEQ_NUM": seqNum,
};
}

@ -22,6 +22,8 @@ class GetDayHoursTypeDetailsList {
dynamic? fROMROWNUM; dynamic? fROMROWNUM;
String? lATEINFLAG; String? lATEINFLAG;
String? lATEINHRS; String? lATEINHRS;
String? lEAVEDESCRIPTION;
String? lEAVETYPECODE;
String? mISSINGSWIPEFLAG; String? mISSINGSWIPEFLAG;
String? nONSCHEDULEDFLAG; String? nONSCHEDULEDFLAG;
dynamic? nOOFROWS; dynamic? nOOFROWS;
@ -66,6 +68,8 @@ class GetDayHoursTypeDetailsList {
this.fROMROWNUM, this.fROMROWNUM,
this.lATEINFLAG, this.lATEINFLAG,
this.lATEINHRS, this.lATEINHRS,
this.lEAVEDESCRIPTION,
this.lEAVETYPECODE,
this.mISSINGSWIPEFLAG, this.mISSINGSWIPEFLAG,
this.nONSCHEDULEDFLAG, this.nONSCHEDULEDFLAG,
this.nOOFROWS, this.nOOFROWS,
@ -110,6 +114,8 @@ class GetDayHoursTypeDetailsList {
fROMROWNUM = json['FROM_ROW_NUM']; fROMROWNUM = json['FROM_ROW_NUM'];
lATEINFLAG = json['LATE_IN_FLAG']; lATEINFLAG = json['LATE_IN_FLAG'];
lATEINHRS = json['LATE_IN_HRS']; lATEINHRS = json['LATE_IN_HRS'];
lEAVEDESCRIPTION = json['LEAVE_DESCRIPTION'];
lEAVETYPECODE = json['LEAVE_TYPE_CODE'];
mISSINGSWIPEFLAG = json['MISSING_SWIPE_FLAG']; mISSINGSWIPEFLAG = json['MISSING_SWIPE_FLAG'];
nONSCHEDULEDFLAG = json['NON_SCHEDULED_FLAG']; nONSCHEDULEDFLAG = json['NON_SCHEDULED_FLAG'];
nOOFROWS = json['NO_OF_ROWS']; nOOFROWS = json['NO_OF_ROWS'];
@ -156,6 +162,8 @@ class GetDayHoursTypeDetailsList {
data['FROM_ROW_NUM'] = this.fROMROWNUM; data['FROM_ROW_NUM'] = this.fROMROWNUM;
data['LATE_IN_FLAG'] = this.lATEINFLAG; data['LATE_IN_FLAG'] = this.lATEINFLAG;
data['LATE_IN_HRS'] = this.lATEINHRS; data['LATE_IN_HRS'] = this.lATEINHRS;
data['LEAVE_DESCRIPTION'] = this.lEAVEDESCRIPTION;
data['LEAVE_TYPE_CODE'] = this.lEAVETYPECODE;
data['MISSING_SWIPE_FLAG'] = this.mISSINGSWIPEFLAG; data['MISSING_SWIPE_FLAG'] = this.mISSINGSWIPEFLAG;
data['NON_SCHEDULED_FLAG'] = this.nONSCHEDULEDFLAG; data['NON_SCHEDULED_FLAG'] = this.nONSCHEDULEDFLAG;
data['NO_OF_ROWS'] = this.nOOFROWS; data['NO_OF_ROWS'] = this.nOOFROWS;

@ -0,0 +1,142 @@
import 'dart:convert';
class GetGreetingCardsModelResponse {
List<GetGreetingCardsModelResponseElement>? getGreetingCardsModelResponse;
GetGreetingCardsModelResponse({
this.getGreetingCardsModelResponse,
});
factory GetGreetingCardsModelResponse.fromRawJson(String str) => GetGreetingCardsModelResponse.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory GetGreetingCardsModelResponse.fromJson(Map<String, dynamic> json) => GetGreetingCardsModelResponse(
getGreetingCardsModelResponse: json["Get_GreetingCardsModel_Response"] == null ? [] : List<GetGreetingCardsModelResponseElement>.from(json["Get_GreetingCardsModel_Response"]!.map((x) => GetGreetingCardsModelResponseElement.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"Get_GreetingCardsModel_Response": getGreetingCardsModelResponse == null ? [] : List<dynamic>.from(getGreetingCardsModelResponse!.map((x) => x.toJson())),
};
}
class GetGreetingCardsModelResponseElement {
String? backgroundImageUrlAr;
String? backgroundImageUrlEn;
String? buttonBgColor;
String? buttonText;
String? buttonTextN;
int? cardType;
int? categoryId;
String? categoryNameAr;
String? categoryNameEn;
int? channel;
String? createdOn;
String? descriptionAr;
String? descriptionEn;
String? endDate;
bool? hasButton;
int? id;
bool? isActive;
int? moduleId;
String? moduleName;
String? moduleNameN;
String? startDate;
String? textColor;
String? titleAr;
String? titleEn;
String? urlAr;
String? urlEn;
GetGreetingCardsModelResponseElement({
this.backgroundImageUrlAr,
this.backgroundImageUrlEn,
this.buttonBgColor,
this.buttonText,
this.buttonTextN,
this.cardType,
this.categoryId,
this.categoryNameAr,
this.categoryNameEn,
this.channel,
this.createdOn,
this.descriptionAr,
this.descriptionEn,
this.endDate,
this.hasButton,
this.id,
this.isActive,
this.moduleId,
this.moduleName,
this.moduleNameN,
this.startDate,
this.textColor,
this.titleAr,
this.titleEn,
this.urlAr,
this.urlEn,
});
factory GetGreetingCardsModelResponseElement.fromRawJson(String str) => GetGreetingCardsModelResponseElement.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory GetGreetingCardsModelResponseElement.fromJson(Map<String, dynamic> json) => GetGreetingCardsModelResponseElement(
backgroundImageUrlAr: json["BackgroundImageUrlAr"],
backgroundImageUrlEn: json["BackgroundImageUrlEn"],
buttonBgColor: json["ButtonBgColor"],
buttonText: json["ButtonText"],
buttonTextN: json["ButtonTextN"],
cardType: json["CardType"],
categoryId: json["CategoryID"],
categoryNameAr: json["CategoryNameAr"],
categoryNameEn: json["CategoryNameEn"],
channel: json["Channel"],
createdOn: json["CreatedOn"],
descriptionAr: json["DescriptionAr"],
descriptionEn: json["DescriptionEn"],
endDate: json["EndDate"],
hasButton: json["HasButton"],
id: json["ID"],
isActive: json["IsActive"],
moduleId: json["ModuleID"],
moduleName: json["ModuleName"],
moduleNameN: json["ModuleNameN"],
startDate: json["StartDate"],
textColor: json["TextColor"],
titleAr: json["TitleAr"],
titleEn: json["TitleEn"],
urlAr: json["UrlAr"],
urlEn: json["UrlEn"],
);
Map<String, dynamic> toJson() => {
"BackgroundImageUrlAr": backgroundImageUrlAr,
"BackgroundImageUrlEn": backgroundImageUrlEn,
"ButtonBgColor": buttonBgColor,
"ButtonText": buttonText,
"ButtonTextN": buttonTextN,
"CardType": cardType,
"CategoryID": categoryId,
"CategoryNameAr": categoryNameAr,
"CategoryNameEn": categoryNameEn,
"Channel": channel,
"CreatedOn": createdOn,
"DescriptionAr": descriptionAr,
"DescriptionEn": descriptionEn,
"EndDate": endDate,
"HasButton": hasButton,
"ID": id,
"IsActive": isActive,
"ModuleID": moduleId,
"ModuleName": moduleName,
"ModuleNameN": moduleNameN,
"StartDate": startDate,
"TextColor": textColor,
"TitleAr": titleAr,
"TitleEn": titleEn,
"UrlAr": urlAr,
"UrlEn": urlEn,
};
}

@ -21,7 +21,9 @@ 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/mohemm_itg_pending_task_responseitem.dart';
import 'package:mohem_flutter_app/models/dashboard/courses_response_model.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/eit/get_eit_transaction_model.dart';
import 'package:mohem_flutter_app/models/eit_attachment_ticket_model.dart';
import 'package:mohem_flutter_app/models/generic_response_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/itg/itg_response_model.dart';
import 'package:mohem_flutter_app/models/offers_and_discounts/get_offers_list.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/models/sso_auth_model.dart';
@ -73,6 +75,10 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
CoursesResponseModel? coursesResponse; CoursesResponseModel? coursesResponse;
List<CourseStatus> coursesList = []; List<CourseStatus> coursesList = [];
bool isGreetingCardsLoading = true;
bool isDisplayEidGreetings = false;
List<GetGreetingCardsModelResponseElement>? greetingCardsList;
//Attendance Tracking API's & Methods //Attendance Tracking API's & Methods
Future<bool> fetchAttendanceTracking(context) async { Future<bool> fetchAttendanceTracking(context) async {
try { try {
@ -121,6 +127,8 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
getMenuEntriesList = null; getMenuEntriesList = null;
isOffersLoading = true; isOffersLoading = true;
getOffersList = []; getOffersList = [];
isGreetingCardsLoading = true;
isDisplayEidGreetings = false;
drawerMenuItemList = [ drawerMenuItemList = [
DrawerMenuItem("assets/images/drawer/my_profile.svg", LocaleKeys.myProfile.tr(), AppRoutes.profile), DrawerMenuItem("assets/images/drawer/my_profile.svg", LocaleKeys.myProfile.tr(), AppRoutes.profile),
@ -130,7 +138,7 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
DrawerMenuItem("assets/images/drawer/mowadhafi.svg", LocaleKeys.keen.tr(), AppRoutes.etqanOvr), 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/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/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/drawer_marathon.svg", LocaleKeys.brainMarathon.tr(), AppRoutes.marathonIntroScreen),
DrawerMenuItem("assets/images/drawer/change_password.svg", LocaleKeys.changePassword.tr(), AppRoutes.changePassword), DrawerMenuItem("assets/images/drawer/change_password.svg", LocaleKeys.changePassword.tr(), AppRoutes.changePassword),
]; ];
@ -316,10 +324,33 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
} }
} }
void fetchGreetingCards() async {
isGreetingCardsLoading = true;
notifyListeners();
try {
GetGreetingCardsModelResponse? response = await DashboardApiClient().getGreetingCards();
greetingCardsList = response?.getGreetingCardsModelResponse ?? [];
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();
}
}
Future<void> fetchTicketBooking() async { Future<void> fetchTicketBooking() async {
try { try {
GenericResponseModel? genericResponseModel = await DashboardApiClient().getTicketBookingRedirection(); GenericResponseModel? genericResponseModel = await DashboardApiClient().getTicketBookingRedirection();
if (genericResponseModel?.portalDirectionData?.pRedirection!.toLowerCase() == "alma") { if (genericResponseModel?.portalDirectionData?.pRedirection!.toLowerCase() == "alma") {
// ticketBookingResponse = TicketBookingResult(true, "a9f4d1a0596d4aea8f830992ec4bdac1");
ticketBookingResponse = TicketBookingResult(true, genericResponseModel?.portalDirectionData?.clientID); ticketBookingResponse = TicketBookingResult(true, genericResponseModel?.portalDirectionData?.clientID);
return; return;
} }
@ -329,7 +360,7 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
isEventLoadingLoading = false; isEventLoadingLoading = false;
notifyListeners(); notifyListeners();
Utils.handleException(ex, null, null); Utils.handleException(ex, null, null);
ticketBookingResponse = TicketBookingResult(false, null); // Ensure a return value in case of an exception ticketBookingResponse = TicketBookingResult(false, null);
} }
} }
@ -377,6 +408,23 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
} }
} }
Future<GetEitAttachmentTicket?> getTicketEitPDFDownload({String? peiExtraInfoId}) async {
try {
GetEitAttachmentTicket? res = await DashboardApiClient().getTicketEitPDFDownload(peiExtraInfoId: peiExtraInfoId!);
if (res?.getEitAttachmentList != null && res?.getEitAttachmentList!.length! != 0 && res!.getEitAttachmentList!.first.fileData != null) {
return res;
} else {
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<Menus> parseMenus(List<GetMenuEntriesList> getMenuEntriesList) { List<Menus> parseMenus(List<GetMenuEntriesList> getMenuEntriesList) {
List<Menus> menus = []; List<Menus> menus = [];
for (int i = 0; i < getMenuEntriesList.length; i++) { for (int i = 0; i < getMenuEntriesList.length; i++) {

@ -315,6 +315,26 @@ class _MonthlyAttendanceScreenState extends State<MonthlyAttendanceScreen> {
bool isDayIsPresent = getDayHoursTypeDetailsList[index].aTTENDEDFLAG == 'Y'; bool isDayIsPresent = getDayHoursTypeDetailsList[index].aTTENDEDFLAG == 'Y';
bool isDayIsAbsent = getDayHoursTypeDetailsList[index].aTTENDEDFLAG == 'N' && getDayHoursTypeDetailsList[index].aBSENTFLAG == 'Y'; bool isDayIsAbsent = getDayHoursTypeDetailsList[index].aTTENDEDFLAG == 'N' && getDayHoursTypeDetailsList[index].aBSENTFLAG == 'Y';
// Get leave type code and corresponding color
String? leaveTypeCode = getDayHoursTypeDetailsList[index].lEAVETYPECODE;
Color? leaveTypeColor;
bool useGradient = false;
// Determine color based on leave type code
if (leaveTypeCode != null && leaveTypeCode.isNotEmpty) {
leaveTypeColor = leaveTypeColors[leaveTypeCode];
}
// If no leave type color found, use default colors based on attendance status
if (leaveTypeColor == null) {
if (isDayIsPresent) {
leaveTypeColor = leaveTypeColors['Present'];
useGradient = true; // Use gradient for present days without leave type
} else if (isDayIsAbsent) {
leaveTypeColor = leaveTypeColors['Absent'];
}
}
if (isDayIsOff) { if (isDayIsOff) {
return Container( return Container(
margin: const EdgeInsets.all(4), margin: const EdgeInsets.all(4),
@ -331,12 +351,13 @@ class _MonthlyAttendanceScreenState extends State<MonthlyAttendanceScreen> {
return Container( return Container(
margin: const EdgeInsets.all(4), margin: const EdgeInsets.all(4),
decoration: BoxDecoration( decoration: BoxDecoration(
gradient: const LinearGradient( gradient: useGradient && leaveTypeColor != null ? LinearGradient(
transform: GradientRotation(.46), transform: GradientRotation(.46),
begin: Alignment.topRight, begin: Alignment.topRight,
end: Alignment.bottomLeft, end: Alignment.bottomLeft,
colors: [MyColors.gradiantEndColor, MyColors.gradiantStartColor], colors: [MyColors.gradiantEndColor, MyColors.gradiantStartColor],
), ) : null,
color: !useGradient && leaveTypeColor != null ? leaveTypeColor : null,
shape: BoxShape.circle, shape: BoxShape.circle,
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
@ -358,7 +379,7 @@ class _MonthlyAttendanceScreenState extends State<MonthlyAttendanceScreen> {
return Container( return Container(
margin: const EdgeInsets.all(4), margin: const EdgeInsets.all(4),
decoration: BoxDecoration( decoration: BoxDecoration(
color: MyColors.backgroundBlackColor, color: leaveTypeColor ?? MyColors.backgroundBlackColor,
shape: BoxShape.circle, shape: BoxShape.circle,
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
@ -751,3 +772,24 @@ class Meeting {
Color background; Color background;
bool isAllDay; bool isAllDay;
} }
const Map<String, Color> leaveTypeColors = {
'Present': Color(0xFF00ad62),
'Absent': Color(0xFFcb3232),
'HOLIDAY': Color(0xFFF26B0F),
'BUS_TRIP': Color(0xFF001A6E),
'WFH': Color(0xFF5DB996),
'ANNUAL': Color(0xFFf39c12),
'EMERGENCY': Color(0xFFFF2929),
'EXAM': Color(0xFFCB6040),
'HAJJ': Color(0xFF798645),
'HALF': Color(0xFFE8B86D),
'LWOP': Color(0xFFCD5C08),
'LWOP_MATUNPAID': Color(0xFFE73879),
'LWOP_UNAUUNPAID': Color(0xFFA02334),
'MATPAID': Color(0xFFE73879),
'MRGE': Color(0xFF0D7C66),
'PAT': Color(0xFFC96868),
'PROF': Color(0xFF6256CA),
'SICK': Color(0xFFA5B68D),
};

@ -110,15 +110,20 @@ class _EtqanOvrCreateRequestState extends State<EtqanOvrCreateRequest> {
if (ticketInfo != null) { if (ticketInfo != null) {
String ticketNumber = ticketInfo['ticketNumber'] ?? ''; String ticketNumber = ticketInfo['ticketNumber'] ?? '';
String ticketId = ticketInfo['id'] ?? ''; 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( Utils.showErrorDialog(
context: context, context: context,
message: successMessage, message: successMessage,
onOkTapped: () { onOkTapped: () {
Navigator.popAndPushNamed(context, AppRoutes.etqanOvr); Navigator.pop(context);
Navigator.pop(context);
// Navigator.popAndPushNamed(context, AppRoutes.etqanOvr);
}, },
onCloseTap: () { onCloseTap: () {
Navigator.popAndPushNamed(context, AppRoutes.etqanOvr); Navigator.pop(context);
Navigator.pop(context);
// Navigator.popAndPushNamed(context, AppRoutes.etqanOvr);
}, },
); );
} }

@ -1,7 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_countdown_timer/flutter_countdown_timer.dart'; import 'package:flutter_countdown_timer/flutter_countdown_timer.dart';
@ -34,6 +33,7 @@ import 'package:mohem_flutter_app/widgets/shimmer/offers_shimmer_widget.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart'; import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:signalr_netcore/signalr_client.dart'; import 'package:signalr_netcore/signalr_client.dart';
import 'package:url_launcher/url_launcher.dart';
late HubConnection chatHubConnection; late HubConnection chatHubConnection;
@ -156,6 +156,7 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
data.fetchMenuEntries(); data.fetchMenuEntries();
data.fetchEventActivity(); data.fetchEventActivity();
data.getCategoryOffersListAPI(context); data.getCategoryOffersListAPI(context);
data.fetchGreetingCards();
marathonProvider.getMarathonDetailsFromApi(); marathonProvider.getMarathonDetailsFromApi();
marathonProvider.getMarathonTutorial(); marathonProvider.getMarathonTutorial();
if (isFromInit) { if (isFromInit) {
@ -164,7 +165,7 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
if (!cProvider.disbaleChatForThisUser && !isFromInit) checkHubCon(); if (!cProvider.disbaleChatForThisUser && !isFromInit) checkHubCon();
_refreshController.refreshCompleted(); _refreshController.refreshCompleted();
// await data.fetchTicketBooking(); await data.fetchTicketBooking();
// if (data.ticketBookingResponse != null && !data.ticketBookingResponse!.success) { // if (data.ticketBookingResponse != null && !data.ticketBookingResponse!.success) {
// data.fetchTicketBalance(); // data.fetchTicketBalance();
@ -316,103 +317,103 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
child: Consumer<DashboardProviderModel>( child: Consumer<DashboardProviderModel>(
builder: (BuildContext context, DashboardProviderModel model, Widget? child) { builder: (BuildContext context, DashboardProviderModel model, Widget? child) {
return (model.isAttendanceTrackingLoading return (model.isAttendanceTrackingLoading
? GetAttendanceTrackingShimmer() ? GetAttendanceTrackingShimmer()
: Container( : Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15), borderRadius: BorderRadius.circular(15),
gradient: const LinearGradient( gradient: const LinearGradient(
transform: GradientRotation(.46), transform: GradientRotation(.46),
begin: Alignment.topRight, begin: Alignment.topRight,
end: Alignment.bottomLeft, end: Alignment.bottomLeft,
colors: [MyColors.gradiantEndColor, MyColors.gradiantStartColor], colors: [MyColors.gradiantEndColor, MyColors.gradiantStartColor],
), ),
), ),
child: Stack( child: Stack(
alignment: Alignment.center, alignment: Alignment.center,
children: [ children: [
if (model.isTimeRemainingInSeconds == 0) SvgPicture.asset("assets/images/thumb.svg"), if (model.isTimeRemainingInSeconds == 0) SvgPicture.asset("assets/images/thumb.svg"),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Expanded( Expanded(
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
LocaleKeys.markAttendance.tr().toText14(color: Colors.white, isBold: true), 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) DateTime.now().toString().split(" ")[0].toText12(color: Colors.white),
if (model.isTimeRemainingInSeconds != 0) if (model.isTimeRemainingInSeconds != 0)
Column( Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, 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<Color>(Colors.white),
backgroundColor: const Color(0xff196D73),
),
),
],
),
],
).paddingOnly(top: 12, right: 15, left: 12),
),
Row(
children: [ children: [
9.height, Expanded(
Directionality( child: Column(
textDirection: ui.TextDirection.ltr, mainAxisSize: MainAxisSize.min,
child: CountdownTimer( crossAxisAlignment: CrossAxisAlignment.start,
endTime: model.endTime, children: [
onEnd: null, LocaleKeys.checkIn.tr().toText12(color: Colors.white),
endWidget: "00:00:00".toText14(color: Colors.white, isBold: true), (model.attendanceTracking!.pSwipeIn == null ? "--:--" : model.attendanceTracking!.pSwipeIn).toString().toText14(
textStyle: const TextStyle(color: Colors.white, fontSize: 14, letterSpacing: -0.48, fontWeight: FontWeight.bold), color: Colors.white,
), isBold: true,
),
4.height,
],
).paddingOnly(left: 12, right: 12),
), ),
LocaleKeys.timeLeftToday.tr().toText12(color: Colors.white), Container(
9.height, margin: EdgeInsets.only(top: AppState().isArabic(context) ? 6 : 0),
ClipRRect( width: 45,
borderRadius: const BorderRadius.all(Radius.circular(20)), height: 45,
child: LinearProgressIndicator( padding: const EdgeInsets.only(left: 10, right: 10),
value: model.progress, decoration: BoxDecoration(
minHeight: 8, color: const Color(0xff259EA4),
valueColor: const AlwaysStoppedAnimation<Color>(Colors.white), borderRadius: BorderRadius.only(
backgroundColor: const Color(0xff196D73), 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,
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(); .animatedSwither();
}, },
), ),
@ -424,8 +425,29 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
), ),
], ],
).paddingOnly(left: 21, right: 21, top: 7, bottom: 21), ).paddingOnly(left: 21, right: 21, top: 7, bottom: 21),
eventActivityWidget(context), Consumer<DashboardProviderModel>(
builder: (BuildContext context, DashboardProviderModel model, Widget? child) {
if (model.isGreetingCardsLoading) {
return const GreetingCardShimmer();
} else if (model.isDisplayEidGreetings && model.greetingCardsList != null && model.greetingCardsList!.isNotEmpty) {
return SizedBox(
width: double.infinity,
child: SvgPicture.network(
AppState().isArabic(context)
? (model.greetingCardsList!.first.backgroundImageUrlAr ?? "https://www.hmg.com/Lists/CS_Greeting_Cards/Attachments/5/CS_Ramadan_26.jpg")
: (model.greetingCardsList!.first.backgroundImageUrlEn ?? "https://www.hmg.com/Lists/CS_Greeting_Cards/Attachments/5/CS_Ramadan_26.jpg"),
fit: BoxFit.cover,
placeholderBuilder: (context) => ClipRRect(borderRadius: BorderRadius.circular(18), child: Container(height: 80, color: Colors.white).toShimmer()),
).onPress(() {
launchUrl(Uri.parse(AppState().isArabic(context) ? model.greetingCardsList!.first.urlAr! : model.greetingCardsList!.first.urlEn!));
}),
);
} else {
return const SizedBox();
}
},
).paddingOnly(bottom: 24, left: 24, right: 24),
// eventActivityWidget(context),
if (isDisplayMazaya) ...[ if (isDisplayMazaya) ...[
Column( Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
@ -461,70 +483,70 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
flex: 2, flex: 2,
child: RichText( child: RichText(
text: text:
AppState().isArabic(context) AppState().isArabic(context)
? TextSpan( ? TextSpan(
children: [ children: [
TextSpan( TextSpan(
text: 'اطلع على مميزات', text: 'اطلع على مميزات',
style: TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
letterSpacing: -0.2, letterSpacing: -0.2,
fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins', fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins',
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,
height: 24 / 16, height: 24 / 16,
color: Color(0xFF5D5E5E), color: const Color(0xFF5D5E5E),
), ),
), ),
TextSpan( TextSpan(
text: ' مزايا', text: ' مزايا',
style: TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins', fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins',
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,
letterSpacing: -0.2, letterSpacing: -0.2,
height: 24 / 16, height: 24 / 16,
color: MyColors.mazayaRedColor, // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed color: MyColors.mazayaRedColor, // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed
), ),
), ),
], ],
) )
: TextSpan( : TextSpan(
children: [ children: [
TextSpan( TextSpan(
text: LocaleKeys.explore.tr() + ' ', text: LocaleKeys.explore.tr() + ' ',
style: const TextStyle( style: const TextStyle(
fontSize: 16, fontSize: 16,
letterSpacing: -0.2, letterSpacing: -0.2,
fontFamily: 'Poppins', fontFamily: 'Poppins',
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,
height: 24 / 16, height: 24 / 16,
color: Color(0xFF5D5E5E), color: Color(0xFF5D5E5E),
), ),
), ),
TextSpan( TextSpan(
text: LocaleKeys.mazaya.tr(), text: LocaleKeys.mazaya.tr(),
style: const TextStyle( style: const TextStyle(
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,
fontFamily: 'Poppins', fontFamily: 'Poppins',
letterSpacing: -0.2, letterSpacing: -0.2,
height: 24 / 16, height: 24 / 16,
color: MyColors.mazayaRedColor, // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed color: MyColors.mazayaRedColor, // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed
), ),
), ),
TextSpan( TextSpan(
text: ' ' + LocaleKeys.benefits.tr(), text: ' ' + LocaleKeys.benefits.tr(),
style: const TextStyle( style: const TextStyle(
fontSize: 16, fontSize: 16,
letterSpacing: -0.2, letterSpacing: -0.2,
fontFamily: 'Poppins', fontFamily: 'Poppins',
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,
height: 24 / 16, height: 24 / 16,
color: Color(0xFF5D5E5E), color: Color(0xFF5D5E5E),
), ),
), ),
], ],
), ),
), ),
), ),
const Expanded(flex: 1, child: SizedBox()), const Expanded(flex: 1, child: SizedBox()),
@ -577,12 +599,10 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
LocaleKeys.discounts.tr().toText24(isBold: true), LocaleKeys.discounts.tr().toText24(isBold: true),
6.width, 6.width,
Container( Container(
padding: const EdgeInsets.only(left: 8, right: 8), padding: const EdgeInsets.only(left: 8, right: 8),
decoration: BoxDecoration( decoration: BoxDecoration(color: MyColors.yellowColor, borderRadius: BorderRadius.circular(10)),
color: MyColors.yellowColor, child: LocaleKeys.newString.tr().toText10(isBold: true),
borderRadius: BorderRadius.circular(10), ),
),
child: LocaleKeys.newString.tr().toText10(isBold: true)),
], ],
), ),
], ],
@ -590,7 +610,7 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
), ),
LocaleKeys.viewAllOffers.tr().toText12(isUnderLine: true).onPress(() { LocaleKeys.viewAllOffers.tr().toText12(isUnderLine: true).onPress(() {
Navigator.pushNamed(context, AppRoutes.offersAndDiscounts); Navigator.pushNamed(context, AppRoutes.offersAndDiscounts);
}) }),
], ],
).paddingOnly(left: 21, right: 21), ).paddingOnly(left: 21, right: 21),
Consumer<DashboardProviderModel>( Consumer<DashboardProviderModel>(
@ -598,59 +618,54 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
return SizedBox( return SizedBox(
height: 103 + 33, height: 103 + 33,
child: ListView.separated( child: ListView.separated(
shrinkWrap: true, shrinkWrap: true,
physics: const BouncingScrollPhysics(), physics: const BouncingScrollPhysics(),
padding: const EdgeInsets.only(left: 21, right: 21, top: 13), padding: const EdgeInsets.only(left: 21, right: 21, top: 13),
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext cxt, int index) { itemBuilder: (BuildContext cxt, int index) {
return model.isOffersLoading return model.isOffersLoading
? const OffersShimmerWidget() ? const OffersShimmerWidget()
: InkWell( : InkWell(
onTap: () { onTap: () {
navigateToDetails(data.getOffersList[index]); navigateToDetails(data.getOffersList[index]);
}, },
child: SizedBox( child: SizedBox(
width: 73, width: 73,
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Container( Container(
width: 73, width: 73,
height: 73, height: 73,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: const BorderRadius.all( borderRadius: const BorderRadius.all(Radius.circular(100)),
Radius.circular(100), border: Border.all(color: MyColors.lightGreyE3Color, width: 1),
),
border: Border.all(color: MyColors.lightGreyE3Color, width: 1),
),
child: ClipRRect(
borderRadius: const BorderRadius.all(
Radius.circular(50),
), ),
child: Hero( child: ClipRRect(
tag: "ItemImage" + data.getOffersList[index].offersDiscountId.toString()!, borderRadius: const BorderRadius.all(Radius.circular(50)),
transitionOnUserGestures: true, child: Hero(
child: Image.network( tag: "ItemImage" + data.getOffersList[index].offersDiscountId.toString()!,
data.getOffersList[index].logo ?? "", transitionOnUserGestures: true,
fit: BoxFit.contain, child: Image.network(data.getOffersList[index].logo ?? "", fit: BoxFit.contain),
), ),
), ),
), ),
), 4.height,
4.height, Expanded(
Expanded( child:
child: AppState().isArabic(context) AppState().isArabic(context)
? data.getOffersList[index].titleAr!.toText12(isCenter: true, maxLine: 1) ? data.getOffersList[index].titleAr!.toText12(isCenter: true, maxLine: 1)
: data.getOffersList[index].titleEn!.toText12(isCenter: true, maxLine: 1), : data.getOffersList[index].titleEn!.toText12(isCenter: true, maxLine: 1),
), ),
], ],
),
), ),
), );
); },
}, separatorBuilder: (BuildContext cxt, int index) => 8.width,
separatorBuilder: (BuildContext cxt, int index) => 8.width, itemCount: 9,
itemCount: 9), ),
); );
}, },
), ),
@ -773,28 +788,28 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
SvgPicture.asset( SvgPicture.asset(
"assets/icons/chat/chat.svg", "assets/icons/chat/chat.svg",
color: color:
!checkIfPrivilegedForChat() !checkIfPrivilegedForChat()
? MyColors.lightGreyE3Color ? MyColors.lightGreyE3Color
: currentIndex == 4 : currentIndex == 4
? MyColors.grey3AColor ? MyColors.grey3AColor
: cProvider.disbaleChatForThisUser : cProvider.disbaleChatForThisUser
? MyColors.lightGreyE3Color ? MyColors.lightGreyE3Color
: MyColors.grey98Color, : MyColors.grey98Color,
).paddingAll(4), ).paddingAll(4),
Consumer<ChatProviderModel>( Consumer<ChatProviderModel>(
builder: (BuildContext cxt, ChatProviderModel data, Widget? child) { builder: (BuildContext cxt, ChatProviderModel data, Widget? child) {
return !checkIfPrivilegedForChat() return !checkIfPrivilegedForChat()
? const SizedBox() ? const SizedBox()
: Positioned( : Positioned(
right: 0, right: 0,
top: 0, top: 0,
child: Container( child: Container(
padding: const EdgeInsets.only(left: 4, right: 4), padding: const EdgeInsets.only(left: 4, right: 4),
alignment: Alignment.center, alignment: Alignment.center,
decoration: BoxDecoration(color: cProvider.disbaleChatForThisUser ? MyColors.pinkDarkColor : MyColors.redColor, borderRadius: BorderRadius.circular(17)), decoration: BoxDecoration(color: cProvider.disbaleChatForThisUser ? MyColors.pinkDarkColor : MyColors.redColor, borderRadius: BorderRadius.circular(17)),
child: data.chatUConvCounter.toString().toText10(color: Colors.white), child: data.chatUConvCounter.toString().toText10(color: Colors.white),
), ),
); );
}, },
), ),
], ],
@ -865,4 +880,4 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
} }
return false; return false;
} }
} }

@ -49,32 +49,18 @@ class _AppDrawerState extends State<AppDrawer> {
children: <Widget>[ children: <Widget>[
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [Image.asset("assets/images/logos/main_mohemm_logo.png", width: 134, height: 24), const Icon(Icons.clear).onPress(() => Navigator.pop(context))],
Image.asset("assets/images/logos/main_mohemm_logo.png", width: 134, height: 24),
const Icon(Icons.clear).onPress(() => Navigator.pop(context)),
],
).paddingOnly(left: 4, right: 14), ).paddingOnly(left: 4, right: 14),
Row( Row(
children: [ children: [
AppState().memberInformationList!.eMPLOYEEIMAGE == null AppState().memberInformationList!.eMPLOYEEIMAGE == null
? SvgPicture.asset( ? SvgPicture.asset("assets/images/user.svg", height: 52, width: 52)
"assets/images/user.svg", : CircleAvatar(radius: 52 / 2, backgroundImage: MemoryImage(Utils.dataFromBase64String(AppState().memberInformationList!.eMPLOYEEIMAGE!)), backgroundColor: Colors.black),
height: 52,
width: 52,
)
: CircleAvatar(
radius: 52 / 2,
backgroundImage: MemoryImage(Utils.dataFromBase64String(AppState().memberInformationList!.eMPLOYEEIMAGE!)),
backgroundColor: Colors.black,
),
12.width, 12.width,
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [AppState().memberInformationList!.eMPLOYEENAME!.toText18(isBold: true), AppState().memberInformationList!.getPositionName().toText14(weight: FontWeight.w500)],
AppState().memberInformationList!.eMPLOYEENAME!.toText18(isBold: true), ).expanded,
AppState().memberInformationList!.getPositionName().toText14(weight: FontWeight.w500),
],
).expanded
], ],
).paddingOnly(left: 14, right: 14, top: 21, bottom: 21), ).paddingOnly(left: 14, right: 14, top: 21, bottom: 21),
// Row( // Row(
@ -99,67 +85,77 @@ class _AppDrawerState extends State<AppDrawer> {
// ), // ),
// ], // ],
// ).paddingOnly(left: 14, right: 14, bottom: 14), // ).paddingOnly(left: 14, right: 14, bottom: 14),
const Divider( const Divider(height: 1, thickness: 1, color: MyColors.lightGreyEFColor),
height: 1,
thickness: 1,
color: MyColors.lightGreyEFColor,
),
ListView( ListView(
padding: const EdgeInsets.only(top: 21, bottom: 21), padding: const EdgeInsets.only(top: 21, bottom: 21),
children: [ children: [
ListView.builder( ListView.builder(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
shrinkWrap: true, shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
itemCount: drawerMenuItemList.length, itemCount: drawerMenuItemList.length,
itemBuilder: (cxt, index) { itemBuilder: (cxt, index) {
return menuItem(drawerMenuItemList[index].icon, drawerMenuItemList[index].title, drawerMenuItemList[index].routeName, onPress: () { return menuItem(
drawerMenuItemList[index].icon,
drawerMenuItemList[index].title,
drawerMenuItemList[index].routeName,
onPress: () {
Navigator.pushNamed(context, drawerMenuItemList[index].routeName); Navigator.pushNamed(context, drawerMenuItemList[index].routeName);
}); },
}), );
},
),
menuItem("assets/images/drawer/employee_id.svg", LocaleKeys.employeeDigitalID.tr(), "", closeDrawer: false, onPress: () => showMDialog(context, child: EmployeeDigitialIdDialog())), menuItem("assets/images/drawer/employee_id.svg", LocaleKeys.employeeDigitalID.tr(), "", closeDrawer: false, onPress: () => showMDialog(context, child: EmployeeDigitialIdDialog())),
if (AppState().businessCardPrivilege) if (AppState().businessCardPrivilege)
menuItem("assets/images/drawer/view_business_card.svg", LocaleKeys.viewBusinessCard.tr(), "", closeDrawer: false, onPress: () => showMDialog(context, child: BusinessCardDialog(), isBusniessCard: true)), menuItem(
menuItem("assets/images/drawer/logout.svg", LocaleKeys.logout.tr(), "", color: MyColors.redA3Color, closeDrawer: false, onPress: (){Utils.performLogout(context, chatData);}), "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: () async {
await Utils.performLogout(context, chatData);
},
),
// menuItem("assets/images/drawer/logout.svg", LocaleKeys.logout.tr(), "", color: MyColors.redA3Color, closeDrawer: false, onPress: () {Navigator.pushNamed(context, AppRoutes.survey,); // menuItem("assets/images/drawer/logout.svg", LocaleKeys.logout.tr(), "", color: MyColors.redA3Color, closeDrawer: false, onPress: () {Navigator.pushNamed(context, AppRoutes.survey,);
], ],
).expanded, ).expanded,
const Divider( const Divider(height: 1, thickness: 1, color: MyColors.lightGreyEFColor),
height: 1,
thickness: 1,
color: MyColors.lightGreyEFColor,
),
Row( Row(
children: [ children: [
RichText( RichText(
text: TextSpan(text: LocaleKeys.poweredBy.tr() + " ", style: const TextStyle(color: MyColors.grey98Color, fontSize: 14, letterSpacing: -0.56, fontWeight: FontWeight.w600), children: [ text: TextSpan(
TextSpan( text: LocaleKeys.poweredBy.tr() + " ",
text: LocaleKeys.cloudSolutions.tr(), style: const TextStyle(color: MyColors.grey98Color, fontSize: 14, letterSpacing: -0.56, fontWeight: FontWeight.w600),
style: const TextStyle(color: MyColors.grey3AColor, fontSize: 14, letterSpacing: -0.56, fontWeight: FontWeight.w600), children: [TextSpan(text: LocaleKeys.cloudSolutions.tr(), style: const TextStyle(color: MyColors.grey3AColor, fontSize: 14, letterSpacing: -0.56, fontWeight: FontWeight.w600))],
), ),
]),
).expanded, ).expanded,
Image.asset("assets/images/logos/bn_cloud_soloution.jpg", width: 40, height: 40) Image.asset("assets/images/logos/bn_cloud_soloution.jpg", width: 40, height: 40),
], ],
).paddingOnly(left: 21, right: 21, top: 21) ).paddingOnly(left: 21, right: 21, top: 21),
], ],
).paddingOnly(top: 21, bottom: 21), ).paddingOnly(top: 21, bottom: 21),
); );
} }
Widget menuItem(String icon, String title, String routeName, {Color? color, bool closeDrawer = true, VoidCallback? onPress}) { Widget menuItem(String icon, String title, String routeName, {Color? color, bool closeDrawer = true, VoidCallback? onPress}) {
return Row( return Row(children: [SvgPicture.asset(icon, height: 20, width: 20), 9.width, title.toText14(color: color, textAlign: AppState().isArabic(context) ? TextAlign.right : null).expanded])
children: [ .paddingOnly(left: 21, top: 10, bottom: 10, right: 21)
SvgPicture.asset(icon, height: 20, width: 20), .onPress(
9.width, closeDrawer
title.toText14(color: color, textAlign: AppState().isArabic(context) ? TextAlign.right : null).expanded, ? () async {
], Navigator.pop(context);
).paddingOnly(left: 21, top: 10, bottom: 10, right: 21).onPress(closeDrawer Future.delayed(const Duration(microseconds: 200), onPress);
? () async { }
Navigator.pop(context); : onPress!,
Future.delayed(const Duration(microseconds: 200), onPress); );
}
: onPress!);
} }
void postLanguageChange(BuildContext context) { void postLanguageChange(BuildContext context) {
@ -171,13 +167,13 @@ class _AppDrawerState extends State<AppDrawer> {
setState(() {}); setState(() {});
} }
// void performLogout() async { void performLogout() async {
// // AppState().isAuthenticated = false; AppState().isAuthenticated = false;
// // AppState().isLogged = false; AppState().isLogged = false;
// // AppState().setPostParamsInitConfig(); AppState().setPostParamsInitConfig();
// // chatData.disposeData(); chatData.disposeData();
// // // SharedPreferences prefs = await SharedPreferences.getInstance(); // SharedPreferences prefs = await SharedPreferences.getInstance();
// // // await prefs.clear(); // await prefs.clear();
// // Navigator.pushNamedAndRemoveUntil(context, AppRoutes.login, (Route<dynamic> route) => false, arguments: null); Navigator.pushNamedAndRemoveUntil(context, AppRoutes.login, (Route<dynamic> route) => false, arguments: null);
// } }
} }

@ -8,6 +8,7 @@ import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/extensions/string_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/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/models/eit/get_eit_transaction_model.dart';
import 'package:mohem_flutter_app/models/sso_auth_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/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/dynamic_screens/dynamic_listview_screen.dart';
@ -122,28 +123,28 @@ class MenusWidget extends StatelessWidget {
], ],
).paddingOnly(left: 10, right: 10, bottom: 6, top: 6), ).paddingOnly(left: 10, right: 10, bottom: 6, top: 6),
).onPress(() async { ).onPress(() async {
Navigator.pushNamed(context, AppRoutes.dynamicScreen, arguments: DynamicListViewParams(LocaleKeys.ticketBalance.tr(), "HMG_TKT_NEW_EIT_SS")); // Navigator.pushNamed(context, AppRoutes.dynamicScreen, arguments: DynamicListViewParams(LocaleKeys.ticketBalance.tr(), "HMG_TKT_NEW_EIT_SS"));
// var pro = Provider.of<DashboardProviderModel>(context, listen: false); var pro = Provider.of<DashboardProviderModel>(context, listen: false);
//
// // if (menuEntry.menuName == "HMG_TICKET_REQUESTS") { // if (menuEntry.menuName == "HMG_TICKET_REQUESTS") {
// Utils.showLoading(context); Utils.showLoading(context);
// //Ticket Work //Ticket Work
// if (pro.ticketBookingResponse != null && pro.ticketBookingResponse!.success) { if (pro.ticketBookingResponse != null && pro.ticketBookingResponse!.success) {
// SSOAuthModel? ssoToken = await pro.fetchSSOAuthRedirection(clientID: pro.ticketBookingResponse!.clientId); SSOAuthModel? ssoToken = await pro.fetchSSOAuthRedirection(clientID: pro.ticketBookingResponse!.clientId);
// if (ssoToken != null) { if (ssoToken != null) {
// dynamic url = await pro.fetchURLRedirection(token: ssoToken.data!.accessToken!); dynamic url = await pro.fetchURLRedirection(token: ssoToken.data!.accessToken!);
// await pro.fetchTicketAccuralBalance(context, DateTime.now()); await pro.fetchTicketAccuralBalance(context, DateTime.now());
// pro.ticketHistoryTransactionList = await EITApiClient().getEITTransactions("HMG_TICKET_ITENARY_HR_EIT_SS", isCompleteList: true); pro.ticketHistoryTransactionList = await EITApiClient().getEITTransactions("HMG_TICKET_ITENARY_HR_EIT_SS", isCompleteList: true);
//
// Utils.hideLoading(context); Utils.hideLoading(context);
// // Here Need Work // Here Need Work
// Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => TicketDetailedScreen(url: url, jwtToken: ssoToken.data!.accessToken))); Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => TicketDetailedScreen(url: url, jwtToken: ssoToken.data!.accessToken)));
// } }
// //} //}
// } else { } else {
// Navigator.pushNamed(context, AppRoutes.dynamicScreen, arguments: DynamicListViewParams(LocaleKeys.ticketBalance.tr(), "HMG_TKT_NEW_EIT_SS")); Navigator.pushNamed(context, AppRoutes.dynamicScreen, arguments: DynamicListViewParams(LocaleKeys.ticketBalance.tr(), "HMG_TKT_NEW_EIT_SS"));
// } }
}), }),
], ],
); );

@ -92,7 +92,7 @@ class ServicesWidget extends StatelessWidget {
aspectRatio: 105 / 105, aspectRatio: 105 / 105,
child: child:
data.isServicesMenusLoading data.isServicesMenusLoading
? ServicesMenuShimmer() ? const ServicesMenuShimmer()
: Container( : Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
@ -266,7 +266,6 @@ class ServicesWidget extends StatelessWidget {
await pro.fetchTicketAccuralBalance(context, DateTime.now()); await pro.fetchTicketAccuralBalance(context, DateTime.now());
pro.ticketHistoryTransactionList = await EITApiClient().getEITTransactions("HMG_TICKET_ITENARY_HR_EIT_SS", isCompleteList: true); pro.ticketHistoryTransactionList = await EITApiClient().getEITTransactions("HMG_TICKET_ITENARY_HR_EIT_SS", isCompleteList: true);
Utils.hideLoading(context); Utils.hideLoading(context);
// Here Need Work // Here Need Work
Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => TicketDetailedScreen(url: url, jwtToken: ssoToken.data!.accessToken))); 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), padding: const EdgeInsets.only(left: 21, right: 21, top: 13, bottom: 13),
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
itemBuilder: (cxt, index) { itemBuilder: (cxt, index) {
return AspectRatio(aspectRatio: 105 / 105, child: ServicesMenuShimmer()); return AspectRatio(aspectRatio: 105 / 105, child: const ServicesMenuShimmer());
}, },
separatorBuilder: (cxt, index) => 9.width, separatorBuilder: (cxt, index) => 9.width,
itemCount: 4, itemCount: 4,

@ -192,10 +192,78 @@ class _MowadhafhiHRRequestState extends State<MowadhafhiHRRequest> {
title.toText16().expanded, title.toText16().expanded,
6.width, 6.width,
SimpleButton(LocaleKeys.add.tr(), () async { SimpleButton(LocaleKeys.add.tr(), () async {
FilePickerResult? result = await FilePicker.platform.pickFiles(allowMultiple: true); FilePickerResult? result = await FilePicker.platform.pickFiles(
allowMultiple: true,
);
if (result != null) { if (result != null) {
attachmentFiles = attachmentFiles + result.paths.map((path) => File(path!)).toList(); // Maximum file size: 2 MB (in bytes)
attachmentFiles = attachmentFiles.toSet().toList(); const int maxFileSizeInBytes = 2 * 1024 * 1024; // 2 MB = 2097152 bytes
List<File> newFiles = [];
List<String> oversizedFiles = [];
for (PlatformFile platformFile in result.files) {
if (platformFile.path != null) {
File file = File(platformFile.path!);
// Get file size - check multiple sources for iOS compatibility
int fileSize = 0;
// Method 1: Check platformFile.size first
if (platformFile.size > 0) {
fileSize = platformFile.size;
debugPrint('Using platformFile.size: $fileSize bytes');
}
// Method 2: Always verify with file.length() as well
try {
int fileLengthSize = await file.length();
debugPrint('Using file.length(): $fileLengthSize bytes');
// Use the maximum of both to ensure we catch the real size
if (fileLengthSize > fileSize) {
fileSize = fileLengthSize;
debugPrint('Using larger value from file.length()');
}
} catch (e) {
debugPrint('Error getting file.length(): $e');
// If file.length() fails, rely on platformFile.size
if (fileSize == 0) {
debugPrint('Cannot determine file size, rejecting file: ${platformFile.name}');
oversizedFiles.add('${platformFile.name} (unknown size)');
continue;
}
}
double fileSizeMB = fileSize / (1024 * 1024);
debugPrint('Final file size - ${platformFile.name}: $fileSize bytes (${fileSizeMB.toStringAsFixed(2)} MB)');
// STRICT validation: Only accept files that are 2 MB or less
if (fileSize > 0 && fileSize <= maxFileSizeInBytes) {
debugPrint('✓ File accepted: ${platformFile.name}');
newFiles.add(file);
} else if (fileSize > maxFileSizeInBytes) {
debugPrint('✗ File REJECTED (too large): ${platformFile.name} - ${fileSizeMB.toStringAsFixed(2)} MB');
oversizedFiles.add('${platformFile.name} (${fileSizeMB.toStringAsFixed(2)} MB)');
} else {
debugPrint('✗ File REJECTED (invalid size): ${platformFile.name}');
oversizedFiles.add('${platformFile.name} (invalid)');
}
}
}
// Only add valid files
if (newFiles.isNotEmpty) {
attachmentFiles = attachmentFiles + newFiles;
attachmentFiles = attachmentFiles.toSet().toList();
debugPrint('Total files attached: ${attachmentFiles.length}');
}
// Show error message for rejected files
if (oversizedFiles.isNotEmpty) {
String fileList = oversizedFiles.join('\n');
Utils.showToast('Max 2MB File allowed.');
debugPrint('Total rejected files: ${oversizedFiles.length}');
}
setState(() {}); setState(() {});
} }
}, fontSize: 14), }, fontSize: 14),

@ -5,15 +5,17 @@ import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/app_state/app_state.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/colors.dart';
import 'package:mohem_flutter_app/classes/date_uitl.dart'; import 'package:mohem_flutter_app/classes/date_uitl.dart';
import 'package:mohem_flutter_app/classes/file_process.dart';
import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/classes/utils.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/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_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/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/models/dashboard/get_accural_ticket_balance_model.dart'; import 'package:mohem_flutter_app/models/dashboard/get_accural_ticket_balance_model.dart';
import 'package:mohem_flutter_app/models/eit/get_eit_transaction_model.dart';
import 'package:mohem_flutter_app/models/eit_attachment_ticket_model.dart';
import 'package:mohem_flutter_app/provider/dashboard_provider_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/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/button/default_button.dart';
import 'package:mohem_flutter_app/widgets/item_detail_view_widget.dart'; import 'package:mohem_flutter_app/widgets/item_detail_view_widget.dart';
import 'package:mohem_flutter_app/widgets/sso_webview_widget.dart'; import 'package:mohem_flutter_app/widgets/sso_webview_widget.dart';
@ -113,9 +115,8 @@ class _TicketDetailedScreenState extends State<TicketDetailedScreen> {
), ),
), ),
const SizedBox(height: 21), const SizedBox(height: 21),
dashboardProviderModel == null && dashboardProviderModel!.ticketHistoryTransactionList == null (dashboardProviderModel != null && dashboardProviderModel!.ticketHistoryTransactionList != null && dashboardProviderModel!.ticketHistoryTransactionList!.isNotEmpty)
? const SizedBox() ? ListView(
: ListView(
shrinkWrap: true, shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
children: <Widget>[ children: <Widget>[
@ -126,8 +127,8 @@ class _TicketDetailedScreenState extends State<TicketDetailedScreen> {
shrinkWrap: true, shrinkWrap: true,
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
itemBuilder: (BuildContext cxt, int cardIndex) { itemBuilder: (BuildContext cxt, int cardIndex) {
var transactionDetails = dashboardProviderModel!.ticketHistoryTransactionList![cardIndex]; List<CollectionTransaction> transactionDetails = dashboardProviderModel!.ticketHistoryTransactionList![cardIndex];
const allowedSegmentNames = <String>{ const Set<String> allowedSegmentNames = <String>{
"TICKETS_ROUTE", "TICKETS_ROUTE",
"TRAVELER_NAME", "TRAVELER_NAME",
"TICKETS_EFFECTIVE_DATE", "TICKETS_EFFECTIVE_DATE",
@ -136,11 +137,22 @@ class _TicketDetailedScreenState extends State<TicketDetailedScreen> {
"TICKET_COMP_SHARE", "TICKET_COMP_SHARE",
"TICKET_EMP_SHARE", "TICKET_EMP_SHARE",
}; };
var uniqueDetails = // Get items for display
List<CollectionTransaction> uniqueDetails =
transactionDetails transactionDetails
.where((item) => item.dISPLAYFLAG != 'N' && item.sEGMENTPROMPT != null && item.sEGMENTPROMPT!.isNotEmpty && allowedSegmentNames.contains(item.sEGMENTNAME)) .where(
(CollectionTransaction item) =>
item.dISPLAYFLAG != 'N' && item.sEGMENTPROMPT != null && item.sEGMENTPROMPT!.isNotEmpty && allowedSegmentNames.contains(item.sEGMENTNAME),
)
.toList(); .toList();
// Get PEI_EXTRA_INFO_ID value for View PDF
CollectionTransaction? peiExtraInfoItem = transactionDetails.firstWhere(
(CollectionTransaction item) => item.aPPLICATIONCOLUMNNAME == "PEI_EXTRA_INFO_ID",
orElse: () => CollectionTransaction(),
);
num? peiExtraInfoId = peiExtraInfoItem.nUMBERVALUE;
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
@ -149,15 +161,15 @@ class _TicketDetailedScreenState extends State<TicketDetailedScreen> {
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true, shrinkWrap: true,
itemCount: (uniqueDetails.length / 2).ceil(), itemCount: (uniqueDetails.length / 2).ceil(),
itemBuilder: (context, rowIndex) { itemBuilder: (BuildContext context, int rowIndex) {
int firstIndex = rowIndex * 2; int firstIndex = rowIndex * 2;
int? secondIndex = (firstIndex + 1 < uniqueDetails.length) ? firstIndex + 1 : null; int? secondIndex = (firstIndex + 1 < uniqueDetails.length) ? firstIndex + 1 : null;
bool isLastRow = (rowIndex == (uniqueDetails.length / 2).ceil() - 1); bool isLastRow = (rowIndex == (uniqueDetails.length / 2).ceil() - 1);
var item1 = uniqueDetails[firstIndex]; CollectionTransaction item1 = uniqueDetails[firstIndex];
var child1 = ItemDetailViewCol(item1.sEGMENTPROMPT!, item1.vARCHAR2VALUE ?? item1.nUMBERVALUE?.toString() ?? ""); ItemDetailViewCol child1 = ItemDetailViewCol(item1.sEGMENTPROMPT!, item1.vARCHAR2VALUE ?? item1.nUMBERVALUE?.toString() ?? "");
Widget child2; Widget child2;
if (secondIndex != null) { if (secondIndex != null) {
var item2 = uniqueDetails[secondIndex]; CollectionTransaction item2 = uniqueDetails[secondIndex];
child2 = ItemDetailViewCol(item2.sEGMENTPROMPT!, item2.vARCHAR2VALUE ?? item2.nUMBERVALUE?.toString() ?? ""); child2 = ItemDetailViewCol(item2.sEGMENTPROMPT!, item2.vARCHAR2VALUE ?? item2.nUMBERVALUE?.toString() ?? "");
} else { } else {
child2 = const SizedBox(); // Empty widget if there is no second item child2 = const SizedBox(); // Empty widget if there is no second item
@ -165,6 +177,40 @@ class _TicketDetailedScreenState extends State<TicketDetailedScreen> {
return ItemDetailGrid(child1, child2, isItLast: isLastRow); return ItemDetailGrid(child1, child2, isItLast: isLastRow);
}, },
), ),
// View PDF link at the bottom
if (peiExtraInfoId != null) ...[
const SizedBox(height: 5),
Align(
alignment: Alignment.centerRight,
child: GestureDetector(
onTap: () async {
Utils.showLoading(context);
try {
GetEitAttachmentTicket? result = await dashboardProviderModel!.getTicketEitPDFDownload(peiExtraInfoId: peiExtraInfoId.toString());
if (result != null && result.getEitAttachmentList != null && result.getEitAttachmentList!.isNotEmpty) {
String? base64Data = result.getEitAttachmentList!.first.fileData;
if (base64Data != null && base64Data.isNotEmpty) {
String fileName = result.getEitAttachmentList!.first.fileName!;
await FileProcess.downloadFile(base64Data, fileName);
Utils.hideLoading(context);
FileProcess.openFile(fileName);
} else {
Utils.hideLoading(context);
Utils.showToast("PDF data not available");
}
} else {
Utils.hideLoading(context);
Utils.showToast("No attachment found");
}
} catch (e) {
Utils.hideLoading(context);
Utils.showToast("Something Went Wrong");
}
},
child: Padding(padding: const EdgeInsets.only(top: 8.0, left: 0.0, bottom: 8.0), child: "View PDF".toText14(isUnderLine: true, isBold: true)),
),
),
],
], ],
).objectContainerView(); ).objectContainerView();
}, },
@ -172,7 +218,8 @@ class _TicketDetailedScreenState extends State<TicketDetailedScreen> {
itemCount: dashboardProviderModel!.ticketHistoryTransactionList!.length, itemCount: dashboardProviderModel!.ticketHistoryTransactionList!.length,
), ),
], ],
), )
: const SizedBox(),
], ],
], ],
).expanded, ).expanded,

@ -8,6 +8,8 @@ import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:shimmer/shimmer.dart'; import 'package:shimmer/shimmer.dart';
class GetAttendanceTrackingShimmer extends StatelessWidget { class GetAttendanceTrackingShimmer extends StatelessWidget {
const GetAttendanceTrackingShimmer({Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
@ -17,13 +19,7 @@ class GetAttendanceTrackingShimmer extends StatelessWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.circular(15), borderRadius: BorderRadius.circular(15),
boxShadow: [ boxShadow: [BoxShadow(color: const Color(0xff000000).withOpacity(.05), blurRadius: 26, offset: const Offset(0, -3))],
BoxShadow(
color: const Color(0xff000000).withOpacity(.05),
blurRadius: 26,
offset: const Offset(0, -3),
),
],
), ),
child: Stack( child: Stack(
alignment: Alignment.center, alignment: Alignment.center,
@ -44,15 +40,8 @@ class GetAttendanceTrackingShimmer extends StatelessWidget {
LocaleKeys.timeLeftToday.tr().toText10(color: Colors.white).toShimmer(), LocaleKeys.timeLeftToday.tr().toText10(color: Colors.white).toShimmer(),
9.height, 9.height,
const ClipRRect( const ClipRRect(
borderRadius: BorderRadius.all( borderRadius: BorderRadius.all(Radius.circular(20)),
Radius.circular(20), child: LinearProgressIndicator(value: 0.7, minHeight: 8, valueColor: const AlwaysStoppedAnimation<Color>(Colors.white), backgroundColor: const Color(0xff196D73)),
),
child: LinearProgressIndicator(
value: 0.7,
minHeight: 8,
valueColor: const AlwaysStoppedAnimation<Color>(Colors.white),
backgroundColor: const Color(0xff196D73),
),
).toShimmer(), ).toShimmer(),
], ],
).paddingOnly(top: 12, right: 15, left: 12), ).paddingOnly(top: 12, right: 15, left: 12),
@ -63,9 +52,7 @@ class GetAttendanceTrackingShimmer extends StatelessWidget {
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [LocaleKeys.checkIn.tr().toText12(color: Colors.white).toShimmer()],
LocaleKeys.checkIn.tr().toText12(color: Colors.white).toShimmer(),
],
).paddingOnly(left: 12), ).paddingOnly(left: 12),
), ),
Container( Container(
@ -85,6 +72,8 @@ class GetAttendanceTrackingShimmer extends StatelessWidget {
} }
class MenuShimmer extends StatelessWidget { class MenuShimmer extends StatelessWidget {
const MenuShimmer({Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
@ -92,13 +81,7 @@ class MenuShimmer extends StatelessWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.circular(15), borderRadius: BorderRadius.circular(15),
boxShadow: [ boxShadow: [BoxShadow(color: const Color(0xff000000).withOpacity(.05), blurRadius: 26, offset: const Offset(0, -3))],
BoxShadow(
color: const Color(0xff000000).withOpacity(.05),
blurRadius: 26,
offset: const Offset(0, -3),
),
],
), ),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
@ -107,14 +90,11 @@ class MenuShimmer extends StatelessWidget {
LocaleKeys.workList.tr().toText12(color: Colors.white).toShimmer(), LocaleKeys.workList.tr().toText12(color: Colors.white).toShimmer(),
Row( Row(
children: [ children: [
Expanded( Expanded(flex: 3, child: 123.toString().toText10(color: Colors.white, isBold: true).toShimmer()),
flex: 3,
child: 123.toString().toText10(color: Colors.white, isBold: true).toShimmer(),
),
12.width, 12.width,
SvgPicture.asset("assets/images/arrow_next.svg", color: Colors.white).toShimmer() SvgPicture.asset("assets/images/arrow_next.svg", color: Colors.white).toShimmer(),
], ],
) ),
], ],
).paddingOnly(left: 10, right: 10, bottom: 6, top: 6), ).paddingOnly(left: 10, right: 10, bottom: 6, top: 6),
); );
@ -122,6 +102,8 @@ class MenuShimmer extends StatelessWidget {
} }
class ServicesHeaderShimmer extends StatelessWidget { class ServicesHeaderShimmer extends StatelessWidget {
const ServicesHeaderShimmer({Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Row( return Row(
@ -131,11 +113,7 @@ class ServicesHeaderShimmer extends StatelessWidget {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [LocaleKeys.otherCharges.tr().toText10().toShimmer(), 6.height, LocaleKeys.services.tr().toText12(isBold: true).toShimmer()],
LocaleKeys.otherCharges.tr().toText10().toShimmer(),
6.height,
LocaleKeys.services.tr().toText12(isBold: true).toShimmer(),
],
), ),
), ),
LocaleKeys.viewAllServices.tr().toText12(isUnderLine: true).toShimmer(), LocaleKeys.viewAllServices.tr().toText12(isUnderLine: true).toShimmer(),
@ -145,19 +123,15 @@ class ServicesHeaderShimmer extends StatelessWidget {
} }
class ServicesMenuShimmer extends StatelessWidget { class ServicesMenuShimmer extends StatelessWidget {
const ServicesMenuShimmer({Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.circular(15), borderRadius: BorderRadius.circular(15),
boxShadow: [ boxShadow: [BoxShadow(color: const Color(0xff000000).withOpacity(.05), blurRadius: 26, offset: const Offset(0, -3))],
BoxShadow(
color: const Color(0xff000000).withOpacity(.05),
blurRadius: 26,
offset: const Offset(0, -3),
),
],
), ),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
@ -173,21 +147,54 @@ class ServicesMenuShimmer extends StatelessWidget {
Row( Row(
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
Expanded( Expanded(child: LocaleKeys.attendance.tr().toText11(isBold: false).toShimmer()),
child: LocaleKeys.attendance.tr().toText11(isBold: false).toShimmer(),
),
6.width, 6.width,
SvgPicture.asset("assets/images/arrow_next.svg").paddingOnly(bottom: 4).toShimmer() SvgPicture.asset("assets/images/arrow_next.svg").paddingOnly(bottom: 4).toShimmer(),
], ],
), ),
], ],
) ),
], ],
).paddingOnly(left: 10, right: 10, bottom: 10, top: 12), ).paddingOnly(left: 10, right: 10, bottom: 10, top: 12),
); );
} }
} }
class GreetingCardShimmer extends StatelessWidget {
const GreetingCardShimmer({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
height: 140,
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: [
const SizedBox(width: 10),
Container(width: 65, height: 100, decoration: BoxDecoration(color: Colors.grey[300], borderRadius: BorderRadius.circular(10))).toShimmer().paddingOnly(top: 10),
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(top: 14, bottom: 14);
}
}
class MarathonBannerShimmer extends StatelessWidget { class MarathonBannerShimmer extends StatelessWidget {
const MarathonBannerShimmer({Key? key}) : super(key: key); const MarathonBannerShimmer({Key? key}) : super(key: key);
@ -197,13 +204,7 @@ class MarathonBannerShimmer extends StatelessWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.circular(15), borderRadius: BorderRadius.circular(15),
boxShadow: [ boxShadow: [BoxShadow(color: const Color(0xff000000).withOpacity(.05), blurRadius: 26, offset: const Offset(0, -3))],
BoxShadow(
color: const Color(0xff000000).withOpacity(.05),
blurRadius: 26,
offset: const Offset(0, -3),
),
],
), ),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
@ -219,15 +220,13 @@ class MarathonBannerShimmer extends StatelessWidget {
Row( Row(
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
Expanded( Expanded(child: LocaleKeys.attendance.tr().toText11(isBold: false).toShimmer()),
child: LocaleKeys.attendance.tr().toText11(isBold: false).toShimmer(),
),
6.width, 6.width,
SvgPicture.asset("assets/images/arrow_next.svg").paddingOnly(bottom: 4).toShimmer() SvgPicture.asset("assets/images/arrow_next.svg").paddingOnly(bottom: 4).toShimmer(),
], ],
), ),
], ],
) ),
], ],
).paddingOnly(left: 10, right: 10, bottom: 10, top: 12), ).paddingOnly(left: 10, right: 10, bottom: 10, top: 12),
); );
@ -243,65 +242,43 @@ class ChatHomeShimmer extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
width: double.infinity, width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0), padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0),
child: Column( child: Column(
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
children: <Widget>[ children: <Widget>[
Expanded( Expanded(
child: Shimmer.fromColors( child: Shimmer.fromColors(
baseColor: Colors.white, baseColor: Colors.white,
highlightColor: Colors.grey.shade100, highlightColor: Colors.grey.shade100,
child: ListView.builder( child: ListView.builder(
itemBuilder: (_, __) => Padding( itemBuilder:
padding: const EdgeInsets.only(bottom: 8.0), (_, __) => Padding(
child: Row( padding: const EdgeInsets.only(bottom: 8.0),
crossAxisAlignment: CrossAxisAlignment.start, child: Row(
children: <Widget>[ crossAxisAlignment: CrossAxisAlignment.start,
if (!isDetailedScreen) children: <Widget>[
Container( if (!isDetailedScreen) Container(width: 48.0, height: 48.0, decoration: const BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(40)))),
width: 48.0, if (!isDetailedScreen) const Padding(padding: EdgeInsets.symmetric(horizontal: 8.0)),
height: 48.0, Column(
decoration: const BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(40))), crossAxisAlignment: CrossAxisAlignment.start,
), children: <Widget>[
if (!isDetailedScreen) Container(width: double.infinity, height: 20.0, color: Colors.white),
const Padding( const Padding(padding: EdgeInsets.symmetric(vertical: 2.0)),
padding: EdgeInsets.symmetric(horizontal: 8.0), Container(width: double.infinity, height: 15.0, color: Colors.white),
), const Padding(padding: EdgeInsets.symmetric(vertical: 2.0)),
Column( Container(width: 40.0, height: 10.0, color: Colors.white),
crossAxisAlignment: CrossAxisAlignment.start, ],
children: <Widget>[ ).expanded,
Container( ],
width: double.infinity, ),
height: 20.0,
color: Colors.white,
),
const Padding(
padding: EdgeInsets.symmetric(vertical: 2.0),
),
Container(
width: double.infinity,
height: 15.0,
color: Colors.white,
),
const Padding(
padding: EdgeInsets.symmetric(vertical: 2.0),
),
Container(
width: 40.0,
height: 10.0,
color: Colors.white,
),
],
).expanded
],
), ),
), itemCount: 6,
itemCount: 6,
),
), ),
), ),
], ),
)); ],
),
);
} }
} }

@ -49,7 +49,7 @@ class _SsoLoginWebViewState extends State<SsoLoginWebView> {
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<body onload="document.forms[0].submit()"> <body onload="document.forms[0].submit()">
<form method="POST" action="$url"> <form method="POST" action="https://www.paxes.com/sso/hmg">
<input type="hidden" name="JWTToken" value="${widget.jwtToken}" /> <input type="hidden" name="JWTToken" value="${widget.jwtToken}" />
</form> </form>
<h1>Redirecting...</h1> <h1>Redirecting...</h1>
@ -57,6 +57,7 @@ class _SsoLoginWebViewState extends State<SsoLoginWebView> {
</html>'''); </html>''');
} }
//// <form method="POST" action="${widget.url}">
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold(appBar: null, body:SafeArea(child: WebViewWidget(controller: _controller))); return Scaffold(appBar: null, body:SafeArea(child: WebViewWidget(controller: _controller)));

@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# Read more about iOS versioning at # Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # 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 #version: 3.9.3+1
environment: environment:

Loading…
Cancel
Save