Merge branch 'master_mohemm_flutter'

# Conflicts:
#	android/app/src/main/AndroidManifest.xml
#	ios/Runner.xcodeproj/project.pbxproj
#	lib/app_state/app_state.dart
#	pubspec.yaml
master
haroon amjad 9 months ago
commit 609d3ca48a

@ -1,4 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.mohem_flutter_app">
<uses-permission android:name="android.permission.INTERNET" />
@ -8,6 +9,16 @@
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<!-- Required only if your app needs to access videos
that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<!-- Required only if your app needs to access audio files
that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<!-- Chat Web RTC Calling -->
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
@ -23,6 +34,19 @@
android:label="Al Habib Mohemm"
android:extractNativeLibs="true"
android:networkSecurityConfig="@xml/network_security_config">
android:networkSecurityConfig="@xml/network_security_config"
android:roundIcon="@mipmap/ic_launcher_round">
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileProvider"
android:exported="false"
android:grantUriPermissions="true"
tools:replace="android:authorities">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths"
tools:replace="android:resource" />
</provider>
<activity
android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"

@ -0,0 +1,8 @@
<paths>
<external-path name="external-path" path="."/>
<external-cache-path name="external-cache-path" path="."/>
<external-files-path name="external-files-path" path="."/>
<files-path name="files_path" path="."/>
<cache-path name="cache-path" path="."/>
<root-path name="root" path="."/>
</paths>

Before

Width:  |  Height:  |  Size: 549 B

After

Width:  |  Height:  |  Size: 549 B

Before

Width:  |  Height:  |  Size: 548 B

After

Width:  |  Height:  |  Size: 548 B

Before

Width:  |  Height:  |  Size: 470 B

After

Width:  |  Height:  |  Size: 470 B

@ -16,7 +16,7 @@
"projects": {
"id": "b1cd3fa3-bb27-422e-a4c1-08dac09254df",
"nameEn": "Cloud Solutions",
"nameAr": "333شركة حلول السحابة للاتصالات وتقنية المعلومات",
"nameAr": "شركة حلول السحابة للاتصالات وتقنية المعلومات",
"projectCode": "CS"
},
"sponsors": [
@ -42,5 +42,6 @@
"totalQuestions": 10,
"cancelReason": null,
"marathonBufferTime": 30,
"currentTime": "2022-12-28T08:03:24.3671803Z"
"currentTime": "2022-12-28T08:03:24.3671803Z",
"displayCorrectAnswer": true
}

@ -88,7 +88,7 @@
"atLeastOneNumeric": "رقم واحد على الأقل",
"minimum8Characters": "8 أحرف على الأقل",
"doNotAddRepeatingLetters": "لا تقم بإضافة أحرف متكررة",
"itShouldContainSpecialCharacter": "يجب أن يحتوي على طابع خاص",
"itShouldContainSpecialCharacter": "يجب لا يحتوي على أحرف خاصة",
"confirmPasswordMustMatch": "يجب أن يتطابق تأكيد كلمة المرور",
"sms": "رسالة قصيرة",
"fingerPrint": "بصمة",
@ -542,5 +542,6 @@
"uploadedDocuments": "المستندات التي تم تحميلها",
"addAtLeastOneAttachment": "الرجاء إضافة مرفق واحد على الأقل.",
"pleaseClickButtonToJoinMarathon": "الرجاء الضغط على الزر أدناه للانضمام إلى الماراثون",
"youCannotJoinTheMarathon": "لا يمكنك الانضمام إلى الماراثون لأنك تجاوزت الحد الزمني"
"youCannotJoinTheMarathon": "لا يمكنك الانضمام إلى الماراثون لأنك تجاوزت الحد الزمني",
"open": "يفتح"
}

@ -85,7 +85,7 @@
"atLeastOneNumeric": "At least one numeric",
"minimum8Characters": "Minimum 8 characters",
"doNotAddRepeatingLetters": "Do not add repeating letters",
"itShouldContainSpecialCharacter": "It should contain special character",
"itShouldContainSpecialCharacter": "It should not contain special characters",
"confirmPasswordMustMatch": "Confirm password must match",
"sms": "SMS",
"fingerPrint": "Fingerprint",
@ -559,6 +559,7 @@
"userSearch": "User Search",
"userName": "User Name",
"userId": "UserID",
"open": "open",
"addAtLeastOneAttachment": "Please add at least one attachment.",
"pleaseClickButtonToJoinMarathon": "Press the button below to join the Marathon.",
"youCannotJoinTheMarathon": "You cannot join the Marathon because you have exceeded the time limit."

@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 51;
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
@ -227,6 +227,7 @@
};
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
@ -241,6 +242,7 @@
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
@ -251,7 +253,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n";
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
C4CFBC4C5CAC00182015ACD5 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;

