Compare commits

..

No commits in common. 'master' and 'greeting_card' have entirely different histories.

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 31 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 31 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 730 KiB

@ -1,8 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="19.5" height="19.5" viewBox="0 0 19.5 19.5">
<g id="graduation-cap" transform="translate(0)">
<path id="cap-top" d="M9.75,4.5L3.5,7.5L9.75,10.5L16,7.5L9.75,4.5Z" fill="#2e303a"/>
<path id="cap-body" d="M4.5,8.5V13.5C4.5,14.5,6.5,16.5,9.75,16.5C13,16.5,15,14.5,15,13.5V8.5L9.75,11.5L4.5,8.5Z" fill="#2e303a"/>
<path id="tassel" d="M16,8V12.5L16.5,13L17,12.5V8H16Z" fill="#2e303a"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 457 B

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 1.2 MiB

@ -1,6 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32.774" height="32.788" viewBox="0 0 32.774 32.788">
<g id="park-tickets-couple" transform="translate(-0.205 0.001)">
<path id="Path_4724" data-name="Path 4724" d="M68.36,485.746a1.657,1.657,0,0,1-1.581,1.3.539.539,0,0,0-.206,1.025,1.656,1.656,0,0,1,.955,1.814l-.14.7a1.744,1.744,0,0,1-2.093,1.278c-.25-.06-.506-.106-.759-.156-.373-.073-.745-.15-1.118-.223-.493-.1-.985-.2-1.477-.3l-1.76-.353c-.655-.133-1.311-.263-1.967-.4-.7-.14-1.4-.279-2.1-.423-.719-.143-1.438-.289-2.153-.433l-2.133-.429-2.036-.409c-.622-.123-1.241-.25-1.863-.373-.539-.107-1.078-.216-1.614-.323l-1.291-.26-.888-.18c-.136-.027-.273-.057-.409-.083-.007,0-.013,0-.02,0a1.686,1.686,0,0,1-.12,1.062,1.705,1.705,0,0,1-1.87.958.5.5,0,0,0-.562.246l-.3.649a.5.5,0,0,0,.176.589c.033.027,24.018,11.084,24.058,11.094a.5.5,0,0,0,.562-.246l.3-.649a.5.5,0,0,0-.176-.589,1.7,1.7,0,0,1,1.388-3,.5.5,0,0,0,.562-.246l.3-.649a.5.5,0,0,0-.176-.589,1.7,1.7,0,0,1,1.388-3,.5.5,0,0,0,.562-.246l.3-.649a.5.5,0,0,0-.176-.589,1.7,1.7,0,0,1,1.388-3,.5.5,0,0,0,.562-.246l.329-.719a.41.41,0,0,0-.2-.546L68.416,485.5Z" transform="translate(-39.26 -469.349)" fill="#2bb8a6"/>
<path id="Path_4725" data-name="Path 4725" d="M.519,16.168c.04.02,25.932,5.214,25.975,5.214a.5.5,0,0,0,.489-.369l.14-.7a.5.5,0,0,0-.309-.532,1.7,1.7,0,0,1,.652-3.244.5.5,0,0,0,.489-.369l.1-.512.037-.19a.5.5,0,0,0-.309-.532,1.7,1.7,0,0,1,.652-3.244.5.5,0,0,0,.489-.369l.14-.7a.5.5,0,0,0-.309-.532,1.7,1.7,0,0,1,.652-3.244.5.5,0,0,0,.489-.369l.156-.775a.41.41,0,0,0-.323-.482S3.714,0,3.687,0a.412.412,0,0,0-.4.329L3.128,1.1a.5.5,0,0,0,.309.532A1.7,1.7,0,0,1,2.786,4.88.5.5,0,0,0,2.3,5.25l-.14.7a.5.5,0,0,0,.309.532,1.7,1.7,0,0,1-.652,3.244.5.5,0,0,0-.489.369l-.14.7a.5.5,0,0,0,.309.532A1.7,1.7,0,0,1,.842,14.57a.5.5,0,0,0-.489.369l-.14.7A.494.494,0,0,0,.519,16.168ZM22.7,7.639a.831.831,0,1,1,1.631.326l-1.1,5.464L22.555,16.8a.832.832,0,0,1-.815.669.9.9,0,0,1-.163-.017.833.833,0,0,1-.652-.978l.755-3.757ZM7.7,4.628a.831.831,0,0,1,1.631.326L8.948,6.84,8.519,8.98,8.173,10.7l-.616,3.081a.832.832,0,0,1-.815.669.9.9,0,0,1-.163-.017.4.4,0,0,1-.067-.017.829.829,0,0,1-.582-.962l.123-.622.323-1.611Z" fill="#125765"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

@ -1,16 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="23.959" height="37.006" viewBox="0 0 23.959 37.006">
<g id="Layer_x0020_1" transform="translate(-300.998)">
<g id="_411123120" transform="translate(301)">
<g id="Group_8657" data-name="Group 8657" transform="translate(3.252)">
<path id="Path_13674" data-name="Path 13674" d="M612.691,6.612H619.8V1.691h-7.111ZM620.669,8.3h-8.823A.833.833,0,0,1,611,7.458V.845A.847.847,0,0,1,611.846,0h8.823a.861.861,0,0,1,.845.845V7.458A.847.847,0,0,1,620.669,8.3Z" transform="translate(-607.531)" fill="#2bb8a6"/>
<path id="Path_13675" data-name="Path 13675" d="M466.845,305h15.089a.833.833,0,0,1,.845.845,5.44,5.44,0,0,1-5.42,5.441h-5.918A5.478,5.478,0,0,1,466,305.845.847.847,0,0,1,466.845,305Z" transform="translate(-465.675 -298.388)" fill="#2bb8a6"/>
<path id="Path_13676" data-name="Path 13676" d="M527.845,0A.861.861,0,0,0,527,.845a.847.847,0,0,0,.846.845h12.444a.851.851,0,0,0,.867-.845A.865.865,0,0,0,540.289,0Z" transform="translate(-525.352)" fill="#2bb8a6"/>
<g id="Group_8656" data-name="Group 8656" transform="translate(0 33.863)">
<path id="Path_13677" data-name="Path 13677" d="M455.553,1562v.867a2.276,2.276,0,1,1-4.553,0V1562h4.553Z" transform="translate(-451 -1562)" fill="#2bb8a6"/>
<path id="Path_13678" data-name="Path 13678" d="M1050.553,1562v.867a2.276,2.276,0,0,1-4.553,0V1562h4.553Z" transform="translate(-1033.101 -1562)" fill="#2bb8a6"/>
</g>
</g>
<path id="Subtraction_59" data-name="Subtraction 59" d="M20570.063,22681.4h-16.975a.817.817,0,0,1-.238-.023,3.388,3.388,0,0,1-2.236-1.018,3.476,3.476,0,0,1-1.02-2.471v-19.4a3.557,3.557,0,0,1,1.02-2.475,3.457,3.457,0,0,1,1.906-.975,1.745,1.745,0,0,0-.193.8,6.288,6.288,0,0,0,6.289,6.285h5.92a6.288,6.288,0,0,0,6.285-6.285,1.692,1.692,0,0,0-.217-.8,3.472,3.472,0,0,1,2.949,3.449v19.4a3.476,3.476,0,0,1-1.02,2.471,3.383,3.383,0,0,1-2.236,1.018A.879.879,0,0,1,20570.063,22681.4Zm-10.756-7.187a2.114,2.114,0,1,0,1.494.619A2.1,2.1,0,0,0,20559.307,22674.211Zm4.027.732-.613.621.961.939-.961.943.613.621.963-.949v0l.973.949.609-.621-.961-.943.961-.939-.609-.621-.973.951Zm-4.025-6.031a2.112,2.112,0,0,0-.807,4.063,2.071,2.071,0,0,0,.809.164,2.113,2.113,0,0,0,0-4.227Zm3.543,1.406-.645.584,1.531,1.7,2.637-2.6-.609-.619-1.992,1.963Zm-3.539-6.709a2.158,2.158,0,0,0-.486.059,2.111,2.111,0,1,0,.969,4.109,2.123,2.123,0,0,0,1.57-2.545A2.1,2.1,0,0,0,20559.313,22663.609Zm3.539,1.266-.645.58,1.531,1.7,2.637-2.6-.609-.619-1.992,1.963Z" transform="translate(-20549.596 -22648.381)" fill="#125765"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.5 KiB

@ -1 +0,0 @@
<?xml version="1.0" ?><svg id="Outline" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><defs><style>.cls-1{fill:#ffffff;}</style></defs><path style="fill: #FFF" class="cls-1" d="M376,170a11.34,11.34,0,0,0-16,.15L215.28,317.64l-64-65.22a11.34,11.34,0,0,0-16.18,15.88l72.16,73.58a11.35,11.35,0,0,0,16,.15,12,12,0,0,0,1.43-1.7l.4-.37,151-154A11.33,11.33,0,0,0,376,170Z"/><path style="fill: #FFF" class="cls-1" d="M256,58.65c-108.38,0-196.56,88.18-196.56,196.56S147.62,451.77,256,451.77,452.56,363.6,452.56,255.21,364.38,58.65,256,58.65Zm0,370.45c-95.88,0-173.88-78-173.88-173.89S160.12,81.33,256,81.33s173.88,78,173.88,173.88S351.88,429.1,256,429.1Z"/></svg>

Before

Width:  |  Height:  |  Size: 665 B

@ -1 +0,0 @@
<?xml version="1.0" ?><svg data-name="Livello 1" id="Livello_1" viewBox="0 0 128 128" xmlns="http://www.w3.org/2000/svg"><title/><path style="fill: #fff;" d="M64,0a64,64,0,1,0,64,64A64.07,64.07,0,0,0,64,0Zm0,122a58,58,0,1,1,58-58A58.07,58.07,0,0,1,64,122Z"/><path style="fill: #fff;" d="M92.12,35.79a3,3,0,0,0-4.24,0L64,59.75l-23.87-24A3,3,0,0,0,35.88,40L59.76,64,35.88,88a3,3,0,0,0,4.25,4.24L64,68.25l23.88,24A3,3,0,0,0,92.13,88L68.24,64,92.13,40A3,3,0,0,0,92.12,35.79Z"/></svg>

Before

Width:  |  Height:  |  Size: 479 B

@ -164,7 +164,6 @@
"quotationAnalysis": "تحليل الاقتباس",
"subject": "موضوعات",
"description": "وصف",
"pleaseEnterDescription": "الرجاء إدخال الوصف",
"supplier": "المورد",
"site": "موقع",
"buyer": "مشتر",
@ -259,7 +258,6 @@
"fullName": "الأسم الكامل",
"remove": "حذف",
"submit": "ارسال",
"submitAsAnonymous": "إرسال كمجهول",
"areYouSureYouWantToSubmit": "هل أنت متأكد أنك تريد أن تقدم؟",
"comments": "تعليقات",
"writeComment": "أكتب تعليقا",
@ -644,32 +642,7 @@
"yearsUsed": "سنوات الاستخدام",
"faRequest": "طلب التخلص من FA",
"showMore": "عرض المزيد",
"ticketDetails": "تفاصيل التذكرة",
"currentTicketBalance": "رصيد التذكرة الحالي",
"ticketHistory": "تاريخ التذكرة",
"proceedBooking": "المتابعة للحجز",
"courses": "الدورات التدريبية",
"course": "دورة",
"status": "الحالة",
"deadline": "الموعد النهائي",
"overdue": "متأخر",
"noCoursesAvailable": "لا توجد دورات متاحة",
"pullToRefresh": "اسحب للتحديث",
"courseUrlNotAvailable": "رابط الدورة غير متوفر",
"buyerDetails": "تفاصيل المشتري",
"etqanOVR": "الإبلاغ عن حادثة",
"etqanRequest": "طلبات الحوادث",
"selectProject": "حدد المشروع",
"project": "مشروع",
"keen": "حريص",
"reportIncident": "الإبلاغ عن الحادث",
"myIncidents": "حوادثي",
"incidentDetails": "تفاصيل الحادث",
"ticketNumber": "رقم التذكرة",
"ticketId": "معرف التذكرة",
"pleaseSelectProject": "الرجاء اختيار مشروع",
"viewAttachment" : "عرض المرفق",
"parkingQr": "وقوف السيارات QR",
"startNow": "ابدأ الآن"
}
}

@ -158,7 +158,6 @@
"subject": "Subject",
"quotationAnalysis": "Quotation Analysis",
"description": "Description",
"pleaseEnterDescription": "Please enter description",
"supplier": "Supplier",
"site": "Site",
"buyer": "Buyer",
@ -257,7 +256,6 @@
"remove": "Remove",
"Attendance": "Attendance",
"submit": "Submit",
"submitAsAnonymous": "Submit as Anonymous",
"areYouSureYouWantToSubmit": "Are you sure you want to submit?",
"comments": "Comments",
"writeComment": "Write a comment",
@ -642,31 +640,7 @@
"yearsUsed": "Years Used",
"faRequest": "FA Disposal Request",
"showMore": "Show More",
"ticketDetails": "Ticket Details",
"currentTicketBalance": "Current Ticket Balance",
"ticketHistory": "Ticket History",
"proceedBooking": "Proceed For Booking",
"courses": "Courses",
"course": "Course",
"status": "Status",
"deadline": "Deadline",
"overdue": "Overdue",
"noCoursesAvailable": "No Courses Available",
"pullToRefresh": "Pull to refresh",
"courseUrlNotAvailable": "Course URL not available",
"buyerDetails": "Buyer Details",
"etqanOVR": "Report An Incident",
"etqanRequest": "Incident Requests",
"selectProject": "Select Project",
"project": "Project",
"keen": "Keen",
"reportIncident": "Report Incident",
"myIncidents": "My Incidents",
"incidentDetails": "Incident Details",
"ticketNumber": "Ticket Number",
"ticketId": "Ticket ID",
"pleaseSelectProject": "Please select a project",
"viewAttachment" : "View Attachment",
"parkingQr": "Parking QR",
"startNow": "Start Now"
}

@ -61,8 +61,6 @@
<string>This app requires photo library access to select image as document &amp; upload it.</string>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>NSSpeechRecognitionUsageDescription</key>
<string>This app requires speech recognition access to access voice command features.</string>
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>

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

