Merge branch 'master' into development_sikander

# Conflicts:
#	lib/app_state/app_state.dart
development_sikander
Sikander Saleem 2 years ago
commit 2cea45f0e1

@ -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" />
@ -24,6 +35,17 @@
android:extractNativeLibs="true"
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 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<root-path name="root" path="."/>
<external-path name="external_storage_directory" path="." />
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="files-path" path="../" />
</paths>
</resources>

@ -88,7 +88,7 @@
"atLeastOneNumeric": "رقم واحد على الأقل",
"minimum8Characters": "8 أحرف على الأقل",
"doNotAddRepeatingLetters": "لا تقم بإضافة أحرف متكررة",
"itShouldContainSpecialCharacter": "يجب أن يحتوي على طابع خاص",
"itShouldContainSpecialCharacter": "يجب لا يحتوي على أحرف خاصة",
"confirmPasswordMustMatch": "يجب أن يتطابق تأكيد كلمة المرور",
"sms": "رسالة قصيرة",
"fingerPrint": "بصمة",

@ -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",

@ -376,7 +376,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 3.7.2;
MARKETING_VERSION = 3.7.8;
PRODUCT_BUNDLE_IDENTIFIER = com.cloudsolutions.mohemm;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@ -514,7 +514,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 3.7.2;
MARKETING_VERSION = 3.7.8;
PRODUCT_BUNDLE_IDENTIFIER = com.cloudsolutions.mohemm;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@ -544,7 +544,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 3.7.2;
MARKETING_VERSION = 3.7.8;
PRODUCT_BUNDLE_IDENTIFIER = com.cloudsolutions.mohemm;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";

@ -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": "",
},
);

@ -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};

@ -24,6 +24,7 @@ import 'package:mohem_flutter_app/models/get_user_item_type_list.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';
@ -550,6 +551,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 = {};

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

@ -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",

@ -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();
}

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

@ -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;
}
}

@ -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(

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

@ -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_file/open_file.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
class MowadhafhiRequestDetails extends StatefulWidget {
const MowadhafhiRequestDetails({Key? key}) : super(key: key);
@ -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() {
@ -43,7 +58,7 @@ class _RequestDetailsState extends State<MowadhafhiRequestDetails> {
backgroundColor: Colors.white,
appBar: AppBarWidget(
context,
title: LocaleKeys.mowadhafhiRequest.tr(),
title: LocaleKeys.mowadhafhiRequest.tr(),
),
body: SingleChildScrollView(
child: getTicketsByEmployeeList.length != 0
@ -76,16 +91,16 @@ class _RequestDetailsState extends State<MowadhafhiRequestDetails> {
],
),
8.height,
LocaleKeys.ticketReference.tr().toText12(color: MyColors.grey98Color),
LocaleKeys.ticketReference.tr().toText12(color: MyColors.grey98Color),
getTicketsByEmployeeList![0].ticketReferenceNo!.toText14(color: MyColors.grey57Color),
8.height,
LocaleKeys.section.tr().toText12(color: MyColors.grey98Color),
LocaleKeys.section.tr().toText12(color: MyColors.grey98Color),
getTicketsByEmployeeList![0].sectionName!.toText14(color: MyColors.grey57Color),
8.height,
LocaleKeys.topic.tr().toText12(color: MyColors.grey98Color),
LocaleKeys.topic.tr().toText12(color: MyColors.grey98Color),
getTicketsByEmployeeList![0].topicName!.toText14(color: MyColors.grey57Color),
8.height,
LocaleKeys.description.tr().toText12(color: MyColors.grey98Color),
LocaleKeys.description.tr().toText12(color: MyColors.grey98Color),
getTicketsByEmployeeList![0].description!.toText14(color: MyColors.grey57Color),
],
),
@ -128,15 +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 OpenFile.open(path).catchError((err) {
print(err);
});
} catch (ex) {
Utils.showToast("Cannot open file.");
}
} else {
showDialog(
context: context,
builder: (BuildContext cxt) => ConfirmDialog(
message: "You need to give storage permission to view files.",
onTap: () {
Navigator.pop(context);
},
),
);
}
});
}
});
}
}

@ -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),
);
});

@ -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 {

@ -167,10 +167,14 @@ class ActionsFragment extends StatelessWidget {
Duration duration = DateTime.now().difference(dateTimeFrom);
return "Action duration: " + DateUtil.formatDuration(duration);
} else {
DateTime dateTimeTo = DateUtil.convertSimpleStringDateToDate(actionHistoryList[index].nOTIFICATIONDATE!);
DateTime dateTimeFrom = DateUtil.convertSimpleStringDateToDate(actionHistoryList[index + 1].nOTIFICATIONDATE!);
Duration duration = dateTimeTo.difference(dateTimeFrom);
return "Action duration: " + DateUtil.formatDuration(duration);
if (actionHistoryList[index + 1].nOTIFICATIONDATE!.isEmpty) {
return "";
} else {
DateTime dateTimeTo = DateUtil.convertSimpleStringDateToDate(actionHistoryList[index].nOTIFICATIONDATE!);
DateTime dateTimeFrom = DateUtil.convertSimpleStringDateToDate(actionHistoryList[index + 1].nOTIFICATIONDATE!);
Duration duration = dateTimeTo.difference(dateTimeFrom);
return "Action duration: " + DateUtil.formatDuration(duration);
}
}
}

@ -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,24 +45,42 @@ class ImageOptions {
}
},
onFilesTap: () async {
FilePickerResult? result = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: [
'jpg',
'jpeg ',
'pdf',
'txt',
'docx',
'doc',
'pptx',
'xlsx',
'png',
'rar',
'zip',
],
);
List<File> files = result!.paths.map((path) => File(path!)).toList();
image(result.files.first.path.toString(), files.first);
Permission.storage.isGranted.then((isGranted) {
if (!isGranted) {
Permission.manageExternalStorage.request().then((granted) async {
if (granted == PermissionStatus.granted) {
FilePickerResult? result = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: [
'jpg',
'jpeg ',
'pdf',
'txt',
'docx',
'doc',
'pptx',
'xlsx',
'png',
'rar',
'zip',
],
);
List<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);
},
),
);
}
});
}
});
},
),
);

@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
#version: 3.3.01+300040
version: 3.7.7+1
version: 3.3.6+300046
environment:
sdk: ">=2.16.0 <3.0.0"
@ -60,7 +60,7 @@ dependencies:
# android_id: ^0.1.3+1
platform_device_id: ^1.0.1
image_picker: ^0.8.5+3
file_picker: ^4.6.1
file_picker: 5.2.5
geolocator: ^9.0.2
month_year_picker: ^0.2.0+1
month_picker_dialog_2: 0.5.5
@ -124,6 +124,8 @@ dependencies:
#todo its for temporary purpose, later will remove this.
dotted_border: ^2.0.0+3
# saf: ^1.0.3+4
dependency_overrides:
firebase_core_platform_interface: 4.5.1

Loading…
Cancel
Save