@ -29,6 +29,7 @@ class ChatApiClient {
Future<user.UserAutoLoginModel> getUserLoginToken() async {
user.UserAutoLoginModel userLoginResponse = user.UserAutoLoginModel();
String? deviceToken = AppState().getIsHuawei ? AppState().getHuaweiPushToken : AppState().getDeviceToken;
Response response = await ApiClient().postJsonForResponse(
"${ApiConsts.chatLoginTokenUrl}externaluserlogin",
{
@ -38,6 +39,7 @@ class ChatApiClient {
"platform": Platform.isIOS ? "ios" : "android",
"deviceToken": AppState().getIsHuawei ? AppState().getHuaweiPushToken : AppState().getDeviceToken,
"isHuaweiDevice": AppState().getIsHuawei,
"voipToken": "80a3b01fc1ef2453eb4f1daa4fc31d8142d9cb67baf848e91350b607971fe2ba",
},
);

@ -11,6 +11,7 @@ import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/models/marathon/marathon_generic_model.dart';
import 'package:mohem_flutter_app/models/marathon/marathon_model.dart';
import 'package:mohem_flutter_app/models/marathon/question_model.dart';
import 'package:mohem_flutter_app/models/marathon/tutorial_notification_model.dart';
import 'package:mohem_flutter_app/models/marathon/winner_model.dart';
import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart';
import 'package:provider/provider.dart';
@ -195,6 +196,24 @@ class MarathonApiClient {
return null;
}
Future<TutorialNotificationModel?> getMarathonTutorial() async {
Response response = await ApiClient().getJsonForResponse(
// ApiConsts.marathonGetTutorial,
"https://marathoon.com/uatservice/api/tutorial/GetTutorialNotification",
token: AppState().getMarathonToken == null || AppState().getMarathonToken == "" ? await getMarathonToken() : AppState().getMarathonToken,
);
try {
MarathonGenericModel marathonModel = MarathonGenericModel.fromJson(jsonDecode(response.body));
if (marathonModel.data is List) {
return TutorialNotificationModel.fromJson(marathonModel.data[0]);
}
} catch (ex) {
print(ex);
}
return null;
}
// late HubConnection hubConnection;
// Future<void> buildHubConnection(BuildContext context, String prizeId) async {
// HttpConnectionOptions httpOptions = HttpConnectionOptions(skipNegotiation: false, logMessageContent: true);

@ -1,3 +1,5 @@
import 'dart:convert';
import 'package:mohem_flutter_app/api/api_client.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/consts.dart';
@ -10,6 +12,7 @@ import 'package:mohem_flutter_app/models/mowadhafhi/get_ticket_details.dart';
import 'package:mohem_flutter_app/models/mowadhafhi/get_ticket_transactions.dart';
import 'package:mohem_flutter_app/models/mowadhafhi/get_ticket_types.dart';
import 'package:mohem_flutter_app/models/mowadhafhi/get_tickets_list.dart';
import 'package:mohem_flutter_app/models/mowadhafhi/get_transaction_attachment_model.dart';
class MowadhafhiApiClient {
static final MowadhafhiApiClient _instance = MowadhafhiApiClient._internal();
@ -51,6 +54,18 @@ class MowadhafhiApiClient {
}, url, postParams);
}
Future<GetTransactionAttachmentModel> getTransactionAttachments(int? attachmentID) async {
String url = "${ApiConsts.cocRest}Mohemm_ITG_GetTicketAttachment";
Map<String, dynamic> postParams = {"EmployeeNumber": AppState().memberInformationList?.eMPLOYEENUMBER, "ItgAttachmentId": attachmentID};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject((json) {
GenericResponseModel? responseData = GenericResponseModel.fromJson(json);
var jsonDecodedData = jsonDecode(responseData.mohemmITGResponseItem!);
return GetTransactionAttachmentModel.fromJson(jsonDecodedData);
}, url, postParams);
}
Future<List<GetTicketTypes>> getTicketTypes() async {
String url = "${ApiConsts.cocRest}Mohemm_ITG_GetTicketTypes";
Map<String, dynamic> postParams = {"EmployeeNumber": AppState().memberInformationList?.eMPLOYEENUMBER};

@ -21,9 +21,11 @@ import 'package:mohem_flutter_app/models/get_quotation_analysis_list_model.dart'
import 'package:mohem_flutter_app/models/get_stamp_ms_notification_body_list_model.dart';
import 'package:mohem_flutter_app/models/get_stamp_ns_notification_body_list_model.dart';
import 'package:mohem_flutter_app/models/get_user_item_type_list.dart';
import 'package:mohem_flutter_app/models/itg_forms_models/itg_forms_attachments_model.dart';
import 'package:mohem_flutter_app/models/itg_forms_models/itg_request_model.dart';
import 'package:mohem_flutter_app/models/member_information_list_model.dart';
import 'package:mohem_flutter_app/models/notification_get_respond_attributes_list_model.dart';
import 'package:mohem_flutter_app/models/termination/termination_notification_body.dart';
import 'package:mohem_flutter_app/models/update_user_item_type_list.dart';
import 'package:mohem_flutter_app/models/worklist/GetRFCEmployeeList.dart';
import 'package:mohem_flutter_app/models/worklist/get_favorite_replacements_model.dart';
@ -363,6 +365,21 @@ class WorkListApiClient {
}, url, postParams);
}
Future<List<ITGFormsAttachmentsModel>?> getITGFormAttachments(String requestType, taskId, itemId, String employeeNumber) async {
String url = "${ApiConsts.cocRest}ITGGetFormDetialsAttachment";
Map<String, dynamic> postParams = {
"RequestType": requestType,
"TaskID": taskId,
"ItemIDStr": itemId,
"EmployeeNumber": employeeNumber,
};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject((json) {
ItgFormsModel responseData = ItgFormsModel.fromJson(json);
return responseData.itgFormAttachmentsList;
}, url, postParams);
}
Future<ITGRequest?> rejectITGRequest(String requestType, taskId, itemId, String employeeNumber, String comments) async {
String url = "${ApiConsts.cocRest}ITGRejectRequest";
Map<String, dynamic> postParams = {
@ -550,6 +567,22 @@ class WorkListApiClient {
}, url, postParams);
}
Future<List<TerminationNotificationBody>?> getTerminationNotificationBodyList(int? notificationId) async {
String url = "${ApiConsts.erpRest}GET_TERM_NOTIFICATION_BODY";
Map<String, dynamic> postParams = {
"P_NOTIFICATION_ID": notificationId,
"P_PAGE_LIMIT": 100,
"P_PAGE_NUM": 1,
};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject((json) {
GenericResponseModel responseData = GenericResponseModel.fromJson(json);
return responseData.getTermNotificationBodyList;
}, url, postParams);
}
Future<List<GetFavoriteReplacements>?> getFavoriteReplacementWithoutImage() async {
String url = "${ApiConsts.erpRest}Mohemm_GetFavoriteReplacementsWithoutImage";
Map<String, dynamic> postParams = {};

@ -51,9 +51,9 @@ class ApiConsts {
static String marathonQualifiersUrl = marathonBaseUrl + "winner/getWinner/";
static String marathonSelectedWinner = marathonBaseUrl + "winner/getSelectedWinner/";
static String marathonGetMarathonersCount = marathonBaseUrl + "Participant/GetRemainingParticipants";
static String marathonGetTutorial = marathonBaseUrl + "tutorial/GetTutorialNotification";
//DummyCards for the UI
static CardContent dummyQuestion = const CardContent();
static int tabletMinLength = 500;
}
@ -71,3 +71,5 @@ class SharedPrefsConsts {
static String mohemmWifiPassword = "mohemmWifiPassword";
static String editItemForSale = "editItemForSale";
}

@ -30,7 +30,6 @@ class MyDecorations {
return getContainersDecoration(MyColors.greenColor);
case QuestionsOptionStatus.wrong:
return getContainersDecoration(MyColors.redColor);
case QuestionsOptionStatus.selected:
return getContainersDecoration(MyColors.yellowColorII);
case QuestionsOptionStatus.unSelected:

@ -2,8 +2,9 @@ import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:open_file/open_file.dart';
import 'package:open_filex/open_filex.dart';
import 'package:path_provider/path_provider.dart';
import 'package:http/http.dart' as http;
class FileProcess {
static bool isFolderCreated = false;
@ -23,9 +24,9 @@ class FileProcess {
}
}
static void openFile(String fileName) {
static void openFile(String fileName, {bool isFullPath = false}) {
String dir = directory!.path + "/$fileName.pdf";
OpenFile.open(dir);
OpenFilex.open(isFullPath ? fileName : dir);
}
static Future<File> downloadFile(String base64Content, String fileName) async {
@ -37,4 +38,24 @@ class FileProcess {
await file.writeAsBytes(bytes);
return file;
}
static Future<String> downloadFileFromUrl(String url,String fileName) async {
await checkDocumentFolder();
String filePath = '${directory!.path}/$fileName';
if (await File(filePath).exists()) {
await Future.delayed(const Duration(seconds: 1));
return filePath;
} else {
var response = await http.get(Uri.parse(url));
if (response.statusCode == 200) {
var bytes = response.bodyBytes;
File file = File(filePath);
await file.writeAsBytes(bytes);
return filePath;
} else {
throw Exception('Failed to download file');
}
}
}
}

@ -27,6 +27,7 @@ import 'package:mohem_flutter_app/ui/login/verify_login_screen.dart';
import 'package:mohem_flutter_app/ui/marathon/marathon_intro_screen.dart';
import 'package:mohem_flutter_app/ui/marathon/marathon_screen.dart';
import 'package:mohem_flutter_app/ui/marathon/marathon_sponsor_video_screen.dart';
import 'package:mohem_flutter_app/ui/marathon/marathon_tutorial_viewer_screen.dart';
import 'package:mohem_flutter_app/ui/marathon/marathon_waiting_screen.dart';
import 'package:mohem_flutter_app/ui/misc/request_submit_screen.dart';
import 'package:mohem_flutter_app/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart';
@ -203,6 +204,7 @@ class AppRoutes {
static const String marathonWinnerScreen = "/marathonWinnerScreen";
static const String marathonSponsorVideoScreen = "/marathonSponsorVideoScreen";
static const String marathonWaitingScreen = "/marathonWaitingScreen";
static const String marathonTutorialScreen = "/marathonTutorialScreen";
static const String unsafeDeviceScreen = "/unsafeDeviceScreen";
static const String appUpdateScreen = "/appUpdateScreen";
@ -319,6 +321,7 @@ class AppRoutes {
marathonScreen: (BuildContext context) => MarathonScreen(),
marathonSponsorVideoScreen: (BuildContext context) => const SponsorVideoScreen(),
marathonWaitingScreen: (BuildContext context) => const MarathonWaitingScreen(),
marathonTutorialScreen: (BuildContext context) => const MarathonTutorialViewerScreen(),
unsafeDeviceScreen: (BuildContext context) => const UnsafeDeviceScreen(),
appUpdateScreen: (BuildContext context) => const AppUpdateScreen(),

@ -68,8 +68,9 @@ extension EmailValidator on String {
style: TextStyle(fontSize: 10, fontStyle: fontStyle ?? FontStyle.normal, fontWeight: isBold ? FontWeight.bold : FontWeight.w600, color: color ?? MyColors.darkTextColor, letterSpacing: -0.4),
);
Widget toText11({Color? color, FontWeight? weight, bool isUnderLine = false, bool isBold = false, int maxLine = 0}) => Text(
Widget toText11({Color? color, FontWeight? weight, bool isUnderLine = false, bool isBold = false, bool isCenter = false, int maxLine = 0}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
maxLines: (maxLine > 0) ? maxLine : null,
style: TextStyle(
fontSize: 11,

@ -104,7 +104,7 @@ class CodegenLoader extends AssetLoader {
"atLeastOneNumeric": "رقم واحد على الأقل",
"minimum8Characters": "8 أحرف على الأقل",
"doNotAddRepeatingLetters": "لا تقم بإضافة أحرف متكررة",
"itShouldContainSpecialCharacter": "يجب أن يحتوي على طابع خاص",
"itShouldContainSpecialCharacter": "يجب لا يحتوي على أحرف خاصة",
"confirmPasswordMustMatch": "يجب أن يتطابق تأكيد كلمة المرور",
"sms": "رسالة قصيرة",
"fingerPrint": "بصمة",
@ -639,7 +639,7 @@ class CodegenLoader extends AssetLoader {
"atLeastOneNumeric": "At least one numeric",
"minimum8Characters": "Minimum 8 characters",
"doNotAddRepeatingLetters": "Do not add repeating letters",
"itShouldContainSpecialCharacter": "It should contain special character",
"itShouldContainSpecialCharacter": "It should not contain special character",
"confirmPasswordMustMatch": "Confirm password must match",
"sms": "SMS",
"fingerPrint": "Fingerprint",

@ -549,4 +549,5 @@ abstract class LocaleKeys {
static const addAtLeastOneAttachment ='addAtLeastOneAttachment';
static const pleaseClickButtonToJoinMarathon ='pleaseClickButtonToJoinMarathon';
static const youCannotJoinTheMarathon ='youCannotJoinTheMarathon';
static const open ='open';
}

@ -4,6 +4,7 @@
import 'dart:convert';
import 'package:mohem_flutter_app/models/itg_forms_models/itg_forms_attachments_model.dart';
import 'package:mohem_flutter_app/models/itg_forms_models/itg_request_model.dart';
import 'package:mohem_flutter_app/models/itg_forms_models/request_type_model.dart';
@ -84,7 +85,8 @@ class ItgFormsModel {
dynamic successMsgN;
dynamic vidaUpdatedResponse;
ITGRequest? itgRequest;
dynamic itgFormAttachmentsList;
// dynamic itgFormAttachmentsList;
List<ITGFormsAttachmentsModel>? itgFormAttachmentsList;
String? message;
dynamic mohemmItgDepartmentSectionsList;
dynamic mohemmItgProjectDepartmentsList;
@ -128,7 +130,11 @@ class ItgFormsModel {
successMsgN: json["SuccessMsgN"],
vidaUpdatedResponse: json["VidaUpdatedResponse"],
itgRequest: json['ITGRequest'] != null ? ITGRequest.fromJson(json['ITGRequest']) : null,
itgFormAttachmentsList: json["Itg_FormAttachmentsList"],
itgFormAttachmentsList:
json["Itg_FormAttachmentsList"] == null ? <ITGFormsAttachmentsModel>[] : json["Itg_FormAttachmentsList"]!.map<ITGFormsAttachmentsModel>((v) => ITGFormsAttachmentsModel.fromJson(v)).toList(),
// json["RequestType"] == null ? <RequestType>[] : json['RequestType']!.map<RequestType>((v) => RequestType.fromJson(v)).toList(),
message: json["Message"] == null ? null : json["Message"],
mohemmItgDepartmentSectionsList: json["Mohemm_ITG_DepartmentSectionsList"],
mohemmItgProjectDepartmentsList: json["Mohemm_ITG_ProjectDepartmentsList"],

@ -92,6 +92,7 @@ import 'package:mohem_flutter_app/models/submit_term_transaction_list_model.dart
import 'package:mohem_flutter_app/models/subordinates_on_leaves_model.dart';
import 'package:mohem_flutter_app/models/termination/get_term_cols_structure_list_model.dart';
import 'package:mohem_flutter_app/models/termination/get_term_dff_structure_list_model.dart';
import 'package:mohem_flutter_app/models/termination/termination_notification_body.dart';
import 'package:mohem_flutter_app/models/update_item_type_success_list.dart';
import 'package:mohem_flutter_app/models/update_user_item_type_list.dart';
import 'package:mohem_flutter_app/models/vacation_rule/create_vacation_rule_list_model.dart';
@ -223,7 +224,6 @@ class GenericResponseModel {
List<String>? getOrganizationsSalariesList;
List<GetPaymentInformationList>? getPaymentInformationList;
List<GetPayslipList>? getPayslipList;
// List<String>? getPendingReqDetailsList;
// List<String>? getPendingReqFunctionsList;
List<GetPerformanceAppraisalList>? getPerformanceAppraisalList;
@ -254,7 +254,7 @@ class GenericResponseModel {
List<String>? getSwipesList;
List<GetTermColsStructureList>? getTermColsStructureList;
List<GetTermDffStructureList>? getTermDffStructureList;
List<String>? getTermNotificationBodyList;
List<TerminationNotificationBody>? getTermNotificationBodyList;
List<GetTimeCardSummaryList>? getTimeCardSummaryList;
List<GetTicketsByEmployeeList>? getTicketsByEmployeeList;
List<GetTicketDetailsByEmployee>? getTicketDetailsByEmployee;
@ -680,6 +680,7 @@ class GenericResponseModel {
successMsg = json['SuccessMsg'];
successMsgN = json['SuccessMsgN'];
vidaUpdatedResponse = json['VidaUpdatedResponse'];
if (json['AddAttSuccessList'] != null) {
addAttSuccessList = <AddAttSuccessList>[];
json['AddAttSuccessList'].forEach((v) {
@ -693,6 +694,14 @@ class GenericResponseModel {
businessCardPrivilege = json['BusinessCardPrivilege'];
calculateAbsenceDuration = json['CalculateAbsenceDuration'] != null ? new CalculateAbsenceDuration.fromJson(json['CalculateAbsenceDuration']) : null;
cancelHRTransactionLIst = json['CancelHRTransactionLIst'] != null ? new CancelHRTransactionLIst.fromJson(json['CancelHRTransactionLIst']) : null;
if (json['GetTermNotificationBodyList'] != null) {
getTermNotificationBodyList = <TerminationNotificationBody>[];
json['GetTermNotificationBodyList'].forEach((v) {
getTermNotificationBodyList!.add(TerminationNotificationBody.fromJson(v));
});
}
chatEmployeeLoginList = json['Chat_EmployeeLoginList'];
companyBadge = json['CompanyBadge'];
companyImage = json['CompanyImage'];
@ -1090,7 +1099,7 @@ class GenericResponseModel {
});
}
getTermNotificationBodyList = json['GetTermNotificationBodyList'];
if (json['GetTimeCardSummaryList'] != null) {
getTimeCardSummaryList = <GetTimeCardSummaryList>[];
@ -1612,6 +1621,9 @@ class GenericResponseModel {
data['GetNotificationReassignModeList'] = getNotificationReassignModeList!.map((v) => v.toJson()).toList();
}
if(getTermNotificationBodyList !=null){
data['GetTermNotificationBodyList'] = getTermNotificationBodyList!.map((v) => v.toJson()).toList();
}
data['GetObjectValuesList'] = this.getObjectValuesList;
data['GetOpenMissingSwipesList'] = this.getOpenMissingSwipesList;
data['GetOpenNotificationsList'] = this.getOpenNotificationsList;
@ -1688,7 +1700,6 @@ class GenericResponseModel {
data['GetTermDffStructureList'] = this.getTermDffStructureList!.map((v) => v.toJson()).toList();
}
data['GetTermNotificationBodyList'] = this.getTermNotificationBodyList;
if (this.getTimeCardSummaryList != null) {
data['GetTimeCardSummaryList'] = this.getTimeCardSummaryList!.map((v) => v.toJson()).toList();
}

@ -94,8 +94,9 @@ class ViewAttachFileColl {
dynamic referenceItemId;
dynamic content;
dynamic filePath;
dynamic languageId;
ViewAttachFileColl({this.attachmentId, this.fileName, this.contentType, this.attachFileStream, this.base64String, this.isActive, this.referenceItemId, this.content, this.filePath});
ViewAttachFileColl({this.attachmentId, this.fileName, this.contentType, this.attachFileStream, this.base64String, this.isActive, this.referenceItemId, this.content, this.filePath, this.languageId});
ViewAttachFileColl.fromJson(Map<String, dynamic> json) {
attachmentId = json['attachmentId'];
@ -107,6 +108,7 @@ class ViewAttachFileColl {
referenceItemId = json['referenceItemId'];
content = json['content'];
filePath = json['filePath'];
languageId = json['languageId'];
}
Map<String, dynamic> toJson() {
@ -120,6 +122,7 @@ class ViewAttachFileColl {
data['referenceItemId'] = this.referenceItemId;
data['content'] = this.content;
data['filePath'] = this.filePath;
data['languageId'] = this.languageId;
return data;
}
}

@ -45,20 +45,55 @@ class ItgResponseResult {
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']));
}
final dynamic totalItemsCount;
final ItgResponseData? data;
final dynamic errormsg;
}
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"],
);
//
// 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() => {
Map<String, dynamic> toJson() => {
"totalItemsCount": totalItemsCount,
"data": data == null ? null : data!.toJson(),
"data": data == null ? null : data!.map((v) => v.toJson()).toList(),
"errormsg": errormsg,
};
}

@ -9,13 +9,18 @@ class SurveyModel {
dynamic pageNo;
dynamic languageId;
SurveyModel({this.surveyId, this.referenceNo, this.title, this.description, this.questions, this.isActive, this.pageSize, this.pageNo, this.languageId});
String? descriptionAr;
String? titleAr;
SurveyModel({this.surveyId, this.referenceNo, this.title,this.titleAr, this.description, this.descriptionAr, this.questions, this.isActive, this.pageSize, this.pageNo, this.languageId});
SurveyModel.fromJson(Map<String, dynamic> json) {
surveyId = json['surveyId'];
referenceNo = json['referenceNo'];
title = json['title'];
titleAr = json['titleAr'];
description = json['description'];
descriptionAr = json['descriptionAr'];
if (json['questions'] != null) {
questions = <Questions>[];
json['questions'].forEach((v) {
@ -33,7 +38,9 @@ class SurveyModel {
data['surveyId'] = this.surveyId;
data['referenceNo'] = this.referenceNo;
data['title'] = this.title;
data['titleAr'] = this.titleAr;
data['description'] = this.description;
data['descriptionAr'] = this.descriptionAr;
if (this.questions != null) {
data['questions'] = this.questions!.map((v) => v.toJson()).toList();
}
@ -48,6 +55,7 @@ class SurveyModel {
class Questions {
int? questionId;
String? title;
String? titleAr;
bool? isRequired;
String? type;
int? sequenceNo;
@ -59,11 +67,12 @@ class Questions {
dynamic pageNo;
dynamic languageId;
Questions({this.questionId, this.title, this.isRequired, this.type, this.sequenceNo, this.surveyId, this.options, this.rspPercentage, this.isActive, this.pageSize, this.pageNo, this.languageId});
Questions({this.questionId, this.title, this.titleAr, this.isRequired, this.type, this.sequenceNo, this.surveyId, this.options, this.rspPercentage, this.isActive, this.pageSize, this.pageNo, this.languageId});
Questions.fromJson(Map<String, dynamic> json) {
questionId = json['questionId'];
title = json['title'];
titleAr = json['titleAr'];
isRequired = json['isRequired'];
type = json['type'];
sequenceNo = json['sequenceNo'];
@ -85,6 +94,7 @@ class Questions {
Map<String, dynamic> data = new Map<String, dynamic>();
data['questionId'] = this.questionId;
data['title'] = this.title;
data['titleAr'] = this.titleAr;
data['isRequired'] = this.isRequired;
data['type'] = this.type;
data['sequenceNo'] = this.sequenceNo;
@ -104,6 +114,7 @@ class Questions {
class Options {
int? optionId;
String? title;
String? titleAr;
bool? isCommentsRequired;
int? sequenceNo;
int? questionId;
@ -114,11 +125,12 @@ class Options {
dynamic pageNo;
dynamic languageId;
Options({this.optionId, this.title, this.isCommentsRequired, this.sequenceNo, this.questionId, this.rspPercentage, this.count, this.isActive, this.pageSize, this.pageNo, this.languageId});
Options({this.optionId, this.title,this.titleAr, this.isCommentsRequired, this.sequenceNo, this.questionId, this.rspPercentage, this.count, this.isActive, this.pageSize, this.pageNo, this.languageId});
Options.fromJson(Map<String, dynamic> json) {
optionId = json['optionId'];
title = json['title'];
titleAr = json['titleAr'];
isCommentsRequired = json['isCommentsRequired'];
sequenceNo = json['sequenceNo'];
questionId = json['questionId'];
@ -134,6 +146,7 @@ class Options {
Map<String, dynamic> data = new Map<String, dynamic>();
data['optionId'] = this.optionId;
data['title'] = this.title;
data['titleAr'] = this.titleAr;
data['isCommentsRequired'] = this.isCommentsRequired;
data['sequenceNo'] = this.sequenceNo;
data['questionId'] = this.questionId;

@ -0,0 +1,25 @@
class ITGFormsAttachmentsModel {
String? fileBase64;
dynamic fileData;
String? fileName;
String? fileType;
ITGFormsAttachmentsModel(
{this.fileBase64, this.fileData, this.fileName, this.fileType});
ITGFormsAttachmentsModel.fromJson(Map<String, dynamic> json) {
fileBase64 = json['fileBase64'];
fileData = json['fileData'];
fileName = json['fileName'];
fileType = json['fileType'];
}
Map<String, dynamic> toJson() {
Map<String, dynamic> data = new Map<String, dynamic>();
data['fileBase64'] = this.fileBase64;
data['fileData'] = this.fileData;
data['fileName'] = this.fileName;
data['fileType'] = this.fileType;
return data;
}
}

@ -1,6 +1,6 @@
class CalculateAbsenceDuration {
num? pABSENCEDAYS;
num? pABSENCEHOURS;
double? pABSENCEDAYS;
double? pABSENCEHOURS;
String? pRETURNMSG;
String? pRETURNSTATUS;

@ -1,3 +1,5 @@
import 'dart:developer';
class MarathonDetailModel {
String? id;
String? titleEn;
@ -17,6 +19,7 @@ class MarathonDetailModel {
List<Questions>? questions;
int? totalQuestions;
int? marathonBufferTime;
bool? displayCorrectAnswer;
MarathonDetailModel({
id,
@ -37,6 +40,7 @@ class MarathonDetailModel {
questions,
totalQuestions,
marathonBufferTime,
displayCorrectAnswer,
});
MarathonDetailModel.fromJson(Map<String, dynamic> json) {
@ -68,6 +72,7 @@ class MarathonDetailModel {
}
totalQuestions = json["totalQuestions"];
marathonBufferTime = json["marathonBufferTime"];
displayCorrectAnswer = json["displayCorrectAnswer"];
}
Map<String, dynamic> toJson() {

@ -0,0 +1,104 @@
// class TutorialNotificationModel {
// List<Data>? data;
// bool? isSuccessful;
// String? message;
// int? statusCode;
//
// TutorialNotificationModel({this.data, this.isSuccessful, this.message, this.statusCode});
//
// TutorialNotificationModel.fromJson(Map<String, dynamic> json) {
// if (json['data'] != null) {
// data = <Data>[];
// json['data'].forEach((v) {
// data!.add(new Data.fromJson(v));
// });
// }
// isSuccessful = json['isSuccessful'];
// message = json['message'];
// statusCode = json['statusCode'];
// }
//
// Map<String, dynamic> toJson() {
// final Map<String, dynamic> data = new Map<String, dynamic>();
// if (this.data != null) {
// data['data'] = this.data!.map((v) => v.toJson()).toList();
// }
// data['isSuccessful'] = this.isSuccessful;
// data['message'] = this.message;
// data['statusCode'] = this.statusCode;
//
// return data;
// }
// }
class TutorialNotificationModel {
String? tutorialNotificationId;
String? tutorialName;
String? tutorialDescription;
String? startDate;
String? endDate;
String? fileName;
String? contentType;
String? filePath;
int? orderNo;
bool? isActive;
int? isStatus;
String? created;
String? createdBy;
String? modified;
String? modifiedBy;
TutorialNotificationModel({this.tutorialNotificationId,
this.tutorialName,
this.tutorialDescription,
this.startDate,
this.endDate,
this.fileName,
this.contentType,
this.filePath,
this.orderNo,
this.isActive,
this.isStatus,
this.created,
this.createdBy,
this.modified,
this.modifiedBy});
TutorialNotificationModel.fromJson(Map<String, dynamic> json) {
tutorialNotificationId = json['tutorialNotificationId'];
tutorialName = json['tutorialName'];
tutorialDescription = json['tutorialDescription'];
startDate = json['startDate'];
endDate = json['endDate'];
fileName = json['fileName'];
contentType = json['contentType'];
filePath = json['filePath'];
orderNo = json['orderNo'];
isActive = json['isActive'];
isStatus = json['isStatus'];
created = json['created'];
createdBy = json['createdBy'];
modified = json['modified'];
modifiedBy = json['modifiedBy'];
}
Map<String, dynamic> toJson() {
Map<String, dynamic> data = new Map<String, dynamic>();
data['tutorialNotificationId'] = this.tutorialNotificationId;
data['tutorialName'] = this.tutorialName;
data['tutorialDescription'] = this.tutorialDescription;
data['startDate'] = this.startDate;
data['endDate'] = this.endDate;
data['fileName'] = this.fileName;
data['contentType'] = this.contentType;
data['filePath'] = this.filePath;
data['orderNo'] = this.orderNo;
data['isActive'] = this.isActive;
data['isStatus'] = this.isStatus;
data['created'] = this.created;
data['createdBy'] = this.createdBy;
data['modified'] = this.modified;
data['modifiedBy'] = this.modifiedBy;
return data;
}
}

@ -1,24 +1,24 @@
class GetTicketTransactions {
String? actionBy;
String? actionDate;
List<Attachments>? attachments;
String? comments;
String? statusDisplayText;
String? statusName;
String? ticketId;
int? ticketTransactionId;
GetTicketTransactions(
{this.actionBy,
this.actionDate,
this.comments,
this.statusDisplayText,
this.statusName,
this.ticketId,
this.ticketTransactionId});
GetTicketTransactions({this.actionBy, this.actionDate, this.attachments, this.comments, this.statusDisplayText, this.statusName, this.ticketId, this.ticketTransactionId});
GetTicketTransactions.fromJson(Map<String, dynamic> json) {
actionBy = json['actionBy'];
actionDate = json['actionDate'];
if (json['attachments'] != null) {
attachments = <Attachments>[];
json['attachments'].forEach((v) {
attachments!.add(new Attachments.fromJson(v));
});
}
comments = json['comments'];
statusDisplayText = json['statusDisplayText'];
statusName = json['statusName'];
@ -27,9 +27,12 @@ class GetTicketTransactions {
}
Map<String, dynamic> toJson() {
Map<String, dynamic> data = new Map<String, dynamic>();
Map<String, dynamic> data = Map<String, dynamic>();
data['actionBy'] = this.actionBy;
data['actionDate'] = this.actionDate;
if (this.attachments != null) {
data['attachments'] = this.attachments!.map((v) => v.toJson()).toList();
}
data['comments'] = this.comments;
data['statusDisplayText'] = this.statusDisplayText;
data['statusName'] = this.statusName;
@ -38,3 +41,22 @@ class GetTicketTransactions {
return data;
}
}
class Attachments {
int? attachmentId;
String? fileName;
Attachments({this.attachmentId, this.fileName});
Attachments.fromJson(Map<String, dynamic> json) {
attachmentId = json['attachmentId'];
fileName = json['fileName'];
}
Map<String, dynamic> toJson() {
Map<String, dynamic> data = Map<String, dynamic>();
data['attachmentId'] = this.attachmentId;
data['fileName'] = this.fileName;
return data;
}
}

@ -0,0 +1,52 @@
class GetTransactionAttachmentModel {
int? attachmentId;
String? fileName;
String? contentType;
dynamic attachFileStream;
String? base64String;
dynamic isActive;
dynamic referenceItemId;
dynamic content;
dynamic filePath;
int? languageId;
GetTransactionAttachmentModel(
{this.attachmentId,
this.fileName,
this.contentType,
this.attachFileStream,
this.base64String,
this.isActive,
this.referenceItemId,
this.content,
this.filePath,
this.languageId});
GetTransactionAttachmentModel.fromJson(Map<String, dynamic> json) {
attachmentId = json['attachmentId'];
fileName = json['fileName'];
contentType = json['contentType'];
attachFileStream = json['attachFileStream'];
base64String = json['base64String'];
isActive = json['isActive'];
referenceItemId = json['referenceItemId'];
content = json['content'];
filePath = json['filePath'];
languageId = json['languageId'];
}
Map<String, dynamic> toJson() {
Map<String, dynamic> data = Map<String, dynamic>();
data['attachmentId'] = this.attachmentId;
data['fileName'] = this.fileName;
data['contentType'] = this.contentType;
data['attachFileStream'] = this.attachFileStream;
data['base64String'] = this.base64String;
data['isActive'] = this.isActive;
data['referenceItemId'] = this.referenceItemId;
data['content'] = this.content;
data['filePath'] = this.filePath;
data['languageId'] = this.languageId;
return data;
}
}

@ -0,0 +1,18 @@
class TerminationNotificationBody {
String? sEGMENTPROMPT;
String? sEGMENTVALUEDSP;
TerminationNotificationBody({this.sEGMENTPROMPT, this.sEGMENTVALUEDSP});
TerminationNotificationBody.fromJson(Map<String, dynamic> json) {
sEGMENTPROMPT = json['SEGMENT_PROMPT'];
sEGMENTVALUEDSP = json['SEGMENT_VALUE_DSP'];
}
Map<String, dynamic> toJson() {
Map<String, dynamic> data = new Map<String, dynamic>();
data['SEGMENT_PROMPT'] = this.sEGMENTPROMPT;
data['SEGMENT_VALUE_DSP'] = this.sEGMENTVALUEDSP;
return data;
}
}

@ -37,7 +37,7 @@ import 'package:mohem_flutter_app/models/my_team/get_employee_subordinates_list.
import 'package:mohem_flutter_app/ui/chat/chat_detailed_screen.dart';
import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart';
import 'package:mohem_flutter_app/widgets/image_picker.dart';
import 'package:open_file/open_file.dart';
import 'package:open_filex/open_filex.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:signalr_netcore/hub_connection.dart';
@ -1674,7 +1674,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
try {
String path = await downChatMedia(encodedString, fileTypeName ?? "");
Utils.hideLoading(context);
OpenFile.open(path);
OpenFilex.open(path);
} catch (e) {
Utils.showToast("Cannot open file.");
}

@ -304,10 +304,17 @@ class _MonthlyAttendanceScreenState extends State<MonthlyAttendanceScreen> {
if (details.date.month == formattedDate.month && details.date.year == formattedDate.year) {
int val = details.date.day;
//check day is off
if (getDayHoursTypeDetailsList.isNotEmpty) {
bool isDayIsOff = getDayHoursTypeDetailsList[val - 1].aTTENDEDFLAG == 'N' && getDayHoursTypeDetailsList[val - 1].dAYTYPE == 'OFF';
bool isDayIsPresent = getDayHoursTypeDetailsList[val - 1].aTTENDEDFLAG == 'Y';
bool isDayIsAbsent = getDayHoursTypeDetailsList[val - 1].aTTENDEDFLAG == 'N' && getDayHoursTypeDetailsList[val - 1].aBSENTFLAG == 'Y';
// if (getDayHoursTypeDetailsList.isNotEmpty) {
// bool isDayIsOff = getDayHoursTypeDetailsList[val - 1].aTTENDEDFLAG == 'N' && getDayHoursTypeDetailsList[val - 1].dAYTYPE == 'OFF';
// bool isDayIsPresent = getDayHoursTypeDetailsList[val - 1].aTTENDEDFLAG == 'Y';
// bool isDayIsAbsent = getDayHoursTypeDetailsList[val - 1].aTTENDEDFLAG == 'N' && getDayHoursTypeDetailsList[val - 1].aBSENTFLAG == 'Y';
List<GetDayHoursTypeDetailsList> getDayHours =
getDayHoursTypeDetailsList.where((GetDayHoursTypeDetailsList element) => DateFormat("MM/dd/yyyy", "en_US").parse(element.sCHEDULEDATE!).day == details.date.day).toList();
if (getDayHours.isNotEmpty) {
bool isDayIsOff = getDayHoursTypeDetailsList[0].aTTENDEDFLAG == 'N' && getDayHoursTypeDetailsList[0].dAYTYPE == 'OFF';
bool isDayIsPresent = getDayHoursTypeDetailsList[0].aTTENDEDFLAG == 'Y';
bool isDayIsAbsent = getDayHoursTypeDetailsList[0].aTTENDEDFLAG == 'N' && getDayHoursTypeDetailsList[0].aBSENTFLAG == 'Y';
if (isDayIsOff) {
return Container(

@ -16,6 +16,8 @@ import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/models/itg/itg_main_response.dart';
import 'package:mohem_flutter_app/models/itg/itg_response_model.dart';
import 'package:mohem_flutter_app/models/offers_and_discounts/get_offers_list.dart';
import 'package:mohem_flutter_app/models/privilege_list_model.dart';
import 'package:mohem_flutter_app/provider/chat_provider_model.dart';
@ -150,6 +152,7 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
data.fetchMenuEntries();
data.getCategoryOffersListAPI(context);
marathonProvider.getMarathonDetailsFromApi();
marathonProvider.getMarathonTutorial();
if (isFromInit) {
checkERMChannel();
}
@ -157,39 +160,72 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
_refreshController.refreshCompleted();
}
void checkERMChannel() {
data.getITGNotification().then((val) {
if (val!.result!.data != null) {
print("-------------------- Survey ----------------------------");
if (val.result!.data!.notificationType == "Survey") {
DashboardApiClient().getAdvertisementDetail(val.result!.data!.notificationMasterId ?? "").then(
(value) {
if (value!.mohemmItgResponseItem!.statusCode == 200) {
if (value.mohemmItgResponseItem!.result!.data != null) {
// Navigator.pushNamed(context, AppRoutes.survey, arguments: val.result!.data);
Navigator.pushNamed(context, AppRoutes.survey, arguments: value.mohemmItgResponseItem!.result!.data);
// Navigator.pushNamed(context, AppRoutes.advertisement, arguments: {
// "masterId": val.result!.data!.notificationMasterId,
// "advertisement": value.mohemmItgResponseItem!.result!.data!.advertisement,
// });
}
int ermIndex = 0;
void handleErmChannel(List<ItgResponseData> list) async {
try {
if (ermIndex == list.length) {
return;
}
},
);
Utils.showLoading(context);
ItgMainRes? response = await DashboardApiClient().getAdvertisementDetail(list[ermIndex].notificationMasterId ?? "");
Utils.hideLoading(context);
if (response!.mohemmItgResponseItem!.result!.data != null) {
if (list[ermIndex].notificationType == "Survey") {
await Navigator.pushNamed(context, AppRoutes.survey, arguments: response.mohemmItgResponseItem!.result!.data!.first);
} else {
print("------------------------------------------- Ads --------------------");
DashboardApiClient().getAdvertisementDetail(val.result!.data!.notificationMasterId ?? "").then(
(value) {
if (value!.mohemmItgResponseItem!.statusCode == 200) {
if (value.mohemmItgResponseItem!.result!.data != null) {
Navigator.pushNamed(context, AppRoutes.advertisement, arguments: {
"masterId": val.result!.data!.notificationMasterId,
"advertisement": value.mohemmItgResponseItem!.result!.data!.advertisement,
await Navigator.pushNamed(context, AppRoutes.advertisement, arguments: {
"masterId": list[ermIndex].notificationMasterId,
"advertisement": response.mohemmItgResponseItem!.result!.data!.first.advertisement,
});
}
}
},
);
ermIndex++;
handleErmChannel(list);
} catch (ex) {
Utils.hideLoading(context);
Utils.handleException(ex, context, null);
return;
}
}
void checkERMChannel() {
data.getITGNotification().then((val) async {
if (val!.result!.data != null) {
ermIndex = 0;
val.result?.data?.removeWhere((element) => element.notificationType == "Announcement");
handleErmChannel(val.result?.data ?? []);
{
// if (ERMvalue.notificationType == "Survey") {
// await DashboardApiClient().getAdvertisementDetail(val.result!.data!.first.notificationMasterId ?? "").then(
// (value) async {
// if (value!.mohemmItgResponseItem!.statusCode == 200) {
// if (value.mohemmItgResponseItem!.result!.data != null) {
// // Navigator.pushNamed(context, AppRoutes.survey, arguments: val.result!.data);
// await Navigator.pushNamed(context, AppRoutes.survey, arguments: value.mohemmItgResponseItem!.result!.data!.first);
// // Navigator.pushNamed(context, AppRoutes.advertisement, arguments: {
// // "masterId": val.result!.data!.notificationMasterId,
// // "advertisement": value.mohemmItgResponseItem!.result!.data!.advertisement,
// // });
// }
// }
// },
// );
// } else {
// print("------------------------------------------- Ads --------------------");
// await DashboardApiClient().getAdvertisementDetail(ERMvalue.notificationMasterId ?? "").then(
// (value) async {
// if (value!.mohemmItgResponseItem!.statusCode == 200) {
// if (value.mohemmItgResponseItem!.result!.data != null) {
// await Navigator.pushNamed(context, AppRoutes.advertisement, arguments: {
// "masterId": val.result!.data!.first.notificationMasterId,
// "advertisement": value.mohemmItgResponseItem!.result!.data!.first.advertisement,
// });
// }
// }
// },
// );
// }
}
}
});
@ -493,7 +529,50 @@ 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: 21, 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(
// padding: EdgeInsets.only(bottom: 12, top: 12),
// margin: EdgeInsets.only(left: 21, right: 21, bottom: 21, top: 8),
// width: double.infinity,
// alignment: Alignment.center,
// decoration: BoxDecoration(
// color: MyColors.backgroundBlackColor,
// borderRadius: BorderRadius.circular(20),
// border: Border.all(color: MyColors.lightGreyEDColor, width: 1),
// ),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// mainAxisSize: MainAxisSize.min,
// children: [
// Text(
// "Tutorial:",
// style: TextStyle(
// fontSize: 11,
// fontStyle: FontStyle.italic,
// fontWeight: FontWeight.w600,
// color: MyColors.white.withOpacity(0.83),
// letterSpacing: -0.4,
// ),
// ),
// Text(
// context.read<MarathonProvider>().tutorial?.tutorialName ?? "",
// overflow: TextOverflow.ellipsis,
// style: TextStyle(
// fontStyle: FontStyle.italic,
// fontSize: 19,
// fontWeight: FontWeight.bold,
// color: MyColors.white,
// height: 32 / 22,
// ),
// ),
// ],
// ),
// ).onPress(() {
// checkERMChannel();
// // Navigator.pushNamed(context, AppRoutes.marathonTutorialScreen);
// }),
],
),
),

@ -35,7 +35,9 @@ class _ITGAdsScreenState extends State<ITGAdsScreen> {
bool isImage = false;
bool isAudio = false;
String ext = '';
late File imageFile;
// late File imageFile;
late String imageUrl;
ads.Advertisement? advertisementData;
dynamic data;
String? masterID;
@ -47,12 +49,13 @@ class _ITGAdsScreenState extends State<ITGAdsScreen> {
late CountdownTimerController timerController;
void checkFileType() async {
void checkFileType() {
String? rFile = advertisementData!.viewAttachFileColl!.first.base64String;
String? rFileExt = advertisementData!.viewAttachFileColl!.first.fileName;
ext = "." + rFileExt!.split(".").last.toLowerCase();
if (ext == ".png" || ext == ".jpg" || ext == ".jpeg" || ext == ".gif") {
await processImage(rFile!);
// await processImage();
imageUrl = rFile!;
isImage = true;
} else {
if (ext == ".aac") {
@ -62,11 +65,11 @@ class _ITGAdsScreenState extends State<ITGAdsScreen> {
_futureController = createVideoPlayer(rFile!);
}
advertisementData?.actionButtonsColl!.forEach((element) {
// advertisementData?.actionButtonsColl!.forEach((element) {
advertisementData?.actionButtonsColl!.removeWhere((element1) => element1.actionButtonId == advertisementData?.skipButtonId);
});
//});
setState(() {});
// setState(() {});
}
void changeTimer(bool isTimerEnd) {
@ -80,16 +83,17 @@ class _ITGAdsScreenState extends State<ITGAdsScreen> {
timerController.dispose();
}
Future processImage(String encodedBytes) async {
try {
Uint8List decodedBytes = base64Decode(encodedBytes.split("base64,").last);
Directory appDocumentsDirectory = await getApplicationDocumentsDirectory(); // 1
imageFile = Io.File("${appDocumentsDirectory.path}/addImage$ext");
imageFile.writeAsBytesSync(decodedBytes);
} catch (e) {
logger.d(e);
}
}
//
// Future processImage(String encodedBytes) async {
// try {
// Uint8List decodedBytes = base64Decode(encodedBytes.split("base64,").last);
// Directory appDocumentsDirectory = await getApplicationDocumentsDirectory(); // 1
// imageFile = Io.File("${appDocumentsDirectory.path}/addImage$ext");
// imageFile.writeAsBytesSync(decodedBytes);
// } catch (e) {
// logger.d(e);
// }
// }
Future<VideoPlayerController> createVideoPlayer(String encodedBytes) async {
try {
@ -177,9 +181,7 @@ class _ITGAdsScreenState extends State<ITGAdsScreen> {
String? btnText = AppState().isArabic(context) ? advertisementData?.actionButtonsColl![index].btnTextAr : advertisementData?.actionButtonsColl![index].btnTextEn;
return DefaultButton(btnText!, () async {
Navigator.pop(context);
DashboardApiClient()
.setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, advertisementData?.actionButtonsColl![index].actionValue)
.then((value) {
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);
@ -266,7 +268,7 @@ class _ITGAdsScreenState extends State<ITGAdsScreen> {
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.file(imageFile),
Image.network(imageUrl),
50.height,
Container(padding: const EdgeInsets.all(16), decoration: Utils.containerRadius(MyColors.white, 10), child: const Icon(Icons.thumb_up, color: MyColors.gradiantEndColor)).onPress(
() {

@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_rating_bar/flutter_rating_bar.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:mohem_flutter_app/api/dashboard_api_client.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
@ -14,6 +15,8 @@ import 'package:mohem_flutter_app/models/itg/itg_response_model.dart';
import 'package:mohem_flutter_app/models/itg/survey_model.dart';
import 'package:mohem_flutter_app/widgets/button/default_button.dart';
import 'package:flutter/widgets.dart' as fw;
class SurveyScreen extends StatefulWidget {
const SurveyScreen({Key? key}) : super(key: key);
@ -46,6 +49,8 @@ class _SurveyScreenState extends State<SurveyScreen> {
body: Column(
children: [
Expanded(
child: Directionality(
textDirection: AppState().isArabic(context) ? fw.TextDirection.rtl : fw.TextDirection.ltr,
child: ListView(
children: [
Padding(
@ -53,9 +58,9 @@ class _SurveyScreenState extends State<SurveyScreen> {
child: Column(
children: [
32.height,
itgResponseData?.survey?.title?.toText24() ?? const Text(""),
(AppState().isArabic(context) ? itgResponseData?.survey?.titleAr : itgResponseData?.survey?.title)?.toText24() ?? const Text(""),
8.height,
itgResponseData?.survey?.description?.toText16() ?? const Text(""),
(AppState().isArabic(context) ? itgResponseData?.survey?.descriptionAr : itgResponseData?.survey?.description)?.toText16() ?? const Text(""),
ListView.builder(
padding: EdgeInsets.zero,
shrinkWrap: true,
@ -69,6 +74,7 @@ class _SurveyScreenState extends State<SurveyScreen> {
).paddingOnly(left: 21, right: 21),
),
],
),
)),
DefaultButton(
LocaleKeys.submitSurvey.tr(),
@ -105,7 +111,7 @@ class _SurveyScreenState extends State<SurveyScreen> {
answeredQuestions.clear();
itgResponseData?.survey?.questions?.forEach((element) {
if (element.type != "Stars") {
if(element.type == "Faces") {
if (element.type == "Faces") {
_selectedIndex = element.options![0].optionId!;
}
answeredQuestions.add(element.options![0].optionId.toString());
@ -122,15 +128,16 @@ class _SurveyScreenState extends State<SurveyScreen> {
return Column(
children: [
24.height,
question?.title?.toText18() ?? const Text(""),
(AppState().isArabic(context) ? question?.titleAr : question?.title)?.toText18() ?? const Text(""),
16.height,
GridView.builder(
padding: EdgeInsets.zero,
itemCount: question?.options?.length,
itemCount: question?.options?.length ?? 0,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
return radioOption(question?.options?[index].title ?? "", question?.options?[index].optionId.toString() ?? "", answeredQuestions[parentIndex], parentIndex);
return radioOption((AppState().isArabic(context) ? (question!.options![index].titleAr) : question!.options![index].title) ?? "", question?.options?[index].optionId.toString() ?? "",
answeredQuestions[parentIndex], parentIndex);
},
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
@ -145,7 +152,7 @@ class _SurveyScreenState extends State<SurveyScreen> {
mainAxisSize: MainAxisSize.min,
children: [
24.height,
question?.title?.toText18() ?? Text(""),
(AppState().isArabic(context) ? question?.titleAr : question?.title)?.toText18() ?? Text(""),
16.height,
RatingBar.builder(
initialRating: 3,
@ -171,7 +178,7 @@ class _SurveyScreenState extends State<SurveyScreen> {
mainAxisSize: MainAxisSize.min,
children: [
24.height,
question?.title?.toText18() ?? Text("asdasdasdasd"),
(AppState().isArabic(context) ? question?.titleAr : question?.title)?.toText18() ?? Text(""),
16.height,
GridView(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 5, crossAxisSpacing: 7, mainAxisSpacing: 7),
@ -179,11 +186,13 @@ class _SurveyScreenState extends State<SurveyScreen> {
padding: const EdgeInsets.only(top: 0),
shrinkWrap: true,
children: [
optionUI("poor.svg", question?.options?[0].optionId, parentIndex),
optionUI("bad.svg", question?.options?[1].optionId, parentIndex),
optionUI("normal.svg", question?.options?[2].optionId, parentIndex),
optionUI("good.svg", question?.options?[3].optionId, parentIndex),
optionUI("xcellent.svg", question?.options?[4].optionId, parentIndex),
for (int i = 0; i < (question?.options?.length ?? 0); i++) optionUI("${question?.options![i].title!.toLowerCase()}.svg", question?.options?[i].optionId, parentIndex),
// optionUI("poor.svg", question?.options?[0].optionId, parentIndex),
// optionUI("fair.svg", question?.options?[1].optionId, parentIndex),
// optionUI("ok.svg", question?.options?[2].optionId, parentIndex),
// optionUI("good.svg", question?.options?[3].optionId, parentIndex),
// optionUI("excellent.svg", question?.options?[4].optionId, parentIndex),
],
),
],

@ -40,7 +40,7 @@ class _AddLeaveBalanceScreenState extends State<AddLeaveBalanceScreen> {
GetAbsenceAttendanceTypesList? selectedAbsenceType;
DateTime? startDateTime;
DateTime? endDateTime;
int? totalDays;
double? totalDays;
String comment = "";
ReplacementList? selectedReplacementEmployee;
String? selectedEmp;
@ -90,7 +90,7 @@ class _AddLeaveBalanceScreenState extends State<AddLeaveBalanceScreen> {
Utils.showLoading(context);
CalculateAbsenceDuration duration = await LeaveBalanceApiClient()
.calculateAbsenceDuration(selectedAbsenceType!.aBSENCEATTENDANCETYPEID!, Utils.getMonthNamedFormat(startDateTime!), Utils.getMonthNamedFormat(endDateTime!), -999, empID: selectedEmp);
totalDays = duration.pABSENCEDAYS?.toInt();
totalDays = duration.pABSENCEDAYS?.toDouble();
Utils.hideLoading(context);
setState(() {});
} catch (ex) {
@ -232,7 +232,7 @@ class _AddLeaveBalanceScreenState extends State<AddLeaveBalanceScreen> {
isInputTypeNum: true,
isEnable: false,
onChange: (input) {
totalDays = int.parse(input);
totalDays = double.tryParse(input);
},
),
12.height,

@ -17,11 +17,14 @@ import 'package:mohem_flutter_app/classes/consts.dart';
import 'package:mohem_flutter_app/classes/notifications.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/dialogs/otp_dialog.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/models/basic_member_information_model.dart';
import 'package:mohem_flutter_app/models/check_mobile_app_version_model.dart';
import 'package:mohem_flutter_app/models/generic_response_model.dart';
import 'package:mohem_flutter_app/models/get_mobile_login_info_list_model.dart';
import 'package:mohem_flutter_app/models/member_information_list_model.dart';
import 'package:mohem_flutter_app/models/member_login_list_model.dart';
@ -59,6 +62,9 @@ class _LoginScreenState extends State<LoginScreen> {
bool isOnExternalStorage = false;
bool isDevelopmentModeEnable = false;
BasicMemberInformationModel? _basicMemberInformation;
GenericResponseModel? genericResponseModel;
// late HmsApiAvailability hmsApiAvailability;
@override
@ -199,7 +205,8 @@ class _LoginScreenState extends State<LoginScreen> {
onTap: () async {
if (msg.toLowerCase().contains("password has expired")) {
Navigator.pop(context);
await Navigator.pushNamed(context, AppRoutes.newPassword, arguments: username.text);
// await Navigator.pushNamed(context, AppRoutes.newPassword, arguments: username.text);
performForgotPassword();
} else {
Navigator.pop(context);
}
@ -209,6 +216,53 @@ class _LoginScreenState extends State<LoginScreen> {
}
}
void performForgotPassword() async {
// if (username.text.isEmpty) {
// return;
// }
Utils.showLoading(context);
try {
_basicMemberInformation = await LoginApiClient().getBasicUserInformation("CS", username.text);
genericResponseModel = await LoginApiClient().sendPublicActivationCode(_basicMemberInformation?.pMOBILENUMBER, username.text);
Utils.hideLoading(context);
OtpDialog(
context,
1,
int.tryParse(_basicMemberInformation?.pMOBILENUMBER ?? ""),
(value, TextEditingController _pinPutController) async {
Utils.showLoading(context);
try {
GenericResponseModel? genericResponseModel = await LoginApiClient().checkPublicActivationCode(value, username.text);
if (genericResponseModel?.errorMessage != null) {
Utils.showToast(genericResponseModel?.errorMessage ?? "");
return;
}
Utils.hideLoading(context);
await Navigator.pushNamed(context, AppRoutes.newPassword, arguments: username.text);
Navigator.pop(context);
// Navigator.pop(context);
} catch (ex) {
print(ex);
_pinPutController.clear();
otpFieldClear.value = "";
Utils.hideLoading(context);
Utils.handleException(ex, context, null);
}
},
() => {
Navigator.pop(context),
},
onResendCode: () {
performForgotPassword();
},
).displayDialog(context);
} catch (ex) {
print(ex);
Utils.hideLoading(context);
Utils.handleException(ex, context, null);
}
}
@override
Widget build(BuildContext context) {
if (isAppOpenBySystem == null) {
@ -277,9 +331,12 @@ class _LoginScreenState extends State<LoginScreen> {
9.height,
Align(
alignment: Alignment.centerRight,
child: LocaleKeys.forgotPassword.tr().toText12(isUnderLine: true, color: MyColors.textMixColor).onPress(() {
Navigator.pushNamed(context, AppRoutes.forgotPassword);
}),
child: LocaleKeys.forgotPassword.tr().toText12(isUnderLine: true, color: MyColors.textMixColor).onPress(
() {
// Navigator.pushNamed(context, AppRoutes.forgotPassword);
performForgotPassword();
},
),
),
20.height,
// DefaultButton(

@ -103,7 +103,7 @@ class _NewPasswordScreenState extends State<NewPasswordScreen> {
8.height,
passwordConstraintsUI(LocaleKeys.doNotAddRepeatingLetters.tr(), checkRepeatedChars(password.text)),
// 8.height,
// passwordConstraintsUI(LocaleKeys.itShouldContainSpecialCharacter.tr(), checkRegEx(r'[!@#$%^&*(),.?":{}|<>]')),
// passwordConstraintsUI(LocaleKeys.itShouldContainSpecialCharacter.tr(), checkRegEx(r'^[a-zA-Z0-9]+$')),
8.height,
passwordConstraintsUI(LocaleKeys.confirmPasswordMustMatch.tr(), password.text.isNotEmpty && password.text == confirmPassword.text),
],
@ -114,8 +114,8 @@ class _NewPasswordScreenState extends State<NewPasswordScreen> {
? null
: () async {
setNewPassword();
})
.insideContainer
},
).insideContainer
],
),
);

@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:developer';
import 'package:appinio_swiper/appinio_swiper.dart';
import 'package:easy_localization/easy_localization.dart';
@ -13,6 +14,7 @@ import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/models/marathon/marathon_generic_model.dart';
import 'package:mohem_flutter_app/models/marathon/marathon_model.dart';
import 'package:mohem_flutter_app/models/marathon/question_model.dart';
import 'package:mohem_flutter_app/models/marathon/tutorial_notification_model.dart';
import 'package:mohem_flutter_app/models/marathon/winner_model.dart';
import 'package:mohem_flutter_app/models/privilege_list_model.dart';
import 'package:mohem_flutter_app/ui/marathon/widgets/question_card.dart';
@ -414,13 +416,16 @@ class MarathonProvider extends ChangeNotifier {
notifyListeners();
}
void updateCurrentQuestionOptionStatus(QuestionsOptionStatus status, int index) {
void updateCurrentQuestionOptionStatus({required QuestionsOptionStatus status, required int selectedOptIndex, required int correctOptionIndex}) {
for (int i = 0; i < currentQuestion.questionOptions!.length; i++) {
currentQuestion.questionOptions![i].optionStatus = QuestionsOptionStatus.unSelected;
}
currentQuestion.questionOptions![index].optionStatus = status;
selectedOptionId = currentQuestion.questionOptions![index].id;
selectedOptionIndex = index;
if (status == QuestionsOptionStatus.wrong) {
currentQuestion.questionOptions![correctOptionIndex].optionStatus = QuestionsOptionStatus.correct; // if person's answer is wrong we have to show him the actual right answer
}
currentQuestion.questionOptions![selectedOptIndex].optionStatus = status;
selectedOptionId = currentQuestion.questionOptions![selectedOptIndex].id;
selectedOptionIndex = selectedOptIndex;
notifyListeners();
}
@ -435,22 +440,30 @@ class MarathonProvider extends ChangeNotifier {
}
void getCorrectAnswerAndUpdateAnswerColor() {
log("correctOptionIndex");
callCountThreshold = 1;
int correctOptionIndex = -1;
if (demoMarathonDetailModel.displayCorrectAnswer ?? false) {
correctOptionIndex = currentQuestion.questionOptions!.indexWhere((QuestionOptions element) => element.isCorrectOption ?? false);
log("correctOptionIndex: $correctOptionIndex");
}
if (selectedOptionIndex != null) {
scheduleMicrotask(() async {
if (AppState().getIsDemoMarathon) {
if (currentQuestion.questionOptions![selectedOptionIndex!].isCorrectOption!) {
updateCurrentQuestionOptionStatus(QuestionsOptionStatus.correct, selectedOptionIndex!);
updateCurrentQuestionOptionStatus(status: QuestionsOptionStatus.correct, selectedOptIndex: selectedOptionIndex!, correctOptionIndex: correctOptionIndex);
} else {
updateCurrentQuestionOptionStatus(QuestionsOptionStatus.wrong, selectedOptionIndex!);
updateCurrentQuestionOptionStatus(status: QuestionsOptionStatus.wrong, selectedOptIndex: selectedOptionIndex!, correctOptionIndex: correctOptionIndex);
}
} else {
await callSubmitOptionApi().then((bool value) async {
updateIsUserOutOfGame = !value;
if (value) {
updateCurrentQuestionOptionStatus(QuestionsOptionStatus.correct, selectedOptionIndex!);
updateCurrentQuestionOptionStatus(status: QuestionsOptionStatus.correct, selectedOptIndex: selectedOptionIndex!, correctOptionIndex: correctOptionIndex);
} else {
updateCurrentQuestionOptionStatus(QuestionsOptionStatus.wrong, selectedOptionIndex!);
updateCurrentQuestionOptionStatus(status: QuestionsOptionStatus.wrong, selectedOptIndex: selectedOptionIndex!, correctOptionIndex: correctOptionIndex);
}
});
}
@ -551,7 +564,6 @@ class MarathonProvider extends ChangeNotifier {
notifyListeners();
isPrivilegedWithMarathon = checkIfPrivilegedForMarathon();
demoMarathonDetailModel = await DemoMarathonRepo().getDemoMarathonDetails();
if (isPrivilegedWithMarathon) {
marathonDetailModel = await MarathonApiClient().getMarathonDetails();
updateTotalSecondsToWaitForMarathon = marathonDetailModel.marathonBufferTime ?? 30;
@ -594,4 +606,15 @@ class MarathonProvider extends ChangeNotifier {
AppState().setIsDemoMarathon = true;
await callNextQuestionApi();
}
bool isTutorialLoading = false;
TutorialNotificationModel? tutorial;
Future<void> getMarathonTutorial() async {
isTutorialLoading = true;
notifyListeners();
tutorial = await MarathonApiClient().getMarathonTutorial();
isTutorialLoading = false;
notifyListeners();
}
}

@ -0,0 +1,241 @@
import 'dart:convert';
import 'dart:io' as Io;
import 'dart:io';
import 'dart:typed_data';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_countdown_timer/index.dart';
import 'package:lottie/lottie.dart';
import 'package:mohem_flutter_app/api/dashboard_api_client.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/file_process.dart';
import 'package:mohem_flutter_app/classes/lottie_consts.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/main.dart';
import 'package:mohem_flutter_app/models/itg/advertisement.dart' as ads;
import 'package:mohem_flutter_app/models/marathon/tutorial_notification_model.dart';
import 'package:mohem_flutter_app/ui/chat/common.dart';
import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart';
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
import 'package:mohem_flutter_app/widgets/button/default_button.dart';
import 'package:path_provider/path_provider.dart';
import 'package:provider/provider.dart';
import 'package:video_player/video_player.dart';
class MarathonTutorialViewerScreen extends StatefulWidget {
const MarathonTutorialViewerScreen({Key? key}) : super(key: key);
@override
_MarathonTutorialViewerScreenState createState() => _MarathonTutorialViewerScreenState();
}
class _MarathonTutorialViewerScreenState extends State<MarathonTutorialViewerScreen> {
late Future<VideoPlayerController> _futureController;
VideoPlayerController? _controller;
bool skip = false;
bool isVideo = false;
bool isImage = false;
bool isAudio = false;
bool isPdf = false;
String link = "";
String ext = '';
late File imageFile;
ads.Advertisement? advertisementData;
dynamic data;
String? masterID;
int videoDuration = 0;
ValueNotifier<int> videoLength = ValueNotifier(0);
void checkFileTypes(String link) {
ext = "." + link.split(".").last.toLowerCase();
if (ext == ".png" || ext == ".jpg" || ext == ".jpeg" || ext == ".gif") {
isImage = true;
} else if (ext == ".pdf") {
isPdf = true;
} else {
if (ext == ".aac") {
isAudio = true;
}
isVideo = true;
_futureController = createVideoPlayer(link);
}
setState(() {});
}
Future processImage(String encodedBytes) async {
try {
Uint8List decodedBytes = base64Decode(encodedBytes.split("base64,").last);
Directory appDocumentsDirectory = await getApplicationDocumentsDirectory(); // 1
imageFile = Io.File("${appDocumentsDirectory.path}/addImage$ext");
imageFile.writeAsBytesSync(decodedBytes);
} catch (e) {
logger.d(e);
}
}
Future<VideoPlayerController> createVideoPlayer(String link) async {
try {
VideoPlayerController controller = VideoPlayerController.networkUrl(Uri.parse(link));
await controller.initialize();
await controller.play();
await controller.setVolume(1.0);
await controller.setLooping(false);
controller.addListener(() {
controller.position.then((value) {
videoLength.value = value!.inMilliseconds;
// if(controller.value.isCompleted) {
// videoLength.value = 0;
// }
});
});
return controller;
} catch (e) {
print(e);
return VideoPlayerController.network("https://apimohemmweb.cloudsolutions.com.sa/ErmAttachment/compressedvideo.mp4");
}
}
bool showControls = false;
void showVideoControls() {
showControls = !showControls;
setState(() {});
}
@override
void initState() {
super.initState();
}
@override
void dispose() {
_controller?.dispose();
super.dispose();
}
TutorialNotificationModel? tutorial;
@override
Widget build(BuildContext context) {
if (tutorial == null) {
tutorial ??= context.read<MarathonProvider>().tutorial;
link = tutorial!.filePath!;
checkFileTypes(link);
}
return Scaffold(
backgroundColor: Colors.black,
appBar: AppBarWidget(context, title: tutorial!.fileName!, showHomeButton: false),
body: Stack(
children: [
if (isVideo)
FutureBuilder(
future: _futureController,
builder: (BuildContext context, AsyncSnapshot<Object?> snapshot) {
if (snapshot.connectionState == ConnectionState.done && snapshot.data != null) {
_controller = snapshot.data as VideoPlayerController;
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: isAudio
? Lottie.asset(MyLottieConsts.audioPlaybackLottie)
: AspectRatio(
aspectRatio: _controller!.value.aspectRatio,
child: Stack(
alignment: Alignment.bottomCenter,
children: [
VideoPlayer(_controller!),
AnimatedContainer(
duration: const Duration(milliseconds: 250),
color: Colors.black.withOpacity(showControls ? .4 : .0),
child: AnimatedOpacity(
opacity: showControls ? 1 : 0,
duration: const Duration(milliseconds: 250),
child: Column(
children: [
Icon(_controller!.value.isPlaying ? Icons.pause : Icons.play_arrow, color: Colors.white)
.onPress(() {
if (!showControls) {
showVideoControls();
return;
}
if (_controller!.value.isPlaying) {
_controller!.pause();
}
// else if (_controller!.value.isCompleted) {
// videoLength.value = 0;
// _controller!.play();
// }
else {
_controller!.play();
}
setState(() {});
})
.center
.expanded,
ValueListenableBuilder<int>(
valueListenable: videoLength,
builder: (context, val, child) {
return SeekBar(
duration: _controller!.value.duration,
position: Duration(milliseconds: val),
bufferedPosition: Duration(),
onChanged: (duration) {
_controller!.seekTo(duration);
},
);
}),
],
),
),
).onPress(() {
showVideoControls();
}),
],
),
),
),
30.height,
],
);
} else {
return const Center(
child: CircularProgressIndicator(
color: Colors.white,
),
);
}
},
),
if (isImage) Image.network(link).center,
if (isPdf)
DefaultButton(LocaleKeys.open.tr(), () async {
try {
Utils.showLoading(context);
await FileProcess.downloadFileFromUrl(link, tutorial!.fileName!).then((path) {
Utils.hideLoading(context);
FileProcess.openFile(path, isFullPath: true);
});
} catch (ex) {
Utils.hideLoading(context);
Utils.handleException(ex, context, null);
}
}).paddingAll(21).center
],
),
);
}
}

@ -133,7 +133,7 @@ class AnswerContent extends StatelessWidget {
if (provider.totalCurrentQuestionTime - provider.currentGapTime <= 0) {
null;
} else {
provider.updateCurrentQuestionOptionStatus(QuestionsOptionStatus.selected, index);
provider.updateCurrentQuestionOptionStatus(status: QuestionsOptionStatus.selected, selectedOptIndex: index, correctOptionIndex: -1); //
}
},
);

@ -1,3 +1,8 @@
import 'dart:convert';
import 'dart:io';
import 'dart:io' as Io;
import 'dart:typed_data';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/api/mowadhafhi/mowadhafhi_api_client.dart';
@ -6,9 +11,16 @@ import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/main.dart';
import 'package:mohem_flutter_app/models/mowadhafhi/get_ticket_details.dart';
import 'package:mohem_flutter_app/models/mowadhafhi/get_ticket_transactions.dart';
import 'package:mohem_flutter_app/models/mowadhafhi/get_transaction_attachment_model.dart';
import 'package:mohem_flutter_app/ui/screens/mowadhafhi/view_transaction_attachment.dart';
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
import 'package:mohem_flutter_app/widgets/dialogs/confirm_dialog.dart';
import 'package:open_filex/open_filex.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
class MowadhafhiRequestDetails extends StatefulWidget {
const MowadhafhiRequestDetails({Key? key}) : super(key: key);
@ -21,6 +33,9 @@ class _RequestDetailsState extends State<MowadhafhiRequestDetails> {
String? itgTicketID;
List<GetTicketDetailsByEmployee> getTicketsByEmployeeList = [];
List<GetTicketTransactions> getTicketTransactionsList = [];
GetTransactionAttachmentModel? getTransactionAttachmentModel;
late File imageFile;
@override
void initState() {
@ -128,15 +143,31 @@ class _RequestDetailsState extends State<MowadhafhiRequestDetails> {
Row(
children: [
LocaleKeys.actionBy.tr().toText14(color: MyColors.grey57Color),
": ".toText14(),
getTicketTransactionsList![index].actionBy!.toText14(color: MyColors.grey57Color),
],
),
Row(
children: [
LocaleKeys.actions.tr().toText14(color: MyColors.grey57Color),
": ".toText14(),
getTicketTransactionsList![index].statusDisplayText!.toText14(color: MyColors.grey57Color),
],
),
getTicketTransactionsList![index].comments!.toText14(color: MyColors.grey98Color),
12.height,
if (getTicketTransactionsList[index].attachments != null)
InkWell(
onTap: () {
print(getTicketTransactionsList[index].attachments![0].attachmentId);
getTransactionAttachment(getTicketTransactionsList[index].attachments![0].attachmentId!);
},
child: LocaleKeys.attachments.tr().toText14(color: MyColors.gradiantEndColor, isUnderLine: true),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
getTicketTransactionsList![0].actionDate!.split(" ")[0].toText12(color: MyColors.grey70Color),
getTicketTransactionsList![index].actionDate!.split(" ")[0].toText12(color: MyColors.grey70Color),
],
),
],
@ -212,4 +243,58 @@ class _RequestDetailsState extends State<MowadhafhiRequestDetails> {
Utils.handleException(ex, context, null);
}
}
void getTransactionAttachment(int attachmentID) async {
try {
Utils.showLoading(context);
getTransactionAttachmentModel = await MowadhafhiApiClient().getTransactionAttachments(attachmentID);
Utils.hideLoading(context);
handleTransactionAttachment();
} catch (ex) {
Utils.hideLoading(context);
Utils.handleException(ex, context, null);
}
}
Future<String> _createFileFromString(String encodedStr, String ext) async {
Uint8List bytes = base64.decode(encodedStr);
String dir = (await getApplicationDocumentsDirectory()).path;
File file = File("$dir/" + DateTime.now().millisecondsSinceEpoch.toString() + "." + ext);
await file.writeAsBytes(bytes);
return file.path;
}
void handleTransactionAttachment() async {
Permission.storage.isGranted.then((isGranted) {
if (!isGranted) {
Permission.manageExternalStorage.request().then((granted) async {
if (granted == PermissionStatus.granted) {
String ext = '';
String? rFile = getTransactionAttachmentModel!.base64String;
String? rFileExt = getTransactionAttachmentModel!.fileName;
ext = rFileExt!.split(".").last.toLowerCase();
try {
String path = await _createFileFromString(rFile!.split("base64,").last ?? "", ext ?? "");
await OpenFilex.open(path).catchError((err) {
print(err);
});
} catch (ex) {
Utils.showToast("Cannot open file.");
}
} else {
showDialog(
context: context,
builder: (BuildContext cxt) => ConfirmDialog(
message: "You need to give storage permission to view files.",
onTap: () {
Navigator.pop(context);
},
),
);
}
});
}
});
}
}

@ -0,0 +1,34 @@
import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
class ViewTransactionAttachment extends StatelessWidget {
final File imageFile;
const ViewTransactionAttachment({Key? key, required this.imageFile}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBarWidget(
context,
title: LocaleKeys.mowadhafhiRequest.tr(),
),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.file(imageFile),
50.height,
],
),
),
);
}
}

@ -79,7 +79,7 @@ class _MyDocumentsFragmentState extends State<MyDocumentsFragment> {
Navigator.pushNamed(
context,
AppRoutes.addDynamicInput,
arguments: DynamicListViewParams(documentfilteredList[index].dOCUMENTTYPE!, documentfilteredList[index].fUNCTIONNAME!,
arguments: DynamicListViewParams(documentfilteredList[index].dOCUMENTTYPENAME!, documentfilteredList[index].fUNCTIONNAME!,
selectedEmp: AppState().getUserName, isAttachmentMandatory: true),
);
});

@ -22,7 +22,7 @@ import 'package:mohem_flutter_app/models/get_quotation_analysis_list_model.dart'
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
import 'package:mohem_flutter_app/widgets/circular_avatar.dart';
import 'package:mohem_flutter_app/widgets/item_detail_view_widget.dart';
import 'package:open_file/open_file.dart';
import 'package:open_filex/open_filex.dart';
import 'package:path_provider/path_provider.dart';
class ItemHistoryScreenParams {
@ -278,7 +278,7 @@ class _ItemHistoryScreenState extends State<ItemHistoryScreen> {
).objectContainerView().onPress(() async {
try {
String path = await _createFileFromString(getAttachmentList[index].fILEDATA ?? "", getAttachmentList[index].fILECONTENTTYPE ?? "");
OpenFile.open(path);
OpenFilex.open(path);
} catch (ex) {
Utils.showToast("Cannot open file.");
}

@ -3,6 +3,7 @@ import 'dart:convert';
import 'package:easy_localization/src/public_ext.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:lottie/lottie.dart';
import 'package:mohem_flutter_app/api/worklist/worklist_api_client.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
@ -12,10 +13,12 @@ import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/models/itg_forms_models/allowed_actions_model.dart';
import 'package:mohem_flutter_app/models/itg_forms_models/itg_forms_attachments_model.dart';
import 'package:mohem_flutter_app/models/itg_forms_models/itg_request_model.dart';
import 'package:mohem_flutter_app/models/itg_forms_models/request_detail_model.dart';
import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart';
import 'package:mohem_flutter_app/ui/work_list/itg_fragments/approval_level_fragment.dart';
import 'package:mohem_flutter_app/ui/work_list/itg_fragments/attachments_fragment.dart';
import 'package:mohem_flutter_app/ui/work_list/itg_fragments/request_detail_fragment.dart';
import 'package:mohem_flutter_app/ui/work_list/sheets/delegate_sheet.dart';
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
@ -44,9 +47,12 @@ class _ItgDetailScreenState extends State<ItgDetailScreen> {
bool isRejectAvailable = false;
List<AllowedActions> allowedActionList = [];
List<ITGFormsAttachmentsModel> itgFormAttachmentsList = [];
late DashboardProviderModel providerData;
bool isAttachmentLoaded = false;
@override
void initState() {
providerData = Provider.of<DashboardProviderModel>(context, listen: false);
@ -87,6 +93,7 @@ class _ItgDetailScreenState extends State<ItgDetailScreen> {
requestDetails = AppState().requestAllList![AppState().itgWorkListIndex!]; // ModalRoute.of(context)!.settings.arguments as WorkListResponseModel;
providerData.itgFormsModel!.totalCount = providerData.itgFormsModel!.totalCount! - 1;
getItgData();
getItgRequestAttachments();
}
}
@ -140,6 +147,7 @@ class _ItgDetailScreenState extends State<ItgDetailScreen> {
myTab(LocaleKeys.requestDetails.tr(), 0),
myTab(LocaleKeys.approvalLevel.tr(), 1),
myTab(LocaleKeys.requesterDetails.tr(), 2),
myTab(LocaleKeys.attachments.tr(), 3),
],
),
),
@ -157,6 +165,11 @@ class _ItgDetailScreenState extends State<ItgDetailScreen> {
voidCallback: reloadITG,
),
RequestDetailFragment(fields: itgRequest?.fieldGoups?[0].fields ?? []),
isAttachmentLoaded
? itgFormAttachmentsList.isEmpty
? Utils.getNoDataWidget(context)
: ITGAttachmentsFragment(itgFormAttachmentsList)
: showLoadingAnimation(),
],
).expanded,
if (isApproveAvailable || isRejectAvailable || isCloseAvailable)
@ -405,7 +418,7 @@ class _ItgDetailScreenState extends State<ItgDetailScreen> {
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
title.toText12(color: isSelected ? Colors.white : Colors.white.withOpacity(.74), isCenter: true),
title.toText11(color: isSelected ? Colors.white : Colors.white.withOpacity(.74), isCenter: true),
4.height,
Container(
height: 8,
@ -576,6 +589,35 @@ class _ItgDetailScreenState extends State<ItgDetailScreen> {
}
}
Widget showLoadingAnimation() {
return Lottie.asset(
'assets/lottie/loading.json',
repeat: true,
reverse: false,
);
}
void getItgRequestAttachments() async {
try {
// Utils.showLoading(context);
itgFormAttachmentsList =
(await WorkListApiClient().getITGFormAttachments(requestDetails!.requestType!, requestDetails!.iD, requestDetails!.itemID, AppState().memberInformationList?.eMPLOYEENUMBER ?? ""))!;
// allowedActionList = itgRequest?.allowedActions ?? [];
// if (allowedActionList.isNotEmpty) {
// isCloseAvailable = allowedActionList.any((element) => element.action == "CLOSE");
// isApproveAvailable = itgRequest!.allowedActions!.any((element) => element.action == "Approve");
// isRejectAvailable = itgRequest!.allowedActions!.any((element) => element.action == "Reject");
// }
// Utils.hideLoading(context);
setState(() {
isAttachmentLoaded = true;
});
} catch (ex) {
Utils.hideLoading(context);
Utils.handleException(ex, context, null);
}
}
void reloadITG() {
animationIndex = animationIndex + 1;
AppState().requestAllList!.removeAt(AppState().itgWorkListIndex!);

@ -0,0 +1,78 @@
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/models/itg_forms_models/itg_forms_attachments_model.dart';
import 'package:mohem_flutter_app/widgets/dialogs/confirm_dialog.dart';
import 'package:open_filex/open_filex.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
class ITGAttachmentsFragment extends StatelessWidget {
List<ITGFormsAttachmentsModel> itgFormAttachmentsList;
ITGAttachmentsFragment(this.itgFormAttachmentsList);
@override
Widget build(BuildContext context) {
return ListView.separated(
itemCount: itgFormAttachmentsList.length,
itemBuilder: (context, index) {
return Row(
children: [
SvgPicture.asset(determineFileIcon(itgFormAttachmentsList[index].fileType ?? "")),
12.width,
(itgFormAttachmentsList[index].fileName ?? "").toText16().expanded,
],
).objectContainerView().onPress(() async {
try {
String path = await _createFileFromString(itgFormAttachmentsList[index].fileBase64 ?? "", itgFormAttachmentsList[index].fileType ?? "");
OpenFilex.open(path);
} catch (ex) {
Utils.showToast("Cannot open file.");
}
});
},
separatorBuilder: (BuildContext context, int index) => 12.height,
).paddingAll(21);
}
String determineFileIcon(String fileContentType) {
String icon = "";
switch (fileContentType) {
case "pdf":
icon = "assets/images/pdf.svg";
break;
case "xls":
icon = "assets/images/xls.svg";
break;
case "xlsx":
icon = "assets/images/xls.svg";
break;
case "png":
icon = "assets/images/png.svg";
break;
case "jpg":
icon = "assets/images/jpg.svg";
break;
case "jpeg":
icon = "assets/images/jpg.svg";
break;
}
return icon;
}
Future<String> _createFileFromString(String encodedStr, String ext) async {
Uint8List bytes = base64.decode(encodedStr);
String dir = (await getApplicationDocumentsDirectory()).path;
File file = File("$dir/" + DateTime.now().millisecondsSinceEpoch.toString() + "." + ext);
await file.writeAsBytes(bytes);
return file.path;
}
}

@ -44,6 +44,8 @@ import 'package:mohem_flutter_app/widgets/bottom_sheet.dart';
import 'package:mohem_flutter_app/widgets/button/default_button.dart';
import 'package:mohem_flutter_app/widgets/dialogs/accept_reject_input_dialog.dart';
import 'package:mohem_flutter_app/widgets/dialogs/confirm_dialog.dart';
import 'package:mohem_flutter_app/models/termination/termination_notification_body.dart';
class WorkListDetailScreen extends StatefulWidget {
WorkListDetailScreen({Key? key}) : super(key: key);
@ -80,6 +82,8 @@ class _WorkListDetailScreenState extends State<WorkListDetailScreen> {
List<GetAbsenceCollectionNotificationBodyList>? getAbsenceCollectionNotificationBodyList = [];
GetContactNotificationBodyList? getContactNotificationBodyList;
List<GetAddressNotificationBodyList>? getAddressNotificationBodyList = [];
List<TerminationNotificationBody>? getTerminationNotificationBodyList = [];
GenericResponseModel? getBasicNTFBody;
GenericResponseModel? getICBody;
@ -121,6 +125,7 @@ class _WorkListDetailScreenState extends State<WorkListDetailScreen> {
getItemCreationNtfBody?.itemCreationHeader!.clear();
getPhonesNotificationBodyList!.clear();
getBasicDetNtfBodyList!.clear();
getTerminationNotificationBodyList!.clear();
getAbsenceCollectionNotificationBodyList!.clear();
getContactNotificationBodyList = null;
getAddressNotificationBodyList!.clear();
@ -147,6 +152,8 @@ class _WorkListDetailScreenState extends State<WorkListDetailScreen> {
getContactNotificationBody();
} else if (workListData!.rEQUESTTYPE == "ADDRESS") {
getAddressNotificationBody();
} else if(workListData!.rEQUESTTYPE =='TERMINATION'){
getTerminationNotificationBody();
}
}
if (workListData!.iTEMTYPE == "STAMP") {
@ -257,6 +264,7 @@ class _WorkListDetailScreenState extends State<WorkListDetailScreen> {
getAbsenceCollectionNotificationBodyList: getAbsenceCollectionNotificationBodyList,
getContactNotificationBodyList: getContactNotificationBodyList,
getPrNotificationBodyList: getPrNotificationBody,
getTerminationNotificationBodyList:getTerminationNotificationBodyList
),
(workListData!.iTEMTYPE == "HRSSA" || workListData!.iTEMTYPE == "STAMP")
? DetailFragment(workListData, memberInformationListModel)
@ -854,6 +862,25 @@ class _WorkListDetailScreenState extends State<WorkListDetailScreen> {
Utils.handleException(ex, context, null);
}
}
void getTerminationNotificationBody() async {
try {
if (apiCallCount == 0)
apiCallCount++;
getTerminationNotificationBodyList = await WorkListApiClient().getTerminationNotificationBodyList(workListData!.nOTIFICATIONID);
Utils.hideLoading(context);
apiCallCount--;
if (apiCallCount == 0) {
setState(() {});
}
} catch (ex) {
apiCallCount--;
Utils.hideLoading(context);
Utils.handleException(ex, context, null);
}
}
void getStampNotificationBody() async {
try {

@ -166,6 +166,9 @@ class ActionsFragment extends StatelessWidget {
DateTime dateTimeFrom = DateUtil.convertSimpleStringDateToDate(actionHistoryList[index + 1].nOTIFICATIONDATE!);
Duration duration = DateTime.now().difference(dateTimeFrom);
return "Action duration: " + DateUtil.formatDuration(duration);
} else {
if (actionHistoryList[index + 1].nOTIFICATIONDATE!.isEmpty) {
return "";
} else {
DateTime dateTimeTo = DateUtil.convertSimpleStringDateToDate(actionHistoryList[index].nOTIFICATIONDATE!);
DateTime dateTimeFrom = DateUtil.convertSimpleStringDateToDate(actionHistoryList[index + 1].nOTIFICATIONDATE!);
@ -173,6 +176,7 @@ class ActionsFragment extends StatelessWidget {
return "Action duration: " + DateUtil.formatDuration(duration);
}
}
}
Color getStatusColor(String code) {
if (code == "SUBMIT") {

@ -9,8 +9,10 @@ import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/models/get_attachement_list_model.dart';
import 'package:open_file/open_file.dart';
import 'package:mohem_flutter_app/widgets/dialogs/confirm_dialog.dart';
import 'package:open_filex/open_filex.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
class AttachmentsFragment extends StatelessWidget {
final List<GetAttachementList> getAttachmentList;
@ -31,8 +33,9 @@ class AttachmentsFragment extends StatelessWidget {
).objectContainerView().onPress(() async {
try {
String path = await _createFileFromString(getAttachmentList[index].fILEDATA ?? "", getAttachmentList[index].fILECONTENTTYPE ?? "");
OpenFile.open(path);
} catch (ex) {Utils.showToast("Cannot open file.");
OpenFilex.open(path);
} catch (ex) {
Utils.showToast("Cannot open file.");
}
});
},

@ -20,6 +20,8 @@ import 'package:mohem_flutter_app/models/worklist/hr/get_phones_notification_bod
import 'package:mohem_flutter_app/models/worklist_response_model.dart';
import 'package:mohem_flutter_app/widgets/item_detail_view_widget.dart';
import 'package:mohem_flutter_app/models/termination/termination_notification_body.dart';
class InfoFragment extends StatelessWidget {
WorkListResponseModel? workListData;
List<POHeader> poHeaderList;
@ -33,7 +35,7 @@ class InfoFragment extends StatelessWidget {
GetContactNotificationBodyList? getContactNotificationBodyList;
GetPrNotificationBodyList? getPrNotificationBodyList;
List<GetAddressNotificationBodyList>? getAddressNotificationBodyList = [];
List<TerminationNotificationBody>? getTerminationNotificationBodyList =[];
InfoFragment(
{this.workListData,
this.poHeaderList = const <POHeader>[],
@ -46,7 +48,9 @@ class InfoFragment extends StatelessWidget {
this.getAbsenceCollectionNotificationBodyList,
this.getContactNotificationBodyList,
this.getPrNotificationBodyList,
this.getAddressNotificationBodyList});
this.getAddressNotificationBodyList,
this.getTerminationNotificationBodyList
});
double itemHeight = 0;
double itemWidth = 0;
@ -93,6 +97,7 @@ class InfoFragment extends StatelessWidget {
if (getAbsenceCollectionNotificationBodyList?.isNotEmpty ?? false) getAbsenceCollectionNotificationBodyListWidget(getAbsenceCollectionNotificationBodyList ?? []),
if (getContactNotificationBodyList != null) getContactNotificationBodyListWidget(getContactNotificationBodyList ?? GetContactNotificationBodyList()).objectContainerView(),
if (getAddressNotificationBodyList?.isNotEmpty ?? false) getAddressNotificationBodyListWidget(getAddressNotificationBodyList!),
if (getTerminationNotificationBodyList?.isNotEmpty ?? false) getTerminationNotificationBodyListWidget(getTerminationNotificationBodyList!),
];
return Container(
width: double.infinity,
@ -499,6 +504,39 @@ class InfoFragment extends StatelessWidget {
).objectContainerView();
}
Widget getTerminationNotificationBodyListWidget(List<TerminationNotificationBody> getterminationNotificationBodyList) {
bool isOdd = false;
try {
if (getterminationNotificationBodyList.length % 2 != 0) {
isOdd = true;
getterminationNotificationBodyList.add(TerminationNotificationBody(sEGMENTPROMPT: "--", sEGMENTVALUEDSP: "--"));
}
} catch (e) {}
return GridView.builder(
itemCount: getterminationNotificationBodyList!.length,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) => ItemDetailViewGridItem(
index,
getterminationNotificationBodyList[index].sEGMENTPROMPT,
getterminationNotificationBodyList[index].sEGMENTVALUEDSP,
isNeedToShowEmptyDivider: (getterminationNotificationBodyList.length == index + 1)
? isOdd
? true
: false
: false,
),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: (itemWidth / itemHeight),
),
).objectContainerView();
}
List<Widget> getPRHeaderValues() {
List<Widget> pRHeaders = [];
getPrNotificationBodyList!.pRHeader!.forEach((element) {

@ -8,6 +8,8 @@ import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/widgets/bottom_sheet.dart';
import 'package:mohem_flutter_app/widgets/bottom_sheets/attachment_options.dart';
import 'package:mohem_flutter_app/widgets/dialogs/confirm_dialog.dart';
import 'package:permission_handler/permission_handler.dart';
class ImageOptions {
static void showImageOptionsNew(BuildContext context, bool showFilesOption, Function(String, File) image) {
@ -43,6 +45,10 @@ class ImageOptions {
}
},
onFilesTap: () async {
Permission.storage.isGranted.then((isGranted) async {
if (!isGranted) {
Permission.storage.request().then((granted) async {
if (granted == PermissionStatus.granted) {
FilePickerResult? result = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: [
@ -61,6 +67,39 @@ class ImageOptions {
);
List<File> files = result!.paths.map((path) => File(path!)).toList();
image(result.files.first.path.toString(), files.first);
} else {
showDialog(
context: context,
builder: (BuildContext cxt) => ConfirmDialog(
message: "You need to give storage permission to upload files.",
onTap: () {
Navigator.pop(context);
},
),
);
}
});
} else {
FilePickerResult? result = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: [
'jpg',
'jpeg ',
'pdf',
'txt',
'docx',
'doc',
'pptx',
'xlsx',
'png',
'rar',
'zip',
],
);
List<File> files = result!.paths.map((path) => File(path!)).toList();
image(result.files.first.path.toString(), files.first);
}
});
},
),
);

@ -59,11 +59,12 @@ dependencies:
# android_id: ^0.1.3+1
platform_device_id: ^1.0.1
image_picker: ^0.8.5+3
file_picker: ^4.6.1
file_picker: 5.2.5
geolocator: ^9.0.2
month_year_picker: ^0.2.0+1
month_picker_dialog_2: 0.5.5
open_file: ^3.2.1
month_picker_dialog_2: ^0.5.5
# open_file: ^3.2.1
open_filex: ^4.4.0
wifi_iot: ^0.3.18
flutter_html: ^3.0.0-alpha.6
# flutter_barcode_scanner: ^2.0.0
@ -87,7 +88,7 @@ dependencies:
signalr_netcore: ^1.3.3
logging: ^1.0.1
swipe_to: ^1.0.2
flutter_webrtc: ^0.9.16
flutter_webrtc: ^0.9.17
camera: ^0.10.3
flutter_local_notifications: ^10.0.0
#firebase_analytics: any
@ -99,7 +100,7 @@ dependencies:
#Encryption
flutter_des: ^2.1.0
video_player: ^2.5.1
video_player: 2.7.0
just_audio: ^0.9.30
# safe_device: ^1.1.2
flutter_layout_grid: ^2.0.1

Loading…
Cancel
Save