@ -1,6 +1,5 @@
import 'dart:async';
import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
@ -16,15 +15,12 @@ import 'package:mohem_flutter_app/models/dashboard/get_accural_ticket_balance_mo
import 'package:mohem_flutter_app/models/dashboard/get_attendance_tracking_list_model.dart';
import 'package:mohem_flutter_app/models/dashboard/itg_forms_model.dart';
import 'package:mohem_flutter_app/models/dashboard/list_menu.dart';
import 'package:mohem_flutter_app/models/eit_attachment_ticket_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/get_employee_parking_details_model.dart';
import 'package:mohem_flutter_app/models/greetings/greeting_card_model.dart';
import 'package:mohem_flutter_app/models/itg/itg_main_response.dart';
import 'package:mohem_flutter_app/models/itg/itg_response_model.dart';
import 'package:mohem_flutter_app/models/sso_auth_model.dart';
// import 'package:platform_device_id/platform_device_id.dart';
import 'package:uuid/uuid.dart';
@ -37,7 +33,7 @@ class DashboardApiClient {
Future<GetAttendanceTracking?> getAttendanceTracking() async {
String url = "${ApiConsts.erpRest}GET_Attendance_Tracking";
Map<String, dynamic> postParams = <String, dynamic>{};
Map<String, dynamic> postParams = {};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
@ -51,7 +47,7 @@ class DashboardApiClient {
Future<GenericResponseModel?> getOpenNotifications() async {
String url = "${ApiConsts.erpRest}GET_OPEN_NOTIFICATIONS";
Map<String, dynamic> postParams = <String, dynamic>{};
Map<String, dynamic> postParams = {};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
@ -65,7 +61,7 @@ class DashboardApiClient {
Future<GenericResponseModel?> getCOCNotifications() async {
String url = "${ApiConsts.cocRest}Mohemm_ITG_ReviewerAdmin_Pending_Tasks";
Map<String, dynamic> postParams = <String, dynamic>{"Date": DateUtil.getISODateFormat(DateTime.now()), "EmployeeNumber": AppState().memberInformationList?.eMPLOYEENUMBER};
Map<String, dynamic> postParams = {"Date": DateUtil.getISODateFormat(DateTime.now()), "EmployeeNumber": AppState().memberInformationList?.eMPLOYEENUMBER};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
@ -79,7 +75,7 @@ class DashboardApiClient {
Future<ItgFormsModel?> getItgFormsPendingTask() async {
String url = "${ApiConsts.cocRest}ITGFormsPendingTasks";
Map<String, dynamic> postParams = <String, dynamic>{};
Map<String, dynamic> postParams = {};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
@ -93,13 +89,13 @@ class DashboardApiClient {
Future<List<GetAccrualBalancesList>> getAccrualBalances(String effectiveDate, {String? empID}) async {
String url = "${ApiConsts.erpRest}GET_ACCRUAL_BALANCES";
Map<String, dynamic> postParams = <String, dynamic>{"P_EFFECTIVE_DATE": effectiveDate};
Map<String, dynamic> postParams = {"P_EFFECTIVE_DATE": effectiveDate};
postParams.addAll(AppState().postParamsJson);
if (empID != null) postParams["P_SELECTED_EMPLOYEE_NUMBER"] = empID;
return await ApiClient().postJsonForObject(
(json) {
GenericResponseModel responseData = GenericResponseModel.fromJson(json);
return responseData.getAccrualBalancesList ?? <GetAccrualBalancesList>[];
return responseData.getAccrualBalancesList ?? [];
},
url,
postParams,
@ -108,13 +104,13 @@ class DashboardApiClient {
Future<List<GetTicketAccuralBalanceModel>> getTicketAccuralBalance(String effectiveDate, {String? empID}) async {
String url = "${ApiConsts.erpRest}GET_TICKET_ACCRUAL_BALANCES";
Map<String, dynamic> postParams = <String, dynamic>{"P_EFFECTIVE_DATE": effectiveDate};
Map<String, dynamic> postParams = {"P_EFFECTIVE_DATE": effectiveDate};
postParams.addAll(AppState().postParamsJson);
if (empID != null) postParams["P_SELECTED_EMPLOYEE_NUMBER"] = empID;
return await ApiClient().postJsonForObject(
(json) {
GenericResponseModel responseData = GenericResponseModel.fromJson(json);
return responseData.getAccrualBalancesTicketList ?? <GetTicketAccuralBalanceModel>[];
return responseData.getAccrualBalancesTicketList ?? [];
},
url,
postParams,
@ -123,7 +119,7 @@ class DashboardApiClient {
Future<GenericResponseModel?> getOpenMissingSwipes() async {
String url = "${ApiConsts.erpRest}GET_OPEN_MISSING_SWIPES";
Map<String, dynamic> postParams = <String, dynamic>{};
Map<String, dynamic> postParams = {};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
@ -138,12 +134,12 @@ class DashboardApiClient {
//Menus List
Future<List<ListMenu>> getListMenu() async {
String url = "${ApiConsts.erpRest}GET_MENU";
Map<String, dynamic> postParams = <String, dynamic>{};
Map<String, dynamic> postParams = {};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
GenericResponseModel responseData = GenericResponseModel.fromJson(json);
return responseData.listMenu ?? <ListMenu>[];
return responseData.listMenu ?? [];
},
url,
postParams,
@ -153,7 +149,7 @@ class DashboardApiClient {
//GET_MENU_ENTRIES
Future<GenericResponseModel?> getGetMenuEntries() async {
String url = "${ApiConsts.erpRest}GET_MENU_ENTRIES";
Map<String, dynamic> postParams = <String, dynamic>{"P_SELECTED_RESP_ID": -999, "P_MENU_TYPE": "E"};
Map<String, dynamic> postParams = {"P_SELECTED_RESP_ID": -999, "P_MENU_TYPE": "E"};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
@ -167,7 +163,7 @@ class DashboardApiClient {
Future<GenericResponseModel?> getEventActivity() async {
String url = "${ApiConsts.erpRest}Get_EventActivity";
Map<String, dynamic> postParams = <String, dynamic>{"P_SELECTED_RESP_ID": -999, "P_MENU_TYPE": "E"};
Map<String, dynamic> postParams = {"P_SELECTED_RESP_ID": -999, "P_MENU_TYPE": "E"};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
@ -181,7 +177,7 @@ class DashboardApiClient {
Future<GenericResponseModel?> getTicketBookingRedirection() async {
String url = "${ApiConsts.erpRest}GET_PORTAL_REDIRECTION";
Map<String, dynamic> postParams = <String, dynamic>{"P_USER_NAME": AppState().memberInformationList?.eMPLOYEENUMBER};
Map<String, dynamic> postParams = {"P_USER_NAME": AppState().memberInformationList?.eMPLOYEENUMBER};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
@ -195,7 +191,7 @@ class DashboardApiClient {
Future<GenericResponseModel?> getTicketBalance() async {
String url = "${ApiConsts.erpRest}GET_TICKET_BALANCE";
Map<String, dynamic> postParams = <String, dynamic>{"P_USER_NAME": AppState().memberInformationList?.eMPLOYEENUMBER};
Map<String, dynamic> postParams = {"P_USER_NAME": AppState().memberInformationList?.eMPLOYEENUMBER};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
@ -212,7 +208,7 @@ class DashboardApiClient {
String url = "${ApiConsts.ssoAuthRedirection}?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 = <String, dynamic>{
Map<String, dynamic> postParams = {
"ClientId": clientID,
// "ClientId": "a9f4d1a0596d4aea8f830992ec4bdac1",
"PersonId": AppState().memberInformationList?.eMPLOYEENUMBER,
@ -231,35 +227,19 @@ 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 {
// token =
// "eyJhbGciOiJSUzI1NiIsImtpZCI6IjhjZTE2OWM0YjIwYjQ2ZWM5YTQyOTU3Y2ZhODUzNzQ1IiwidHlwIjoiSldUIn0.eyJ0ZW5hbnRfaWQiOiJhOWY0ZDFhMDU5NmQ0YWVhOGY4MzA5OTJlYzRiZGFjMSIsImVpZCI6IjExNzkzMCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL3NpZCI6Ijk2MDI0OGM1NzA3YzQ3MmFhYTEzM2I1N2ZhODE1ZmVhIiwibGFuZ3VhZ2UiOiJVUyIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL2VtYWlsYWRkcmVzcyI6IjExNzkzMEBobWcuY29tIiwiZXhwIjoxNzgyNDc1NzY5LCJpc3MiOiJodHRwczovL3Nzby11YXQuaG1nLmNvbSIsImF1ZCI6ImE5ZjRkMWEwNTk2ZDRhZWE4ZjgzMDk5MmVjNGJkYWMxIn0.rJcLVsG8D0XECyLERCTD2uqGeWyvp-OBVGE9uL2qKrX4etFUHgdFt_5kYF6edFTtGy-0PIZadHDmv7e-IOhVWHm5HVMClaukiXoRXR8cDN8XA1wfme3Kd-U5PXN-IRh49AyRTzLO0rYNPvH81ScosWGlsFSkOvA-0hJNa2adHdtvgNvB8wJshSU5p7sAmF8mjdDY6aInG19etu2iEuUDwHHA4ZY_ts4hboHo8fE392hFaYGonExoD7bpW5RMx5xKWeRCmWpG_PK8Aw_z1jGzdB9PANus4pteRGuln1J-kmo2lQC9pVrSyZATAKp1HfgfyZ_vUhaHEfM69cMWaCslJQ";
http.MultipartRequest request = http.MultipartRequest('POST', Uri.parse('https://www.paxes.com/sso/hmg'));
// http.MultipartRequest request = http.MultipartRequest('POST', Uri.parse('https://ek.techmaster.in/SSO/HMG'));
request.fields.addAll(<String, String>{'JWTToken': token});
// // var request = http.MultipartRequest('POST', Uri.parse('https://ek.techmaster.in/SSO/HMG'));
var request = http.MultipartRequest('POST', Uri.parse('https://Paxes-release.techmaster.in/SSO/HMG'));
request.fields.addAll({'JWTToken': token});
// request.headers.addAll(headers);
http.StreamedResponse response = await request.send();
if (response.statusCode == 302) {
String res = await response.stream.bytesToString();
print("================== post ==========");
var res = await response.stream.bytesToString();
return response.headers["location"];
} else {
print(response.reasonPhrase);
@ -279,7 +259,7 @@ class DashboardApiClient {
var _mobileDeviceIdentifierPlugin = MobileDeviceIdentifier();
Codec<String, String> stringToBase64 = utf8.fuse(base64);
String url = "${ApiConsts.swpRest}AuthenticateAndSwipeUserSupportNFC";
Uuid uuid = Uuid();
var uuid = Uuid();
String? deviceId = "";
// Generate a v4 (random) id
if (Platform.isAndroid) {
@ -291,7 +271,7 @@ class DashboardApiClient {
IosDeviceInfo iosInfo = await DeviceInfoPlugin().iosInfo;
deviceId = iosInfo.identifierForVendor;
}
Map<String, dynamic> postParams = <String, dynamic>{
Map<String, dynamic> postParams = {
"UID": deviceId, //uuid.v4(), //Mobile Id
// "UID": uuid.v4(), //Mobile Id
"Latitude": lat,
@ -317,10 +297,10 @@ class DashboardApiClient {
//Mark Fake Location
Future<GenericResponseModel?> markFakeLocation({String lat = "0", String? long = "0", required String sourceName}) async {
String url = "${ApiConsts.swpRest}CreateIssueInfo";
Uuid uuid = Uuid();
var uuid = Uuid();
// Generate a v4 (random) id
Map<String, dynamic> postParams = <String, dynamic>{
Map<String, dynamic> postParams = {
"UID": uuid.v4(), //Mobile Id
"Latitude": lat,
"Longitude": long,
@ -344,7 +324,7 @@ class DashboardApiClient {
Future<MohemmItgResponseItem?> getITGPageNotification() async {
String url = "${ApiConsts.cocRest}Mohemm_ITG_GetPageNotification";
Map<String, dynamic> postParams = <String, dynamic>{
Map<String, dynamic> postParams = {
"EmployeeNumber": AppState().getUserName,
"ItgEnableAt": "After Service Submission", //Mobile Id
"ItgServiceName": "Login",
@ -362,26 +342,11 @@ class DashboardApiClient {
);
}
Future<String?> getENSATItgToken() async {
String url = "${ApiConsts.cocRest}Mohemm_ENSAT_GetItgToken";
Map<String, dynamic> postParams = <String, dynamic>{"EmployeeNumber": AppState().getUserName};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
GenericResponseModel responseData = GenericResponseModel.fromJson(json);
return responseData.Mohemm_ENSAT_GetItgToken_Response;
},
url,
postParams,
);
}
//Submit ITG
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";
Map<String, dynamic> postParams = <String, dynamic>{
Map<String, dynamic> postParams = {
"EmployeeNumber": AppState().getUserName,
"ItgComments": comment,
"ItgNotificationMasterId": masterId,
@ -402,7 +367,7 @@ class DashboardApiClient {
Future<ItgMainRes?> getAdvertisementDetail(String masterID) async {
String url = "${ApiConsts.cocRest}Mohemm_ITG_GetPageNotificationDetails";
Map<String, dynamic> postParams = <String, dynamic>{
Map<String, dynamic> postParams = {
"EmployeeNumber": AppState().getUserName,
"ItgNotificationMasterId": masterID, //Mobile Id
};
@ -420,7 +385,7 @@ class DashboardApiClient {
Future setAdvertisementViewed(String masterID, int advertisementId, String? ackValue) async {
String url = "${ApiConsts.cocRest}Mohemm_ITG_UpdateAdvertisementAsViewed";
Map<String, dynamic> postParams = <String, dynamic>{
Map<String, dynamic> postParams = {
"ItgNotificationMasterId": masterID,
"EmployeeNumber": AppState().memberInformationList!.eMPLOYEENUMBER.toString(),
"ItgAdvertisementId": advertisementId,
@ -458,34 +423,11 @@ class DashboardApiClient {
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
GetEmployeeParking responseData = GetEmployeeParking.fromJson(json);
return responseData;
},
url,
postParams,
);
}
//Fetch All Courses Status
Future<CoursesResponseModel?> fetchAllCoursesStatus() async {
String url = ApiConsts.eLearningBaseUrl + "Fetch_All_Courses_Status.php";
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',
'Content-Type': 'application/x-www-form-urlencoded',
};
Map<String, dynamic> postParams = {"username": AppState().memberInformationList?.eMPLOYEENUMBER ?? ""};
return await ApiClient().postJsonForObject(
(json) {
CoursesResponseModel responseData = CoursesResponseModel.fromJson(json);
GetEmployeeParking responseData = GetEmployeeParking.fromJson(json);
return responseData;
},
url,
postParams,
headers: headers,
isFormData: false,
);
}

@ -25,23 +25,16 @@ class EITApiClient {
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(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) {
List<List<CollectionTransaction>> responseData = [];
json['GetEITTransactionList'].forEach((element) {
var transactionList = GetEitTransactionsModel.fromJson(element).collectionTransaction;
if (transactionList != null && transactionList.isNotEmpty) {
responseData.add(transactionList);
}
if (transactionList != null) responseData.add(transactionList);
});
return responseData;
} else {
List<CollectionTransaction>? responseData = GetEitTransactionsModel.fromJson(json['GetEITTransactionList'][0]).collectionTransaction;
return responseData ?? <CollectionTransaction>[];
return responseData;
}
},
url,

@ -1,140 +0,0 @@
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:intl/intl.dart';
import 'package:mohem_flutter_app/api/api_client.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/consts.dart';
import 'package:mohem_flutter_app/models/etqan_ovr/etqan_get_employee_incident_report.dart';
import 'package:mohem_flutter_app/models/etqan_ovr/etqan_get_requests_model.dart';
import 'package:mohem_flutter_app/models/etqan_ovr/etqan_getprojects_model.dart';
import 'package:mohem_flutter_app/models/generic_response_model.dart';
import 'package:mohem_flutter_app/models/mowadhafhi/get_department_sections.dart';
import 'package:mohem_flutter_app/models/mowadhafhi/get_project_departments.dart';
import 'package:mohem_flutter_app/models/mowadhafhi/get_projects.dart';
import 'package:mohem_flutter_app/models/mowadhafhi/get_section_topics.dart';
import 'package:mohem_flutter_app/models/mowadhafhi/get_ticket_details.dart';
import 'package:mohem_flutter_app/models/mowadhafhi/get_ticket_transactions.dart';
import 'package:mohem_flutter_app/models/mowadhafhi/get_ticket_types.dart';
import 'package:mohem_flutter_app/models/mowadhafhi/get_tickets_list.dart';
import 'package:mohem_flutter_app/models/mowadhafhi/get_transaction_attachment_model.dart';
class EtqanApiClient {
static final EtqanApiClient _instance = EtqanApiClient._internal();
EtqanApiClient._internal();
factory EtqanApiClient() => _instance;
Future<List<EtqanGetProjectsResponse>> getEtqanProjects() async {
String url = "${ApiConsts.cocRest}ETQAN_GetProjects";
Map<String, dynamic> postParams = <String, dynamic>{"P_SELECTED_EMPLOYEE_NUMBER": AppState().memberInformationList?.eMPLOYEENUMBER};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
List<EtqanGetProjectsResponse>? responseData = <EtqanGetProjectsResponse>[];
if (json["ETQAN_GetProjects_Response"] != null && json["ETQAN_GetProjects_Response"].isNotEmpty) {
json["ETQAN_GetProjects_Response"].forEach((element) {
responseData.add(EtqanGetProjectsResponse.fromJson(element));
});
}
return responseData;
},
url,
postParams,
);
}
Future<List<EtqanGetEmployeeOvrRequestsResponse>> getEmployeeEtqanRequests() async {
String url = "${ApiConsts.cocRest}ETQAN_GetEmployeeOVRRequests";
Map<String, dynamic> postParams = <String, dynamic>{
"ETQAN_EmployeeID": AppState().memberInformationList?.eMPLOYEENUMBER,
"P_SELECTED_EMPLOYEE_NUMBER": AppState().memberInformationList?.eMPLOYEENUMBER,
};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
List<EtqanGetEmployeeOvrRequestsResponse> responseData = <EtqanGetEmployeeOvrRequestsResponse>[];
if (json["ETQAN_GetEmployeeOVRRequests_Response"] != null && json["ETQAN_GetEmployeeOVRRequests_Response"].isNotEmpty) {
json["ETQAN_GetEmployeeOVRRequests_Response"].forEach((element) {
responseData.add(EtqanGetEmployeeOvrRequestsResponse.fromJson(element));
});
}
if (responseData.isNotEmpty) {
responseData.sort((EtqanGetEmployeeOvrRequestsResponse a, EtqanGetEmployeeOvrRequestsResponse b) {
if (a.createdDate == null && b.createdDate == null) return 0;
if (a.createdDate == null) return 1;
if (b.createdDate == null) return -1;
try {
// Parse dates in format "26-Feb-2026 12:54 PM" or "01-Mar-2026 02:45 PM"
DateFormat dateFormat = DateFormat("dd-MMM-yyyy hh:mm a", "en_US");
DateTime dateA = dateFormat.parse(a.createdDate!);
DateTime dateB = dateFormat.parse(b.createdDate!);
return dateB.compareTo(dateA); // Descending order (newest first)
} catch (e) {
return (b.createdDate ?? '').compareTo(a.createdDate ?? '');
}
});
}
return responseData;
},
url,
postParams,
);
}
Future<List<EtqanGetIncidentRequestResponse>> getEtqanIncidentRequests(String ticketNo) async {
String url = "${ApiConsts.cocRest}ETQAN_GetIncidentRequest";
Map<String, dynamic> postParams = <String, dynamic>{"ETQAN_TicketNumber": ticketNo, "P_SELECTED_EMPLOYEE_NUMBER": AppState().memberInformationList?.eMPLOYEENUMBER};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
List<EtqanGetIncidentRequestResponse> responseData = <EtqanGetIncidentRequestResponse>[];
if (json["ETQAN_GetIncidentRequest_Response"] != null && json["ETQAN_GetIncidentRequest_Response"].isNotEmpty) {
json["ETQAN_GetIncidentRequest_Response"].forEach((element) {
responseData.add(EtqanGetIncidentRequestResponse.fromJson(element));
});
}
return responseData;
},
url,
postParams,
);
}
Future<Map<String, dynamic>?> createRequest(String description, int? projectID, String? attachmentBase64, bool? isAnonymous) async {
String url = "${ApiConsts.cocRest}ETQAN_CreateIncident";
Map<String, dynamic> postParams = <String, dynamic>{
"P_SELECTED_EMPLOYEE_NUMBER": AppState().memberInformationList?.eMPLOYEENUMBER,
"P_USER_NAME": AppState().memberInformationList?.eMPLOYEENUMBER,
"ETQAN_Emp_EmployeeNumber": AppState().memberInformationList?.eMPLOYEENUMBER,
"ETQAN_Description": description,
"ETQAN_ProjectId": projectID,
"ETQAN_FileInfoBase64": attachmentBase64,
"ETQAN_IsAnonymous": isAnonymous ?? false,
};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
if (json["ETQAN_CreateIncident_Response"] != null) {
var response = json["ETQAN_CreateIncident_Response"];
if (response["id"] != null && response["ticketNumber"] != null) {
return {"id": response["id"], "ticketNumber": response["ticketNumber"]};
}
return null;
}
return null;
// "ETQAN_CreateIncident_Response": {
// "id": "00adabe4-4a32-4b35-1f00-08de4d152e7c",
// "ticketNumber": "OVR/OLY/2026/224"
// },
},
url,
postParams,
);
}
}

@ -90,7 +90,7 @@ class AppState {
String get getHuaweiPushToken => _huaweiPushToken;
final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 10.0, mobileType: Platform.isAndroid ? "android" : "ios");
final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 9.5, mobileType: Platform.isAndroid ? "android" : "ios");
void setPostParamsInitConfig() {
isAuthenticated = false;

@ -4,22 +4,15 @@ class ApiConsts {
// static String baseUrl = "http://10.200.204.11"; // Local server
// static String baseUrl = "https://erptstapp.srca.org.sa"; // SRCA server
// static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver
// static String baseUrl = "http://10.201.204.101:2024";
static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver
// static String baseUrl = "http://10.201.204.101:2024";
// static String baseUrl = "https://webservices.hmg.com"; // PreProd
// static String baseUrl = "https://hmgwebservices.com"; // Live server
static String baseUrl = "https://mohemm.hmg.com"; // New Live server
static String ssoBaseUrl = "https://sso.hmg.com"; // New Live server
// static String baseUrl = "https://mohemm.hmg.com"; // New Live server
//
// static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver
// static String baseUrl = "http://10.20.200.111:1010/";
// static String baseUrl = "https://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 enSATLiveURL = "https://ensat.hmg.com/auth/autologin"; // ENSAT server live
// static String baseUrl = "http://10.20.200.111:1010/";
// static String baseUrl = "https://webservices.hmg.com"; // PreProd
// static String baseUrl = "https://mohemm.hmg.com";
@ -34,8 +27,7 @@ class ApiConsts {
static String user = baseUrlServices + "api/User/";
static String cocRest = baseUrlServices + "COCWS.svc/REST/";
static String ssoAuthRedirection = ssoBaseUrl + "/api/auth/connect";
static String ssoAuthRedirection = "https://sso-uat.hmg.com/api/auth/connect";
//Chat
static String chatServerBaseUrl = "https://apiderichat.hmg.com/";
@ -63,7 +55,6 @@ class ApiConsts {
static String marathonBaseUrlUAT = "https://marathoon.com/uatservice/api/";
static String marathonBaseUrl = marathonBaseUrlLive;
// static String marathonBaseUrl = marathonBaseUrlUAT;
static String marathonBaseUrlServices = "https://marathoon.com/service/";
static String marathonParticipantLoginUrl = marathonBaseUrl + "auth/participantlogin";
@ -95,3 +86,5 @@ class SharedPrefsConsts {
static String mohemmWifiPassword = "mohemmWifiPassword";
static String editItemForSale = "editItemForSale";
}

@ -135,8 +135,8 @@ class Utils {
}
}
static Future showErrorDialog({required BuildContext context, required VoidCallback onOkTapped, required String message, VoidCallback? onCloseTap}) async {
return showDialog(context: context, builder: (BuildContext context) => ConfirmDialog(message: message, onTap: onOkTapped, onCloseTap: onCloseTap));
static Future showErrorDialog({required BuildContext context, required VoidCallback onOkTapped, required String message}) async {
return showDialog(context: context, builder: (BuildContext context) => ConfirmDialog(message: message, onTap: onOkTapped));
}
static void confirmDialog(cxt, String message, {VoidCallback? onTap}) {

@ -10,9 +10,6 @@ import 'package:mohem_flutter_app/ui/chat/favorite_users_screen.dart';
import 'package:mohem_flutter_app/ui/chat/group_chat_detaied_screen.dart';
import 'package:mohem_flutter_app/ui/chat/group_members.dart';
import 'package:mohem_flutter_app/ui/chat/manage_group.dart';
import 'package:mohem_flutter_app/ui/etqan_ovr/etqan_create_request.dart';
import 'package:mohem_flutter_app/ui/etqan_ovr/etqan_ovr_home.dart';
import 'package:mohem_flutter_app/ui/etqan_ovr/etqan_request_detailed.dart';
import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart';
import 'package:mohem_flutter_app/ui/landing/itg/change_itg_ad_password_screen.dart';
import 'package:mohem_flutter_app/ui/landing/itg/its_add_screen_video_image.dart';
@ -58,7 +55,6 @@ import 'package:mohem_flutter_app/ui/profile/profile_screen.dart';
import 'package:mohem_flutter_app/ui/screens/announcements/announcement_details.dart';
import 'package:mohem_flutter_app/ui/screens/announcements/announcements.dart';
import 'package:mohem_flutter_app/ui/screens/child_education/child_education_assistance.dart';
import 'package:mohem_flutter_app/ui/screens/courses/courses_screen.dart';
// import 'package:mohem_flutter_app/ui/my_attendance/work_from_home_screen.dart';
import 'package:mohem_flutter_app/ui/screens/eit/add_eit.dart';
import 'package:mohem_flutter_app/ui/screens/event_activity/event_activity.dart';
@ -171,9 +167,6 @@ class AppRoutes {
static const String offersAndDiscounts = "/offersAndDiscounts";
static const String offersAndDiscountsDetails = "/offersAndDiscountsDetails";
// Courses
static const String courses = "/courses";
//Pay slip
static const String monthlyPaySlip = "/monthlyPaySlip";
@ -219,10 +212,6 @@ class AppRoutes {
static const String activityScreen = "/activityScreen";
static const String etqanOvr = "/etqanOvr";
static const String etqanCreateRequest = "/etqanCreateRequest";
static const String etqanGetIncidientRequest = "/etqanGetIncidientRequest";
//Parking QR
static const String parkingQr = "/parkingQrScreen";
@ -306,9 +295,6 @@ class AppRoutes {
offersAndDiscounts: (BuildContext context) => OffersAndDiscountsHome(),
offersAndDiscountsDetails: (BuildContext context) => OffersAndDiscountsDetails(),
// Courses
courses: (BuildContext context) => const CoursesScreen(),
//pay slip
monthlyPaySlip: (BuildContext context) => MonthlyPaySlipScreen(),
performanceEvaluation: (BuildContext context) => PerformanceAppraisal(),
@ -348,12 +334,6 @@ class AppRoutes {
childEducation: (BuildContext context) => ChildEducationAssistance(),
activityScreen:(BuildContext context) => const EventActivityScreen(),
//ETQAN OVR
etqanOvr: (BuildContext context) => EtqanOvrHome(),
etqanCreateRequest: (BuildContext context) => EtqanOvrCreateRequest(),
etqanGetIncidientRequest: (BuildContext context) => EtqanOvrRequestDetailed(),
activityScreen:(BuildContext context) => const EventActivityScreen(),
//Parking QR
parkingQr: (BuildContext context) => const ParkingQrScreen(),

@ -180,7 +180,6 @@ class CodegenLoader extends AssetLoader{
"quotationAnalysis": "تحليل الاقتباس",
"subject": "موضوعات",
"description": "وصف",
"pleaseEnterDescription": "الرجاء إدخال الوصف",
"supplier": "المورد",
"site": "موقع",
"buyer": "مشتر",
@ -275,7 +274,6 @@ class CodegenLoader extends AssetLoader{
"fullName": "الأسم الكامل",
"remove": "حذف",
"submit": "ارسال",
"submitAsAnonymous": "إرسال كمجهول",
"areYouSureYouWantToSubmit": "هل أنت متأكد أنك تريد أن تقدم؟",
"comments": "تعليقات",
"writeComment": "أكتب تعليقا",
@ -657,31 +655,7 @@ class CodegenLoader extends AssetLoader{
"yearsUsed": "سنوات الاستخدام",
"faRequest": "طلب التخلص من FA",
"showMore": "عرض المزيد",
"ticketDetails": "تفاصيل التذكرة",
"currentTicketBalance": "رصيد التذكرة الحالي",
"ticketHistory": "تاريخ التذكرة",
"proceedBooking": "المتابعة للحجز",
"courses": "الدورات التدريبية",
"course": "دورة",
"status": "الحالة",
"deadline": "الموعد النهائي",
"overdue": "متأخر",
"noCoursesAvailable": "لا توجد دورات متاحة",
"pullToRefresh": "اسحب للتحديث",
"courseUrlNotAvailable": "رابط الدورة غير متوفر",
"buyerDetails": "تفاصيل المشتري",
"etqanOVR": "الإبلاغ عن حادثة",
"etqanRequest": "طلبات الحوادث",
"selectProject": "حدد المشروع",
"project": "مشروع",
"keen": "حريص",
"reportIncident": "الإبلاغ عن الحادث",
"myIncidents": "حوادثي",
"incidentDetails": "تفاصيل الحادث",
"ticketNumber": "رقم التذكرة",
"ticketId": "معرف التذكرة",
"pleaseSelectProject": "الرجاء اختيار مشروع",
"viewAttachment": "عرض المرفق",
"parkingQr": "وقوف السيارات QR",
"startNow": "ابدأ الآن"
};
@ -845,7 +819,6 @@ static const Map<String,dynamic> _en_US = {
"subject": "Subject",
"quotationAnalysis": "Quotation Analysis",
"description": "Description",
"pleaseEnterDescription": "Please enter description",
"supplier": "Supplier",
"site": "Site",
"buyer": "Buyer",
@ -944,7 +917,6 @@ static const Map<String,dynamic> _en_US = {
"remove": "Remove",
"Attendance": "Attendance",
"submit": "Submit",
"submitAsAnonymous": "Submit as Anonymous",
"areYouSureYouWantToSubmit": "Are you sure you want to submit?",
"comments": "Comments",
"writeComment": "Write a comment",
@ -1328,31 +1300,7 @@ static const Map<String,dynamic> _en_US = {
"yearsUsed": "Years Used",
"faRequest": "FA Disposal Request",
"showMore": "Show More",
"ticketDetails": "Ticket Details",
"currentTicketBalance": "Current Ticket Balance",
"ticketHistory": "Ticket History",
"proceedBooking": "Proceed For Booking",
"courses": "Courses",
"course": "Course",
"status": "Status",
"deadline": "Deadline",
"overdue": "Overdue",
"noCoursesAvailable": "No Courses Available",
"pullToRefresh": "Pull to refresh",
"courseUrlNotAvailable": "Course URL not available",
"buyerDetails": "Buyer Details",
"etqanOVR": "Report An Incident",
"etqanRequest": "Incident Requests",
"selectProject": "Select Project",
"project": "Project",
"keen": "Keen",
"reportIncident": "Report Incident",
"myIncidents": "My Incidents",
"incidentDetails": "Incident Details",
"ticketNumber": "Ticket Number",
"ticketId": "Ticket ID",
"pleaseSelectProject": "Please select a project",
"viewAttachment": "View Attachment",
"parkingQr": "Parking QR",
"startNow": "Start Now"
};

@ -167,7 +167,6 @@ abstract class LocaleKeys {
static const quotationAnalysis = 'quotationAnalysis';
static const subject = 'subject';
static const description = 'description';
static const pleaseEnterDescription = 'pleaseEnterDescription';
static const supplier = 'supplier';
static const site = 'site';
static const buyer = 'buyer';
@ -262,7 +261,6 @@ abstract class LocaleKeys {
static const fullName = 'fullName';
static const remove = 'remove';
static const submit = 'submit';
static const submitAsAnonymous = 'submitAsAnonymous';
static const areYouSureYouWantToSubmit = 'areYouSureYouWantToSubmit';
static const comments = 'comments';
static const writeComment = 'writeComment';
@ -629,31 +627,7 @@ abstract class LocaleKeys {
static const yearsUsed = 'yearsUsed';
static const faRequest = 'faRequest';
static const showMore = 'showMore';
static const ticketDetails = 'ticketDetails';
static const currentTicketBalance = 'currentTicketBalance';
static const ticketHistory = 'ticketHistory';
static const proceedBooking = 'proceedBooking';
static const courses = 'courses';
static const course = 'course';
static const status = 'status';
static const deadline = 'deadline';
static const overdue = 'overdue';
static const noCoursesAvailable = 'noCoursesAvailable';
static const pullToRefresh = 'pullToRefresh';
static const courseUrlNotAvailable = 'courseUrlNotAvailable';
static const buyerDetails = 'buyerDetails';
static const etqanOVR = 'etqanOVR';
static const etqanRequest = 'etqanRequest';
static const selectProject = 'selectProject';
static const project = 'project';
static const keen = 'keen';
static const reportIncident = 'reportIncident';
static const myIncidents = 'myIncidents';
static const incidentDetails = 'incidentDetails';
static const ticketNumber = 'ticketNumber';
static const ticketId = 'ticketId';
static const pleaseSelectProject = 'pleaseSelectProject';
static const viewAttachment = 'viewAttachment';
static const parkingQr = 'parkingQr';
static const startNow = 'startNow';

@ -12,7 +12,6 @@ import 'package:mohem_flutter_app/models/post_params_model.dart';
import 'package:mohem_flutter_app/provider/chat_provider_model.dart';
import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart';
import 'package:mohem_flutter_app/provider/eit_provider_model.dart';
import 'package:mohem_flutter_app/provider/etqan_ovr_provider.dart';
import 'package:mohem_flutter_app/theme/app_theme.dart';
import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart';
import 'package:month_year_picker/month_year_picker.dart';
@ -54,7 +53,6 @@ Future<void> main() async {
ChangeNotifierProvider<EITProviderModel>(create: (_) => EITProviderModel()),
ChangeNotifierProvider<ChatProviderModel>(create: (_) => ChatProviderModel()),
ChangeNotifierProvider<MarathonProvider>(create: (_) => MarathonProvider()),
ChangeNotifierProvider<EtqanOvrProviderModel>(create: (_) => EtqanOvrProviderModel()),
// ChangeNotifierProvider<ChatCallProvider>(
// create: (_) => ChatCallProvider(),
// ),

@ -1,94 +0,0 @@
class CoursesResponseModel {
bool? success;
int? status;
String? username;
List<CourseStatus>? coursesStatus;
int? totalCourses;
CoursesResponseModel({
this.success,
this.status,
this.username,
this.coursesStatus,
this.totalCourses,
});
CoursesResponseModel.fromJson(Map<String, dynamic> json) {
success = json['success'];
status = json['status'];
username = json['username'];
if (json['courses_status'] != null) {
coursesStatus = <CourseStatus>[];
json['courses_status'].forEach((v) {
coursesStatus!.add(CourseStatus.fromJson(v));
});
}
totalCourses = json['total_courses'];
}
Map<String, dynamic> toJson() {
Map<String, dynamic> data = <String, dynamic>{};
data['success'] = success;
data['status'] = status;
data['username'] = username;
if (coursesStatus != null) {
data['courses_status'] = coursesStatus!.map((v) => v.toJson()).toList();
}
data['total_courses'] = totalCourses;
return data;
}
}
class CourseStatus {
String? cId;
String? cFullname;
String? cNameAr;
String? cShortname;
String? cStatus;
String? cIsMohemmAffective;
String? cStartdate;
String? cEnddate;
String? cUrl;
String? token;
CourseStatus({
this.cId,
this.cFullname,
this.cNameAr,
this.cShortname,
this.cStatus,
this.cIsMohemmAffective,
this.cStartdate,
this.cEnddate,
this.cUrl,
this.token
});
CourseStatus.fromJson(Map<String, dynamic> json) {
cId = json['c_id'];
cFullname = json['c_fullname'];
cNameAr = json['c_name_ar'];
cShortname = json['c_shortname'];
cStatus = json['c_status'];
cIsMohemmAffective = json['c_is_mohemm_affective'];
cStartdate = json['c_startdate'];
cEnddate = json['c_enddate'];
cUrl = json['c_url'];
token =json['c_token'];
}
Map<String, dynamic> toJson() {
Map<String, dynamic> data = <String, dynamic>{};
data['c_id'] = cId;
data['c_fullname'] = cFullname;
data['c_name_ar'] = cNameAr;
data['c_shortname'] = cShortname;
data['c_status'] = cStatus;
data['c_is_mohemm_affective'] = cIsMohemmAffective;
data['c_startdate'] = cStartdate;
data['c_enddate'] = cEnddate;
data['c_url'] = cUrl;
data['c_token'] = token;
return data;
}
}

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

@ -1,97 +0,0 @@
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,
};
}

@ -1,57 +0,0 @@
import 'dart:convert';
class EtqanGetEmployeeIncidentRequestModel {
List<EtqanGetIncidentRequestResponse>? etqanGetIncidentRequestResponse;
EtqanGetEmployeeIncidentRequestModel({
this.etqanGetIncidentRequestResponse,
});
factory EtqanGetEmployeeIncidentRequestModel.fromRawJson(String str) => EtqanGetEmployeeIncidentRequestModel.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory EtqanGetEmployeeIncidentRequestModel.fromJson(Map<String, dynamic> json) => EtqanGetEmployeeIncidentRequestModel(
etqanGetIncidentRequestResponse: json["ETQAN_GetIncidentRequest_Response"] == null ? [] : List<EtqanGetIncidentRequestResponse>.from(json["ETQAN_GetIncidentRequest_Response"]!.map((x) => EtqanGetIncidentRequestResponse.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"ETQAN_GetIncidentRequest_Response": etqanGetIncidentRequestResponse == null ? [] : List<dynamic>.from(etqanGetIncidentRequestResponse!.map((x) => x.toJson())),
};
}
class EtqanGetIncidentRequestResponse {
String? key;
String? keyAr;
String? value;
String? valueAr;
List<String>? subValues;
EtqanGetIncidentRequestResponse({
this.key,
this.keyAr,
this.value,
this.valueAr,
this.subValues,
});
factory EtqanGetIncidentRequestResponse.fromRawJson(String str) => EtqanGetIncidentRequestResponse.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory EtqanGetIncidentRequestResponse.fromJson(Map<String, dynamic> json) => EtqanGetIncidentRequestResponse(
key: json["key"],
keyAr: json["keyAr"],
value: json["value"],
valueAr: json["valueAr"],
subValues: json["subValues"] == null ? [] : List<String>.from(json["subValues"]!.map((x) => x)),
);
Map<String, dynamic> toJson() => {
"key": key,
"keyAr": keyAr,
"value": value,
"valueAr": valueAr,
"subValues": subValues == null ? [] : List<dynamic>.from(subValues!.map((x) => x)),
};
}

@ -1,65 +0,0 @@
import 'dart:convert';
class EtqanGetEmployeeRequestsModel {
List<EtqanGetEmployeeOvrRequestsResponse>? etqanGetEmployeeOvrRequestsResponse;
EtqanGetEmployeeRequestsModel({
this.etqanGetEmployeeOvrRequestsResponse,
});
factory EtqanGetEmployeeRequestsModel.fromRawJson(String str) => EtqanGetEmployeeRequestsModel.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory EtqanGetEmployeeRequestsModel.fromJson(Map<String, dynamic> json) => EtqanGetEmployeeRequestsModel(
etqanGetEmployeeOvrRequestsResponse: json["ETQAN_GetEmployeeOVRRequests_Response"] == null ? [] : List<EtqanGetEmployeeOvrRequestsResponse>.from(json["ETQAN_GetEmployeeOVRRequests_Response"]!.map((x) => EtqanGetEmployeeOvrRequestsResponse.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"ETQAN_GetEmployeeOVRRequests_Response": etqanGetEmployeeOvrRequestsResponse == null ? [] : List<dynamic>.from(etqanGetEmployeeOvrRequestsResponse!.map((x) => x.toJson())),
};
}
class EtqanGetEmployeeOvrRequestsResponse {
String? createdDate;
String? description;
String? id;
bool? isAnonymous;
String? status;
String? statusAr;
String? ticketNumber;
EtqanGetEmployeeOvrRequestsResponse({
this.createdDate,
this.description,
this.id,
this.isAnonymous,
this.status,
this.statusAr,
this.ticketNumber,
});
factory EtqanGetEmployeeOvrRequestsResponse.fromRawJson(String str) => EtqanGetEmployeeOvrRequestsResponse.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory EtqanGetEmployeeOvrRequestsResponse.fromJson(Map<String, dynamic> json) => EtqanGetEmployeeOvrRequestsResponse(
createdDate: json["createdDate"],
description: json["description"],
id: json["id"],
isAnonymous: json["isAnonymous"],
status: json["status"],
statusAr: json["statusAr"],
ticketNumber: json["ticketNumber"],
);
Map<String, dynamic> toJson() => {
"createdDate": createdDate,
"description": description,
"id": id,
"isAnonymous": isAnonymous,
"status": status,
"statusAr": statusAr,
"ticketNumber": ticketNumber,
};
}

@ -1,53 +0,0 @@
import 'dart:convert';
class EtqanGetProjectsModel {
List<EtqanGetProjectsResponse>? etqanGetProjectsResponse;
EtqanGetProjectsModel({
this.etqanGetProjectsResponse,
});
factory EtqanGetProjectsModel.fromRawJson(String str) => EtqanGetProjectsModel.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory EtqanGetProjectsModel.fromJson(Map<String, dynamic> json) => EtqanGetProjectsModel(
etqanGetProjectsResponse: json["ETQAN_GetProjects_Response"] == null ? [] : List<EtqanGetProjectsResponse>.from(json["ETQAN_GetProjects_Response"]!.map((x) => EtqanGetProjectsResponse.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"ETQAN_GetProjects_Response": etqanGetProjectsResponse == null ? [] : List<dynamic>.from(etqanGetProjectsResponse!.map((x) => x.toJson())),
};
}
class EtqanGetProjectsResponse {
String? projectAr;
String? projectCode;
String? projectEn;
int? projectId;
EtqanGetProjectsResponse({
this.projectAr,
this.projectCode,
this.projectEn,
this.projectId,
});
factory EtqanGetProjectsResponse.fromRawJson(String str) => EtqanGetProjectsResponse.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory EtqanGetProjectsResponse.fromJson(Map<String, dynamic> json) => EtqanGetProjectsResponse(
projectAr: json["projectAr"],
projectCode: json["projectCode"],
projectEn: json["projectEn"],
projectId: json["projectId"],
);
Map<String, dynamic> toJson() => {
"projectAr": projectAr,
"projectCode": projectCode,
"projectEn": projectEn,
"projectId": projectId,
};
}

@ -398,7 +398,6 @@ class GenericResponseModel {
bool? isActiveCode;
bool? isSMSSent;
PortalDirectionData? portalDirectionData;
String? Mohemm_ENSAT_GetItgToken_Response;
GenericResponseModel({
this.date,
@ -670,8 +669,7 @@ class GenericResponseModel {
this.ePharmacyGetItemOnHandList,
this.isActiveCode,
this.isSMSSent,
this.getFADisposalNtfDetails,
this.Mohemm_ENSAT_GetItgToken_Response,
this.getFADisposalNtfDetails
});
GenericResponseModel.fromJson(Map<String, dynamic> json) {
@ -945,6 +943,7 @@ class GenericResponseModel {
getFADisposalNtfDetails = json['GetFADisposalNtfDetails'] != null ? GetFaDisposalNtfDetails.fromJson(json['GetFADisposalNtfDetails']) : null;
if (json['GetEarningsList'] != null) {
getEarningsList = <GetEarningsList>[];
json['GetEarningsList'].forEach((v) {
@ -1465,7 +1464,6 @@ class GenericResponseModel {
ePharmacyGetItemOnHandList = json['ePharmacy_GetItemOnHandList'];
isActiveCode = json['isActiveCode'];
isSMSSent = json['isSMSSent'];
Mohemm_ENSAT_GetItgToken_Response = json['Mohemm_ENSAT_GetItgToken_Response'];
}
Map<String, dynamic> toJson() {
@ -1563,7 +1561,7 @@ class GenericResponseModel {
if (this.getActionHistoryList != null) {
data['GetActionHistoryList'] = this.getActionHistoryList!.map((v) => v.toJson()).toList();
}
data['GetFADisposalNtfDetails'] = this.getFADisposalNtfDetails;
data['GetFADisposalNtfDetails'] =this.getFADisposalNtfDetails;
data['GetAddressDffStructureList'] = this.getAddressDffStructureList;
data['GetAddressNotificationBodyList'] = this.getAddressNotificationBodyList;
@ -1951,7 +1949,6 @@ class GenericResponseModel {
data['ePharmacy_GetItemOnHandList'] = this.ePharmacyGetItemOnHandList;
data['isActiveCode'] = this.isActiveCode;
data['isSMSSent'] = this.isSMSSent;
data['Mohemm_ENSAT_GetItgToken_Response'] = this.Mohemm_ENSAT_GetItgToken_Response;
return data;
}
}

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

@ -21,60 +21,42 @@ class GetGreetingCardsModelResponse {
}
class GetGreetingCardsModelResponseElement {
String? backgroundImageUrlAr;
int? id;
dynamic titleEn;
String? titleAr;
String? descriptionEn;
String? descriptionAr;
String? startDate;
String? endDate;
String? urlEn;
String? urlAr;
String? backgroundImageUrlEn;
String? buttonBgColor;
String? buttonText;
String? buttonTextN;
int? cardType;
String? backgroundImageUrlAr;
int? channel;
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.id,
this.titleEn,
this.titleAr,
this.descriptionEn,
this.descriptionAr,
this.startDate,
this.endDate,
this.urlEn,
this.urlAr,
this.backgroundImageUrlEn,
this.buttonBgColor,
this.buttonText,
this.buttonTextN,
this.cardType,
this.backgroundImageUrlAr,
this.channel,
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));
@ -82,61 +64,42 @@ class GetGreetingCardsModelResponseElement {
String toRawJson() => json.encode(toJson());
factory GetGreetingCardsModelResponseElement.fromJson(Map<String, dynamic> json) => GetGreetingCardsModelResponseElement(
backgroundImageUrlAr: json["BackgroundImageUrlAr"],
id: json["ID"],
titleEn: json["TitleEn"],
titleAr: json["TitleAr"],
descriptionEn: json["DescriptionEn"],
descriptionAr: json["DescriptionAr"],
startDate: json["StartDate"],
endDate: json["EndDate"],
urlEn: json["UrlEn"],
urlAr: json["UrlAr"],
backgroundImageUrlEn: json["BackgroundImageUrlEn"],
buttonBgColor: json["ButtonBgColor"],
buttonText: json["ButtonText"],
buttonTextN: json["ButtonTextN"],
cardType: json["CardType"],
backgroundImageUrlAr: json["BackgroundImageUrlAr"],
channel: json["Channel"],
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,
"ID": id,
"TitleEn": titleEn,
"TitleAr": titleAr,
"DescriptionEn": descriptionEn,
"DescriptionAr": descriptionAr,
"StartDate": startDate,
"EndDate": endDate,
"UrlEn": urlEn,
"UrlAr": urlAr,
"BackgroundImageUrlEn": backgroundImageUrlEn,
"ButtonBgColor": buttonBgColor,
"ButtonText": buttonText,
"ButtonTextN": buttonTextN,
"CardType": cardType,
"BackgroundImageUrlAr": backgroundImageUrlAr,
"Channel": channel,
"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,
};
}

@ -136,21 +136,10 @@ class ActionButtonsColl {
late String btnTextEn;
late String btnTextAr;
late String actionValue;
dynamic iconOrImage;
String? actionType;
late dynamic iconOrImage;
late int orderNo;
String? url;
ActionButtonsColl({
required this.actionButtonId,
required this.btnTextEn,
required this.btnTextAr,
required this.actionValue,
this.iconOrImage,
this.actionType,
required this.orderNo,
this.url,
});
ActionButtonsColl({required this.actionButtonId, required this.btnTextEn, required this.btnTextAr, required this.actionValue, required this.iconOrImage, required this.orderNo});
ActionButtonsColl.fromJson(Map<String, dynamic> json) {
actionButtonId = json['actionButtonId'];
@ -158,9 +147,7 @@ class ActionButtonsColl {
btnTextAr = json['btnTextAr'];
actionValue = json['actionValue'];
iconOrImage = json['iconOrImage'];
actionType = json['actionType'];
orderNo = json['orderNo'];
url = json['url'];
}
Map<String, dynamic> toJson() {
@ -170,9 +157,7 @@ class ActionButtonsColl {
data['btnTextAr'] = this.btnTextAr;
data['actionValue'] = this.actionValue;
data['iconOrImage'] = this.iconOrImage;
data['actionType'] = this.actionType;
data['orderNo'] = this.orderNo;
data['url'] = this.url;
return data;
}
}

@ -12,7 +12,12 @@ MohemmItgResponseItem mohemmItgResponseItemFromJson(String str) => MohemmItgResp
String mohemmItgResponseItemToJson(MohemmItgResponseItem data) => json.encode(data.toJson());
class MohemmItgResponseItem {
MohemmItgResponseItem({this.statusCode, this.message, this.originalErrMsg, this.result});
MohemmItgResponseItem({
this.statusCode,
this.message,
this.originalErrMsg,
this.result,
});
final int? statusCode;
final dynamic? message;
@ -20,64 +25,77 @@ class MohemmItgResponseItem {
final ItgResponseResult? result;
factory MohemmItgResponseItem.fromJson(Map<String, dynamic> json) => MohemmItgResponseItem(
statusCode: json["statusCode"] == null ? null : json["statusCode"],
message: json["message"],
originalErrMsg: json["originalErrMsg"],
result: json["result"] == null ? null : ItgResponseResult.fromJson(json["result"]),
);
statusCode: json["statusCode"] == null ? null : json["statusCode"],
message: json["message"],
originalErrMsg: json["originalErrMsg"],
result: json["result"] == null ? null : ItgResponseResult.fromJson(json["result"]),
);
Map<String, dynamic> toJson() => {"statusCode": statusCode == null ? null : statusCode, "message": message, "originalErrMsg": originalErrMsg, "result": result == null ? null : result!.toJson()};
Map<String, dynamic> toJson() => {
"statusCode": statusCode == null ? null : statusCode,
"message": message,
"originalErrMsg": originalErrMsg,
"result": result == null ? null : result!.toJson(),
};
}
class ItgResponseResult {
ItgResponseResult({this.totalItemsCount, this.data, this.errormsg});
//
// final dynamic totalItemsCount;
// final ItgResponseData? data;
// final dynamic errormsg;
//
// factory ItgResponseResult.fromJson(Map<String, dynamic> json) => ItgResponseResult(
// totalItemsCount: json["totalItemsCount"],
// data: json["data"] == null ? null : ItgResponseData.fromJson(json["data"]),
// errormsg: json["errormsg"],
// );
//
// Map<String, dynamic> toJson() => {
// "totalItemsCount": totalItemsCount,
// "data": data == null ? null : data!.toJson(),
// "errormsg": errormsg,
// };
// }
// todo these lines, for ERM new change on UAT
dynamic totalItemsCount;
List<ItgResponseData>? data;
dynamic errormsg;
ItgResponseResult.fromJson(Map<String, dynamic> json) {
totalItemsCount = json['totalItemsCount'];
if (json['data'] != null) {
data = [];
if (json['data'] is List) {
json['data'].forEach((v) {
data!.add(ItgResponseData.fromJson(v));
});
} else {
data!.add(ItgResponseData.fromJson(json['data']));
}
ItgResponseResult({
this.totalItemsCount,
this.data,
this.errormsg,
});
//
// final dynamic totalItemsCount;
// final ItgResponseData? data;
// final dynamic errormsg;
//
// factory ItgResponseResult.fromJson(Map<String, dynamic> json) => ItgResponseResult(
// totalItemsCount: json["totalItemsCount"],
// data: json["data"] == null ? null : ItgResponseData.fromJson(json["data"]),
// errormsg: json["errormsg"],
// );
//
// Map<String, dynamic> toJson() => {
// "totalItemsCount": totalItemsCount,
// "data": data == null ? null : data!.toJson(),
// "errormsg": errormsg,
// };
// }
// todo these lines, for ERM new change on UAT
dynamic totalItemsCount;
List<ItgResponseData>? data;
dynamic errormsg;
ItgResponseResult.fromJson(Map<String, dynamic> json) {
totalItemsCount = json['totalItemsCount'];
if (json['data'] != null) {
data = [];
if(json['data'] is List) {
json['data'].forEach((v) {
data!.add(ItgResponseData.fromJson(v));
});
} else {
data!.add(ItgResponseData.fromJson(json['data']));
}
errormsg = json['errormsg'];
}
//
// factory ItgResponseResult.fromJson(Map<String, dynamic> json) => ItgResponseResult(
// totalItemsCount: json["totalItemsCount"],
// data: json["data"] == null ? null : ItgResponseData.fromJson(json["data"]),
// errormsg: json["errormsg"],
// );
}
errormsg = json['errormsg'];
}
Map<String, dynamic> toJson() => {"totalItemsCount": totalItemsCount, "data": data == null ? null : data!.map((v) => v.toJson()).toList(), "errormsg": errormsg};
//
// factory ItgResponseResult.fromJson(Map<String, dynamic> json) => ItgResponseResult(
// totalItemsCount: json["totalItemsCount"],
// data: json["data"] == null ? null : ItgResponseData.fromJson(json["data"]),
// errormsg: json["errormsg"],
// );
Map<String, dynamic> toJson() => {
"totalItemsCount": totalItemsCount,
"data": data == null ? null : data!.map((v) => v.toJson()).toList(),
"errormsg": errormsg,
};
}
class ItgResponseData {
@ -103,7 +121,6 @@ class ItgResponseData {
this.pageSize,
this.pageNo,
this.languageId,
this.deadline,
});
final String? notificationMasterId;
@ -127,55 +144,52 @@ class ItgResponseData {
final dynamic pageSize;
final dynamic pageNo;
final dynamic languageId;
dynamic deadline;
factory ItgResponseData.fromJson(Map<String, dynamic> json) => ItgResponseData(
notificationMasterId: json["notificationMasterId"] == null ? null : json["notificationMasterId"],
notificationType: json["notificationType"] == null ? null : json["notificationType"],
referenceItemId: json["referenceItemId"] == null ? null : json["referenceItemId"],
notificationTitle: json["notificationTitle"] == null ? null : json["notificationTitle"],
enableAt: json["enableAt"] == null ? null : json["enableAt"],
applicationItemId: json["applicationItemId"],
startDate: json["startDate"],
endDate: json["endDate"],
deadline: json["deadline"] == null ? null : json["deadline"],
isRepeat: json["isRepeat"] == null ? null : json["isRepeat"],
channelId: json["channelId"] == null ? null : json["channelId"],
serviceId: json["serviceId"] == null ? null : json["serviceId"],
channelName: json["channelName"] == null ? null : json["channelName"],
serviceName: json["serviceName"] == null ? null : json["serviceName"],
isDeleted: json["isDeleted"] == null ? null : json["isDeleted"],
showDelete: json["showDelete"] == null ? null : json["showDelete"],
advertisement: json["advertisement"] == null ? null : Advertisement.fromJson(json["advertisement"]),
survey: json["survey"] == null ? null : SurveyModel.fromJson(json["survey"]),
isActive: json["isActive"],
pageSize: json["pageSize"],
pageNo: json["pageNo"],
languageId: json["languageId"],
);
notificationMasterId: json["notificationMasterId"] == null ? null : json["notificationMasterId"],
notificationType: json["notificationType"] == null ? null : json["notificationType"],
referenceItemId: json["referenceItemId"] == null ? null : json["referenceItemId"],
notificationTitle: json["notificationTitle"] == null ? null : json["notificationTitle"],
enableAt: json["enableAt"] == null ? null : json["enableAt"],
applicationItemId: json["applicationItemId"],
startDate: json["startDate"],
endDate: json["endDate"],
isRepeat: json["isRepeat"] == null ? null : json["isRepeat"],
channelId: json["channelId"] == null ? null : json["channelId"],
serviceId: json["serviceId"] == null ? null : json["serviceId"],
channelName: json["channelName"] == null ? null : json["channelName"],
serviceName: json["serviceName"] == null ? null : json["serviceName"],
isDeleted: json["isDeleted"] == null ? null : json["isDeleted"],
showDelete: json["showDelete"] == null ? null : json["showDelete"],
advertisement: json["advertisement"] == null ? null : Advertisement.fromJson(json["advertisement"]),
survey: json["survey"] == null ? null : SurveyModel.fromJson(json["survey"]),
isActive: json["isActive"],
pageSize: json["pageSize"],
pageNo: json["pageNo"],
languageId: json["languageId"],
);
Map<String, dynamic> toJson() => {
"notificationMasterId": notificationMasterId == null ? null : notificationMasterId,
"notificationType": notificationType == null ? null : notificationType,
"referenceItemId": referenceItemId == null ? null : referenceItemId,
"notificationTitle": notificationTitle == null ? null : notificationTitle,
"enableAt": enableAt == null ? null : enableAt,
"applicationItemId": applicationItemId,
"startDate": startDate,
"endDate": endDate,
"deadline": deadline == null ? null : deadline ,
"isRepeat": isRepeat == null ? null : isRepeat,
"channelId": channelId == null ? null : channelId,
"serviceId": serviceId == null ? null : serviceId,
"channelName": channelName == null ? null : channelName,
"serviceName": serviceName == null ? null : serviceName,
"isDeleted": isDeleted == null ? null : isDeleted,
"showDelete": showDelete == null ? null : showDelete,
"advertisement": advertisement,
"survey": survey,
"isActive": isActive,
"pageSize": pageSize,
"pageNo": pageNo,
"languageId": languageId,
};
"notificationMasterId": notificationMasterId == null ? null : notificationMasterId,
"notificationType": notificationType == null ? null : notificationType,
"referenceItemId": referenceItemId == null ? null : referenceItemId,
"notificationTitle": notificationTitle == null ? null : notificationTitle,
"enableAt": enableAt == null ? null : enableAt,
"applicationItemId": applicationItemId,
"startDate": startDate,
"endDate": endDate,
"isRepeat": isRepeat == null ? null : isRepeat,
"channelId": channelId == null ? null : channelId,
"serviceId": serviceId == null ? null : serviceId,
"channelName": channelName == null ? null : channelName,
"serviceName": serviceName == null ? null : serviceName,
"isDeleted": isDeleted == null ? null : isDeleted,
"showDelete": showDelete == null ? null : showDelete,
"advertisement": advertisement,
"survey": survey,
"isActive": isActive,
"pageSize": pageSize,
"pageNo": pageNo,
"languageId": languageId,
};
}

@ -19,9 +19,7 @@ import 'package:mohem_flutter_app/models/dashboard/list_menu.dart';
import 'package:mohem_flutter_app/models/dashboard/menu_entries.dart';
import 'package:mohem_flutter_app/models/dashboard/menus.dart';
import 'package:mohem_flutter_app/models/dashboard/mohemm_itg_pending_task_responseitem.dart';
import 'package:mohem_flutter_app/models/dashboard/courses_response_model.dart';
import 'package:mohem_flutter_app/models/eit/get_eit_transaction_model.dart';
import 'package:mohem_flutter_app/models/eit_attachment_ticket_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';
@ -70,11 +68,6 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
bool isOffersLoading = true;
List<OffersListModel> getOffersList = [];
//Courses
bool isCoursesLoading = true;
CoursesResponseModel? coursesResponse;
List<CourseStatus> coursesList = [];
bool isGreetingCardsLoading = true;
bool isDisplayEidGreetings = false;
List<GetGreetingCardsModelResponseElement>? greetingCardsList;
@ -134,11 +127,8 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
DrawerMenuItem("assets/images/drawer/my_profile.svg", LocaleKeys.myProfile.tr(), AppRoutes.profile),
DrawerMenuItem("assets/images/drawer/performance_evaluation.svg", LocaleKeys.performanceEvaluation.tr(), AppRoutes.performanceEvaluation),
DrawerMenuItem("assets/images/drawer/mowadhafi.svg", LocaleKeys.mowadhafhi.tr(), AppRoutes.mowadhafhi),
// DrawerMenuItem("assets/images/drawer/mowadhafi.svg", LocaleKeys.etqanOVR.tr(), AppRoutes.etqanOvr),
DrawerMenuItem("assets/images/drawer/mowadhafi.svg", LocaleKeys.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/courses.svg", "courses".tr(), AppRoutes.courses),
// DrawerMenuItem("assets/images/drawer/drawer_marathon.svg", LocaleKeys.brainMarathon.tr(), AppRoutes.marathonIntroScreen),
DrawerMenuItem("assets/images/drawer/change_password.svg", LocaleKeys.changePassword.tr(), AppRoutes.changePassword),
];
@ -350,7 +340,6 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
try {
GenericResponseModel? genericResponseModel = await DashboardApiClient().getTicketBookingRedirection();
if (genericResponseModel?.portalDirectionData?.pRedirection!.toLowerCase() == "alma") {
// ticketBookingResponse = TicketBookingResult(true, "a9f4d1a0596d4aea8f830992ec4bdac1");
ticketBookingResponse = TicketBookingResult(true, genericResponseModel?.portalDirectionData?.clientID);
return;
}
@ -360,7 +349,7 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
isEventLoadingLoading = false;
notifyListeners();
Utils.handleException(ex, null, null);
ticketBookingResponse = TicketBookingResult(false, null);
ticketBookingResponse = TicketBookingResult(false, null); // Ensure a return value in case of an exception
}
}
@ -408,23 +397,6 @@ 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> menus = [];
for (int i = 0; i < getMenuEntriesList.length; i++) {
@ -458,35 +430,6 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
return res;
}
Future<String?> getENSATItgToken() async {
String? res = await DashboardApiClient().getENSATItgToken();
return res;
}
//Courses API's & Methods
Future<void> fetchCourses(BuildContext context) async {
try {
isCoursesLoading = true;
notifyListeners();
coursesResponse = await DashboardApiClient().fetchAllCoursesStatus();
if (coursesResponse != null && coursesResponse!.success == true) {
coursesList = coursesResponse!.coursesStatus ?? [];
} else {
coursesList = [];
}
isCoursesLoading = false;
notifyListeners();
} catch (ex) {
isCoursesLoading = false;
coursesList = [];
notifyListeners();
Utils.handleException(ex, context, null);
}
}
void notify() {
notifyListeners();
}

@ -1,262 +0,0 @@
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/api/etqan_ovr_api_client.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/models/etqan_ovr/etqan_get_employee_incident_report.dart';
import 'package:mohem_flutter_app/models/etqan_ovr/etqan_get_requests_model.dart';
import 'package:mohem_flutter_app/models/etqan_ovr/etqan_getprojects_model.dart';
import 'package:speech_to_text/speech_recognition_result.dart';
import 'package:speech_to_text/speech_to_text.dart';
class EtqanOvrProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
// Home screen state
List<EtqanGetProjectsResponse>? getEtqanProjectsList;
List<EtqanGetEmployeeOvrRequestsResponse>? getEtqanEmployeeRequestsList;
List<EtqanGetIncidentRequestResponse>? getEtqanEmployeeIncidnetRequest;
bool isLoading = false;
String? _ticketId;
String? _currentStatus;
String? _currentStatusAr;
bool? _currentIsAnonymous;
// Speech to text state
final SpeechToText _speechToText = SpeechToText();
bool _speechEnabled = false;
bool _isListening = false;
String _currentLocaleId = '';
TextEditingController? _currentController;
String _baseText = ''; // Text that was there when we started listening
String _currentSessionText = ''; // Text captured in current listening session
// Getters for speech state
bool get speechEnabled => _speechEnabled;
bool get isListening => _isListening;
// Getter for ticketId
String get getTicketId => _ticketId ?? '';
String get getCurrentStatus => _currentStatus ?? '';
String get getCurrentStatusAr => _currentStatusAr ?? '';
bool get getCurrentIsAnonymous => _currentIsAnonymous ?? false;
// Setter for ticketId with status and isAnonymous
void setTicketId(String ticketId, {String? status, String? statusAr, bool? isAnonymous}) {
_ticketId = ticketId;
_currentStatus = status;
_currentStatusAr = statusAr;
_currentIsAnonymous = isAnonymous;
notifyListeners();
}
// Create request screen state
EtqanGetProjectsResponse? selectedProject;
String? selectedEmployeeNumber;
File? attachment;
String? attachmentBase64;
String description = '';
bool isAnonymous = false;
/// Initialize speech recognition - call this once when screen loads
Future<void> initSpeech() async {
_speechEnabled = await _speechToText.initialize(
onStatus: (String status) {
print('Speech status: $status, isListening: $_isListening');
// If user wants to keep listening but speech stopped, restart it
if ((status == 'done' || status == 'notListening') && _isListening && _currentController != null) {
// Save the finalized text before restarting
if (_currentSessionText.isNotEmpty) {
_baseText = _currentController!.text.trim();
_currentSessionText = '';
}
// Automatically restart listening after a brief pause
Future.delayed(const Duration(milliseconds: 300), () {
if (_isListening && _currentController != null) {
_startListeningInternal(_currentLocaleId, _currentController!);
}
});
}
},
);
notifyListeners();
}
/// Internal method to start listening
Future<void> _startListeningInternal(String localeId, TextEditingController controller) async {
if (!_speechEnabled) return;
await _speechToText.listen(
onResult: (SpeechRecognitionResult result) {
_currentSessionText = result.recognizedWords;
// Combine base text with current session text
String combinedText = _baseText.isEmpty
? _currentSessionText
: _baseText + (_baseText.endsWith(' ') ? '' : ' ') + _currentSessionText;
description = combinedText;
controller.text = combinedText;
controller.selection = TextSelection.fromPosition(TextPosition(offset: controller.text.length));
notifyListeners();
},
localeId: localeId,
listenFor: const Duration(seconds: 60),
pauseFor: const Duration(seconds: 10),
listenOptions: SpeechListenOptions(
partialResults: true,
listenMode: ListenMode.confirmation,
cancelOnError: false,
),
);
}
/// Start listening for speech input
Future<void> startListening(String localeId, TextEditingController controller) async {
_isListening = true;
_currentLocaleId = localeId;
_currentController = controller;
_baseText = controller.text.trim(); // Save existing text
_currentSessionText = '';
notifyListeners();
await _startListeningInternal(localeId, controller);
}
/// Stop listening for speech input
Future<void> stopListening() async {
_isListening = false;
_currentLocaleId = '';
_currentController = null;
_baseText = '';
_currentSessionText = '';
await _speechToText.stop();
notifyListeners();
}
/// Toggle listening state
Future<void> toggleListening(String localeId, TextEditingController controller) async {
if (_isListening) {
await stopListening();
} else {
await startListening(localeId, controller);
}
}
// Fetch Etqan Projects
Future<void> fetchEtqanProjects(BuildContext context) async {
isLoading = true;
notifyListeners();
Utils.showLoading(context);
getEtqanProjectsList?.clear();
getEtqanProjectsList = await EtqanApiClient().getEtqanProjects();
Utils.hideLoading(context);
isLoading = false;
notifyListeners();
}
// Fetch Etqan Employee Requests
Future<void> fetchEtqanEmployeeRequests(BuildContext context) async {
isLoading = true;
notifyListeners();
Utils.showLoading(context);
getEtqanEmployeeRequestsList?.clear();
getEtqanEmployeeRequestsList = await EtqanApiClient().getEmployeeEtqanRequests();
Utils.hideLoading(context);
isLoading = false;
notifyListeners();
}
// Fetch Etqan Employee Incident Report
Future<void> fetchEtqanEmployeeIncidentRequests(BuildContext context, String ticketNo) async {
isLoading = true;
notifyListeners();
Utils.showLoading(context);
getEtqanEmployeeIncidnetRequest?.clear();
getEtqanEmployeeIncidnetRequest = await EtqanApiClient().getEtqanIncidentRequests(ticketNo);
Utils.hideLoading(context);
isLoading = false;
notifyListeners();
}
// Set selected project
void setSelectedProject(EtqanGetProjectsResponse? project) {
selectedProject = project;
notifyListeners();
}
// Set selected employee number
void setSelectedEmployeeNumber(String? employeeNumber) {
selectedEmployeeNumber = employeeNumber;
notifyListeners();
}
// Set attachment with base64
void setAttachment(File file, String base64) {
attachment = file;
attachmentBase64 = base64;
notifyListeners();
}
// Remove attachment
void removeAttachment() {
attachment = null;
attachmentBase64 = null;
notifyListeners();
}
// Set description
void setDescription(String value) {
description = value;
notifyListeners();
}
// Validate description
bool isDescriptionValid() {
return description.trim().isNotEmpty;
}
// Set isAnonymous
void setIsAnonymous(bool value) {
isAnonymous = value;
notifyListeners();
}
// Clear create request form
void clearCreateRequestForm() {
selectedProject = null;
selectedEmployeeNumber = null;
attachment = null;
attachmentBase64 = null;
description = '';
isAnonymous = false;
notifyListeners();
}
// Submit request
Future<Map<String, dynamic>?> submitRequest(BuildContext context) async {
try {
Utils.showLoading(context);
Map<String, dynamic>? response = await EtqanApiClient().createRequest(description, selectedProject?.projectId, attachmentBase64, isAnonymous);
Utils.hideLoading(context);
if (response != null) {
getEtqanEmployeeRequestsList = await EtqanApiClient().getEmployeeEtqanRequests();
notifyListeners();
return response;
}
return null;
} catch (ex) {
Utils.hideLoading(context);
Utils.handleException(ex, context, null);
return null;
}
}
@override
void dispose() {
if (_isListening) {
_speechToText.stop();
}
super.dispose();
}
}

@ -301,6 +301,7 @@ class _MonthlyAttendanceScreenState extends State<MonthlyAttendanceScreen> {
monthCellBuilder: (build, details) {
if (details.date.month == formattedDate.month && details.date.year == formattedDate.year) {
int val = details.date.day;
int index = val-1;
//check day is off
// if (getDayHoursTypeDetailsList.isNotEmpty) {
// bool isDayIsOff = getDayHoursTypeDetailsList[val - 1].aTTENDEDFLAG == 'N' && getDayHoursTypeDetailsList[val - 1].dAYTYPE == 'OFF';
@ -310,30 +311,9 @@ class _MonthlyAttendanceScreenState extends State<MonthlyAttendanceScreen> {
getDayHoursTypeDetailsList.where((GetDayHoursTypeDetailsList element) => DateFormat("MM/dd/yyyy", "en_US").parse(element.sCHEDULEDATE!).day == details.date.day).toList();
if (getDayHours.isNotEmpty) {
GetDayHoursTypeDetailsList dayData = getDayHours.first;
bool isDayIsOff = dayData.aTTENDEDFLAG == 'N' && dayData.dAYTYPE == 'OFF';
bool isDayIsPresent = dayData.aTTENDEDFLAG == 'Y';
bool isDayIsAbsent = dayData.aTTENDEDFLAG == 'N' && dayData.aBSENTFLAG == 'Y';
// Get leave type code and corresponding color
String? leaveTypeCode = dayData.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'];
}
}
bool isDayIsOff = getDayHoursTypeDetailsList[index].aTTENDEDFLAG == 'N' && getDayHoursTypeDetailsList[index].dAYTYPE == 'OFF';
bool isDayIsPresent = getDayHoursTypeDetailsList[index].aTTENDEDFLAG == 'Y';
bool isDayIsAbsent = getDayHoursTypeDetailsList[index].aTTENDEDFLAG == 'N' && getDayHoursTypeDetailsList[index].aBSENTFLAG == 'Y';
if (isDayIsOff) {
return Container(
@ -351,13 +331,12 @@ class _MonthlyAttendanceScreenState extends State<MonthlyAttendanceScreen> {
return Container(
margin: const EdgeInsets.all(4),
decoration: BoxDecoration(
gradient: useGradient && leaveTypeColor != null ? LinearGradient(
gradient: const LinearGradient(
transform: GradientRotation(.46),
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: [MyColors.gradiantEndColor, MyColors.gradiantStartColor],
) : null,
color: !useGradient && leaveTypeColor != null ? leaveTypeColor : null,
),
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
@ -379,7 +358,7 @@ class _MonthlyAttendanceScreenState extends State<MonthlyAttendanceScreen> {
return Container(
margin: const EdgeInsets.all(4),
decoration: BoxDecoration(
color: leaveTypeColor ?? MyColors.backgroundBlackColor,
color: MyColors.backgroundBlackColor,
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
@ -428,18 +407,12 @@ class _MonthlyAttendanceScreenState extends State<MonthlyAttendanceScreen> {
}
void calendarTapped(CalendarTapDetails details) async {
if (details.date == null) return;
// Filter to find the matching day data
List<GetDayHoursTypeDetailsList> getDayHours =
getDayHoursTypeDetailsList.where((GetDayHoursTypeDetailsList element) =>
DateFormat("MM/dd/yyyy", "en_US").parse(element.sCHEDULEDATE!).day == details.date!.day).toList();
if (getDayHours.isEmpty) return;
GetDayHoursTypeDetailsList dayData = getDayHours.first;
pRTPID = dayData.rTPID;
await getScheduleShiftsDetails(details.date!.day, pRTPID);
dynamic index = details.date?.day;
if (index != null) {
index = index - 1;
}
pRTPID = getDayHoursTypeDetailsList[index].rTPID;
await getScheduleShiftsDetails(index, pRTPID);
dynamic value = getScheduleShiftsDetailsList!.pERCENTAGE;
dynamic percentage;
if (value!.indexOf('%') == 3) {
@ -452,7 +425,8 @@ class _MonthlyAttendanceScreenState extends State<MonthlyAttendanceScreen> {
percentage = 0;
}
if (details.date!.month == formattedDate.month && details.date!.year == formattedDate.year) {
dayData.aTTENDEDFLAG == 'Y'
int val = details.date!.day;
getDayHoursTypeDetailsList?[val - 1].aTTENDEDFLAG == 'Y'
? showModalBottomSheet(
context: context,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(25)),
@ -597,7 +571,7 @@ class _MonthlyAttendanceScreenState extends State<MonthlyAttendanceScreen> {
LocaleKeys.lateIn.tr().toText11(
color: MyColors.grey67Color,
),
"${dayData.lATEINHRS}".toText22(color: MyColors.redColor, isBold: true),
"${getDayHoursTypeDetailsList[index].lATEINHRS}".toText22(color: MyColors.redColor, isBold: true),
],
).expanded,
Column(
@ -606,7 +580,7 @@ class _MonthlyAttendanceScreenState extends State<MonthlyAttendanceScreen> {
LocaleKeys.excess.tr().toText11(
color: MyColors.grey67Color,
),
"${dayData.eXCESSHRS}".toText22(color: MyColors.backgroundBlackColor, isBold: true),
"${getDayHoursTypeDetailsList[index].eXCESSHRS}".toText22(color: MyColors.backgroundBlackColor, isBold: true),
],
).expanded,
],
@ -626,7 +600,7 @@ class _MonthlyAttendanceScreenState extends State<MonthlyAttendanceScreen> {
LocaleKeys.shortage.tr().toText11(
color: MyColors.grey67Color,
),
"${dayData.sHORTAGEHRS}".toText22(color: MyColors.backgroundBlackColor, isBold: true),
"${getDayHoursTypeDetailsList[index].sHORTAGEHRS}".toText22(color: MyColors.backgroundBlackColor, isBold: true),
],
).expanded,
Column(
@ -635,7 +609,7 @@ class _MonthlyAttendanceScreenState extends State<MonthlyAttendanceScreen> {
LocaleKeys.earlyOut.tr().toText11(
color: MyColors.grey67Color,
),
"${dayData.eARLYOUTHRS}".toText22(color: Colors.black, isBold: true),
"${getDayHoursTypeDetailsList[index].eARLYOUTHRS}".toText22(color: Colors.black, isBold: true),
],
).expanded,
],
@ -777,24 +751,3 @@ class Meeting {
Color background;
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),
};

@ -1,360 +0,0 @@
import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/models/etqan_ovr/etqan_getprojects_model.dart';
import 'package:mohem_flutter_app/provider/etqan_ovr_provider.dart';
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
import 'package:mohem_flutter_app/widgets/bottom_sheet.dart';
import 'package:mohem_flutter_app/widgets/button/default_button.dart';
import 'package:mohem_flutter_app/widgets/image_picker.dart';
import 'package:provider/provider.dart';
class EtqanOvrCreateRequest extends StatefulWidget {
const EtqanOvrCreateRequest({Key? key}) : super(key: key);
@override
_EtqanOvrCreateRequestState createState() => _EtqanOvrCreateRequestState();
}
class _EtqanOvrCreateRequestState extends State<EtqanOvrCreateRequest> {
final TextEditingController _descriptionController = TextEditingController();
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
var provider = context.read<EtqanOvrProviderModel>();
provider.initSpeech();
provider.fetchEtqanProjects(context);
provider.clearCreateRequestForm();
});
}
@override
void dispose() {
// Stop listening if active
context.read<EtqanOvrProviderModel>().stopListening();
_descriptionController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBarWidget(context, title: LocaleKeys.reportIncident.tr(), showHomeButton: false),
body: Consumer<EtqanOvrProviderModel>(
builder: (BuildContext context, EtqanOvrProviderModel provider, Widget? child) {
return Column(
children: <Widget>[
(ListView(
shrinkWrap: true,
physics: const BouncingScrollPhysics(),
padding: const EdgeInsets.all(21),
children: <Widget>[
_buildDropdownField(
label: LocaleKeys.project.tr(),
hint: LocaleKeys.selectProject.tr(),
value: _getProjectDisplayName(provider.selectedProject),
onTap: () => _showProjectSelectionSheet(context, provider),
isMandatory: true,
),
16.height,
// _buildDropdownField(
// label: 'Employee Number',
// hint: 'Write a message',
// value: provider.selectedEmployeeNumber,
// onTap: () {
// // TODO: Show employee selection dialog
// },
// ),
// 16.height,
_buildAttachmentSection(provider),
16.height,
_buildDescriptionField(provider),
8.height,
_buildAnonymousCheckbox(provider),
24.height,
],
)).expanded,
DefaultButton(LocaleKeys.submit.tr(), () async {
provider.setDescription(_descriptionController.text);
if (provider.selectedProject == null) {
Utils.showErrorDialog(
context: context,
message: LocaleKeys.pleaseSelectProject.tr(),
onOkTapped: () {
Navigator.of(context).pop();
},
);
return;
}
if (!provider.isDescriptionValid()) {
Utils.showErrorDialog(
context: context,
message: LocaleKeys.pleaseEnterDescription.tr(),
onOkTapped: () {
Navigator.of(context).pop();
},
);
return;
}
Map<String, dynamic>? ticketInfo = await provider.submitRequest(context);
if (ticketInfo != null) {
String ticketNumber = ticketInfo['ticketNumber'] ?? '';
String ticketId = ticketInfo['id'] ?? '';
// String successMessage = '${LocaleKeys.requestCreatedSuccessfully.tr()}\n\n${LocaleKeys.ticketNumber.tr()}: $ticketNumber\n${LocaleKeys.ticketId.tr()}: $ticketId';
String successMessage = '${LocaleKeys.requestCreatedSuccessfully.tr()}\n\n${LocaleKeys.ticketNumber.tr()}: $ticketNumber';
Utils.showErrorDialog(
context: context,
message: successMessage,
onOkTapped: () {
Navigator.pop(context);
Navigator.pop(context);
// Navigator.popAndPushNamed(context, AppRoutes.etqanOvr);
},
onCloseTap: () {
Navigator.pop(context);
Navigator.pop(context);
// Navigator.popAndPushNamed(context, AppRoutes.etqanOvr);
},
);
}
}).insideContainer,
],
);
},
),
);
}
String? _getProjectDisplayName(EtqanGetProjectsResponse? project) {
if (project == null) return null;
return AppState().isArabic(context) ? project.projectAr : project.projectEn;
}
void _showProjectSelectionSheet(BuildContext context, EtqanOvrProviderModel provider) {
if (provider.getEtqanProjectsList == null || provider.getEtqanProjectsList!.isEmpty) {
return;
}
showMyBottomSheet(
context,
callBackFunc: () {},
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Text(LocaleKeys.selectProject.tr(), style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600, color: Color(0xff2B353E))),
),
const Divider(),
ListView.separated(
shrinkWrap: true,
physics: const BouncingScrollPhysics(),
itemCount: provider.getEtqanProjectsList!.length,
separatorBuilder: (BuildContext context, int index) => const Divider(height: 1),
itemBuilder: (BuildContext context, int index) {
EtqanGetProjectsResponse project = provider.getEtqanProjectsList![index];
bool isSelected = provider.selectedProject?.projectId == project.projectId;
return ListTile(
title: Text(
AppState().isArabic(context) ? (project.projectAr ?? '') : (project.projectEn ?? ''),
style: TextStyle(fontSize: 14, fontWeight: isSelected ? FontWeight.w600 : FontWeight.w400, color: isSelected ? MyColors.gradiantEndColor : const Color(0xff2B353E)),
),
trailing: isSelected ? const Icon(Icons.check, color: MyColors.gradiantEndColor) : null,
onTap: () {
provider.setSelectedProject(project);
Navigator.pop(context);
},
);
},
),
16.height,
],
),
);
}
Widget _buildDropdownField({required String label, required String hint, String? value, required VoidCallback onTap, bool isMandatory = false}) {
return InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(15),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 15),
decoration: BoxDecoration(borderRadius: BorderRadius.circular(15), color: Colors.white, border: Border.all(color: const Color(0xffefefef), width: 1)),
child: Row(
children: <Widget>[
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
children: <Widget>[
Text(label, style: const TextStyle(fontSize: 11, fontWeight: FontWeight.w600, color: Color(0xff2B353E), letterSpacing: -0.44)),
if (isMandatory) const Text(' *', style: TextStyle(fontSize: 11, fontWeight: FontWeight.w600, color: Colors.red, letterSpacing: -0.44)),
],
),
const SizedBox(height: 4),
Text(value ?? hint, style: TextStyle(fontSize: 14, fontWeight: FontWeight.w400, color: value != null ? const Color(0xff2B353E) : const Color(0xff575757), letterSpacing: -0.56)),
],
),
),
const Icon(Icons.keyboard_arrow_down, color: Color(0xff575757)),
],
),
),
);
}
Widget _buildAttachmentSection(EtqanOvrProviderModel provider) {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(borderRadius: BorderRadius.circular(15), color: Colors.white, border: Border.all(color: const Color(0xffefefef), width: 1)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(LocaleKeys.supportingDocument.tr(), style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Color(0xff2B353E))),
const SizedBox(height: 12),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(LocaleKeys.attachments.tr(), style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: Color(0xff2B353E))),
if (provider.attachment == null)
InkWell(
onTap: () {
ImageOptions.showImageOptionsNew(context, true, (String base64, File file) {
provider.setAttachment(file, base64);
Navigator.of(context).pop();
});
},
borderRadius: BorderRadius.circular(8),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 8),
decoration: BoxDecoration(color: MyColors.gradiantEndColor, borderRadius: BorderRadius.circular(8)),
child: Text(LocaleKeys.add.tr(), style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w600, color: Colors.white)),
),
),
],
),
if (provider.attachment != null) ...<Widget>[
const SizedBox(height: 12),
Padding(
padding: const EdgeInsets.only(bottom: 8),
child: Row(
children: <Widget>[
const Icon(Icons.attach_file, size: 18, color: Color(0xff575757)),
const SizedBox(width: 8),
Expanded(child: Text(provider.attachment!.path.split('/').last, style: const TextStyle(fontSize: 12, color: Color(0xff575757)), overflow: TextOverflow.ellipsis)),
InkWell(
onTap: () {
provider.removeAttachment();
},
child: const Icon(Icons.close, size: 18, color: Colors.red),
),
],
),
),
],
],
),
);
}
Widget _buildDescriptionField(EtqanOvrProviderModel provider) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 15),
decoration: BoxDecoration(borderRadius: BorderRadius.circular(15), color: Colors.white, border: Border.all(color: const Color(0xffefefef), width: 1)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Row(
children: <Widget>[
Text(LocaleKeys.description.tr(), style: const TextStyle(fontSize: 11, fontWeight: FontWeight.w600, color: Color(0xff2B353E), letterSpacing: -0.44)),
const Text(' *', style: TextStyle(fontSize: 11, fontWeight: FontWeight.w600, color: Colors.red, letterSpacing: -0.44)),
],
),
GestureDetector(
onTap:
provider.speechEnabled
? () {
String localeId = AppState().isArabic(context) ? 'ar_SA' : 'en_US';
provider.toggleListening(localeId, _descriptionController);
}
: null,
child: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(color: provider.isListening ? MyColors.gradiantEndColor.withOpacity(0.1) : Colors.transparent, borderRadius: BorderRadius.circular(20)),
child: Icon(
provider.isListening ? Icons.mic : Icons.mic_none,
color: provider.isListening ? MyColors.gradiantEndColor : (provider.speechEnabled ? MyColors.grey57Color : Colors.grey.shade300),
size: 24,
),
),
),
],
),
if (provider.isListening)
Padding(
padding: const EdgeInsets.only(bottom: 8),
child: Row(
children: <Widget>[
Container(width: 8, height: 8, decoration: BoxDecoration(color: Colors.red, borderRadius: BorderRadius.circular(4))),
const SizedBox(width: 8),
const Text('Listening...', style: TextStyle(fontSize: 12, color: MyColors.gradiantEndColor, fontWeight: FontWeight.w500)),
],
),
),
TextField(
controller: _descriptionController,
maxLines: 4,
onChanged: (String value) => provider.setDescription(value),
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w400, color: Color(0xff2B353E), letterSpacing: -0.44),
decoration: InputDecoration(
isDense: true,
hintText: LocaleKeys.writeAMessage.tr(),
hintStyle: const TextStyle(fontSize: 14, fontWeight: FontWeight.w400, color: Color(0xff575757), letterSpacing: -0.56),
contentPadding: EdgeInsets.zero,
border: InputBorder.none,
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
),
),
],
),
);
}
Widget _buildAnonymousCheckbox(EtqanOvrProviderModel provider) {
return InkWell(
onTap: () {
provider.setIsAnonymous(!provider.isAnonymous);
},
child: Row(
children: <Widget>[
Checkbox(
value: provider.isAnonymous,
onChanged: (bool? value) {
if (value != null) {
provider.setIsAnonymous(value);
}
},
activeColor: MyColors.gradiantEndColor,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)),
),
Expanded(child: Text(LocaleKeys.submitAsAnonymous.tr(), style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: Color(0xff2B353E), letterSpacing: -0.44))),
],
),
);
}
}

@ -1,165 +0,0 @@
import 'package:easy_localization/easy_localization.dart' as lclize;
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/models/etqan_ovr/etqan_get_requests_model.dart';
import 'package:mohem_flutter_app/provider/etqan_ovr_provider.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
import 'package:mohem_flutter_app/widgets/button/default_button.dart';
import 'package:provider/provider.dart';
import 'package:intl/src/intl/text_direction.dart' as intl;
import 'package:sizer/sizer.dart';
class EtqanOvrHome extends StatefulWidget {
const EtqanOvrHome({Key? key}) : super(key: key);
@override
_EtqanOvrHomeState createState() => _EtqanOvrHomeState();
}
class _EtqanOvrHomeState extends State<EtqanOvrHome> {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
context.read<EtqanOvrProviderModel>().fetchEtqanEmployeeRequests(context);
});
}
Color _getStatusColor(String status) {
String statusLower = status.toLowerCase();
if (statusLower.contains('open') || statusLower.contains('مفتوح')) {
return const Color(0xff2196F3); // Blue for open
} else if (statusLower.contains('progress') || statusLower.contains('قيد التنفيذ')) {
return const Color(0xffFF9800); // Orange for in progress
} else if (statusLower.contains('closed') || statusLower.contains('مغلق')) {
return const Color(0xff4CAF50); // Green for closed
}
return MyColors.grey70Color; // Default gray
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBarWidget(context, title: LocaleKeys.myIncidents.tr()),
body: Consumer<EtqanOvrProviderModel>(
builder: (BuildContext context, EtqanOvrProviderModel provider, Widget? child) {
return Column(
children: <Widget>[
(provider.getEtqanEmployeeRequestsList == null || provider.getEtqanEmployeeRequestsList!.isEmpty
? Utils.getNoDataWidget(context)
: ListView.separated(
physics: const BouncingScrollPhysics(),
padding: const EdgeInsets.all(20),
itemBuilder: (BuildContext context, int index) {
EtqanGetEmployeeOvrRequestsResponse data = provider.getEtqanEmployeeRequestsList![index];
return InkWell(
onTap: () {
context.read<EtqanOvrProviderModel>().setTicketId(data.ticketNumber ?? '', status: data.status, statusAr: data.statusAr, isAnonymous: data.isAnonymous);
Navigator.pushNamed(context, AppRoutes.etqanGetIncidientRequest);
},
child: Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(15), border: Border.all(color: const Color(0xffefefef), width: 1)),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
children: [
Expanded(
child: Wrap(
spacing: 8,
runSpacing: 8,
children: [
if (data.status != null && data.status!.isNotEmpty)
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: _getStatusColor(data.status ?? "").withOpacity(0.1),
borderRadius: BorderRadius.circular(6),
border: Border.all(color: _getStatusColor(data.status ?? "").withOpacity(0.3), width: 1),
),
child: (AppState().isArabic(context) ? (data.statusAr ?? "") : (data.status ?? "")).toText11(
color: _getStatusColor(data.status ?? ""),
isBold: true,
),
),
if (data.isAnonymous == true)
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: MyColors.grey70Color.withOpacity(0.15),
borderRadius: BorderRadius.circular(6),
border: Border.all(color: MyColors.grey70Color.withOpacity(0.3), width: 1),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.visibility_off, size: 12, color: MyColors.grey70Color),
const SizedBox(width: 4),
(AppState().isArabic(context) ? "مجهول" : "Anonymous").toText11(color: MyColors.grey70Color, isBold: true),
],
),
),
],
),
),
const SizedBox(width: 8),
],
),
8.height,
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
(data.ticketNumber ?? "").toText14(isBold: true, color: MyColors.darkTextColor),
Directionality(textDirection: TextDirection.ltr, child: (data.createdDate!.split(" ").first ?? "").toText12(color: MyColors.grey70Color)),
],
),
8.height,
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [(data.description ?? "").toText12(color: MyColors.grey57Color).expanded]),
3.height,
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.end,
children: [
RotatedBox(
quarterTurns: AppState().isArabic(context) ? 2 : 0,
child: SvgPicture.asset("assets/images/arrow_next.svg", color: MyColors.grey70Color, width: 16, height: 16),
),
],
),
],
),
),
],
),
),
);
},
separatorBuilder: (BuildContext context, int index) => 12.height,
itemCount: provider.getEtqanEmployeeRequestsList!.length,
))
.expanded,
DefaultButton(LocaleKeys.reportIncident.tr(), () async {
await Navigator.pushNamed(context, AppRoutes.etqanCreateRequest);
// getOpenTickets();
}).insideContainer,
],
);
},
),
);
}
}

@ -1,235 +0,0 @@
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/models/etqan_ovr/etqan_get_employee_incident_report.dart';
import 'package:mohem_flutter_app/provider/etqan_ovr_provider.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
import 'package:provider/provider.dart';
import 'package:open_filex/open_filex.dart';
import 'package:path_provider/path_provider.dart';
class EtqanOvrRequestDetailed extends StatefulWidget {
const EtqanOvrRequestDetailed({Key? key}) : super(key: key);
@override
_EtqanOvrRequestDetailedState createState() => _EtqanOvrRequestDetailedState();
}
class _EtqanOvrRequestDetailedState extends State<EtqanOvrRequestDetailed> {
List<String> get fieldOrder => ['Status', 'Project', 'Created', 'Is Anonymous', 'Occurrence Time', 'OVR Reference No', 'Involved Employee Number', 'Description'];
List<String> get hiddenFields => ['OVR Id'];
Color _getStatusColor(String status) {
String statusLower = status.toLowerCase();
if (statusLower.contains('open') || statusLower.contains('مفتوح')) {
return const Color(0xff2196F3); // Blue for open
} else if (statusLower.contains('progress') || statusLower.contains('قيد التنفيذ')) {
return const Color(0xffFF9800); // Orange for in progress
} else if (statusLower.contains('closed') || statusLower.contains('مغلق')) {
return const Color(0xff4CAF50); // Green for closed
}
return MyColors.grey70Color; // Default gray
}
Future<void> _viewAttachment(BuildContext context, String base64Data) async {
try {
Uint8List bytes = base64.decode(base64Data);
String dir = (await getApplicationDocumentsDirectory()).path;
String ext = 'pdf';
if (base64Data.startsWith('/9j/')) {
ext = 'jpg';
} else if (base64Data.startsWith('iVBORw0KGgo')) {
ext = 'png';
}
File file = File("$dir/${DateTime.now().millisecondsSinceEpoch}.$ext");
await file.writeAsBytes(bytes);
OpenFilex.open(file.path);
} catch (e) {
Utils.showToast("Cannot open attachment.");
}
}
List<EtqanGetIncidentRequestResponse> _getOrderedList(List<EtqanGetIncidentRequestResponse> list, EtqanOvrProviderModel provider) {
List<EtqanGetIncidentRequestResponse> orderedList = [];
List<EtqanGetIncidentRequestResponse> filteredList = list.where((EtqanGetIncidentRequestResponse item) => !hiddenFields.any((f) => f.toLowerCase() == item.key?.toLowerCase())).toList();
for (String fieldName in fieldOrder) {
// Check if this is Status or Is Anonymous - inject from provider
if (fieldName.toLowerCase() == 'status' && provider.getCurrentStatus.isNotEmpty) {
orderedList.add(EtqanGetIncidentRequestResponse(
key: 'Status',
keyAr: 'الحالة',
value: provider.getCurrentStatus,
valueAr: provider.getCurrentStatusAr.isNotEmpty ? provider.getCurrentStatusAr : provider.getCurrentStatus,
));
} else if (fieldName.toLowerCase() == 'is anonymous') {
orderedList.add(EtqanGetIncidentRequestResponse(
key: 'Is Anonymous',
keyAr: 'مجهول',
value: provider.getCurrentIsAnonymous.toString(),
valueAr: provider.getCurrentIsAnonymous.toString(),
));
} else {
// Regular field from API
var item = filteredList.firstWhere((e) => e.key?.toLowerCase() == fieldName.toLowerCase(), orElse: () => EtqanGetIncidentRequestResponse());
if (item.key != null) {
orderedList.add(item);
}
}
}
for (var item in filteredList) {
if (!fieldOrder.any((f) => f.toLowerCase() == item.key?.toLowerCase())) {
orderedList.add(item);
}
}
return orderedList;
}
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
EtqanOvrProviderModel provider = context.read<EtqanOvrProviderModel>();
provider.fetchEtqanEmployeeIncidentRequests(context, provider.getTicketId);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBarWidget(context, title: LocaleKeys.incidentDetails.tr()),
body: Consumer<EtqanOvrProviderModel>(
builder: (BuildContext context, EtqanOvrProviderModel provider, Widget? child) {
if (provider.getEtqanEmployeeIncidnetRequest == null || provider.getEtqanEmployeeIncidnetRequest!.isEmpty) {
return Utils.getNoDataWidget(context);
}
List<EtqanGetIncidentRequestResponse> orderedList = _getOrderedList(provider.getEtqanEmployeeIncidnetRequest!, provider);
return SingleChildScrollView(
physics: const BouncingScrollPhysics(),
padding: const EdgeInsets.all(16),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15),
border: Border.all(color: const Color(0xffefefef), width: 1),
boxShadow: <BoxShadow>[BoxShadow(color: Colors.black.withValues(alpha: 0.05), blurRadius: 10, offset: const Offset(0, 2))],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children:
orderedList.asMap().entries.map((MapEntry<int, EtqanGetIncidentRequestResponse> entry) {
int index = entry.key;
EtqanGetIncidentRequestResponse data = entry.value;
bool isLast = index == orderedList.length - 1;
bool isAttachment = data.key?.toLowerCase() == 'attachment';
bool isStatus = data.key?.toLowerCase() == 'status';
bool isAnonymous = data.key?.toLowerCase() == 'is anonymous';
String displayKey = context.locale.languageCode == "ar" ? (data.keyAr ?? data.key ?? "") : (data.key ?? "");
String displayValue = context.locale.languageCode == "ar" ? (data.valueAr ?? data.value ?? "") : (data.value ?? "");
bool hasSubValues = data.subValues != null && data.subValues!.isNotEmpty;
return Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(flex: 2, child: displayKey.toText12(isBold: true, color: MyColors.grey57Color)),
8.width,
Expanded(
flex: 3,
child: isStatus
? displayValue.toText14(
color: _getStatusColor(displayValue),
isBold: true,
)
: isAnonymous
? (displayValue.toLowerCase() == 'true' || displayValue.toLowerCase() == 'yes' || displayValue == '1'
? (context.locale.languageCode == "ar" ? "نعم" : "Yes")
: (context.locale.languageCode == "ar" ? "لا" : "No")
).toText14(color: MyColors.darkTextColor)
: isAttachment && hasSubValues
? Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: data.subValues!.asMap().entries.map((entry) {
int subIndex = entry.key;
String base64Data = entry.value;
return Padding(
padding: EdgeInsets.only(bottom: subIndex < data.subValues!.length - 1 ? 8.0 : 0),
child: GestureDetector(
onTap: () => _viewAttachment(context, base64Data),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: context.locale.languageCode == "ar" ? MainAxisAlignment.end : MainAxisAlignment.start,
children: [
Text(
data.subValues!.length > 1 ? '${LocaleKeys.viewAttachment.tr()} ${subIndex + 1}' : LocaleKeys.viewAttachment.tr(),
style: const TextStyle(
fontSize: 14,
color: MyColors.green9CColor,
decoration: TextDecoration.underline,
decorationColor: MyColors.green9CColor,
),
),
],
),
),
);
}).toList(),
)
: hasSubValues
? Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (displayValue.isNotEmpty) displayValue.toText14(color: MyColors.darkTextColor),
if (displayValue.isNotEmpty) 8.height,
...data.subValues!
.map(
(subValue) => Padding(
padding: const EdgeInsets.only(bottom: 4),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [const Text("", style: TextStyle(fontSize: 14)), Expanded(child: subValue.toText14(color: MyColors.darkTextColor))],
),
),
)
.toList(),
],
)
: (displayValue.isNotEmpty ? displayValue : "-").toText14(color: MyColors.darkTextColor),
),
],
),
),
if (!isLast) const Padding(padding: EdgeInsets.only(left: 14, right: 14), child: Divider(height: 1, thickness: 1, color: Color(0xffefefef))),
],
);
}).toList(),
),
),
);
},
).paddingOnly(bottom: 20),
);
}
}

@ -33,7 +33,6 @@ import 'package:mohem_flutter_app/widgets/shimmer/offers_shimmer_widget.dart';
import 'package:provider/provider.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:signalr_netcore/signalr_client.dart';
import 'package:url_launcher/url_launcher.dart';
late HubConnection chatHubConnection;
@ -155,8 +154,8 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
data.fetchLeaveTicketBalance(context, DateTime.now());
data.fetchMenuEntries();
data.fetchEventActivity();
data.getCategoryOffersListAPI(context);
data.fetchGreetingCards();
data.getCategoryOffersListAPI(context);
marathonProvider.getMarathonDetailsFromApi();
marathonProvider.getMarathonTutorial();
if (isFromInit) {
@ -165,12 +164,11 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
if (!cProvider.disbaleChatForThisUser && !isFromInit) checkHubCon();
_refreshController.refreshCompleted();
await data.fetchTicketBooking();
// await data.fetchTicketBooking();
// if (data.ticketBookingResponse != null && !data.ticketBookingResponse!.success) {
// data.fetchTicketBalance();
// // data.fetchTicketBalance();
// }
//continue here
}
@ -185,18 +183,13 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
ItgMainRes? response = await DashboardApiClient().getAdvertisementDetail(list[ermIndex].notificationMasterId ?? "");
// Utils.hideLoading(context);
if (response!.mohemmItgResponseItem!.result!.data != null) {
for (ItgResponseData payload in response.mohemmItgResponseItem!.result!.data!) {
if (payload.notificationMasterId == list[ermIndex].notificationMasterId) {
payload.deadline = list[ermIndex].deadline;
}
}
if (list[ermIndex].notificationType == "Survey") {
await Navigator.pushNamed(context, AppRoutes.survey, arguments: response.mohemmItgResponseItem!.result!.data!.first);
} else {
await Navigator.pushNamed(
context,
AppRoutes.advertisement,
arguments: {"masterId": list[ermIndex].notificationMasterId, "advertisement": response.mohemmItgResponseItem!.result!.data!.first},
arguments: {"masterId": list[ermIndex].notificationMasterId, "advertisement": response.mohemmItgResponseItem!.result!.data!.first.advertisement},
);
}
}
@ -290,9 +283,7 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
});
},
),
Image
.asset("assets/images/logos/main_mohemm_logo.png", width: 134, height: 28)
.expanded,
Image.asset("assets/images/logos/main_mohemm_logo.png", width: 134, height: 28).expanded,
SvgPicture.asset("assets/images/announcements.svg", matchTextDirection: true).onPress(() async {
await Navigator.pushNamed(context, AppRoutes.announcements);
}),
@ -324,103 +315,103 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
child: Consumer<DashboardProviderModel>(
builder: (BuildContext context, DashboardProviderModel model, Widget? child) {
return (model.isAttendanceTrackingLoading
? GetAttendanceTrackingShimmer()
: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
gradient: const LinearGradient(
transform: GradientRotation(.46),
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: [MyColors.gradiantEndColor, MyColors.gradiantStartColor],
),
),
child: Stack(
alignment: Alignment.center,
children: [
if (model.isTimeRemainingInSeconds == 0) SvgPicture.asset("assets/images/thumb.svg"),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.markAttendance.tr().toText14(color: Colors.white, isBold: true),
if (model.isTimeRemainingInSeconds == 0) DateTime.now().toString().split(" ")[0].toText12(color: Colors.white),
if (model.isTimeRemainingInSeconds != 0)
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
? GetAttendanceTrackingShimmer()
: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
gradient: const LinearGradient(
transform: GradientRotation(.46),
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: [MyColors.gradiantEndColor, MyColors.gradiantStartColor],
),
),
child: Stack(
alignment: Alignment.center,
children: [
if (model.isTimeRemainingInSeconds == 0) SvgPicture.asset("assets/images/thumb.svg"),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.markAttendance.tr().toText14(color: Colors.white, isBold: true),
if (model.isTimeRemainingInSeconds == 0) DateTime.now().toString().split(" ")[0].toText12(color: Colors.white),
if (model.isTimeRemainingInSeconds != 0)
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
9.height,
Directionality(
textDirection: ui.TextDirection.ltr,
child: CountdownTimer(
endTime: model.endTime,
onEnd: null,
endWidget: "00:00:00".toText14(color: Colors.white, isBold: true),
textStyle: const TextStyle(color: Colors.white, fontSize: 14, letterSpacing: -0.48, fontWeight: FontWeight.bold),
),
),
LocaleKeys.timeLeftToday.tr().toText12(color: Colors.white),
9.height,
ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(20)),
child: LinearProgressIndicator(
value: model.progress,
minHeight: 8,
valueColor: const AlwaysStoppedAnimation<Color>(Colors.white),
backgroundColor: const Color(0xff196D73),
),
),
],
),
],
).paddingOnly(top: 12, right: 15, left: 12),
),
Row(
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),
),
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),
),
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),
Container(
margin: EdgeInsets.only(top: AppState().isArabic(context) ? 6 : 0),
width: 45,
height: 45,
padding: const EdgeInsets.only(left: 10, right: 10),
decoration: BoxDecoration(
color: const Color(0xff259EA4),
borderRadius: BorderRadius.only(
bottomRight: AppState().isArabic(context) ? const Radius.circular(0) : const Radius.circular(15),
bottomLeft: AppState().isArabic(context) ? const Radius.circular(15) : const Radius.circular(0),
),
),
),
child: SvgPicture.asset(model.isTimeRemainingInSeconds == 0 ? "assets/images/biometrics.svg" : "assets/images/biometrics.svg"),
).onPress(() {
showMyBottomSheet(context, callBackFunc: () {}, child: MarkAttendanceWidget(model, isFromDashboard: true));
}),
],
),
],
).paddingOnly(top: 12, right: 15, left: 12),
),
Row(
children: [
Expanded(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
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();
},
),
@ -436,25 +427,96 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
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 if (model.isDisplayEidGreetings) {
return Column(
children: [
Directionality(
textDirection: AppState().isArabic(context) ? ui.TextDirection.rtl : ui.TextDirection.ltr,
child: Container(
height: 100,
decoration: BoxDecoration(
color: const Color(0xFFFAF4E7),
border: Border.all(width: 2, color: const Color(0xFFE7E7E7)),
borderRadius: BorderRadius.circular(20),
image: const DecorationImage(
image: NetworkImage(
"https://dummyimage.com/1200X600/faf4e7/faf4e7.jpg&text=0",
// AppState().isArabic(context) ? model.greetingCardsList!.first.backgroundImageUrlAr ?? "" : model.greetingCardsList!.first.backgroundImageUrlEn ?? "",
),
fit: BoxFit.cover,
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SvgPicture.asset("assets/images/greeting.svg", width: 65, height: 81),
const SizedBox(width: 10),
Row(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Row(
children: [
Text(
AppState().isArabic(context) ? model.greetingCardsList!.first.descriptionAr ?? '' : model.greetingCardsList!.first.descriptionEn ?? '',
style: TextStyle(
fontSize: AppState().isArabic(context) ? 18 : 16,
letterSpacing: -0.2,
fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins',
fontWeight: FontWeight.w700,
height: 24 / 16,
color: const Color(0xFF3B3E4F),
),
),
],
),
Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
AppState().isArabic(context) ? model.greetingCardsList!.first.titleAr ?? '' : model.greetingCardsList!.first.titleEn ?? '',
style: TextStyle(
fontSize: AppState().isArabic(context) ? 18 : 16,
letterSpacing: -0.2,
fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins',
fontWeight: FontWeight.w700,
height: 24 / 16,
color: const Color(0xFF3B3E4F),
),
),
],
),
],
),
],
).paddingOnly(top: 10, bottom: 10).expanded,
Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.end,
children: [
LocaleKeys.startNow.tr().toText12(isUnderLine: true, color: const Color(0xFF3B3D4A)).onPress(() {
Navigator.pushNamed(context, AppRoutes.offersAndDiscounts);
}),
],
),
],
).paddingOnly(left: 8, right: 8, top: 6, bottom: 12),
).paddingOnly(left: 21, right: 21, top: 14, bottom: 14),
),
],
);
} else {
return const SizedBox();
}
},
).paddingOnly(bottom: 24, left: 24, right: 24),
// eventActivityWidget(context),
),
eventActivityWidget(context),
if (isDisplayMazaya) ...[
Column(
mainAxisSize: MainAxisSize.min,
@ -490,70 +552,70 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
flex: 2,
child: RichText(
text:
AppState().isArabic(context)
? TextSpan(
children: [
TextSpan(
text: 'اطلع على مميزات',
style: TextStyle(
fontSize: 16,
letterSpacing: -0.2,
fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins',
fontWeight: FontWeight.w700,
height: 24 / 16,
color: const Color(0xFF5D5E5E),
),
),
TextSpan(
text: ' مزايا',
style: TextStyle(
fontSize: 16,
fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins',
fontWeight: FontWeight.w700,
letterSpacing: -0.2,
height: 24 / 16,
color: MyColors.mazayaRedColor, // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed
),
),
],
)
: TextSpan(
children: [
TextSpan(
text: LocaleKeys.explore.tr() + ' ',
style: const TextStyle(
fontSize: 16,
letterSpacing: -0.2,
fontFamily: 'Poppins',
fontWeight: FontWeight.w700,
height: 24 / 16,
color: Color(0xFF5D5E5E),
),
),
TextSpan(
text: LocaleKeys.mazaya.tr(),
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w700,
fontFamily: 'Poppins',
letterSpacing: -0.2,
height: 24 / 16,
color: MyColors.mazayaRedColor, // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed
),
),
TextSpan(
text: ' ' + LocaleKeys.benefits.tr(),
style: const TextStyle(
fontSize: 16,
letterSpacing: -0.2,
fontFamily: 'Poppins',
fontWeight: FontWeight.w700,
height: 24 / 16,
color: Color(0xFF5D5E5E),
),
),
],
),
AppState().isArabic(context)
? TextSpan(
children: [
TextSpan(
text: 'اطلع على مميزات',
style: TextStyle(
fontSize: 16,
letterSpacing: -0.2,
fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins',
fontWeight: FontWeight.w700,
height: 24 / 16,
color: const Color(0xFF5D5E5E),
),
),
TextSpan(
text: ' مزايا',
style: TextStyle(
fontSize: 16,
fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins',
fontWeight: FontWeight.w700,
letterSpacing: -0.2,
height: 24 / 16,
color: MyColors.mazayaRedColor, // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed
),
),
],
)
: TextSpan(
children: [
TextSpan(
text: LocaleKeys.explore.tr() + ' ',
style: const TextStyle(
fontSize: 16,
letterSpacing: -0.2,
fontFamily: 'Poppins',
fontWeight: FontWeight.w700,
height: 24 / 16,
color: Color(0xFF5D5E5E),
),
),
TextSpan(
text: LocaleKeys.mazaya.tr(),
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w700,
fontFamily: 'Poppins',
letterSpacing: -0.2,
height: 24 / 16,
color: MyColors.mazayaRedColor, // Use your MAZAYA red color here if defined, e.g. MyColors.mazayaRed
),
),
TextSpan(
text: ' ' + LocaleKeys.benefits.tr(),
style: const TextStyle(
fontSize: 16,
letterSpacing: -0.2,
fontFamily: 'Poppins',
fontWeight: FontWeight.w700,
height: 24 / 16,
color: Color(0xFF5D5E5E),
),
),
],
),
),
),
const Expanded(flex: 1, child: SizedBox()),
@ -633,42 +695,42 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
return model.isOffersLoading
? const OffersShimmerWidget()
: InkWell(
onTap: () {
navigateToDetails(data.getOffersList[index]);
},
child: SizedBox(
width: 73,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
width: 73,
height: 73,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: const BorderRadius.all(Radius.circular(100)),
border: Border.all(color: MyColors.lightGreyE3Color, width: 1),
),
child: ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(50)),
child: Hero(
tag: "ItemImage" + data.getOffersList[index].offersDiscountId.toString()!,
transitionOnUserGestures: true,
child: Image.network(data.getOffersList[index].logo ?? "", fit: BoxFit.contain),
onTap: () {
navigateToDetails(data.getOffersList[index]);
},
child: SizedBox(
width: 73,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
width: 73,
height: 73,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: const BorderRadius.all(Radius.circular(100)),
border: Border.all(color: MyColors.lightGreyE3Color, width: 1),
),
child: ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(50)),
child: Hero(
tag: "ItemImage" + data.getOffersList[index].offersDiscountId.toString()!,
transitionOnUserGestures: true,
child: Image.network(data.getOffersList[index].logo ?? "", fit: BoxFit.contain),
),
),
),
),
),
4.height,
Expanded(
child:
AppState().isArabic(context)
? data.getOffersList[index].titleAr!.toText12(isCenter: true, maxLine: 1)
: data.getOffersList[index].titleEn!.toText12(isCenter: true, maxLine: 1),
4.height,
Expanded(
child:
AppState().isArabic(context)
? data.getOffersList[index].titleAr!.toText12(isCenter: true, maxLine: 1)
: data.getOffersList[index].titleEn!.toText12(isCenter: true, maxLine: 1),
),
],
),
],
),
),
);
),
);
},
separatorBuilder: (BuildContext cxt, int index) => 8.width,
itemCount: 9,
@ -691,9 +753,7 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
mainAxisSize: MainAxisSize.min,
children: [
ServicesWidget(),
context
.watch<MarathonProvider>()
.isLoading ? const MarathonBannerShimmer().paddingAll(20) : const MarathonBanner().paddingOnly(left: 21, right: 21, bottom: 8, top: 8),
context.watch<MarathonProvider>().isLoading ? const MarathonBannerShimmer().paddingAll(20) : const MarathonBanner().paddingOnly(left: 21, right: 21, bottom: 8, top: 8),
// context.watch<MarathonProvider>().isTutorialLoading
// ? const MarathonBannerShimmer().paddingAll(20)
// : Container(
@ -797,28 +857,28 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
SvgPicture.asset(
"assets/icons/chat/chat.svg",
color:
!checkIfPrivilegedForChat()
? MyColors.lightGreyE3Color
: currentIndex == 4
? MyColors.grey3AColor
: cProvider.disbaleChatForThisUser
? MyColors.lightGreyE3Color
: MyColors.grey98Color,
!checkIfPrivilegedForChat()
? MyColors.lightGreyE3Color
: currentIndex == 4
? MyColors.grey3AColor
: cProvider.disbaleChatForThisUser
? MyColors.lightGreyE3Color
: MyColors.grey98Color,
).paddingAll(4),
Consumer<ChatProviderModel>(
builder: (BuildContext cxt, ChatProviderModel data, Widget? child) {
return !checkIfPrivilegedForChat()
? const SizedBox()
: Positioned(
right: 0,
top: 0,
child: Container(
padding: const EdgeInsets.only(left: 4, right: 4),
alignment: Alignment.center,
decoration: BoxDecoration(color: cProvider.disbaleChatForThisUser ? MyColors.pinkDarkColor : MyColors.redColor, borderRadius: BorderRadius.circular(17)),
child: data.chatUConvCounter.toString().toText10(color: Colors.white),
),
);
right: 0,
top: 0,
child: Container(
padding: const EdgeInsets.only(left: 4, right: 4),
alignment: Alignment.center,
decoration: BoxDecoration(color: cProvider.disbaleChatForThisUser ? MyColors.pinkDarkColor : MyColors.redColor, borderRadius: BorderRadius.circular(17)),
child: data.chatUConvCounter.toString().toText10(color: Colors.white),
),
);
},
),
],
@ -854,16 +914,9 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
}
Widget eventActivityWidget(BuildContext context) {
return (context
.watch<DashboardProviderModel>()
.isEventLoadingLoading)
return (context.watch<DashboardProviderModel>().isEventLoadingLoading)
? const MarathonBannerShimmer().paddingOnly(left: 21, right: 21, bottom: 21, top: 0)
: (context
.watch<DashboardProviderModel>()
.eventActivity != null && context
.watch<DashboardProviderModel>()
.eventActivity!
.isActive == true)
: (context.watch<DashboardProviderModel>().eventActivity != null && context.watch<DashboardProviderModel>().eventActivity!.isActive == true)
? const EventActivityBanner().paddingOnly(left: 21, right: 21, bottom: 21, top: 0)
: const SizedBox();
}

@ -1,27 +1,19 @@
import 'package:flutter/material.dart';
import 'package:flutter_countdown_timer/index.dart';
import 'package:jiffy/jiffy.dart';
import 'package:lottie/lottie.dart';
import 'package:mohem_flutter_app/api/dashboard_api_client.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/lottie_consts.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/main.dart';
import 'package:mohem_flutter_app/models/dashboard/menu_entries.dart';
import 'package:mohem_flutter_app/models/itg/advertisement.dart' as ads;
import 'package:mohem_flutter_app/models/itg/itg_response_model.dart' as itgres;
import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart';
import 'package:mohem_flutter_app/ui/my_attendance/services_menu_list_screen.dart';
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
import 'package:mohem_flutter_app/widgets/button/default_button.dart';
import 'package:mohem_flutter_app/widgets/my_video_progress_indicator.dart';
import 'package:provider/provider.dart';
import 'package:sizer/sizer.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:video_player/video_player.dart';
@ -34,7 +26,7 @@ class ITGAdsScreen extends StatefulWidget {
class _ITGAdsScreenState extends State<ITGAdsScreen> {
late Future<VideoPlayerController> _futureController;
VideoPlayerController? _controller;
late VideoPlayerController _controller;
bool skip = false;
bool isVideo = false;
bool isImage = false;
@ -45,7 +37,6 @@ class _ITGAdsScreenState extends State<ITGAdsScreen> {
// late File imageFile;
late String imageUrl;
itgres.ItgResponseData? advertisementPayload;
ads.Advertisement? advertisementData;
dynamic data;
String? masterID;
@ -56,7 +47,6 @@ class _ITGAdsScreenState extends State<ITGAdsScreen> {
final ValueNotifier<bool> hasTimerEnded = ValueNotifier(false);
late CountdownTimerController timerController;
CountdownTimerController? deadlineTimerController;
void checkFileType() {
if (advertisementData!.viewAttachFileColl!.first.contentType!.toLowerCase() == "text") {
@ -133,227 +123,34 @@ class _ITGAdsScreenState extends State<ITGAdsScreen> {
});
}
String getDeadlineText() {
if (advertisementPayload?.deadline == null) {
return "";
}
try {
// Parse the deadline string using Jiffy (format: MM/dd/yyyy hh:mm:ss aa)
Jiffy deadlineJiffy = Jiffy.parse(advertisementPayload!.deadline!, pattern: "MM/dd/yyyy hh:mm:ss aa");
Jiffy nowJiffy = Jiffy.now();
// Calculate days left
int daysLeft = deadlineJiffy.diff(nowJiffy, unit: Unit.day).toInt();
if (daysLeft < 0) {
// Deadline has passed
int daysAgo = daysLeft.abs();
if (AppState().isArabic(context)) {
return "انتهى الموعد النهائي منذ $daysAgo ${daysAgo == 1 ? 'يوم' : 'أيام'}";
} else {
return "Deadline passed $daysAgo ${daysAgo == 1 ? 'day' : 'days'} ago";
}
} else if (daysLeft == 0) {
// Deadline is today
if (AppState().isArabic(context)) {
return "الموعد النهائي اليوم!";
} else {
return "Deadline is today!";
}
} else if (daysLeft == 1) {
// Deadline is tomorrow
if (AppState().isArabic(context)) {
return "الموعد النهائي غداً";
} else {
return "Deadline is tomorrow";
}
} else {
// Deadline is in the future
if (AppState().isArabic(context)) {
return "متبقي $daysLeft ${daysLeft <= 10 ? 'أيام' : 'يوم'}";
} else {
return "$daysLeft ${daysLeft == 1 ? 'day' : 'days'} left";
}
}
} catch (e) {
logger.e("Error parsing deadline: $e");
return "Deadline: ${Utils.formatDate(advertisementPayload!.deadline)}";
}
}
void initDeadlineTimer() {
if (advertisementPayload?.deadline == null) return;
try {
// Parse the deadline string using Jiffy (format: MM/dd/yyyy hh:mm:ss aa)
Jiffy deadlineJiffy = Jiffy.parse(advertisementPayload!.deadline!, pattern: "MM/dd/yyyy hh:mm:ss aa");
DateTime deadlineDate = deadlineJiffy.dateTime;
int endTime = deadlineDate.millisecondsSinceEpoch;
int currentTime = DateTime.now().millisecondsSinceEpoch;
// Only create timer if deadline is in the future
if (endTime > currentTime) {
deadlineTimerController = CountdownTimerController(
endTime: endTime,
onEnd: () {
// Timer ended, could trigger a refresh or notification
logger.d("Deadline timer ended");
},
);
}
} catch (e) {
logger.e("Error initializing deadline timer: $e");
}
}
@override
void dispose() {
_controller?.dispose();
deadlineTimerController?.dispose();
if (_controller != null) _controller.dispose();
super.dispose();
}
// Helper method to get localized text
String _getLocalizedText(String arabic, String english) {
return AppState().isArabic(context) ? arabic : english;
}
// Build advertisement content text
Widget _buildAdvertisementContent() {
String content = AppState().isArabic(context) ? advertisementData!.viewAttachFileColl![0].base64String! : advertisementData!.viewAttachFileColl![1].base64String!;
return content.toText16(color: MyColors.darkTextColor);
}
// Build deadline section with timer
Widget _buildDeadlineSection() {
if (deadlineTimerController != null) {
return Center(
child: Column(crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [_buildEndDateText(), 4.height, _buildTimeRemainingRow(), 8.height]),
);
} else {
return Center(child: _buildEndDateText(isLargeText: true));
}
}
// Build end date text
Widget _buildEndDateText({bool isLargeText = false}) {
String label = _getLocalizedText("تاريخ الانتهاء: ", "End Date: ");
String fullText = label + advertisementPayload!.deadline ?? "";
return isLargeText ? fullText.toText16(color: MyColors.darkTextColor) : fullText.toText14(color: MyColors.darkTextColor);
}
// Build time remaining row with timer
Widget _buildTimeRemainingRow() {
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [_getLocalizedText("الوقت المتبقي", "Time Remaining").toText16(color: MyColors.darkTextColor, isBold: true), 8.width, _buildCountdownTimer()],
);
}
// Build countdown timer widget
Widget _buildCountdownTimer() {
return CountdownTimer(
controller: deadlineTimerController,
endWidget: _getLocalizedText("انتهى الموعد النهائي!", "Deadline Expired!").toText16(color: MyColors.redColor, isBold: true),
textStyle: const TextStyle(color: MyColors.darkTextColor, fontSize: 16, letterSpacing: -0.48, fontWeight: FontWeight.bold),
);
}
// Build action buttons list
Widget _buildActionButtons() {
return ListView.separated(
itemCount: advertisementData!.actionButtonsColl?.length ?? 0,
separatorBuilder: (cxt, index) => 16.height,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
padding: EdgeInsets.zero,
itemBuilder: (cxt, index) {
var actionButton = advertisementData!.actionButtonsColl![index];
String btnText = _getLocalizedText(actionButton.btnTextAr, actionButton.btnTextEn);
return DefaultButton(btnText, () => _handleButtonAction(actionButton));
},
);
}
// Handle button action based on type
Future<void> _handleButtonAction(actionButton) async {
String actionValue = actionButton.actionValue.toLowerCase();
if (actionValue == "skip") {
Navigator.pop(context);
return;
}
String actionType = actionButton.actionType?.toLowerCase() ?? '';
if (actionType == 'redirect' && actionValue == 'external') {
await _handleExternalRedirect(actionButton.url);
} else if (actionType == 'redirect' && actionValue == 'internal') {
await _handleInternalRedirect(actionButton.url);
} else if (actionType == 'eit' && actionValue == 'internal') {
await _handleEitInternal(actionButton.url);
} else {
await _handleExternalRedirect(actionButton.iconOrImage);
}
}
// Handle external URL redirect
Future<void> _handleExternalRedirect(String url) async {
Uri uri = Uri.parse(url);
await launchUrl(uri, mode: LaunchMode.externalApplication).catchError((err) {
Utils.showToast('Could not launch');
});
Navigator.pop(context);
}
// Handle internal route navigation
Future<void> _handleInternalRedirect(String url) async {
await Navigator.pushNamed(context, url);
}
// Handle EIT internal navigation
Future<void> _handleEitInternal(String url) async {
var pro = Provider.of<DashboardProviderModel>(context, listen: false);
List<GetMenuEntriesList> menuList =
pro.getMenuEntriesList?.where((element) => element.parentMenuName == url && (element.menuEntryType == "FUNCTION" || element.menuEntryType == "MENU")).toList() ?? [];
Navigator.pushNamed(context, AppRoutes.servicesMenuListScreen, arguments: ServicesMenuListScreenParams(advertisementData!.advertisementTitle!, menuList));
}
@override
Widget build(BuildContext context) {
data = ModalRoute.of(context)!.settings.arguments;
advertisementPayload ??= data["advertisement"] as itgres.ItgResponseData;
advertisementData = advertisementPayload!.advertisement;
advertisementData ??= data["advertisement"] as ads.Advertisement;
masterID ??= data["masterId"];
if (advertisementData != null) {
checkFileType();
if (isTextURL) {
if (advertisementPayload?.deadline != null && deadlineTimerController == null) {
initDeadlineTimer();
}
} else {
videoDuration = advertisementData?.durationInSeconds ?? 0;
timerController = CountdownTimerController(endTime: DateTime.now().millisecondsSinceEpoch + 1000 * videoDuration, onEnd: onTimerEnd);
}
videoDuration = advertisementData?.durationInSeconds ?? 0;
timerController = CountdownTimerController(endTime: DateTime.now().millisecondsSinceEpoch + 1000 * videoDuration, onEnd: onTimerEnd);
}
return Scaffold(
backgroundColor: isTextURL ? Colors.white : Colors.black,
appBar:
isTextURL
? AppBar(
centerTitle: true,
automaticallyImplyLeading: false,
backgroundColor: Colors.white,
title: (AppState().isArabic(context) ? advertisementData!.advertisementTitleAr! : advertisementData!.advertisementTitle!).toText24(color: MyColors.darkTextColor, isBold: true),
)
: null,
appBar: isTextURL
? AppBar(
centerTitle: true,
automaticallyImplyLeading: false,
backgroundColor: Colors.white,
title: (AppState().isArabic(context) ? advertisementData!.advertisementTitleAr! : advertisementData!.advertisementTitle!).toText24(color: MyColors.darkTextColor, isBold: true),
//advertisementData!.viewAttachFileColl!.first.base64String!.toText24(color: MyColors.darkTextColor, isBold: true),
)
: null,
body: Stack(
children: [
if (isVideo)
@ -366,33 +163,38 @@ class _ITGAdsScreenState extends State<ITGAdsScreen> {
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child:
isAudio
? Lottie.asset(MyLottieConsts.audioPlaybackLottie)
: AspectRatio(
aspectRatio: _controller!.value.aspectRatio,
child: Stack(
alignment: Alignment.bottomCenter,
children: [
VideoPlayer(_controller!),
if (advertisementData?.isOptional ?? false)
Positioned(
top: 4,
right: 8,
child: Container(
padding: const EdgeInsets.only(left: 8, right: 8, top: 4, bottom: 4),
decoration: BoxDecoration(color: Colors.white.withOpacity(0.5), borderRadius: BorderRadius.circular(30)),
child: Row(mainAxisSize: MainAxisSize.min, children: [Text(AppState().isArabic(context) ? "يتخطى" : "Skip"), Icon(Icons.skip_next)]),
).onPress(() {
Navigator.pop(context);
DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, "Skip").then((value) {
logger.d(value);
});
}),
),
],
),
child: isAudio
? Lottie.asset(MyLottieConsts.audioPlaybackLottie)
: AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: Stack(
alignment: Alignment.bottomCenter,
children: [
VideoPlayer(_controller),
if (advertisementData?.isOptional ?? false)
Positioned(
top: 4,
right: 8,
child: Container(
padding: const EdgeInsets.only(left: 8, right: 8, top: 4, bottom: 4),
decoration: BoxDecoration(color: Colors.white.withOpacity(0.5), borderRadius: BorderRadius.circular(30)),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(AppState().isArabic(context) ? "يتخطى" : "Skip"),
Icon(Icons.skip_next),
],
),
).onPress(() {
Navigator.pop(context);
DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, "Skip").then((value) {
logger.d(value);
});
}),
),
],
),
),
),
30.height,
CountdownTimer(
@ -428,7 +230,7 @@ class _ITGAdsScreenState extends State<ITGAdsScreen> {
alignment: Alignment.center,
children: [
MyVideoProgressIndicator(
_controller!,
_controller,
allowScrubbing: false,
//padding: EdgeInsets.only(left: 60, right: 60),
),
@ -436,13 +238,13 @@ class _ITGAdsScreenState extends State<ITGAdsScreen> {
btnText!,
hasTimerEndedBool
? () async {
Navigator.pop(context);
DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, advertisementData?.actionButtonsColl![index].actionValue).then((
value,
) {
logger.d(value);
});
}
Navigator.pop(context);
DashboardApiClient()
.setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, advertisementData?.actionButtonsColl![index].actionValue)
.then((value) {
logger.d(value);
});
}
: null,
disabledColor: Colors.transparent,
textColor: !hasTimerEndedBool ? Colors.white.withOpacity(.5) : Colors.white,
@ -450,12 +252,15 @@ class _ITGAdsScreenState extends State<ITGAdsScreen> {
],
);
}
return DefaultButton(btnText!, () async {
Navigator.pop(context);
DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, advertisementData?.actionButtonsColl![index].actionValue).then((value) {
logger.d(value);
});
}).paddingOnly(left: 60.0, right: 60.0, top: 8, bottom: 8);
return DefaultButton(
btnText!,
() async {
Navigator.pop(context);
DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, advertisementData?.actionButtonsColl![index].actionValue).then((value) {
logger.d(value);
});
},
).paddingOnly(left: 60.0, right: 60.0, top: 8, bottom: 8);
},
// gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
// crossAxisCount: 1,
@ -528,7 +333,9 @@ class _ITGAdsScreenState extends State<ITGAdsScreen> {
],
);
} else {
return const Center(child: CircularProgressIndicator());
return const Center(
child: CircularProgressIndicator(),
);
}
},
),
@ -541,17 +348,19 @@ class _ITGAdsScreenState extends State<ITGAdsScreen> {
children: [
Image.network(imageUrl),
50.height,
Container(padding: const EdgeInsets.all(16), decoration: Utils.containerRadius(MyColors.white, 10), child: const Icon(Icons.thumb_up, color: MyColors.gradiantEndColor)).onPress(() {
try {
Navigator.pop(context);
DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, "Like").then((value) {
logger.d(value);
});
} catch (ex) {
logger.wtf(ex);
Utils.handleException(ex, context, null);
}
}),
Container(padding: const EdgeInsets.all(16), decoration: Utils.containerRadius(MyColors.white, 10), child: const Icon(Icons.thumb_up, color: MyColors.gradiantEndColor)).onPress(
() {
try {
Navigator.pop(context);
DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, "Like").then((value) {
logger.d(value);
});
} catch (ex) {
logger.wtf(ex);
Utils.handleException(ex, context, null);
}
},
),
],
),
),
@ -562,11 +371,35 @@ class _ITGAdsScreenState extends State<ITGAdsScreen> {
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
_buildAdvertisementContent(),
(AppState().isArabic(context) ? advertisementData!.viewAttachFileColl![0].base64String! : advertisementData!.viewAttachFileColl![1].base64String!)
.toText16(color: MyColors.darkTextColor),
24.height,
if (advertisementPayload != null && advertisementPayload!.deadline != null) _buildDeadlineSection(),
if (advertisementPayload != null && advertisementPayload!.deadline != null) 24.height,
_buildActionButtons(),
ListView.separated(
itemCount: advertisementData!.actionButtonsColl?.length ?? 0,
separatorBuilder: (cxt, index) => 16.height,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
padding: EdgeInsets.zero,
itemBuilder: (cxt, index) => DefaultButton(
AppState().isArabic(context) ? advertisementData!.actionButtonsColl![index].btnTextAr : advertisementData!.actionButtonsColl![index].btnTextEn,
() async {
if (advertisementData!.actionButtonsColl![index].actionValue.toLowerCase() == "skip") {
Navigator.pop(context);
} else {
Uri uri = Uri.parse(advertisementData!.actionButtonsColl![index].iconOrImage);
// if (await canLaunchUrl(uri)) {
await launchUrl(uri, mode: LaunchMode.externalApplication).catchError((err) {
// print(err);
Utils.showToast('Could not launch');
});
Navigator.pop(context);
// } else {
// Utils.showToast('Could not launch');
// }
}
},
),
),
],
),
),

@ -58,15 +58,15 @@ class _AppDrawerState extends State<AppDrawer> {
children: [
AppState().memberInformationList!.eMPLOYEEIMAGE == null
? SvgPicture.asset(
"assets/images/user.svg",
height: 52,
width: 52,
)
"assets/images/user.svg",
height: 52,
width: 52,
)
: CircleAvatar(
radius: 52 / 2,
backgroundImage: MemoryImage(Utils.dataFromBase64String(AppState().memberInformationList!.eMPLOYEEIMAGE!)),
backgroundColor: Colors.black,
),
radius: 52 / 2,
backgroundImage: MemoryImage(Utils.dataFromBase64String(AppState().memberInformationList!.eMPLOYEEIMAGE!)),
backgroundColor: Colors.black,
),
12.width,
Column(
crossAxisAlignment: CrossAxisAlignment.start,
@ -119,7 +119,7 @@ class _AppDrawerState extends State<AppDrawer> {
}),
menuItem("assets/images/drawer/employee_id.svg", LocaleKeys.employeeDigitalID.tr(), "", closeDrawer: false, onPress: () => showMDialog(context, child: EmployeeDigitialIdDialog())),
if (AppState().businessCardPrivilege)
menuItem("assets/images/drawer/view_business_card.svg", LocaleKeys.viewBusinessCard.tr(), "", closeDrawer: false, onPress: () => showMDialog(context, child: BusinessCardDialog(), isBusniessCard: true)),
menuItem("assets/images/drawer/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: (){Utils.performLogout(context, chatData);}),
// menuItem("assets/images/drawer/logout.svg", LocaleKeys.logout.tr(), "", color: MyColors.redA3Color, closeDrawer: false, onPress: () {Navigator.pushNamed(context, AppRoutes.survey,);
],
@ -156,9 +156,9 @@ class _AppDrawerState extends State<AppDrawer> {
],
).paddingOnly(left: 21, top: 10, bottom: 10, right: 21).onPress(closeDrawer
? () async {
Navigator.pop(context);
Future.delayed(const Duration(microseconds: 200), onPress);
}
Navigator.pop(context);
Future.delayed(const Duration(microseconds: 200), onPress);
}
: onPress!);
}
@ -171,13 +171,13 @@ class _AppDrawerState extends State<AppDrawer> {
setState(() {});
}
// void performLogout() async {
// // AppState().isAuthenticated = false;
// // AppState().isLogged = false;
// // AppState().setPostParamsInitConfig();
// // chatData.disposeData();
// // // SharedPreferences prefs = await SharedPreferences.getInstance();
// // // await prefs.clear();
// // Navigator.pushNamedAndRemoveUntil(context, AppRoutes.login, (Route<dynamic> route) => false, arguments: null);
// }
// void performLogout() async {
// // AppState().isAuthenticated = false;
// // AppState().isLogged = false;
// // AppState().setPostParamsInitConfig();
// // chatData.disposeData();
// // // SharedPreferences prefs = await SharedPreferences.getInstance();
// // // await prefs.clear();
// // Navigator.pushNamedAndRemoveUntil(context, AppRoutes.login, (Route<dynamic> route) => false, arguments: null);
// }
}

@ -1,18 +1,13 @@
import 'package:easy_localization/src/public_ext.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:mohem_flutter_app/api/eit_api_client.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/models/eit/get_eit_transaction_model.dart';
import 'package:mohem_flutter_app/models/sso_auth_model.dart';
import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart';
import 'package:mohem_flutter_app/ui/my_attendance/dynamic_screens/dynamic_listview_screen.dart';
import 'package:mohem_flutter_app/ui/screens/ticket/ticket_detailed_screen.dart';
import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart';
import 'package:provider/provider.dart';
@ -122,29 +117,8 @@ class MenusWidget extends StatelessWidget {
),
],
).paddingOnly(left: 10, right: 10, bottom: 6, top: 6),
).onPress(() async {
// Navigator.pushNamed(context, AppRoutes.dynamicScreen, arguments: DynamicListViewParams(LocaleKeys.ticketBalance.tr(), "HMG_TKT_NEW_EIT_SS"));
var pro = Provider.of<DashboardProviderModel>(context, listen: false);
// if (menuEntry.menuName == "HMG_TICKET_REQUESTS") {
Utils.showLoading(context);
//Ticket Work
if (pro.ticketBookingResponse != null && pro.ticketBookingResponse!.success) {
SSOAuthModel? ssoToken = await pro.fetchSSOAuthRedirection(clientID: pro.ticketBookingResponse!.clientId);
if (ssoToken != null) {
dynamic url = await pro.fetchURLRedirection(token: ssoToken.data!.accessToken!);
await pro.fetchTicketAccuralBalance(context, DateTime.now());
pro.ticketHistoryTransactionList = await EITApiClient().getEITTransactions("HMG_TICKET_ITENARY_HR_EIT_SS", isCompleteList: true);
Utils.hideLoading(context);
// Here Need Work
Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => TicketDetailedScreen(url: url, jwtToken: ssoToken.data!.accessToken)));
}
//}
} else {
Navigator.pushNamed(context, AppRoutes.dynamicScreen, arguments: DynamicListViewParams(LocaleKeys.ticketBalance.tr(), "HMG_TKT_NEW_EIT_SS"));
}
).onPress(() {
Navigator.pushNamed(context, AppRoutes.dynamicScreen, arguments: DynamicListViewParams(LocaleKeys.ticketBalance.tr(), "HMG_TKT_NEW_EIT_SS"));
}),
],
);

@ -1,333 +0,0 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/inAppWebView.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/models/dashboard/courses_response_model.dart';
import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart';
import 'package:mohem_flutter_app/theme/colors.dart' as theme_colors;
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
import 'package:mohem_flutter_app/widgets/sso_webview_widget.dart';
import 'package:provider/provider.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
class CoursesScreen extends StatefulWidget {
const CoursesScreen({Key? key}) : super(key: key);
@override
_CoursesScreenState createState() => _CoursesScreenState();
}
class _CoursesScreenState extends State<CoursesScreen> {
late DashboardProviderModel data;
final RefreshController _refreshController = RefreshController(initialRefresh: false);
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
data = Provider.of<DashboardProviderModel>(context, listen: false);
_onRefresh();
});
}
void _onRefresh() async {
await data.fetchCourses(context);
_refreshController.refreshCompleted();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBarWidget(
context,
title: LocaleKeys.courses.tr(),
),
body: Consumer<DashboardProviderModel>(
builder: (context, provider, child) {
return SmartRefresher(
enablePullDown: true,
enablePullUp: false,
controller: _refreshController,
onRefresh: _onRefresh,
child: provider.isCoursesLoading
? _buildShimmerLoading()
: provider.coursesList.isEmpty
? _buildEmptyState()
: _buildCoursesList(provider.coursesList),
);
},
),
);
}
Widget _buildShimmerLoading() {
return ListView.builder(
padding: const EdgeInsets.all(21),
itemCount: 5,
itemBuilder: (context, index) {
return Container(
margin: const EdgeInsets.only(bottom: 12),
height: 150,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15),
boxShadow: [
BoxShadow(
color: const Color(0xff000000).withOpacity(.05),
blurRadius: 26,
offset: const Offset(0, -3),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: 20,
width: 200,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(4),
),
).toShimmer(),
12.height,
Container(
height: 14,
width: 100,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(4),
),
).toShimmer(),
const Spacer(),
Container(
height: 40,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(6),
),
).toShimmer(),
],
).paddingAll(14),
);
},
);
}
Widget _buildEmptyState() {
return Utils.getNoDataWidget(context);
}
Widget _buildCoursesList(List<CourseStatus> courses) {
return ListView.separated(
physics: const BouncingScrollPhysics(),
shrinkWrap: true,
padding: const EdgeInsets.all(21),
itemBuilder: (BuildContext context, int index) {
return _buildCourseCard(courses[index]);
},
separatorBuilder: (BuildContext context, int index) => 12.height,
itemCount: courses.length,
);
}
Widget _buildCourseCard(CourseStatus course) {
bool isArabic = AppState().isArabic(context);
String courseName = isArabic && course.cNameAr != null && course.cNameAr!.isNotEmpty
? course.cNameAr!
: course.cFullname ?? '';
String status = course.cStatus ?? 'Unknown';
Color statusColor = _getStatusColor(status);
return InkWell(
onTap: () => _openCourse(course.cUrl, course.token),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Course Title
Row(
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: MyColors.lightGreyEFColor,
borderRadius: BorderRadius.circular(8),
),
child: const Icon(
Icons.school_rounded,
color: MyColors.gradiantStartColor,
size: 20,
),
),
12.width,
Expanded(
child: courseName.toText14(isBold: true, color: MyColors.darkTextColor),
),
],
),
12.height,
// Status Badge
Row(
children: [
Icon(
_getStatusIcon(status),
size: 16,
color: statusColor,
),
6.width,
LocaleKeys.status.tr().toText11(color: MyColors.grey98Color),
8.width,
Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
decoration: BoxDecoration(
color: statusColor.withOpacity(0.1),
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: statusColor.withOpacity(0.3),
width: 1,
),
),
child: status.toText10(color: statusColor, isBold: true),
),
],
),
10.height,
// Start Date
if (course.cEnddate != null && course.cEnddate!.isNotEmpty)
Row(
children: [
const Icon(
Icons.calendar_month_rounded,
size: 16,
color: MyColors.darkIconColor,
),
6.width,
LocaleKeys.endDateT.tr().toText11(color: MyColors.grey98Color),
8.width,
Expanded(
child: _formatDate(course.cEnddate!).toText11(
color: MyColors.darkTextColor,
isBold: true,
),
),
],
),
if (course.cStartdate != null && course.cStartdate!.isNotEmpty) 14.height,
// Open Button
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
LocaleKeys.open.tr().toText12(color: MyColors.gradiantStartColor, isUnderLine: true),
6.width,
RotatedBox(
quarterTurns: AppState().isArabic(context) ? 2 : 4,
child: SvgPicture.asset(
"assets/images/arrow_next.svg",
color: MyColors.gradiantStartColor,
width: 16,
height: 16,
),
),
],
),
],
).objectContainerView(),
);
}
IconData _getStatusIcon(String status) {
if (status.toLowerCase().contains('passed')) {
return Icons.check_circle_rounded;
} else if (status.toLowerCase().contains('not passed') || status.toLowerCase().contains('failed')) {
return Icons.cancel_rounded;
} else if (status.toLowerCase().contains('in progress')) {
return Icons.pending_rounded;
} else {
return Icons.info_rounded;
}
}
Color _getStatusColor(String status) {
if (status.toLowerCase().contains('passed') && !status.toLowerCase().contains('not passed')) {
return Colors.green;
} else if (status.toLowerCase().contains('not passed') || status.toLowerCase().contains('failed')) {
return Colors.red;
} else if (status.toLowerCase().contains('in progress')) {
return Colors.yellow[700]!;
} else {
return MyColors.grey98Color;
}
}
DateTime? _parseDate(String? date) {
if (date == null || date.isEmpty) return null;
try {
return DateTime.parse(date.replaceAll(' ', 'T'));
} catch (e) {
try {
DateFormat format = DateFormat('yyyy-MM-dd HH:mm:ss');
return format.parse(date);
} catch (e) {
return null;
}
}
}
String _formatDate(String date) {
DateTime? dateTime = _parseDate(date);
if (dateTime == null) return date;
bool isArabic = AppState().isArabic(context);
DateFormat format = DateFormat('dd MMM yyyy, hh:mm a', isArabic ? 'ar' : 'en');
return format.format(dateTime);
}
void _openCourse(String? url, String? jwtToken) {
Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => SsoLoginWebView(url: url, jwtToken: jwtToken, ssoType: SsoType.forCourses)));
//Utils.showToast(LocaleKeys.courseUrlNotAvailable.tr());
// return;
// }
//
// MyInAppBrowser browser = MyInAppBrowser(
// onExitCallback: () {},
// onLoadStartCallback: (String url) {},
// );
//
// var settings = InAppBrowserClassSettings(
// webViewSettings: InAppWebViewSettings(
// useShouldOverrideUrlLoading: false,
// transparentBackground: false,
// ),
// browserSettings: InAppBrowserSettings(
// hideUrlBar: true,
// hideTitleBar: false,
// toolbarTopBackgroundColor: theme_colors.primaryColor,
// ),
// );
//
// browser.openUrlRequest(
// urlRequest: URLRequest(url: WebUri(url)),
// settings: settings,
// );
}
@override
void dispose() {
_refreshController.dispose();
super.dispose();
}
}

@ -192,78 +192,10 @@ class _MowadhafhiHRRequestState extends State<MowadhafhiHRRequest> {
title.toText16().expanded,
6.width,
SimpleButton(LocaleKeys.add.tr(), () async {
FilePickerResult? result = await FilePicker.platform.pickFiles(
allowMultiple: true,
);
FilePickerResult? result = await FilePicker.platform.pickFiles(allowMultiple: true);
if (result != null) {
// Maximum file size: 2 MB (in bytes)
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}');
}
attachmentFiles = attachmentFiles + result.paths.map((path) => File(path!)).toList();
attachmentFiles = attachmentFiles.toSet().toList();
setState(() {});
}
}, fontSize: 14),

@ -5,17 +5,14 @@ import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/date_uitl.dart';
import 'package:mohem_flutter_app/classes/file_process.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/models/dashboard/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/widgets/app_bar_widget.dart';
import 'package:mohem_flutter_app/widgets/balances_dashboard_widget.dart';
import 'package:mohem_flutter_app/widgets/button/default_button.dart';
import 'package:mohem_flutter_app/widgets/item_detail_view_widget.dart';
import 'package:mohem_flutter_app/widgets/sso_webview_widget.dart';
@ -58,7 +55,7 @@ class _TicketDetailedScreenState extends State<TicketDetailedScreen> {
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBarWidget(context, title: LocaleKeys.ticketDetails.tr()),
appBar: AppBarWidget(context, title: "Ticket Details"),
body: Column(
children: <Widget>[
ListView(
@ -77,7 +74,7 @@ class _TicketDetailedScreenState extends State<TicketDetailedScreen> {
children: <Widget>[
Row(
children: <Widget>[
LocaleKeys.currentTicketBalance.tr().toText20().expanded,
"Current Ticket Balance".toText20().expanded,
Row(
children: <Widget>[
const Icon(Icons.calendar_month_rounded, color: MyColors.darkIconColor, size: 16),
@ -115,20 +112,21 @@ class _TicketDetailedScreenState extends State<TicketDetailedScreen> {
),
),
const SizedBox(height: 21),
(dashboardProviderModel != null && dashboardProviderModel!.ticketHistoryTransactionList != null && dashboardProviderModel!.ticketHistoryTransactionList!.isNotEmpty)
? ListView(
dashboardProviderModel == null && dashboardProviderModel!.ticketHistoryTransactionList == null
? const SizedBox()
: ListView(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
children: <Widget>[
LocaleKeys.ticketHistory.tr().toText20().expanded,
"Tickets History".toText20().expanded,
12.height,
ListView.separated(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
padding: EdgeInsets.zero,
itemBuilder: (BuildContext cxt, int cardIndex) {
List<CollectionTransaction> transactionDetails = dashboardProviderModel!.ticketHistoryTransactionList![cardIndex];
const Set<String> allowedSegmentNames = <String>{
var transactionDetails = dashboardProviderModel!.ticketHistoryTransactionList![cardIndex];
const allowedSegmentNames = <String>{
"TICKETS_ROUTE",
"TRAVELER_NAME",
"TICKETS_EFFECTIVE_DATE",
@ -137,22 +135,11 @@ class _TicketDetailedScreenState extends State<TicketDetailedScreen> {
"TICKET_COMP_SHARE",
"TICKET_EMP_SHARE",
};
// Get items for display
List<CollectionTransaction> uniqueDetails =
var uniqueDetails =
transactionDetails
.where(
(CollectionTransaction item) =>
item.dISPLAYFLAG != 'N' && item.sEGMENTPROMPT != null && item.sEGMENTPROMPT!.isNotEmpty && allowedSegmentNames.contains(item.sEGMENTNAME),
)
.where((item) => item.dISPLAYFLAG != 'N' && item.sEGMENTPROMPT != null && item.sEGMENTPROMPT!.isNotEmpty && allowedSegmentNames.contains(item.sEGMENTNAME))
.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(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
@ -161,15 +148,15 @@ class _TicketDetailedScreenState extends State<TicketDetailedScreen> {
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: (uniqueDetails.length / 2).ceil(),
itemBuilder: (BuildContext context, int rowIndex) {
itemBuilder: (context, rowIndex) {
int firstIndex = rowIndex * 2;
int? secondIndex = (firstIndex + 1 < uniqueDetails.length) ? firstIndex + 1 : null;
bool isLastRow = (rowIndex == (uniqueDetails.length / 2).ceil() - 1);
CollectionTransaction item1 = uniqueDetails[firstIndex];
ItemDetailViewCol child1 = ItemDetailViewCol(item1.sEGMENTPROMPT!, item1.vARCHAR2VALUE ?? item1.nUMBERVALUE?.toString() ?? "");
var item1 = uniqueDetails[firstIndex];
var child1 = ItemDetailViewCol(item1.sEGMENTPROMPT!, item1.vARCHAR2VALUE ?? item1.nUMBERVALUE?.toString() ?? "");
Widget child2;
if (secondIndex != null) {
CollectionTransaction item2 = uniqueDetails[secondIndex];
var item2 = uniqueDetails[secondIndex];
child2 = ItemDetailViewCol(item2.sEGMENTPROMPT!, item2.vARCHAR2VALUE ?? item2.nUMBERVALUE?.toString() ?? "");
} else {
child2 = const SizedBox(); // Empty widget if there is no second item
@ -177,40 +164,6 @@ class _TicketDetailedScreenState extends State<TicketDetailedScreen> {
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();
},
@ -218,14 +171,13 @@ class _TicketDetailedScreenState extends State<TicketDetailedScreen> {
itemCount: dashboardProviderModel!.ticketHistoryTransactionList!.length,
),
],
)
: const SizedBox(),
),
],
],
).expanded,
DefaultButton(LocaleKeys.proceedBooking.tr(), () {
DefaultButton("Proceed For Booking", () {
if (widget.url != null && widget.jwtToken != null) {
Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => SsoLoginWebView(url: widget.url, jwtToken: widget.jwtToken, ssoType: SsoType.forTicket)));
Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => SsoLoginWebView(url: widget.url, jwtToken: widget.jwtToken)));
}
}).insideContainer,
],

@ -168,8 +168,8 @@ class ApprovalLevelfragment extends StatelessWidget {
if (wFHistory[index].date!.isEmpty || wFHistory[index].action!.toLowerCase() == "NO ACTION" || wFHistory[index + 1].date! == "") {
return "";
} else {
DateTime dateTimeTo = DateUtil.convertSimpleStringDateToDate(wFHistory[index].date!, isITG: true);
DateTime dateTimeFrom = DateUtil.convertSimpleStringDateToDate(wFHistory[index + 1].date!, isITG: true);
DateTime dateTimeTo = DateUtil.convertSimpleStringDateToDate(wFHistory[index].date!);
DateTime dateTimeFrom = DateUtil.convertSimpleStringDateToDate(wFHistory[index + 1].date!);
Duration duration = dateTimeTo.difference(dateTimeFrom);
return "Action duration: " + DateUtil.formatDuration(duration);
}

@ -5,7 +5,6 @@ import 'package:flutter_svg/svg.dart';
import 'package:mohem_flutter_app/api/worklist/worklist_api_client.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/consts.dart';
import 'package:mohem_flutter_app/classes/date_uitl.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/config/routes.dart';
@ -22,7 +21,6 @@ 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/bottom_sheet.dart';
import 'package:mohem_flutter_app/widgets/bottom_sheets/worklist_advance_search_bottom_sheet.dart';
import 'package:mohem_flutter_app/widgets/sso_webview_widget.dart';
import 'package:provider/provider.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
@ -109,13 +107,13 @@ class _WorkListScreenState extends State<WorkListScreen> {
),
WorkListItemTypeModelData(
value: 0,
name: 'ENSAT',
name: 'COC',
fullName: LocaleKeys.itemCreation.tr(),
active: false,
color: [const Color(0xff787299), Color(0xff1AB170)],
color: [Color(0xff787299), Color(0xff1AB170)],
icon: "assets/images/miss_swipe.svg",
key: 'COC',
disable: false,
disable: true,
),
WorkListItemTypeModelData(
value: 0,
@ -137,6 +135,7 @@ class _WorkListScreenState extends State<WorkListScreen> {
key: 'HMG_FA_D',
disable: false,
),
];
int? workListItemIndex;
@ -232,12 +231,6 @@ class _WorkListScreenState extends State<WorkListScreen> {
if ((itgFormsModel?.requestType?.length ?? 0) > 0) {
itgRequestTypeIndex = 0;
}
} else if (workListItemTypes[workListItemIndex!].key == "COC") {
String? enSAToken = await DashboardProviderModel().getENSATItgToken();
Utils.hideLoading(context);
dynamic url = "${ApiConsts.enSATLiveURL}?empId=${AppState().getUserName}&token=$enSAToken";
Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => SsoLoginWebView(url: url, jwtToken: enSAToken, ssoType: SsoType.forEnsat)));
} else {
itgRequestTypeIndex = null;
List<WorkListResponseModel>? _list = await WorkListApiClient().getWorkList(pageNumber, workListItemTypes[workListItemIndex!].key, pNotificationType.toString());

@ -141,7 +141,7 @@ void galleryImageAndroid(Function(String, File) image) async {
}
void cameraImageAndroid(Function(String, File) image) async {
File _image = File((await picker.pickImage(source: ImageSource.camera, imageQuality: 20))?.path ?? "");
File _image = File(( await picker.pickMedia())?.path ?? "");
String fileName = _image.path;
var bytes = File(fileName).readAsBytesSync();
String base64Encode = base64.encode(bytes);
@ -159,7 +159,7 @@ class _BottomSheet extends StatelessWidget {
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 12.0),
decoration: const BoxDecoration( borderRadius: BorderRadius.only(topLeft: Radius.circular(16.0), topRight: Radius.circular(16.0))),
decoration: BoxDecoration( borderRadius: const BorderRadius.only(topLeft: Radius.circular(16.0), topRight: Radius.circular(16.0))),
child: SafeArea(
top: false,
child: Column(

@ -19,7 +19,13 @@ class GetAttendanceTrackingShimmer extends StatelessWidget {
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15),
boxShadow: [BoxShadow(color: const Color(0xff000000).withOpacity(.05), blurRadius: 26, offset: const Offset(0, -3))],
boxShadow: [
BoxShadow(
color: const Color(0xff000000).withOpacity(.05),
blurRadius: 26,
offset: const Offset(0, -3),
),
],
),
child: Stack(
alignment: Alignment.center,
@ -40,8 +46,15 @@ class GetAttendanceTrackingShimmer extends StatelessWidget {
LocaleKeys.timeLeftToday.tr().toText10(color: Colors.white).toShimmer(),
9.height,
const ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(20)),
child: LinearProgressIndicator(value: 0.7, minHeight: 8, valueColor: const AlwaysStoppedAnimation<Color>(Colors.white), backgroundColor: const Color(0xff196D73)),
borderRadius: BorderRadius.all(
Radius.circular(20),
),
child: LinearProgressIndicator(
value: 0.7,
minHeight: 8,
valueColor: const AlwaysStoppedAnimation<Color>(Colors.white),
backgroundColor: const Color(0xff196D73),
),
).toShimmer(),
],
).paddingOnly(top: 12, right: 15, left: 12),
@ -52,7 +65,9 @@ class GetAttendanceTrackingShimmer extends StatelessWidget {
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [LocaleKeys.checkIn.tr().toText12(color: Colors.white).toShimmer()],
children: [
LocaleKeys.checkIn.tr().toText12(color: Colors.white).toShimmer(),
],
).paddingOnly(left: 12),
),
Container(
@ -81,7 +96,13 @@ class MenuShimmer extends StatelessWidget {
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15),
boxShadow: [BoxShadow(color: const Color(0xff000000).withOpacity(.05), blurRadius: 26, offset: const Offset(0, -3))],
boxShadow: [
BoxShadow(
color: const Color(0xff000000).withOpacity(.05),
blurRadius: 26,
offset: const Offset(0, -3),
),
],
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
@ -90,11 +111,14 @@ class MenuShimmer extends StatelessWidget {
LocaleKeys.workList.tr().toText12(color: Colors.white).toShimmer(),
Row(
children: [
Expanded(flex: 3, child: 123.toString().toText10(color: Colors.white, isBold: true).toShimmer()),
Expanded(
flex: 3,
child: 123.toString().toText10(color: Colors.white, isBold: true).toShimmer(),
),
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),
);
@ -113,7 +137,11 @@ class ServicesHeaderShimmer extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [LocaleKeys.otherCharges.tr().toText10().toShimmer(), 6.height, LocaleKeys.services.tr().toText12(isBold: true).toShimmer()],
children: [
LocaleKeys.otherCharges.tr().toText10().toShimmer(),
6.height,
LocaleKeys.services.tr().toText12(isBold: true).toShimmer(),
],
),
),
LocaleKeys.viewAllServices.tr().toText12(isUnderLine: true).toShimmer(),
@ -131,7 +159,13 @@ class ServicesMenuShimmer extends StatelessWidget {
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15),
boxShadow: [BoxShadow(color: const Color(0xff000000).withOpacity(.05), blurRadius: 26, offset: const Offset(0, -3))],
boxShadow: [
BoxShadow(
color: const Color(0xff000000).withOpacity(.05),
blurRadius: 26,
offset: const Offset(0, -3),
),
],
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
@ -147,13 +181,15 @@ class ServicesMenuShimmer extends StatelessWidget {
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Expanded(child: LocaleKeys.attendance.tr().toText11(isBold: false).toShimmer()),
Expanded(
child: LocaleKeys.attendance.tr().toText11(isBold: false).toShimmer(),
),
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),
);
@ -166,35 +202,69 @@ class GreetingCardShimmer extends StatelessWidget {
@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)),
height: 100,
decoration: BoxDecoration(
color: const Color(0xFFFAF4E7),
border: Border.all(width: 2, color: const Color(0xFFE7E7E7)),
borderRadius: BorderRadius.circular(20),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(width: 10),
Container(width: 65, height: 100, decoration: BoxDecoration(color: Colors.grey[300], borderRadius: BorderRadius.circular(10))).toShimmer().paddingOnly(top: 10),
Container(
width: 65,
height: 81,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(10),
),
).toShimmer(),
const SizedBox(width: 10),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(width: 150, height: 16, decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(4))).toShimmer(),
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(),
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()],
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);
).paddingOnly(left: 21, right: 21, top: 14, bottom: 14);
}
}
class MarathonBannerShimmer extends StatelessWidget {
const MarathonBannerShimmer({Key? key}) : super(key: key);
@ -204,7 +274,13 @@ class MarathonBannerShimmer extends StatelessWidget {
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15),
boxShadow: [BoxShadow(color: const Color(0xff000000).withOpacity(.05), blurRadius: 26, offset: const Offset(0, -3))],
boxShadow: [
BoxShadow(
color: const Color(0xff000000).withOpacity(.05),
blurRadius: 26,
offset: const Offset(0, -3),
),
],
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
@ -220,13 +296,15 @@ class MarathonBannerShimmer extends StatelessWidget {
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Expanded(child: LocaleKeys.attendance.tr().toText11(isBold: false).toShimmer()),
Expanded(
child: LocaleKeys.attendance.tr().toText11(isBold: false).toShimmer(),
),
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),
);
@ -242,43 +320,66 @@ class ChatHomeShimmer extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0),
child: Column(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Expanded(
child: Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey.shade100,
child: ListView.builder(
itemBuilder:
(_, __) => Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
if (!isDetailedScreen) Container(width: 48.0, height: 48.0, decoration: const BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(40)))),
if (!isDetailedScreen) const Padding(padding: EdgeInsets.symmetric(horizontal: 8.0)),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
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,
],
),
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0),
child: Column(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Expanded(
child: Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey.shade100,
child: ListView.builder(
itemBuilder: (_, __) => Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
if (!isDetailedScreen)
Container(
width: 48.0,
height: 48.0,
decoration: const BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(40))),
),
if (!isDetailedScreen)
const Padding(
padding: EdgeInsets.symmetric(horizontal: 8.0),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
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,
),
),
),
),
],
),
);
],
));
}
}

@ -1,17 +1,13 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
import 'package:webview_flutter/webview_flutter.dart';
// Enum for SSO types
enum SsoType { forTicket, forEnsat, forCourses }
class SsoLoginWebView extends StatefulWidget {
final String? url;
final String? jwtToken;
final SsoType ssoType;
const SsoLoginWebView({Key? key, required this.url, this.jwtToken, required this.ssoType}) : super(key: key);
SsoLoginWebView({this.url, this.jwtToken});
@override
State<SsoLoginWebView> createState() => _SsoLoginWebViewState();
@ -19,27 +15,11 @@ class SsoLoginWebView extends StatefulWidget {
class _SsoLoginWebViewState extends State<SsoLoginWebView> {
late final WebViewController _controller;
String? url;
bool _isTicketLoadingVisible = false;
void _showTicketLoading() {
if (widget.ssoType != SsoType.forTicket || _isTicketLoadingVisible || !mounted) return;
_isTicketLoadingVisible = true;
Utils.showLoading(context);
}
void _hideTicketLoading() {
if (widget.ssoType != SsoType.forTicket || !_isTicketLoadingVisible || !mounted) return;
_isTicketLoadingVisible = false;
Utils.hideLoading(context);
}
@override
void initState() {
// TODO: implement initState
super.initState();
url = widget.url ?? "";
_controller =
WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
@ -47,72 +27,35 @@ class _SsoLoginWebViewState extends State<SsoLoginWebView> {
NavigationDelegate(
onProgress: (int progress) {
print("WebView is loading (progress: $progress%)");
if (widget.ssoType == SsoType.forEnsat && progress == 100) {
Utils.hideLoading(context);
}
},
onPageStarted: (String url) {
print("Page started loading: $url");
_showTicketLoading();
},
onPageFinished: (String url) {
print("Page finished loading: $url");
_hideTicketLoading();
},
onHttpError: (HttpResponseError error) {
print("HTTP error: ${error.toString()} for URL: ${error.response!.statusCode}");
_hideTicketLoading();
},
onWebResourceError: (WebResourceError error) {
print("Web resource error: ${error.description} for URL: ${error.errorType}");
_hideTicketLoading();
},
),
);
// Load content based on SSO type
if (widget.ssoType == SsoType.forEnsat) {
// For ENSAT, just load the URL directly (GET request)
_controller.loadRequest(Uri.parse(url!));
} else {
if (widget.ssoType == SsoType.forTicket) {
WidgetsBinding.instance.addPostFrameCallback((_) {
_showTicketLoading();
});
}
// For Paxes (Ticket, Courses), use HTML form POST
_controller.loadHtmlString(_buildHtmlContent());
}
}
// Build HTML content for the SSO form
String _buildHtmlContent() {
String formAction;
if (widget.ssoType == SsoType.forTicket) {
formAction = "https://www.paxes.com/sso/hmg";
} else {
formAction = url ?? "";
}
return '''
)
..loadHtmlString('''
<!DOCTYPE html>
<html>
<body onload="document.forms[0].submit()">
<form method="POST" action="$formAction">
<form method="POST" action="https://Paxes-release.techmaster.in/SSO/HMG">
<input type="hidden" name="JWTToken" value="${widget.jwtToken}" />
</form>
<h1></h1>
<h1>Redirecting...</h1>
</body>
</html>''';
}
@override
void dispose() {
_hideTicketLoading();
super.dispose();
</html>''');
}
@override
Widget build(BuildContext context) {
return Scaffold(appBar: AppBarWidget(context, title: "MoheM", showWorkListSettingButton: false), body: SafeArea(child: WebViewWidget(controller: _controller)));
return Scaffold(appBar: AppBar(title: Text('Logging in...')), body: WebViewWidget(controller: _controller));
}
}

@ -17,8 +17,8 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 3.7.2+300082
#version: 3.9.3+1
#version: 3.7.1+300081
version: 3.9.3+1
environment:
sdk: ^3.7.0
@ -102,9 +102,6 @@ dependencies:
audio_waveforms: ^1.3.0
rxdart: ^0.27.7
#Speech to Text
speech_to_text: ^7.0.0
#Encryption
flutter_des: ^2.1.0
@ -112,7 +109,6 @@ dependencies:
just_audio: ^0.9.30
# safe_device: ^1.1.2
flutter_layout_grid: ^2.0.1
jiffy: ^6.4.4
#Huawei Dependencies
# huawei_hmsavailability: ^6.6.0+300

Loading…
Cancel
Save