diff --git a/android/app/build.gradle b/android/app/build.gradle index 4e4b395..596d981 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -23,6 +23,7 @@ if (flutterVersionName == null) { apply plugin: 'com.android.application' apply plugin: 'kotlin-android' +apply plugin: 'com.google.gms.google-services' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { @@ -43,8 +44,8 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.mohem_flutter_app" - minSdkVersion 16 + applicationId "hmg.cloudSolutions.mohem" + minSdkVersion 21 targetSdkVersion 30 versionCode flutterVersionCode.toInteger() versionName flutterVersionName diff --git a/android/app/google-services.json b/android/app/google-services.json new file mode 100644 index 0000000..62fbaea --- /dev/null +++ b/android/app/google-services.json @@ -0,0 +1,40 @@ +{ + "project_info": { + "project_number": "679409052782", + "firebase_url": "https://mohemm-dce93.firebaseio.com", + "project_id": "mohemm-dce93", + "storage_bucket": "mohemm-dce93.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:679409052782:android:dba155ac0859d7fea78a7f", + "android_client_info": { + "package_name": "hmg.cloudSolutions.mohem" + } + }, + "oauth_client": [ + { + "client_id": "679409052782-mtd6d8rjltucnm9uatn6g7et08sm6lbv.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyDgWjuSBIKGghWxYg_KGBRIZTi-O_UA8mU" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "679409052782-mtd6d8rjltucnm9uatn6g7et08sm6lbv.apps.googleusercontent.com", + "client_type": 3 + } + ] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 472e794..7be27d5 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,8 +1,12 @@ + + + + + + + + + + diff --git a/assets/icons/home.svg b/assets/icons/home.svg new file mode 100644 index 0000000..fb67997 --- /dev/null +++ b/assets/icons/home.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/assets/icons/item_for_sale.svg b/assets/icons/item_for_sale.svg new file mode 100644 index 0000000..0a87567 --- /dev/null +++ b/assets/icons/item_for_sale.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/nfc/ic_done.png b/assets/icons/nfc/ic_done.png new file mode 100644 index 0000000..5b80285 Binary files /dev/null and b/assets/icons/nfc/ic_done.png differ diff --git a/assets/icons/nfc/ic_nfc.png b/assets/icons/nfc/ic_nfc.png new file mode 100644 index 0000000..274e1b8 Binary files /dev/null and b/assets/icons/nfc/ic_nfc.png differ diff --git a/assets/icons/work_list.svg b/assets/icons/work_list.svg new file mode 100644 index 0000000..a802c53 --- /dev/null +++ b/assets/icons/work_list.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/assets/images/play.svg b/assets/images/play.svg new file mode 100644 index 0000000..1608b2e --- /dev/null +++ b/assets/images/play.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/thumb.svg b/assets/images/thumb.svg new file mode 100644 index 0000000..855ba71 --- /dev/null +++ b/assets/images/thumb.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 1d9e8bc..e8892a8 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -48,12 +48,30 @@ "employeeId": "هوية الموظف", "loginCodeWillSentToMobileNumber": "الرجاء إدخال معرف الموظف الخاص بك ، وسيتم إرسال رمز تسجيل الدخول إلى رقم هاتفك المحمول", "changePassword": "تغيير كلمة المرور", + "ok": "موافق", + "confirm": "تؤكد", + "passwordChangedSuccessfully": "تم تغيير الرقم السري بنجاح", "itemsForSale": "سلع للبيع", + "doNotUseRecentPassword": "لا تستخدم كلمة مرور حديثة", + "atLeastOneLowercase": "حرف صغير واحد على الأقل", + "atLeastOneUppercase": "حرف كبير واحد على الأقل", + "atLeastOneNumeric": "رقم واحد على الأقل", + "minimum8Characters": "8 أحرف على الأقل", + "doNotAddRepeatingLetters": "لا تقم بإضافة أحرف متكررة", + "itShouldContainSpecialCharacter": "يجب أن يحتوي على طابع خاص", + "confirmPasswordMustMatch": "يجب أن يتطابق تأكيد كلمة المرور", + "sms": "رسالة قصيرة", + "fingerPrint": "بصمة", + "face": "التعرف على الوجه", + "whatsapp": "واتس اب", + "reject": "يرفض", + "approve": "يوافق", "msg": "Hello {} in the {} world ", "msg_named": "{} are written in the {lang} language", "clickMe": "Click me", - "human": "Human", - "resources": "Resources", + "human": "بشري", + "resources": "موارد", + "details": "تفاصيل", "profile": { "reset_password": { "label": "Reset Password", diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 9c812ce..f5b9b44 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -48,12 +48,30 @@ "employeeId": "Employee ID", "loginCodeWillSentToMobileNumber": "Please Enter your Employee ID, A login code will be sent to your mobile number", "changePassword": "Change Password", + "ok": "OK", + "confirm": "Confirm", + "passwordChangedSuccessfully": "Password changed successfully", "itemsForSale": "Items for Sale", + "doNotUseRecentPassword": "Do not use recent password", + "atLeastOneLowercase": "At least one lowercase", + "atLeastOneUppercase": "At least one uppercase", + "atLeastOneNumeric": "At least one numeric", + "minimum8Characters": "Minimum 8 characters", + "doNotAddRepeatingLetters": "Do not add repeating letters", + "itShouldContainSpecialCharacter": "It should contain special character", + "confirmPasswordMustMatch": "Confirm password must match", + "sms": "SMS", + "fingerPrint": "Fingerprint", + "face": "Face", + "whatsapp": "Whatsapp", + "reject": "Reject", + "approve": "Approve", "msg": "Hello {} in the {} world ", "msg_named": "{} are written in the {lang} language", "clickMe": "Click me", "human": "Human", "resources": "Resources", + "details": "Details", "profile": { "reset_password": { "label": "Reset Password", diff --git a/lib/api/api_client.dart b/lib/api/api_client.dart index a08ed01..17eac0d 100644 --- a/lib/api/api_client.dart +++ b/lib/api/api_client.dart @@ -7,6 +7,8 @@ import 'package:http/http.dart'; import 'package:http/io_client.dart'; import 'package:mohem_flutter_app/exceptions/api_exception.dart'; +import '../main.dart'; + typedef FactoryConstructor = U Function(dynamic); class APIError { @@ -74,25 +76,25 @@ class ApiClient { print("body:$jsonObject"); } var response = await postJsonForResponse(url, jsonObject, token: token, queryParameters: queryParameters, headers: _headers, retryTimes: retryTimes); - try { - if (!kReleaseMode) { - print("res: " + response.body); - } - var jsonData = jsonDecode(response.body); - if (jsonData["ErrorMessage"] == null) { - return factoryConstructor(jsonData); - } else { - APIError? apiError; - apiError = APIError(jsonData['ErrorCode'], jsonData['ErrorMessage']); - throw APIException(APIException.BAD_REQUEST, error: apiError); - } - } catch (ex) { - if (ex is APIException) { - rethrow; - } else { - throw APIException(APIException.BAD_RESPONSE_FORMAT, arguments: ex); - } + // try { + if (!kReleaseMode) { + logger.i("res: " + response.body); } + var jsonData = jsonDecode(response.body); + if (jsonData["ErrorMessage"] == null) { + return factoryConstructor(jsonData); + } else { + APIError? apiError; + apiError = APIError(jsonData['ErrorCode'], jsonData['ErrorMessage']); + throw APIException(APIException.BAD_REQUEST, error: apiError); + } + // } catch (ex) { + // if (ex is APIException) { + // rethrow; + // } else { + // throw APIException(APIException.BAD_RESPONSE_FORMAT, arguments: ex); + // } + // } } Future postJsonForResponse(String url, T jsonObject, {String? token, Map? queryParameters, Map? headers, int retryTimes = 0}) async { @@ -160,6 +162,68 @@ class ApiClient { } } + Future getJsonForResponse(String url, {String? token, Map? queryParameters, Map? headers, int retryTimes = 0}) async { + if (headers == null) { + headers = {'Content-Type': 'application/json'}; + } else { + headers['Content-Type'] = 'application/json'; + } + return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes); + } + + Future _getForResponse(String url, {String? token, Map? queryParameters, Map? headers, int retryTimes = 0}) async { + try { + var _headers = {}; + if (token != null) { + _headers['Authorization'] = 'Bearer $token'; + } + + if (headers != null && headers.isNotEmpty) { + _headers.addAll(headers); + } + + if (queryParameters != null) { + var queryString = new Uri(queryParameters: queryParameters).query; + url = url + '?' + queryString; + } + var response = await _get(Uri.parse(url), headers: _headers).timeout(Duration(seconds: 60)); + + if (response.statusCode >= 200 && response.statusCode < 300) { + return response; + } else { + throw _throwAPIException(response); + } + } on SocketException catch (e) { + if (retryTimes > 0) { + print('will retry after 3 seconds...'); + await Future.delayed(Duration(seconds: 3)); + return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); + } else { + throw APIException(APIException.OTHER, arguments: e); + } + } on HttpException catch (e) { + if (retryTimes > 0) { + print('will retry after 3 seconds...'); + await Future.delayed(Duration(seconds: 3)); + return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); + } else { + throw APIException(APIException.OTHER, arguments: e); + } + } on TimeoutException catch (e) { + throw APIException(APIException.TIMEOUT, arguments: e); + } on ClientException catch (e) { + if (retryTimes > 0) { + print('will retry after 3 seconds...'); + await Future.delayed(Duration(seconds: 3)); + return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); + } else { + throw APIException(APIException.OTHER, arguments: e); + } + } + } + + Future _get(url, {Map? headers}) => _withClient((client) => client.get(url, headers: headers)); + bool _certificateCheck(X509Certificate cert, String host, int port) => true; Future _withClient(Future Function(Client) fn) async { @@ -173,4 +237,4 @@ class ApiClient { } Future _post(url, {Map? headers, body, Encoding? encoding}) => _withClient((client) => client.post(url, headers: headers, body: body, encoding: encoding)); -} + } diff --git a/lib/api/dashboard_api_client.dart b/lib/api/dashboard_api_client.dart index 5b6f961..f4c583d 100644 --- a/lib/api/dashboard_api_client.dart +++ b/lib/api/dashboard_api_client.dart @@ -4,26 +4,28 @@ import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/consts.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/dashboard/get_attendance_tracking_list_model.dart'; import 'package:mohem_flutter_app/models/dashboard/itg_forms_model.dart'; import 'package:mohem_flutter_app/models/generic_response_model.dart'; import 'package:mohem_flutter_app/models/member_login_list_model.dart'; +import 'package:uuid/uuid.dart'; import 'api_client.dart'; -class DashbaordApiClient { - static final DashbaordApiClient _instance = DashbaordApiClient._internal(); +class DashboardApiClient { + static final DashboardApiClient _instance = DashboardApiClient._internal(); - DashbaordApiClient._internal(); + DashboardApiClient._internal(); - factory DashbaordApiClient() => _instance; + factory DashboardApiClient() => _instance; - Future getAttendanceTracking() async { + Future getAttendanceTracking() async { String url = "${ApiConsts.erpRest}GET_Attendance_Tracking"; Map postParams = {}; postParams.addAll(AppState().postParamsJson); return await ApiClient().postJsonForObject((json) { GenericResponseModel responseData = GenericResponseModel.fromJson(json); - return responseData; + return responseData.getAttendanceTrackingList; }, url, postParams); } @@ -66,4 +68,49 @@ class DashbaordApiClient { return responseData; }, url, postParams); } + + //Menus List + Future getListMenu() async { + String url = "${ApiConsts.erpRest}GET_MENU"; + Map postParams = {}; + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject((json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData; + }, url, postParams); + } + + //GET_MENU_ENTRIES + Future getGetMenuEntries() async { + String url = "${ApiConsts.erpRest}GET_MENU_ENTRIES"; + Map postParams = {"P_SELECTED_RESP_ID": -999, "P_MENU_TYPE": "E"}; + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject((json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData; + }, url, postParams); + } + + //Mark Attendance + Future markAttendance({String lat = "0", String? long = "0", required int pointType, String nfcValue = "", bool isGpsRequired = false}) async { + String url = "${ApiConsts.swpRest}AuthenticateAndSwipeUserSupportNFC"; + var uuid = Uuid(); + // Generate a v4 (random) id + + Map postParams = { + "UID": uuid.v4(), //Mobile Id + "Latitude": lat, + "Longitude": long, + "QRValue": "", + "PointType": pointType, // NFC=2, Wifi = 3, QR= 1, + "NFCValue": nfcValue, + "WifiValue": "", + "IsGpsRequired": isGpsRequired + }; + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject((json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData; + }, url, postParams); + } } diff --git a/lib/api/login_api_client.dart b/lib/api/login_api_client.dart index fb6bb80..070fa27 100644 --- a/lib/api/login_api_client.dart +++ b/lib/api/login_api_client.dart @@ -5,6 +5,7 @@ import 'package:mohem_flutter_app/classes/consts.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_login_list_model.dart'; import 'api_client.dart'; @@ -16,6 +17,41 @@ class LoginApiClient { factory LoginApiClient() => _instance; + Future getMobileLoginInfoNEW(String deviceToken, String deviceType) async { + String url = "${ApiConsts.erpRest}Mohemm_GetMobileLoginInfo_NEW"; + Map postParams = {}; + postParams["DeviceToken"] = deviceToken; + postParams["DeviceType"] = deviceType; + return await ApiClient().postJsonForObject((json) { + GenericResponseModel? responseData = GenericResponseModel.fromJson(json); + return (responseData.mohemmGetMobileLoginInfoList?.length ?? 0) > 0 ? responseData.mohemmGetMobileLoginInfoList!.first : null; + }, url, postParams); + } + + Future insertMobileLoginInfoNEW( + String email, int sessionId, String employeeName, int loginType, String mobileNumber, String userName, String deviceToken, String deviceType) async { + String url = "${ApiConsts.erpRest}Mohemm_InsertMobileLoginInfo"; + Map postParams = { + "MobileNumber": mobileNumber, + "P_USER_NAME": userName, + "UserName": userName, + "CompanyID": 1, // todo 'sikander' @discuss umer for companyID + "DeviceToken": deviceToken, + "LoginType": loginType, + "EmployeeName": employeeName, + "P_SESSION_ID": sessionId, + "P_EMAIL_ADDRESS": email + }; + postParams["DeviceToken"] = deviceToken; + postParams["DeviceType"] = deviceType; + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject((json) { + GenericResponseModel? responseData = GenericResponseModel.fromJson(json); + AppState().setLogged = true; + return responseData; + }, url, postParams); + } + Future checkMobileAppVersion() async { String url = "${ApiConsts.utilitiesRest}CheckMobileAppVersion"; Map postParams = {}; @@ -47,7 +83,6 @@ class LoginApiClient { postParams.addAll(AppState().postParamsJson); return await ApiClient().postJsonForObject((json) { GenericResponseModel responseData = GenericResponseModel.fromJson(json); - AppState().setLogged = true; AppState().postParamsObject?.setTokenID = responseData.tokenID; AppState().postParamsObject?.mobileNumber = responseData.basicMemberInformation!.pMOBILENUMBER; AppState().postParamsObject?.userName = AppState().getUserName; @@ -55,6 +90,7 @@ class LoginApiClient { AppState().postParamsObject?.pSessionId = responseData.pSESSIONID; AppState().postParamsObject?.pUserName = AppState().getUserName; AppState().postParamsObject?.pSelectedEmployeeNumber = AppState().getUserName; + return responseData; }, url, postParams); } @@ -83,7 +119,7 @@ class LoginApiClient { postParams.addAll(AppState().postParamsJson); return await ApiClient().postJsonForObject((json) { GenericResponseModel responseData = GenericResponseModel.fromJson(json); - AppState().setForgetPasswordTokenID = responseData.tokenID; + AppState().setForgetPasswordTokenID = responseData.forgetPasswordTokenID; return responseData; }, url, postParams); } diff --git a/lib/api/worklist/worklist_api_client.dart b/lib/api/worklist/worklist_api_client.dart new file mode 100644 index 0000000..a473ba7 --- /dev/null +++ b/lib/api/worklist/worklist_api_client.dart @@ -0,0 +1,41 @@ +import 'dart:async'; + +import 'package:mohem_flutter_app/api/api_client.dart'; +import 'package:mohem_flutter_app/app_state/app_state.dart'; +import 'package:mohem_flutter_app/classes/consts.dart'; +import 'package:mohem_flutter_app/models/dashboard/itg_forms_model.dart'; +import 'package:mohem_flutter_app/models/generic_response_model.dart'; +import 'package:mohem_flutter_app/models/worklist_response_model.dart'; + +class WorkListApiClient { + static final WorkListApiClient _instance = WorkListApiClient._internal(); + + WorkListApiClient._internal(); + + factory WorkListApiClient() => _instance; + + Future?> getWorkList(int pPageNum, String pItemType) async { + String url = "${ApiConsts.erpRest}GET_WORKLIST"; + Map postParams = { + "P_NOTIFICATION_TYPE": "1", + "P_PAGE_NUM": pPageNum, + "P_PAGE_LIMIT": 50, + "P_ITEM_TYPE": pItemType, + }; + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject((json) { + GenericResponseModel? responseData = GenericResponseModel.fromJson(json); + return responseData.getWorkList; + }, url, postParams); + } + + Future GetITGTaskCountRequestType() async { + String url = "${ApiConsts.cocRest}ITGGetTaskCountRequestType"; + Map postParams = {}; + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject((json) { + ItgFormsModel responseData = ItgFormsModel.fromJson(json); + return responseData; + }, url, postParams); + } +} diff --git a/lib/app_state/app_state.dart b/lib/app_state/app_state.dart index 65d5184..08d2f70 100644 --- a/lib/app_state/app_state.dart +++ b/lib/app_state/app_state.dart @@ -1,5 +1,8 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:mohem_flutter_app/models/member_information_list_model.dart'; import 'package:mohem_flutter_app/models/member_login_list_model.dart'; import 'package:mohem_flutter_app/models/post_params_model.dart'; +import 'package:mohem_flutter_app/models/privilege_list_model.dart'; class AppState { static final AppState _instance = AppState._internal(); @@ -30,15 +33,34 @@ class AppState { this._postParams = _postParams; } + bool isArabic(context) => EasyLocalization.of(context)?.locale.languageCode == "ar"; + String? _username; + // todo ''sikander' added password for now, later will remove & improve + String? password; + set setUserName(v) => _username = v; String? get getUserName => _username; + set setUserPassword(_password) => password = _password; + MemberLoginListModel? _memberLoginList; MemberLoginListModel? get memberLoginList => _memberLoginList; set setMemberLoginListModel(MemberLoginListModel? _memberLoginList) => this._memberLoginList = _memberLoginList; + + MemberInformationListModel? _memberInformationList; + + MemberInformationListModel? get memberInformationList => _memberInformationList; + + set setMemberInformationListModel(MemberInformationListModel? _memberInformationList) => this._memberInformationList = _memberInformationList; + + List? _privilegeListModel; + + List? get privilegeListModel => _privilegeListModel; + + set setPrivilegeListModel(List? _privilegeListModel) => this._privilegeListModel = _privilegeListModel; } diff --git a/lib/classes/app_permissions.dart b/lib/classes/app_permissions.dart new file mode 100644 index 0000000..a70342c --- /dev/null +++ b/lib/classes/app_permissions.dart @@ -0,0 +1,30 @@ +import 'package:permission_handler/permission_handler.dart'; + +class AppPermissions{ + static location(Function(bool) completion) { + Permission.location.isGranted.then((isGranted){ + if(!isGranted){ + Permission.location.request().then((granted){ + completion(granted == PermissionStatus.granted); + }); + } + completion(isGranted); + }); + + } + + static checkAll(Function(bool) completion){ + [ + Permission.location + ].request().then((value){ + + bool allGranted = false; + value.values.forEach((element) { + allGranted = allGranted && element == PermissionStatus.granted; + }); + + completion(allGranted); + + }); + } +} \ No newline at end of file diff --git a/lib/classes/colors.dart b/lib/classes/colors.dart index 2e5eaef..0d80b05 100644 --- a/lib/classes/colors.dart +++ b/lib/classes/colors.dart @@ -16,6 +16,7 @@ class MyColors { static const Color grey98Color = Color(0xff989898); static const Color lightGreyEFColor = Color(0xffEFEFEF); static const Color lightGreyEDColor = Color(0xffEDEDED); + static const Color lightGreyE6Color = Color(0xffE6E6E6); static const Color lightGreyEAColor = Color(0xffEAEAEA); static const Color darkWhiteColor = Color(0xffE0E0E0); static const Color redColor = Color(0xffD02127); diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 4bad83c..a95e5b4 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -1,22 +1,23 @@ class ApiConsts { //static String baseUrl = "http://10.200.204.20:2801/"; // Local server static String baseUrl = "https://uat.hmgwebservices.com"; // UAT server - static String baseUrlServices = baseUrl + "/services/"; // server + // static String baseUrl = "https://hmgwebservices.com"; // Live server + static String baseUrlServices = baseUrl + "/Services/"; // server // static String baseUrlServices = "https://api.cssynapses.com/tangheem/"; // Live server static String utilitiesRest = baseUrlServices + "Utilities.svc/REST/"; static String erpRest = baseUrlServices + "ERP.svc/REST/"; + static String swpRest = baseUrlServices + "SWP.svc/REST/"; static String user = baseUrlServices + "api/User/"; static String cocRest = baseUrlServices + "COCWS.svc/REST/"; } - - -class GlobalConsts { +class SharedPrefsConsts { static String isRememberMe = "remember_me"; - static String email = "email"; + static String username = "username"; static String password = "password"; - static String bookmark = "bookmark"; - static String fontZoomSize = "font_zoom_size"; + static String privilegeList = "privilegeList"; + static String firebaseToken = "firebaseToken"; + static String memberInformation = "memberInformation"; static String welcomeVideoUrl = "welcomeVideoUrl"; static String doNotShowWelcomeVideo = "doNotShowWelcomeVideo"; } diff --git a/lib/classes/date_uitl.dart b/lib/classes/date_uitl.dart new file mode 100644 index 0000000..d0f4b1f --- /dev/null +++ b/lib/classes/date_uitl.dart @@ -0,0 +1,444 @@ +import 'package:intl/intl.dart'; + +class DateUtil { + /// convert String To Date function + /// [date] String we want to convert + static DateTime convertStringToDate(String date) { + // /Date(1585774800000+0300)/ + if (date != null) { + const start = "/Date("; + const end = "+0300)"; + final startIndex = date.indexOf(start); + final endIndex = date.indexOf(end, startIndex + start.length); + return DateTime.fromMillisecondsSinceEpoch( + int.parse( + date.substring(startIndex + start.length, endIndex), + ), + ); + } else + return DateTime.now(); + } + + static DateTime convertSimpleStringDateToDate(String date) { + return DateFormat("MM/dd/yyyy hh:mm:ss").parse(date); + } + + static DateTime convertStringToDateNoTimeZone(String date) { + // /Date(1585774800000+0300)/ + if (date != null) { + const start = "/Date("; + const end = ")"; + final startIndex = date.indexOf(start); + final endIndex = date.indexOf(end, startIndex + start.length); + return DateTime.fromMillisecondsSinceEpoch( + int.parse( + date.substring(startIndex + start.length, endIndex), + ), + ); + } else + return DateTime.now(); + } + + static DateTime convertStringToDateTime(String date) { + if (date != null) { + try { + var dateT = date.split('/'); + var year = dateT[2].substring(0, 4); + var dateP = DateTime(int.parse(year), int.parse(dateT[1]), int.parse(dateT[0])); + return dateP; + } catch (e) { + print(e); + } + + return DateTime.now(); + } else + return DateTime.now(); + } + + static String convertDateToString(DateTime date) { + const start = "/Date("; + const end = "+0300)"; + int milliseconds = date.millisecondsSinceEpoch; + + return start + "$milliseconds" + end; + } + + static String convertDateToStringLocation(DateTime date) { + const start = "/Date("; + const end = ")/"; + int milliseconds = date.millisecondsSinceEpoch; + + return start + "$milliseconds" + end; + } + + static String formatDateToDate(DateTime date, bool isArabic) { + return DateFormat('dd MMM yyy', isArabic ? "ar_SA" : "en_US").format(date); + } + + static String formatDateToTime(DateTime date) { + return DateFormat('hh:mm a').format(date); + } + + static String yearMonthDay(DateTime dateTime) { + String dateFormat = '${dateTime.year}-${dateTime.month}-${dateTime.day}'; + return dateFormat; + } + + static String time(DateTime dateTime) { + String dateFormat = '${dateTime.hour}:${dateTime.minute}:00'; + return dateFormat; + } + + static String convertDateMSToJsonDate(utc) { + var dt = new DateTime.fromMicrosecondsSinceEpoch(utc); + + return "/Date(" + (dt.millisecondsSinceEpoch * 1000).toString() + '+0300' + ")/"; + } + + /// check Date + /// [dateString] String we want to convert + static String checkDate(DateTime checkedTime) { + DateTime currentTime = DateTime.now(); + if ((currentTime.year == checkedTime.year) && (currentTime.month == checkedTime.month) && (currentTime.day == checkedTime.day)) { + return "Today"; + } else if ((currentTime.year == checkedTime.year) && (currentTime.month == checkedTime.month)) { + if ((currentTime.day - checkedTime.day) == 1) { + return "YESTERDAY"; + } else if ((currentTime.day - checkedTime.day) == -1) { + return "Tomorrow"; + } + + if ((currentTime.day - checkedTime.day) <= -2) { + return "Next Week"; + } else { + return "Old Date"; + } + } + return "Old Date"; + } + + static String getDateFormatted(String date) { + DateTime dateObj = DateUtil.convertStringToDate(date); + return DateUtil.getWeekDay(dateObj.weekday) + ", " + dateObj.day.toString() + " " + DateUtil.getMonth(dateObj.month) + " " + dateObj.year.toString(); + } + + static String getISODateFormat(DateTime dateTime) { + // 2020-04-30T00:00:00.000 + return dateTime.toIso8601String(); + } + + /// get month by + /// [month] convert month number in to month name + static getMonth(int month) { + switch (month) { + case 1: + return "January"; + case 2: + return "February"; + case 3: + return "March"; + case 4: + return "April"; + case 5: + return "May"; + case 6: + return "June"; + case 7: + return "July"; + case 8: + return "August"; + case 9: + return "September"; + case 10: + return "October"; + case 11: + return "November"; + case 12: + return "December"; + } + } + + /// get month by + /// [month] convert month number in to month name in Arabic + static getMonthArabic(int month) { + switch (month) { + case 1: + return "يناير"; + case 2: + return " فبراير"; + case 3: + return "مارس"; + case 4: + return "أبريل"; + case 5: + return "مايو"; + case 6: + return "يونيو"; + case 7: + return "يوليو"; + case 8: + return "أغسطس"; + case 9: + return "سبتمبر"; + case 10: + return " اكتوبر"; + case 11: + return " نوفمبر"; + case 12: + return "ديسمبر"; + } + } + + static getMonthByName(String month) { + switch (month.toLowerCase()) { + case 'january': + return 1; + case 'february': + return 2; + case 'march': + return 3; + case 'april': + return 4; + case 'may': + return 5; + case 'june': + return 6; + case 'july': + return 7; + case 'august': + return 8; + case 'september': + return 9; + case 'october': + return 10; + case 'november': + return 11; + case 'december': + return 12; + } + } + + static DateTime getMonthDateTime(String month, yearName) { + DateTime? date; + try { + date = DateTime(int.parse(yearName), getMonthByName(month)); + } catch (e) { + print(e); + } + return date ?? DateTime.now(); + } + + /// get month by + /// [weekDay] convert week day in int to week day name + static getWeekDay(int weekDay) { + switch (weekDay) { + case 1: + return "Monday"; + case 2: + return "Tuesday"; + case 3: + return "Wednesday"; + case 4: + return "Thursday"; + case 5: + return "Friday"; + case 6: + return "Saturday "; + case 7: + return "Sunday"; + } + } + + /// get month by + /// [weekDay] convert week day in int to week day name arabic + static getWeekDayArabic(int weekDay) { + switch (weekDay) { + case 1: + return "الاثنين"; + case 2: + return "الثلاثاء"; + case 3: + return "الاربعاء"; + case 4: + return "الخميس"; + case 5: + return "الجمعه"; + case 6: + return "السبت "; + case 7: + return "الاحد"; + } + } + + static getWeekDayEnglish(int weekDay) { + switch (weekDay) { + case 1: + return "Monday"; + case 2: + return "Tuesday"; + case 3: + return "Wednesday"; + case 4: + return "Thursday"; + case 5: + return "Friday"; + case 6: + return "Saturday "; + case 7: + return "Sunday"; + } + } + + /// get data formatted like Apr 26,2020 + /// [dateTime] convert DateTime to data formatted + static String getMonthDayYearDateFormatted(DateTime dateTime) { + if (dateTime != null) + return getMonth(dateTime.month) + " " + dateTime.day.toString() + ", " + dateTime.year.toString(); + else + return ""; + } + + /// get data formatted like Apr 26,2020 + /// [dateTime] convert DateTime to data formatted Arabic + static String getMonthDayYearDateFormattedAr(DateTime dateTime) { + if (dateTime != null) + return getMonthArabic(dateTime.month) + " " + dateTime.day.toString() + ", " + dateTime.year.toString(); + else + return ""; + } + + /// get data formatted like Thursday, Apr 26,2020 + /// [dateTime] convert DateTime to date formatted + static String getWeekDayMonthDayYearDateFormatted(DateTime dateTime, String lang) { + // print(dateTime); + // print(dateTime.weekday); + // print(dateTime.weekday.getDayOfWeekEnumValue.value); + if (dateTime != null) + return lang == 'en' + ? getWeekDayEnglish(dateTime.weekday) + ", " + getMonth(dateTime.month) + " " + dateTime.day.toString() + " " + dateTime.year.toString() + : getWeekDayArabic(dateTime.weekday) + ", " + dateTime.day.toString() + " " + getMonthArabic(dateTime.month) + " " + dateTime.year.toString(); + else + return ""; + } + + static String getMonthDayYearLangDateFormatted(DateTime dateTime, String lang) { + if (dateTime != null) + return lang == 'en' + ? getMonth(dateTime.month) + " " + dateTime.day.toString() + " " + dateTime.year.toString() + : dateTime.day.toString() + " " + getMonthArabic(dateTime.month) + " " + dateTime.year.toString(); + else + return ""; + } + + /// get data formatted like 26/4/2020 + static String getDayMonthYearLangDateFormatted(DateTime dateTime, String lang) { + if (dateTime != null) + return lang == 'en' + ? dateTime.day.toString() + " " + getMonth(dateTime.month) + " " + dateTime.year.toString() + : dateTime.day.toString() + " " + getMonthArabic(dateTime.month) + " " + dateTime.year.toString(); + else + return ""; + } + + static String getMonthYearLangDateFormatted(DateTime dateTime, String lang) { + if (dateTime != null) + return lang == 'en' ? getMonth(dateTime.month) + " " + dateTime.year.toString() : getMonthArabic(dateTime.month) + " " + dateTime.year.toString(); + else + return ""; + } + + /// get data formatted like 26/4/2020 + /// [dateTime] convert DateTime to data formatted + static String getDayMonthYearDateFormatted(DateTime dateTime) { + if (dateTime != null) + return dateTime.day.toString() + "/" + dateTime.month.toString() + "/" + dateTime.year.toString(); + else + return ""; + } + + /// get data formatted like 26/4/2020 + /// [dateTime] convert DateTime to data formatted + static String getDayMonthDateFormatted(DateTime dateTime) { + if (dateTime != null) + return DateFormat('dd/MM').format(dateTime); + else + return ""; + } + + /// get data formatted like 26/4/2020 + /// [dateTime] convert DateTime to data formatted according to language + static String getDayMonthYearDateFormattedLang(DateTime dateTime, bool isArabic) { + if (dateTime != null) + return DateFormat('dd/MM/yyyy', isArabic ? "ar_SA" : "en_US").format(dateTime); + else + return ""; + } + + /// get data formatted like 10:30 according to lang + static String formatDateToTimeLang(DateTime date, bool isArabic) { + return DateFormat('HH:mm', isArabic ? "ar_SA" : "en_US").format(date); + } + + /// get data formatted like 26/4/2020 10:30 + /// [dateTime] convert DateTime to data formatted + static String getDayMonthYearHourMinuteDateFormatted(DateTime dateTime) { + if (dateTime != null) + return dateTime.day.toString() + "/" + dateTime.month.toString() + "/" + dateTime.year.toString() + " " + DateFormat('HH:mm').format(dateTime); + else + return ""; + } + + /// get data formatted like 2020-8-13 09:43:00 + /// [dateTime] convert DateTime to data formatted + static String getYearMonthDayHourMinSecDateFormatted(DateTime dateTime) { + if (dateTime != null) + return dateTime.year.toString() + + "-" + + dateTime.month.toString() + + "-" + + dateTime.day.toString() + + " " + + dateTime.hour.toString() + + ":" + + dateTime.minute.toString() + + ":" + + dateTime.second.toString(); + else + return ""; + } + + static String getFormattedDate(DateTime dateTime, String formattedString) { + return DateFormat(formattedString).format(dateTime); + } + + static convertISODateToJsonDate(String isoDate) { + return "/Date(" + DateFormat('mm-dd-yyy').parse(isoDate).millisecondsSinceEpoch.toString() + ")/"; + } + + // static String getDay(DayOfWeek dayOfWeek) { + // switch (dayOfWeek) { + // case DayOfWeek.Monday: + // return "Monday"; + // break; + // case DayOfWeek.Tuesday: + // return "Tuesday"; + // break; + // case DayOfWeek.Wednesday: + // return "Wednesday"; + // break; + // case DayOfWeek.Thursday: + // return "Thursday"; + // break; + // case DayOfWeek.Friday: + // return "Friday"; + // break; + // case DayOfWeek.Saturday: + // return "Saturday"; + // break; + // case DayOfWeek.Sunday: + // return "Sunday"; + // break; + // } + // return ""; + // } +} diff --git a/lib/classes/utils.dart b/lib/classes/utils.dart index d80fdf5..fc942c4 100644 --- a/lib/classes/utils.dart +++ b/lib/classes/utils.dart @@ -3,7 +3,9 @@ import 'package:fluttertoast/fluttertoast.dart'; // import 'package:fluttertoast/fluttertoast.dart'; import 'package:mohem_flutter_app/exceptions/api_exception.dart'; +import 'package:mohem_flutter_app/widgets/dialogs/confirm_dialog.dart'; import 'package:mohem_flutter_app/widgets/loading_dialog.dart'; +import 'package:shared_preferences/shared_preferences.dart'; class Utils { static bool _isLoadingVisible = false; @@ -44,6 +46,10 @@ class Utils { }); } + static Future delay(int millis) async { + return await Future.delayed(Duration(milliseconds: millis)); + } + static void hideLoading(BuildContext context) { if (_isLoadingVisible) { _isLoadingVisible = false; @@ -52,6 +58,16 @@ class Utils { _isLoadingVisible = false; } + static Future getStringFromPrefs(String key) async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + return prefs.getString(key) ?? ""; + } + + static Future saveStringFromPrefs(String key, String value) async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + return await prefs.setString(key, value); + } + static void handleException(dynamic exception, Function(String)? onErrorMessage) { String errorMessage; if (exception is APIException) { @@ -69,4 +85,13 @@ class Utils { showToast(errorMessage); } } + + static void confirmDialog(cxt, String message) { + showDialog( + context: cxt, + builder: (cxt) => ConfirmDialog( + message: message, + ), + ); + } } diff --git a/lib/config/routes.dart b/lib/config/routes.dart index 39a4ebc..3eba985 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -1,9 +1,10 @@ import 'package:flutter/material.dart'; -import 'package:mohem_flutter_app/ui/landing/dashboard.dart'; +import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart'; import 'package:mohem_flutter_app/ui/landing/today_attendance_screen.dart'; import 'package:mohem_flutter_app/ui/login/forgot_password_screen.dart'; import 'package:mohem_flutter_app/ui/login/login_screen.dart'; import 'package:mohem_flutter_app/ui/login/new_password_screen.dart'; +import 'package:mohem_flutter_app/ui/login/verify_last_login_screen.dart'; import 'package:mohem_flutter_app/ui/login/verify_login_screen.dart'; import 'package:mohem_flutter_app/ui/work_list/missing_swipe/missing_swipe_screen.dart'; import 'package:mohem_flutter_app/ui/work_list/work_list_screen.dart'; @@ -14,6 +15,7 @@ class AppRoutes { static const String loginVerifyAccount = "/loginVerifyAccount"; static const String login = "/login"; static const String verifyLogin = "/verifyLogin"; + static const String verifyLastLogin = "/verifyLastLogin"; static const String forgotPassword = "/forgotPassword"; static const String newPassword = "/newPassword"; static const String loginVerification = "/loginVerification"; @@ -28,7 +30,8 @@ class AppRoutes { static final Map routes = { login: (context) => LoginScreen(), verifyLogin: (context) => VerifyLoginScreen(), - dashboard: (context) => Dashboard(), + verifyLastLogin: (context) => VerifyLastLoginScreen(), + dashboard: (context) => DashboardScreen(), newPassword: (context) => NewPasswordScreen(), forgotPassword: (context) => ForgotPasswordScreen(), todayAttendance: (context) => TodayAttendanceScreen(), diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index 9db4829..2db6135 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -1,6 +1,18 @@ +import 'package:easy_localization/src/public_ext.dart'; import 'package:flutter/cupertino.dart'; import 'package:intl/intl.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; + +extension CapExtension on String { + String get toCamelCase => "${this[0].toUpperCase()}${this.substring(1)}"; + + String get inCaps => '${this[0].toUpperCase()}${this.substring(1)}'; + + String get allInCaps => this.toUpperCase(); + + String get capitalizeFirstofEach => this.trim().length > 0 ? this.trim().toLowerCase().split(" ").map((str) => str.inCaps).join(" ") : ""; +} extension EmailValidator on String { Widget get toWidget => Text(this); @@ -57,9 +69,9 @@ extension EmailValidator on String { style: TextStyle(height: 1, color: color ?? MyColors.darkTextColor, fontSize: 22, letterSpacing: -1.44, fontWeight: isBold ? FontWeight.bold : FontWeight.w600), ); - Widget toText24({Color? color, bool isBold = false}) => Text( + Widget toText24({Color? color, bool isBold = false, bool considerHeight = true}) => Text( this, - style: TextStyle(height: 23 / 24, color: color ?? MyColors.darkTextColor, fontSize: 24, letterSpacing: -1.44, fontWeight: isBold ? FontWeight.bold : FontWeight.w600), + style: TextStyle(height: considerHeight ? 23 / 24 : null, color: color ?? MyColors.darkTextColor, fontSize: 24, letterSpacing: -1.44, fontWeight: isBold ? FontWeight.bold : FontWeight.w600), ); Widget toText32({Color? color, bool isBold = false}) => Text( @@ -67,6 +79,38 @@ extension EmailValidator on String { style: TextStyle(height: 32 / 32, color: color ?? MyColors.darkTextColor, fontSize: 32, letterSpacing: -1.92, fontWeight: isBold ? FontWeight.bold : FontWeight.w600), ); + Widget toSectionHeading({String upperHeading = "", String lowerHeading = ""}) { + String upper = ""; + String lower = ""; + String heading = this; + if (heading.isNotEmpty) { + List data = heading.split(" "); + + if (data.length > 1) { + upper = data[0]; + data.removeAt(0); + lower = data.join(" "); + } else { + lower = data[0]; + } + } + if (upperHeading.isNotEmpty) { + upper = upperHeading; + } + if (lowerHeading.isNotEmpty) { + lower = lowerHeading; + } + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + if (upper.isNotEmpty) upper.toText12(), + lower.toText24(isBold: true), + ], + ); + } + bool isValidEmail() { return RegExp(r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$').hasMatch(this); } diff --git a/lib/extensions/widget_extensions.dart b/lib/extensions/widget_extensions.dart index 787894d..5169f19 100644 --- a/lib/extensions/widget_extensions.dart +++ b/lib/extensions/widget_extensions.dart @@ -1,11 +1,39 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; +import 'package:shimmer/shimmer.dart'; extension WidgetExtensions on Widget { Widget onPress(VoidCallback onTap) => InkWell(onTap: onTap, child: this); + Widget get expanded => Expanded(child: this); + + Widget get center => Center(child: this); + Widget paddingAll(double _value) => Padding(padding: EdgeInsets.all(_value), child: this); Widget paddingOnly({double left = 0.0, double right = 0.0, double top = 0.0, double bottom = 0.0}) => Padding(padding: EdgeInsets.only(left: left, right: right, top: top, bottom: bottom), child: this); + + Widget toShimmer({bool isShow = true}) => isShow + ? Shimmer.fromColors( + baseColor: Color(0xffe8eff0), + highlightColor: Colors.white, + child: Container( + child: this, + color: Colors.white, + ), + ) + : Container( + child: this, + ); + + Widget animatedSwither() => AnimatedSwitcher( + duration: const Duration(milliseconds: 500), + // transitionBuilder: (Widget child, Animation animation) { + // return ScaleTransition(scale: animation, child: child); + // }, + switchInCurve: Curves.linearToEaseOut, + switchOutCurve: Curves.linearToEaseOut, + child: this, + ); } diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index b43f3bd..f4a2a6c 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -6,191 +6,193 @@ import 'dart:ui'; import 'package:easy_localization/easy_localization.dart' show AssetLoader; -class CodegenLoader extends AssetLoader{ +class CodegenLoader extends AssetLoader { const CodegenLoader(); @override - Future> load(String fullPath, Locale locale ) { + Future> load(String fullPath, Locale locale) { return Future.value(mapLocales[locale.toString()]); } - static const Map ar_SA = { - "mohemm": "Mohemm", - "english": "English", - "arabic": "Arabic", - "login": "تسجيل الدخول", - "pleaseEnterLoginDetails": "الرجاء إدخال التفاصيل أدناه لتسجيل الدخول", - "username": "اسم المستخدم", - "password": "كلمة المرور", - "welcomeBack": "مرحبا بعودتك", - "wouldYouLikeToLoginWithCurrentUsername": "هل ترغب في تسجيل الدخول باسم المستخدم الحالي؟", - "lastLoginDetails": "تفاصيل تسجيل الدخول الأخير:", - "verificationType": "نوع التحقق:", - "pleaseVerify": "ارجوك تحقق", - "verifyThroughFace": "تحقق من خلال الوجه", - "verifyThroughFingerprint": "تحقق من خلال بصمة الإصبع", - "verifyThroughSMS": "تحقق من خلال الرسائل القصيرة", - "verifyThroughWhatsapp": "تحقق من خلال Whatsapp", - "useAnotherAccount": "استخدم حسابا آخر", - "pleaseEnterTheVerificationCodeSentTo": "الرجاء إدخال رمز التحقق المرسل إلى ", - "theVerificationCodeWillExpireIn": "ستنتهي صلاحية رمز التحقق في ", - "goodMorning": "صباح الخير", - "markAttendance": "علامة الحضور", - "timeLeftToday": "الوقت المتبقي اليوم", - "checkIn": "تحقق في", - "workList": "قائمة العمل", - "leaveBalance": "رصيد الاجازات", - "missingSwipes": "الضربات الشديدة في عداد المفقودين", - "ticketBalance": "رصيد التذكرة", - "other": "آخر", - "services": "خدمات", - "viewAllServices": "عرض جميع الخدمات", - "monthlyAttendance": "الحضور الشهري", - "workFromHome": "العمل من المنزل", - "ticketRequest": "طلب تذكرة", - "viewAllOffers": "مشاهدة جميع العروض", - "offers": "عروض & ", - "discounts": "الخصومات", - "newString": "جديد", - "setTheNewPassword": "قم بتعيين كلمة المرور الجديدة", - "typeYourNewPasswordBelow": "اكتب كلمة المرور الجديدة أدناه", - "confirmPassword": "تأكيد كلمة المرور", - "update": "تحديث", - "title": "عنوان", - "home": "مسكن", - "mySalary": "راتبي", - "createRequest": "إنشاء طلب", - "forgotPassword": "هل نسيت كلمة السر", - "employeeId": "هوية الموظف", - "loginCodeWillSentToMobileNumber": "الرجاء إدخال معرف الموظف الخاص بك ، وسيتم إرسال رمز تسجيل الدخول إلى رقم هاتفك المحمول", - "changePassword": "تغيير كلمة المرور", - "itemsForSale": "سلع للبيع", - "msg": "Hello {} in the {} world ", - "msg_named": "{} are written in the {lang} language", - "clickMe": "Click me", - "human": "Human", - "resources": "Resources", - "profile": { - "reset_password": { - "label": "Reset Password", - "username": "Username", - "password": "password" - } - }, - "clicked": { - "zero": "You clicked {} times!", - "one": "You clicked {} time!", - "two": "You clicked {} times!", - "few": "You clicked {} times!", - "many": "You clicked {} times!", - "other": "You clicked {} times!" - }, - "amount": { - "zero": "Your amount : {} ", - "one": "Your amount : {} ", - "two": "Your amount : {} ", - "few": "Your amount : {} ", - "many": "Your amount : {} ", - "other": "Your amount : {} " - }, - "gender": { - "male": "Hi man ;) ", - "female": "Hello girl :)", - "with_arg": { - "male": "Hi man ;) {}", - "female": "Hello girl :) {}" - } - }, - "reset_locale": "Reset Language" -}; -static const Map en_US = { - "mohemm": "Mohemm", - "english": "English", - "arabic": "Arabic", - "login": "Login", - "pleaseEnterLoginDetails": "Please enter the detail below to login", - "username": "Username", - "password": "Password", - "welcomeBack": "Welcome back", - "wouldYouLikeToLoginWithCurrentUsername": "Would you like to login with current Username?", - "lastLoginDetails": "Last Login Details:", - "verificationType": "Verification Type:", - "pleaseVerify": "Please Verify", - "verifyThroughFace": "Verify Through Face", - "verifyThroughFingerprint": "Verify Through Fingerprint", - "verifyThroughSMS": "Verify Through SMS", - "verifyThroughWhatsapp": "Verify Through Whatsapp", - "useAnotherAccount": "Use Another Account", - "pleaseEnterTheVerificationCodeSentTo": "Please enter the verification code sent to ", - "theVerificationCodeWillExpireIn": "The verification code will expire in ", - "goodMorning": "Good Morning", - "markAttendance": "Mark Attendance", - "timeLeftToday": "Time Left Today", - "checkIn": "Check In", - "workList": "Work List", - "leaveBalance": "Leave Balance", - "missingSwipes": "Missing Swipes", - "ticketBalance": "Ticket Balance", - "other": "Other", - "services": "Services", - "viewAllServices": "View All Services", - "monthlyAttendance": "Monthly Attendance", - "workFromHome": "Work From Home", - "ticketRequest": "Ticket Request", - "viewAllOffers": "View All Offers", - "offers": "Offers & ", - "discounts": "Discounts", - "newString": "New", - "setTheNewPassword": "Set the new password", - "typeYourNewPasswordBelow": "Type your new password below", - "confirmPassword": "Confirm Password", - "update": "Update", - "title": "Title", - "home": "Home", - "mySalary": "My Salary", - "createRequest": "Create Request", - "forgotPassword": "Forgot Password", - "employeeId": "Employee ID", - "loginCodeWillSentToMobileNumber": "Please Enter your Employee ID, A login code will be sent to your mobile number", - "changePassword": "Change Password", - "itemsForSale": "Items for Sale", - "msg": "Hello {} in the {} world ", - "msg_named": "{} are written in the {lang} language", - "clickMe": "Click me", - "human": "Human", - "resources": "Resources", - "profile": { - "reset_password": { - "label": "Reset Password", - "username": "Username", - "password": "password" - } - }, - "clicked": { - "zero": "You clicked {} times!", - "one": "You clicked {} time!", - "two": "You clicked {} times!", - "few": "You clicked {} times!", - "many": "You clicked {} times!", - "other": "You clicked {} times!" - }, - "amount": { - "zero": "Your amount : {} ", - "one": "Your amount : {} ", - "two": "Your amount : {} ", - "few": "Your amount : {} ", - "many": "Your amount : {} ", - "other": "Your amount : {} " - }, - "gender": { - "male": "Hi man ;) ", - "female": "Hello girl :)", - "with_arg": { - "male": "Hi man ;) {}", - "female": "Hello girl :) {}" - } - }, - "reset_locale": "Reset Language" -}; -static const Map> mapLocales = {"ar_SA": ar_SA, "en_US": en_US}; + static const Map ar_SA = { + "mohemm": "Mohemm", + "english": "English", + "arabic": "Arabic", + "login": "تسجيل الدخول", + "pleaseEnterLoginDetails": "الرجاء إدخال التفاصيل أدناه لتسجيل الدخول", + "username": "اسم المستخدم", + "password": "كلمة المرور", + "welcomeBack": "مرحبا بعودتك", + "wouldYouLikeToLoginWithCurrentUsername": "هل ترغب في تسجيل الدخول باسم المستخدم الحالي؟", + "lastLoginDetails": "تفاصيل تسجيل الدخول الأخير:", + "verificationType": "نوع التحقق:", + "pleaseVerify": "ارجوك تحقق", + "verifyThroughFace": "تحقق من خلال الوجه", + "verifyThroughFingerprint": "تحقق من خلال بصمة الإصبع", + "verifyThroughSMS": "تحقق من خلال الرسائل القصيرة", + "verifyThroughWhatsapp": "تحقق من خلال Whatsapp", + "useAnotherAccount": "استخدم حسابا آخر", + "pleaseEnterTheVerificationCodeSentTo": "الرجاء إدخال رمز التحقق المرسل إلى ", + "theVerificationCodeWillExpireIn": "ستنتهي صلاحية رمز التحقق في ", + "goodMorning": "صباح الخير", + "markAttendance": "علامة الحضور", + "timeLeftToday": "الوقت المتبقي اليوم", + "checkIn": "تحقق في", + "workList": "قائمة العمل", + "leaveBalance": "رصيد الاجازات", + "missingSwipes": "الضربات الشديدة في عداد المفقودين", + "ticketBalance": "رصيد التذكرة", + "other": "آخر", + "services": "خدمات", + "viewAllServices": "عرض جميع الخدمات", + "monthlyAttendance": "الحضور الشهري", + "workFromHome": "العمل من المنزل", + "ticketRequest": "طلب تذكرة", + "viewAllOffers": "مشاهدة جميع العروض", + "offers": "عروض & ", + "discounts": "الخصومات", + "newString": "جديد", + "setTheNewPassword": "قم بتعيين كلمة المرور الجديدة", + "typeYourNewPasswordBelow": "اكتب كلمة المرور الجديدة أدناه", + "confirmPassword": "تأكيد كلمة المرور", + "update": "تحديث", + "title": "عنوان", + "home": "مسكن", + "mySalary": "راتبي", + "createRequest": "إنشاء طلب", + "forgotPassword": "هل نسيت كلمة السر", + "employeeId": "هوية الموظف", + "loginCodeWillSentToMobileNumber": "الرجاء إدخال معرف الموظف الخاص بك ، وسيتم إرسال رمز تسجيل الدخول إلى رقم هاتفك المحمول", + "changePassword": "تغيير كلمة المرور", + "ok": "موافق", + "confirm": "تؤكد", + "passwordChangedSuccessfully": "تم تغيير الرقم السري بنجاح", + "itemsForSale": "سلع للبيع", + "doNotUseRecentPassword": "لا تستخدم كلمة مرور حديثة", + "atLeastOneLowercase": "حرف صغير واحد على الأقل", + "atLeastOneUppercase": "حرف كبير واحد على الأقل", + "atLeastOneNumeric": "رقم واحد على الأقل", + "minimum8Characters": "8 أحرف على الأقل", + "doNotAddRepeatingLetters": "لا تقم بإضافة أحرف متكررة", + "itShouldContainSpecialCharacter": "يجب أن يحتوي على طابع خاص", + "confirmPasswordMustMatch": "يجب أن يتطابق تأكيد كلمة المرور", + "sms": "رسالة قصيرة", + "fingerPrint": "بصمة", + "face": "التعرف على الوجه", + "whatsapp": "واتس اب", + "msg": "Hello {} in the {} world ", + "msg_named": "{} are written in the {lang} language", + "clickMe": "Click me", + "human": "Human", + "resources": "Resources", + "profile": { + "reset_password": {"label": "Reset Password", "username": "Username", "password": "password"} + }, + "clicked": { + "zero": "You clicked {} times!", + "one": "You clicked {} time!", + "two": "You clicked {} times!", + "few": "You clicked {} times!", + "many": "You clicked {} times!", + "other": "You clicked {} times!" + }, + "amount": {"zero": "Your amount : {} ", "one": "Your amount : {} ", "two": "Your amount : {} ", "few": "Your amount : {} ", "many": "Your amount : {} ", "other": "Your amount : {} "}, + "gender": { + "male": "Hi man ;) ", + "female": "Hello girl :)", + "with_arg": {"male": "Hi man ;) {}", "female": "Hello girl :) {}"} + }, + "reset_locale": "Reset Language" + }; + static const Map en_US = { + "mohemm": "Mohemm", + "english": "English", + "arabic": "Arabic", + "login": "Login", + "pleaseEnterLoginDetails": "Please enter the detail below to login", + "username": "Username", + "password": "Password", + "welcomeBack": "Welcome back", + "wouldYouLikeToLoginWithCurrentUsername": "Would you like to login with current Username?", + "lastLoginDetails": "Last Login Details:", + "verificationType": "Verification Type:", + "pleaseVerify": "Please Verify", + "verifyThroughFace": "Verify Through Face", + "verifyThroughFingerprint": "Verify Through Fingerprint", + "verifyThroughSMS": "Verify Through SMS", + "verifyThroughWhatsapp": "Verify Through Whatsapp", + "useAnotherAccount": "Use Another Account", + "pleaseEnterTheVerificationCodeSentTo": "Please enter the verification code sent to ", + "theVerificationCodeWillExpireIn": "The verification code will expire in ", + "goodMorning": "Good Morning", + "markAttendance": "Mark Attendance", + "timeLeftToday": "Time Left Today", + "checkIn": "Check In", + "workList": "Work List", + "leaveBalance": "Leave Balance", + "missingSwipes": "Missing Swipes", + "ticketBalance": "Ticket Balance", + "other": "Other", + "services": "Services", + "viewAllServices": "View All Services", + "monthlyAttendance": "Monthly Attendance", + "workFromHome": "Work From Home", + "ticketRequest": "Ticket Request", + "viewAllOffers": "View All Offers", + "offers": "Offers & ", + "discounts": "Discounts", + "newString": "New", + "setTheNewPassword": "Set the new password", + "typeYourNewPasswordBelow": "Type your new password below", + "confirmPassword": "Confirm Password", + "update": "Update", + "title": "Title", + "home": "Home", + "mySalary": "My Salary", + "createRequest": "Create Request", + "forgotPassword": "Forgot Password", + "employeeId": "Employee ID", + "loginCodeWillSentToMobileNumber": "Please Enter your Employee ID, A login code will be sent to your mobile number", + "changePassword": "Change Password", + "ok": "OK", + "confirm": "Confirm", + "passwordChangedSuccessfully": "Password changed successfully", + "itemsForSale": "Items for Sale", + "doNotUseRecentPassword": "Do not use recent password", + "atLeastOneLowercase": "At least one lowercase", + "atLeastOneUppercase": "At least one uppercase", + "atLeastOneNumeric": "At least one numeric", + "minimum8Characters": "Minimum 8 characters", + "doNotAddRepeatingLetters": "Do not add repeating letters", + "itShouldContainSpecialCharacter": "It should contain special character", + "confirmPasswordMustMatch": "Confirm password must match", + "sms": "SMS", + "fingerPrint": "Fingerprint", + "face": "Face", + "whatsapp": "Whatsapp", + "msg": "Hello {} in the {} world ", + "msg_named": "{} are written in the {lang} language", + "clickMe": "Click me", + "human": "Human", + "resources": "Resources", + "profile": { + "reset_password": {"label": "Reset Password", "username": "Username", "password": "password"} + }, + "clicked": { + "zero": "You clicked {} times!", + "one": "You clicked {} time!", + "two": "You clicked {} times!", + "few": "You clicked {} times!", + "many": "You clicked {} times!", + "other": "You clicked {} times!" + }, + "amount": {"zero": "Your amount : {} ", "one": "Your amount : {} ", "two": "Your amount : {} ", "few": "Your amount : {} ", "many": "Your amount : {} ", "other": "Your amount : {} "}, + "gender": { + "male": "Hi man ;) ", + "female": "Hello girl :)", + "with_arg": {"male": "Hi man ;) {}", "female": "Hello girl :) {}"} + }, + "reset_locale": "Reset Language" + }; + static const Map> mapLocales = {"ar_SA": ar_SA, "en_US": en_US}; } diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 24d7171..55e543b 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -1,6 +1,6 @@ // DO NOT EDIT. This is code generated via package:easy_localization/generate.dart -abstract class LocaleKeys { +abstract class LocaleKeys { static const mohemm = 'mohemm'; static const english = 'english'; static const arabic = 'arabic'; @@ -49,12 +49,30 @@ abstract class LocaleKeys { static const employeeId = 'employeeId'; static const loginCodeWillSentToMobileNumber = 'loginCodeWillSentToMobileNumber'; static const changePassword = 'changePassword'; + static const ok = 'ok'; + static const confirm = 'confirm'; + static const passwordChangedSuccessfully = 'passwordChangedSuccessfully'; static const itemsForSale = 'itemsForSale'; + static const doNotUseRecentPassword = 'doNotUseRecentPassword'; + static const atLeastOneLowercase = 'atLeastOneLowercase'; + static const atLeastOneUppercase = 'atLeastOneUppercase'; + static const atLeastOneNumeric = 'atLeastOneNumeric'; + static const minimum8Characters = 'minimum8Characters'; + static const doNotAddRepeatingLetters = 'doNotAddRepeatingLetters'; + static const itShouldContainSpecialCharacter = 'itShouldContainSpecialCharacter'; + static const confirmPasswordMustMatch = 'confirmPasswordMustMatch'; + static const sms = 'sms'; + static const fingerPrint = 'fingerPrint'; + static const face = 'face'; + static const whatsapp = 'whatsapp'; static const msg = 'msg'; static const msg_named = 'msg_named'; static const clickMe = 'clickMe'; static const human = 'human'; static const resources = 'resources'; + static const details = 'details'; + static const reject = 'reject'; + static const approve = 'approve'; static const profile_reset_password_label = 'profile.reset_password.label'; static const profile_reset_password_username = 'profile.reset_password.username'; static const profile_reset_password_password = 'profile.reset_password.password'; @@ -65,5 +83,4 @@ abstract class LocaleKeys { static const gender_with_arg = 'gender.with_arg'; static const gender = 'gender'; static const reset_locale = 'reset_locale'; - } diff --git a/lib/main.dart b/lib/main.dart index 99cff95..29a8e17 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,5 @@ import 'dart:io'; +import 'dart:typed_data'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; @@ -6,14 +7,30 @@ import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/config/app_provider.dart'; import 'package:mohem_flutter_app/generated/codegen_loader.g.dart'; import 'package:mohem_flutter_app/models/post_params_model.dart'; +import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; import 'package:mohem_flutter_app/theme/app_theme.dart'; +import 'package:mohem_flutter_app/widgets/nfc/nfc_reader_sheet.dart'; +import 'package:nfc_manager/nfc_manager.dart'; +import 'package:nfc_manager/platform_tags.dart'; +import 'package:provider/provider.dart'; import 'package:sizer/sizer.dart'; - +import 'package:firebase_core/firebase_core.dart'; import 'config/routes.dart'; +import 'package:logger/logger.dart'; + +var logger = Logger( + // filter: null, // Use the default LogFilter (-> only log in debug mode) + printer: PrettyPrinter(lineLength: 0), // Use the PrettyPrinter to format and print log + // output: null, // U +); Future main() async { WidgetsFlutterBinding.ensureInitialized(); await EasyLocalization.ensureInitialized(); + await Firebase.initializeApp(); + AppState().setPostParamsModel( + PostParamsModel(channel: 31, versionID: 3.4, mobileType: Platform.isAndroid ? "android" : "ios"), + ); runApp( EasyLocalization( supportedLocales: const [ @@ -22,7 +39,12 @@ Future main() async { ], path: 'assets/langs', assetLoader: CodegenLoader(), - child: MyApp(), + child: MultiProvider( + providers: [ + ChangeNotifierProvider(create: (_) => DashboardProviderModel()), + ], + child: MyApp(), + ), ), ); } @@ -40,23 +62,159 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { - return AppProvider( - child: Sizer( - builder: (context, orientation, deviceType) { - AppState().setPostParamsModel( - PostParamsModel(languageID: EasyLocalization.of(context)?.locale.languageCode == "ar" ? 1 : 2, channel: 31, versionID: 3.2, mobileType: Platform.isAndroid ? "android" : "ios"), - ); - return MaterialApp( - theme: AppTheme.getTheme(EasyLocalization.of(context)?.locale.languageCode == "ar"), - debugShowCheckedModeBanner: false, - localizationsDelegates: context.localizationDelegates, - supportedLocales: context.supportedLocales, - locale: context.locale, - initialRoute: AppRoutes.initialRoute, - routes: AppRoutes.routes, - ); - }, - ), + return Sizer( + builder: (context, orientation, deviceType) { + print(AppState().postParamsObject?.toJson()); + var obj = AppState().postParamsObject; + obj?.languageID = EasyLocalization.of(context)?.locale.languageCode == "ar" ? 1 : 2; + AppState().setPostParamsModel(obj!); + return MaterialApp( + theme: AppTheme.getTheme(EasyLocalization.of(context)?.locale.languageCode == "ar"), + debugShowCheckedModeBanner: false, + localizationsDelegates: context.localizationDelegates, + supportedLocales: context.supportedLocales, + locale: context.locale, + initialRoute: AppRoutes.initialRoute, + routes: AppRoutes.routes, + ); + }, ); } } + +// class MyApp extends StatefulWidget { +// @override +// State createState() => MyAppState(); +// } +// +// class MyAppState extends State { +// ValueNotifier result = ValueNotifier(null); +// +// @override +// Widget build(BuildContext context) { +// return MaterialApp( +// home: Scaffold( +// appBar: AppBar(title: Text('NfcManager Plugin Example')), +// body: SafeArea( +// child: FutureBuilder( +// future: NfcManager.instance.isAvailable(), +// builder: (context, ss) => ss.data != true +// ? Center(child: Text('NfcManager.isAvailable(): ${ss.data}')) +// : Flex( +// mainAxisAlignment: MainAxisAlignment.spaceBetween, +// direction: Axis.vertical, +// children: [ +// Flexible( +// flex: 2, +// child: Container( +// margin: EdgeInsets.all(4), +// constraints: BoxConstraints.expand(), +// decoration: BoxDecoration(border: Border.all()), +// child: SingleChildScrollView( +// child: ValueListenableBuilder( +// valueListenable: result, +// builder: (context, value, _) => Text('${value ?? ''}'), +// ), +// ), +// ), +// ), +// Flexible( +// flex: 3, +// child: GridView.count( +// padding: EdgeInsets.all(4), +// crossAxisCount: 2, +// childAspectRatio: 4, +// crossAxisSpacing: 4, +// mainAxisSpacing: 4, +// children: [ +// ElevatedButton(child: Text('Tag Read'), onPressed: _tagRead), +// ElevatedButton(child: Text('Ndef Write'), onPressed: _ndefWrite), +// ElevatedButton(child: Text('Ndef Write Lock'), onPressed: _ndefWriteLock), +// ], +// ), +// ), +// ], +// ), +// ), +// ), +// ), +// ); +// } +// +// void _tagRead() { +// showNfcReader( +// context, +// onNcfScan: (String? nfcId) {}, +// ); +// // NfcManager.instance.startSession(onDiscovered: (NfcTag tag) async { +// // result.value = tag.data; +// // print(tag.data); +// // var ndef = Ndef.from(tag); +// // +// // var f = MifareUltralight(tag: tag, identifier: tag.data["nfca"]["identifier"], type: 2, maxTransceiveLength: 252, timeout: 22); +// // final String identifier = f.identifier.map((e) => e.toRadixString(16).padLeft(2, '0')).join(''); +// // print(identifier); // => 0428fcf2255e81 +// // print(ndef!.additionalData); +// // +// // // onDiscovered callback +// // // final mifare = MiFare.from(tag); +// // // if (mifare == null) { +// // // print('Tag is not compatible with MiFare.'); +// // // return; +// // // } +// // // print(mifare.identifier); +// // // final String identifier = mifare.identifier.map((e) => e.toRadixString(16).padLeft(2, '0')).join(''); +// // // print(identifier); // => 0428fcf2255e81 +// // NfcManager.instance.stopSession(); +// // }); +// } +// +// void _ndefWrite() { +// NfcManager.instance.startSession(onDiscovered: (NfcTag tag) async { +// var ndef = Ndef.from(tag); +// if (ndef == null || !ndef.isWritable) { +// result.value = 'Tag is not ndef writable'; +// NfcManager.instance.stopSession(errorMessage: result.value); +// return; +// } +// +// NdefMessage message = NdefMessage([ +// NdefRecord.createText('Hello World!'), +// NdefRecord.createUri(Uri.parse('https://flutter.dev')), +// NdefRecord.createMime('text/plain', Uint8List.fromList('Hello'.codeUnits)), +// NdefRecord.createExternal('com.example', 'mytype', Uint8List.fromList('mydata'.codeUnits)), +// ]); +// +// try { +// await ndef.write(message); +// result.value = 'Success to "Ndef Write"'; +// NfcManager.instance.stopSession(); +// } catch (e) { +// result.value = e; +// NfcManager.instance.stopSession(errorMessage: result.value.toString()); +// return; +// } +// }); +// } +// +// void _ndefWriteLock() { +// NfcManager.instance.startSession(onDiscovered: (NfcTag tag) async { +// var ndef = Ndef.from(tag); +// if (ndef == null) { +// result.value = 'Tag is not ndef'; +// NfcManager.instance.stopSession(errorMessage: result.value.toString()); +// return; +// } +// +// try { +// await ndef.writeLock(); +// result.value = 'Success to "Ndef Write Lock"'; +// NfcManager.instance.stopSession(); +// } catch (e) { +// result.value = e; +// NfcManager.instance.stopSession(errorMessage: result.value.toString()); +// return; +// } +// }); +// } +// } diff --git a/lib/models/dashboard/get_attendance_tracking_list_model.dart b/lib/models/dashboard/get_attendance_tracking_list_model.dart index 66b9ed8..fb415b0 100644 --- a/lib/models/dashboard/get_attendance_tracking_list_model.dart +++ b/lib/models/dashboard/get_attendance_tracking_list_model.dart @@ -1,5 +1,5 @@ -class GetAttendanceTrackingList { - GetAttendanceTrackingList({ +class GetAttendanceTracking { + GetAttendanceTracking({ this.pBreakHours, this.pLateInHours, this.pRemainingHours, @@ -25,7 +25,7 @@ class GetAttendanceTrackingList { dynamic pSwipeIn; dynamic pSwipeOut; - factory GetAttendanceTrackingList.fromMap(Map json) => GetAttendanceTrackingList( + factory GetAttendanceTracking.fromMap(Map json) => GetAttendanceTracking( pBreakHours: json["P_BREAK_HOURS"] == null ? null : json["P_BREAK_HOURS"], pLateInHours: json["P_LATE_IN_HOURS"] == null ? null : json["P_LATE_IN_HOURS"], pRemainingHours: json["P_REMAINING_HOURS"] == null ? null : json["P_REMAINING_HOURS"], diff --git a/lib/models/dashboard/itg_forms_model.dart b/lib/models/dashboard/itg_forms_model.dart index c5a0145..5ed719b 100644 --- a/lib/models/dashboard/itg_forms_model.dart +++ b/lib/models/dashboard/itg_forms_model.dart @@ -93,97 +93,163 @@ class ItgFormsModel { dynamic mohemmItgProjectsList; dynamic mohemmItgTicketTypesList; DateTime? referenceNumber; - dynamic requestType; + List? requestType; int? totalCount; int? statuseCode; factory ItgFormsModel.fromJson(Map json) => ItgFormsModel( - date: json["Date"], - languageId: json["LanguageID"] == null ? null : json["LanguageID"], - serviceName: json["ServiceName"] == null ? null : json["ServiceName"], - time: json["Time"], - androidLink: json["AndroidLink"], - authenticationTokenId: json["AuthenticationTokenID"], - data: json["Data"], - dataw: json["Dataw"] == null ? null : json["Dataw"], - dietType: json["DietType"] == null ? null : json["DietType"], - dietTypeId: json["DietTypeID"] == null ? null : json["DietTypeID"], - errorCode: json["ErrorCode"], - errorEndUserMessage: json["ErrorEndUserMessage"], - errorEndUserMessageN: json["ErrorEndUserMessageN"], - errorMessage: json["ErrorMessage"], - errorType: json["ErrorType"] == null ? null : json["ErrorType"], - foodCategory: json["FoodCategory"] == null ? null : json["FoodCategory"], - iosLink: json["IOSLink"], - isAuthenticated: json["IsAuthenticated"] == null ? null : json["IsAuthenticated"], - mealOrderStatus: json["MealOrderStatus"] == null ? null : json["MealOrderStatus"], - mealType: json["MealType"] == null ? null : json["MealType"], - messageStatus: json["MessageStatus"] == null ? null : json["MessageStatus"], - numberOfResultRecords: json["NumberOfResultRecords"] == null ? null : json["NumberOfResultRecords"], - patientBlodType: json["PatientBlodType"], - successMsg: json["SuccessMsg"] == null ? null : json["SuccessMsg"], - successMsgN: json["SuccessMsgN"], - vidaUpdatedResponse: json["VidaUpdatedResponse"], - itgRequest: json["ITGRequest"], - itgFormAttachmentsList: json["Itg_FormAttachmentsList"], - message: json["Message"] == null ? null : json["Message"], - mohemmItgDepartmentSectionsList: json["Mohemm_ITG_DepartmentSectionsList"], - mohemmItgProjectDepartmentsList: json["Mohemm_ITG_ProjectDepartmentsList"], - mohemmItgResponseItem: json["Mohemm_ITG_ResponseItem"], - mohemmItgSectionTopicsList: json["Mohemm_ITG_SectionTopicsList"], - mohemmItgTicketDetailsList: json["Mohemm_ITG_TicketDetailsList"], - mohemmItgTicketTransactionsList: json["Mohemm_ITG_TicketTransactionsList"], - mohemmItgTicketsByEmployeeList: json["Mohemm_ITG_TicketsByEmployeeList"], - mohemmItgProjectsList: json["Mohemm_Itg_ProjectsList"], - mohemmItgTicketTypesList: json["Mohemm_Itg_TicketTypesList"], - referenceNumber: json["ReferenceNumber"] == null ? null : DateTime.parse(json["ReferenceNumber"]), - requestType: json["RequestType"], - totalCount: json["TotalCount"] == null ? null : json["TotalCount"], - statuseCode: json["statuseCode"] == null ? null : json["statuseCode"], - ); + date: json["Date"], + languageId: json["LanguageID"] == null ? null : json["LanguageID"], + serviceName: json["ServiceName"] == null ? null : json["ServiceName"], + time: json["Time"], + androidLink: json["AndroidLink"], + authenticationTokenId: json["AuthenticationTokenID"], + data: json["Data"], + dataw: json["Dataw"] == null ? null : json["Dataw"], + dietType: json["DietType"] == null ? null : json["DietType"], + dietTypeId: json["DietTypeID"] == null ? null : json["DietTypeID"], + errorCode: json["ErrorCode"], + errorEndUserMessage: json["ErrorEndUserMessage"], + errorEndUserMessageN: json["ErrorEndUserMessageN"], + errorMessage: json["ErrorMessage"], + errorType: json["ErrorType"] == null ? null : json["ErrorType"], + foodCategory: json["FoodCategory"] == null ? null : json["FoodCategory"], + iosLink: json["IOSLink"], + isAuthenticated: json["IsAuthenticated"] == null ? null : json["IsAuthenticated"], + mealOrderStatus: json["MealOrderStatus"] == null ? null : json["MealOrderStatus"], + mealType: json["MealType"] == null ? null : json["MealType"], + messageStatus: json["MessageStatus"] == null ? null : json["MessageStatus"], + numberOfResultRecords: json["NumberOfResultRecords"] == null ? null : json["NumberOfResultRecords"], + patientBlodType: json["PatientBlodType"], + successMsg: json["SuccessMsg"] == null ? null : json["SuccessMsg"], + successMsgN: json["SuccessMsgN"], + vidaUpdatedResponse: json["VidaUpdatedResponse"], + itgRequest: json["ITGRequest"], + itgFormAttachmentsList: json["Itg_FormAttachmentsList"], + message: json["Message"] == null ? null : json["Message"], + mohemmItgDepartmentSectionsList: json["Mohemm_ITG_DepartmentSectionsList"], + mohemmItgProjectDepartmentsList: json["Mohemm_ITG_ProjectDepartmentsList"], + mohemmItgResponseItem: json["Mohemm_ITG_ResponseItem"], + mohemmItgSectionTopicsList: json["Mohemm_ITG_SectionTopicsList"], + mohemmItgTicketDetailsList: json["Mohemm_ITG_TicketDetailsList"], + mohemmItgTicketTransactionsList: json["Mohemm_ITG_TicketTransactionsList"], + mohemmItgTicketsByEmployeeList: json["Mohemm_ITG_TicketsByEmployeeList"], + mohemmItgProjectsList: json["Mohemm_Itg_ProjectsList"], + mohemmItgTicketTypesList: json["Mohemm_Itg_TicketTypesList"], + referenceNumber: json["ReferenceNumber"] == null ? null : DateTime.parse(json["ReferenceNumber"]), + requestType: json["RequestType"] == null ? [] : json['RequestType']!.map((v) => RequestType.fromJson(v)).toList(), + totalCount: json["TotalCount"] == null ? null : json["TotalCount"], + statuseCode: json["statuseCode"] == null ? null : json["statuseCode"], + ); Map toMap() => { - "Date": date, - "LanguageID": languageId == null ? null : languageId, - "ServiceName": serviceName == null ? null : serviceName, - "Time": time, - "AndroidLink": androidLink, - "AuthenticationTokenID": authenticationTokenId, - "Data": data, - "Dataw": dataw == null ? null : dataw, - "DietType": dietType == null ? null : dietType, - "DietTypeID": dietTypeId == null ? null : dietTypeId, - "ErrorCode": errorCode, - "ErrorEndUserMessage": errorEndUserMessage, - "ErrorEndUserMessageN": errorEndUserMessageN, - "ErrorMessage": errorMessage, - "ErrorType": errorType == null ? null : errorType, - "FoodCategory": foodCategory == null ? null : foodCategory, - "IOSLink": iosLink, - "IsAuthenticated": isAuthenticated == null ? null : isAuthenticated, - "MealOrderStatus": mealOrderStatus == null ? null : mealOrderStatus, - "MealType": mealType == null ? null : mealType, - "MessageStatus": messageStatus == null ? null : messageStatus, - "NumberOfResultRecords": numberOfResultRecords == null ? null : numberOfResultRecords, - "PatientBlodType": patientBlodType, - "SuccessMsg": successMsg == null ? null : successMsg, - "SuccessMsgN": successMsgN, - "VidaUpdatedResponse": vidaUpdatedResponse, - "ITGRequest": itgRequest, - "Itg_FormAttachmentsList": itgFormAttachmentsList, - "Message": message == null ? null : message, - "Mohemm_ITG_DepartmentSectionsList": mohemmItgDepartmentSectionsList, - "Mohemm_ITG_ProjectDepartmentsList": mohemmItgProjectDepartmentsList, - "Mohemm_ITG_ResponseItem": mohemmItgResponseItem, - "Mohemm_ITG_SectionTopicsList": mohemmItgSectionTopicsList, - "Mohemm_ITG_TicketDetailsList": mohemmItgTicketDetailsList, - "Mohemm_ITG_TicketTransactionsList": mohemmItgTicketTransactionsList, - "Mohemm_ITG_TicketsByEmployeeList": mohemmItgTicketsByEmployeeList, - "Mohemm_Itg_ProjectsList": mohemmItgProjectsList, - "Mohemm_Itg_TicketTypesList": mohemmItgTicketTypesList, - "ReferenceNumber": referenceNumber == null ? null : referenceNumber!.toIso8601String(), - "RequestType": requestType, - "TotalCount": totalCount == null ? null : totalCount, - "statuseCode": statuseCode == null ? null : statuseCode, - }; + "Date": date, + "LanguageID": languageId == null ? null : languageId, + "ServiceName": serviceName == null ? null : serviceName, + "Time": time, + "AndroidLink": androidLink, + "AuthenticationTokenID": authenticationTokenId, + "Data": data, + "Dataw": dataw == null ? null : dataw, + "DietType": dietType == null ? null : dietType, + "DietTypeID": dietTypeId == null ? null : dietTypeId, + "ErrorCode": errorCode, + "ErrorEndUserMessage": errorEndUserMessage, + "ErrorEndUserMessageN": errorEndUserMessageN, + "ErrorMessage": errorMessage, + "ErrorType": errorType == null ? null : errorType, + "FoodCategory": foodCategory == null ? null : foodCategory, + "IOSLink": iosLink, + "IsAuthenticated": isAuthenticated == null ? null : isAuthenticated, + "MealOrderStatus": mealOrderStatus == null ? null : mealOrderStatus, + "MealType": mealType == null ? null : mealType, + "MessageStatus": messageStatus == null ? null : messageStatus, + "NumberOfResultRecords": numberOfResultRecords == null ? null : numberOfResultRecords, + "PatientBlodType": patientBlodType, + "SuccessMsg": successMsg == null ? null : successMsg, + "SuccessMsgN": successMsgN, + "VidaUpdatedResponse": vidaUpdatedResponse, + "ITGRequest": itgRequest, + "Itg_FormAttachmentsList": itgFormAttachmentsList, + "Message": message == null ? null : message, + "Mohemm_ITG_DepartmentSectionsList": mohemmItgDepartmentSectionsList, + "Mohemm_ITG_ProjectDepartmentsList": mohemmItgProjectDepartmentsList, + "Mohemm_ITG_ResponseItem": mohemmItgResponseItem, + "Mohemm_ITG_SectionTopicsList": mohemmItgSectionTopicsList, + "Mohemm_ITG_TicketDetailsList": mohemmItgTicketDetailsList, + "Mohemm_ITG_TicketTransactionsList": mohemmItgTicketTransactionsList, + "Mohemm_ITG_TicketsByEmployeeList": mohemmItgTicketsByEmployeeList, + "Mohemm_Itg_ProjectsList": mohemmItgProjectsList, + "Mohemm_Itg_TicketTypesList": mohemmItgTicketTypesList, + "ReferenceNumber": referenceNumber == null ? null : referenceNumber!.toIso8601String(), + "RequestType": requestType == null ? null : requestType!.map((v) => v.toJson()).toList(), + "TotalCount": totalCount == null ? null : totalCount, + "statuseCode": statuseCode == null ? null : statuseCode, + }; +} + +class RequestType { + int? itemCount; + List? requestDetails; + String? requestTypeCode; + String? requestTypeName; + + RequestType({this.itemCount, this.requestDetails, this.requestTypeCode, this.requestTypeName}); + + RequestType.fromJson(Map json) { + itemCount = json['ItemCount']; + if (json['RequestDetails'] != null) { + requestDetails = []; + json['RequestDetails'].forEach((v) { + requestDetails!.add(new RequestDetails.fromJson(v)); + }); + } + requestTypeCode = json['RequestTypeCode']; + requestTypeName = json['RequestTypeName']; + } + + Map toJson() { + final Map data = new Map(); + data['ItemCount'] = this.itemCount; + if (this.requestDetails != null) { + data['RequestDetails'] = this.requestDetails!.map((v) => v.toJson()).toList(); + } + data['RequestTypeCode'] = this.requestTypeCode; + data['RequestTypeName'] = this.requestTypeName; + return data; + } +} + +class RequestDetails { + int? iD; + int? itemID; + String? listID; + String? listName; + String? modifiedDate; + String? title; + String? uRL; + + RequestDetails({this.iD, this.itemID, this.listID, this.listName, this.modifiedDate, this.title, this.uRL}); + + RequestDetails.fromJson(Map json) { + iD = json['ID']; + itemID = json['ItemID']; + listID = json['ListID']; + listName = json['ListName']; + modifiedDate = json['ModifiedDate']; + title = json['Title']; + uRL = json['URL']; + } + + Map toJson() { + final Map data = new Map(); + data['ID'] = this.iD; + data['ItemID'] = this.itemID; + data['ListID'] = this.listID; + data['ListName'] = this.listName; + data['ModifiedDate'] = this.modifiedDate; + data['Title'] = this.title; + data['URL'] = this.uRL; + return data; + } } diff --git a/lib/models/dashboard/list_menu.dart b/lib/models/dashboard/list_menu.dart new file mode 100644 index 0000000..a55cd79 --- /dev/null +++ b/lib/models/dashboard/list_menu.dart @@ -0,0 +1,39 @@ +class ListMenu { + ListMenu({ + this.menuId, + this.menuName, + this.menuType, + this.requestGroupId, + this.requestGroupName, + this.respId, + this.subMenuName, + }); + + int? menuId; + String? menuName; + String? menuType; + int? requestGroupId; + String? requestGroupName; + dynamic? respId; + String? subMenuName; + + factory ListMenu.fromJson(Map json) => ListMenu( + menuId: json["MENU_ID"] == null ? null : json["MENU_ID"], + menuName: json["MENU_NAME"] == null ? null : json["MENU_NAME"], + menuType: json["MENU_TYPE"] == null ? null : json["MENU_TYPE"], + requestGroupId: json["REQUEST_GROUP_ID"] == null ? null : json["REQUEST_GROUP_ID"], + requestGroupName: json["REQUEST_GROUP_NAME"] == null ? null : json["REQUEST_GROUP_NAME"], + respId: json["RESP_ID"], + subMenuName: json["SUB_MENU_NAME"] == null ? null : json["SUB_MENU_NAME"], + ); + + Map toJson() => { + "MENU_ID": menuId == null ? null : menuId, + "MENU_NAME": menuName == null ? null : menuName, + "MENU_TYPE": menuType == null ? null : menuType, + "REQUEST_GROUP_ID": requestGroupId == null ? null : requestGroupId, + "REQUEST_GROUP_NAME": requestGroupName == null ? null : requestGroupName, + "RESP_ID": respId, + "SUB_MENU_NAME": subMenuName == null ? null : subMenuName, + }; +} diff --git a/lib/models/dashboard/menu_entries.dart b/lib/models/dashboard/menu_entries.dart new file mode 100644 index 0000000..7678ad8 --- /dev/null +++ b/lib/models/dashboard/menu_entries.dart @@ -0,0 +1,60 @@ +class GetMenuEntriesList { + GetMenuEntriesList({ + this.addButton, + this.deleteButton, + this.entrySequence, + this.functionName, + this.icon, + this.lvl, + this.menuEntryType, + this.menuName, + this.parentMenuName, + this.prompt, + this.requestType, + this.updateButton, + }); + + String? addButton; + String? deleteButton; + int? entrySequence; + String? functionName; + String? icon; + int? lvl; + String? menuEntryType; + String? menuName; + String? parentMenuName; + String? prompt; + String? requestType; + String? updateButton; + + factory GetMenuEntriesList.fromJson(Map json) => GetMenuEntriesList( + addButton: json["ADD_BUTTON"] == null ? null : json["ADD_BUTTON"], + deleteButton: json["DELETE_BUTTON"] == null ? null : json["DELETE_BUTTON"], + entrySequence: json["ENTRY_SEQUENCE"] == null ? null : json["ENTRY_SEQUENCE"], + functionName: json["FUNCTION_NAME"] == null ? null : json["FUNCTION_NAME"], + icon: json["ICON"] == null ? null : json["ICON"], + lvl: json["LVL"] == null ? null : json["LVL"], + menuEntryType: json["MENU_ENTRY_TYPE"] == null ? null : json["MENU_ENTRY_TYPE"], + menuName: json["MENU_NAME"] == null ? null : json["MENU_NAME"], + parentMenuName: json["PARENT_MENU_NAME"] == null ? null : json["PARENT_MENU_NAME"], + prompt: json["PROMPT"] == null ? null : json["PROMPT"], + requestType: json["REQUEST_TYPE"] == null ? null : json["REQUEST_TYPE"], + updateButton: json["UPDATE_BUTTON"] == null ? null :json["UPDATE_BUTTON"], + ); + + Map toJson() => { + "ADD_BUTTON": addButton == null ? null :addButton, + "DELETE_BUTTON": deleteButton == null ? null : deleteButton, + "ENTRY_SEQUENCE": entrySequence == null ? null : entrySequence, + "FUNCTION_NAME": functionName == null ? null : functionName, + "ICON": icon == null ? null : icon, + "LVL": lvl == null ? null : lvl, + "MENU_ENTRY_TYPE": menuEntryType == null ? null : menuEntryType, + "MENU_NAME": menuName == null ? null : menuName, + "PARENT_MENU_NAME": parentMenuName == null ? null : parentMenuName, + "PROMPT": prompt == null ? null : prompt, + "REQUEST_TYPE": requestType == null ? null : requestType, + "UPDATE_BUTTON": updateButton == null ? null : updateButton, + }; +} + diff --git a/lib/models/dashboard/menus.dart b/lib/models/dashboard/menus.dart new file mode 100644 index 0000000..7b88a33 --- /dev/null +++ b/lib/models/dashboard/menus.dart @@ -0,0 +1,10 @@ +import 'package:mohem_flutter_app/models/dashboard/menu_entries.dart'; + +class Menus { + GetMenuEntriesList menuEntry; + List menuEntiesList; + + Menus(this.menuEntry, this.menuEntiesList); + + +} diff --git a/lib/models/generic_response_model.dart b/lib/models/generic_response_model.dart index fad6e51..0b5c497 100644 --- a/lib/models/generic_response_model.dart +++ b/lib/models/generic_response_model.dart @@ -1,10 +1,14 @@ import 'package:mohem_flutter_app/models/member_login_list_model.dart'; +import 'package:mohem_flutter_app/models/worklist_response_model.dart'; import 'basic_member_information_model.dart'; +import 'get_mobile_login_info_list_model.dart'; import 'dashboard/get_accrual_balances_list_model.dart'; import 'dashboard/get_attendance_tracking_list_model.dart'; import 'dashboard/get_open_missing_swipes_list_model.dart'; import 'dashboard/get_open_notifications_list.dart'; +import 'dashboard/list_menu.dart'; +import 'dashboard/menu_entries.dart'; import 'member_information_list_model.dart'; import 'privilege_list_model.dart'; @@ -67,7 +71,7 @@ class GenericResponseModel { List? getAddressNotificationBodyList; List? getApprovesList; List? getAttachementList; - GetAttendanceTrackingList? getAttendanceTrackingList; + GetAttendanceTracking? getAttendanceTrackingList; List? getBasicDetColsStructureList; List? getBasicDetDffStructureList; List? getBasicDetNtfBodyList; @@ -103,7 +107,7 @@ class GenericResponseModel { List? getItemTypeNotificationsList; List? getItemTypesList; List? getLookupValuesList; - List? getMenuEntriesList; + List? getMenuEntriesList; List? getMoItemHistoryList; List? getMoNotificationBodyList; List? getNotificationButtonsList; @@ -147,7 +151,7 @@ class GenericResponseModel { List? getVaccinationOnHandList; List? getVaccinationsList; List? getValueSetValuesList; - List? getWorkList; + List? getWorkList; String? hRCertificateTemplate; String? imgURLsList; String? insertApInv; @@ -169,7 +173,7 @@ class GenericResponseModel { String? listItemImagesDetails; String? listItemMaster; String? listMedicineDetails; - String? listMenu; + List? listMenu; String? listNewEmployees; String? listRadScreen; String? logInTokenID; @@ -178,7 +182,7 @@ class GenericResponseModel { String? mohemmGetBusinessCardEnabledList; List? mohemmGetFavoriteReplacementsList; String? mohemmGetMobileDeviceInfobyEmpInfoList; - String? mohemmGetMobileLoginInfoList; + List? mohemmGetMobileLoginInfoList; String? mohemmGetPatientIDList; String? mohemmITGResponseItem; bool? mohemmIsChangeIsActiveBusinessCardEnable; @@ -198,7 +202,7 @@ class GenericResponseModel { String? pINFORMATION; int? pMBLID; String? pNUMOFSUBORDINATES; - String? pOPENNTFNUMBER; + int? pOPENNTFNUMBER; String? pQUESTION; int? pSESSIONID; String? pSchema; @@ -567,15 +571,13 @@ class GenericResponseModel { getAbsenceCollectionNotificationBodyList = json['GetAbsenceCollectionNotificationBodyList']; getAbsenceDffStructureList = json['GetAbsenceDffStructureList']; getAbsenceTransactionList = json['GetAbsenceTransactionList']; - getAccrualBalancesList: - json["GetAccrualBalancesList"] == null ? null : List.from(json["GetAccrualBalancesList"].map((x) => GetAccrualBalancesList.fromJson(x))); + getAccrualBalancesList = json["GetAccrualBalancesList"] == null ? null : List.from(json["GetAccrualBalancesList"].map((x) => GetAccrualBalancesList.fromJson(x))); getActionHistoryList = json['GetActionHistoryList']; getAddressDffStructureList = json['GetAddressDffStructureList']; getAddressNotificationBodyList = json['GetAddressNotificationBodyList']; getApprovesList = json['GetApprovesList']; getAttachementList = json['GetAttachementList']; - getAttendanceTrackingList: - json["GetAttendanceTrackingList"] == null ? null : GetAttendanceTrackingList.fromMap(json["GetAttendanceTrackingList"]); + getAttendanceTrackingList = json["GetAttendanceTrackingList"] == null ? null : GetAttendanceTracking.fromMap(json["GetAttendanceTrackingList"]); getBasicDetColsStructureList = json['GetBasicDetColsStructureList']; getBasicDetDffStructureList = json['GetBasicDetDffStructureList']; getBasicDetNtfBodyList = json['GetBasicDetNtfBodyList']; @@ -611,15 +613,14 @@ class GenericResponseModel { getItemTypeNotificationsList = json['GetItemTypeNotificationsList']; getItemTypesList = json['GetItemTypesList']; getLookupValuesList = json['GetLookupValuesList']; - getMenuEntriesList = json['GetMenuEntriesList']; + getMenuEntriesList = json["GetMenuEntriesList"] == null ? null : List.from(json["GetMenuEntriesList"].map((x) => GetMenuEntriesList.fromJson(x))); getMoItemHistoryList = json['GetMoItemHistoryList']; getMoNotificationBodyList = json['GetMoNotificationBodyList']; getNotificationButtonsList = json['GetNotificationButtonsList']; getNotificationReassignModeList = json['GetNotificationReassignModeList']; getObjectValuesList = json['GetObjectValuesList']; - getOpenMissingSwipesList: json["GetOpenMissingSwipesList"] == null ? null : GetOpenMissingSwipesList.fromJson(json["GetOpenMissingSwipesList"]); - getOpenNotificationsList: - json["GetOpenNotificationsList"] == null ? null : List.from(json["GetOpenNotificationsList"].map((x) => GetOpenNotificationsList.fromMap(x))); + getOpenMissingSwipesList = json["GetOpenMissingSwipesList"] == null ? null : GetOpenMissingSwipesList.fromJson(json["GetOpenMissingSwipesList"]); + getOpenNotificationsList = json["GetOpenNotificationsList"] == null ? null : List.from(json["GetOpenNotificationsList"].map((x) => GetOpenNotificationsList.fromMap(x))); getOpenNotificationsNumList = json['GetOpenNotificationsNumList']; getOpenPeriodDatesList = json['GetOpenPeriodDatesList']; getOrganizationsSalariesList = json['GetOrganizationsSalariesList']; @@ -656,7 +657,14 @@ class GenericResponseModel { getVaccinationOnHandList = json['GetVaccinationOnHandList']; getVaccinationsList = json['GetVaccinationsList']; getValueSetValuesList = json['GetValueSetValuesList']; - getWorkList = json['GetWorkList']; + + if (json['GetWorkList'] != null) { + getWorkList = []; + json['GetWorkList'].forEach((v) { + getWorkList!.add(WorkListResponseModel.fromJson(v)); + }); + } + hRCertificateTemplate = json['HRCertificateTemplate']; imgURLsList = json['ImgURLsList']; insertApInv = json['InsertApInv']; @@ -678,7 +686,7 @@ class GenericResponseModel { listItemImagesDetails = json['List_ItemImagesDetails']; listItemMaster = json['List_ItemMaster']; listMedicineDetails = json['List_MedicineDetails']; - listMenu = json['List_Menu']; + listMenu = json["List_Menu"] == null ? null : List.from(json["List_Menu"].map((x) => ListMenu.fromJson(x))); listNewEmployees = json['List_NewEmployees']; listRadScreen = json['List_RadScreen']; logInTokenID = json['LogInTokenID']; @@ -692,7 +700,12 @@ class GenericResponseModel { mohemmGetBusinessCardEnabledList = json['Mohemm_GetBusinessCardEnabledList']; mohemmGetFavoriteReplacementsList = json['Mohemm_GetFavoriteReplacementsList']; mohemmGetMobileDeviceInfobyEmpInfoList = json['Mohemm_GetMobileDeviceInfobyEmpInfoList']; - mohemmGetMobileLoginInfoList = json['Mohemm_GetMobileLoginInfoList']; + if (json['Mohemm_GetMobileLoginInfoList'] != null) { + mohemmGetMobileLoginInfoList = []; + json['Mohemm_GetMobileLoginInfoList'].forEach((v) { + mohemmGetMobileLoginInfoList!.add(new GetMobileLoginInfoListModel.fromJson(v)); + }); + } mohemmGetPatientIDList = json['Mohemm_GetPatientID_List']; mohemmITGResponseItem = json['Mohemm_ITG_ResponseItem']; mohemmIsChangeIsActiveBusinessCardEnable = json['Mohemm_IsChangeIsActiveBusinessCardEnable']; @@ -925,7 +938,11 @@ class GenericResponseModel { data['GetVaccinationOnHandList'] = this.getVaccinationOnHandList; data['GetVaccinationsList'] = this.getVaccinationsList; data['GetValueSetValuesList'] = this.getValueSetValuesList; - data['GetWorkList'] = this.getWorkList; + + if (getWorkList != null) { + data['GetWorkList'] = getWorkList!.map((v) => v.toJson()).toList(); + } + data['HRCertificateTemplate'] = this.hRCertificateTemplate; data['ImgURLsList'] = this.imgURLsList; data['InsertApInv'] = this.insertApInv; @@ -958,7 +975,9 @@ class GenericResponseModel { data['Mohemm_GetBusinessCardEnabledList'] = this.mohemmGetBusinessCardEnabledList; data['Mohemm_GetFavoriteReplacementsList'] = this.mohemmGetFavoriteReplacementsList; data['Mohemm_GetMobileDeviceInfobyEmpInfoList'] = this.mohemmGetMobileDeviceInfobyEmpInfoList; - data['Mohemm_GetMobileLoginInfoList'] = this.mohemmGetMobileLoginInfoList; + if (this.mohemmGetMobileLoginInfoList != null) { + data['Mohemm_GetMobileLoginInfoList'] = this.mohemmGetMobileLoginInfoList!.map((v) => v.toJson()).toList(); + } data['Mohemm_GetPatientID_List'] = this.mohemmGetPatientIDList; data['Mohemm_ITG_ResponseItem'] = this.mohemmITGResponseItem; data['Mohemm_IsChangeIsActiveBusinessCardEnable'] = this.mohemmIsChangeIsActiveBusinessCardEnable; diff --git a/lib/models/get_mobile_login_info_list_model.dart b/lib/models/get_mobile_login_info_list_model.dart new file mode 100644 index 0000000..ff419f2 --- /dev/null +++ b/lib/models/get_mobile_login_info_list_model.dart @@ -0,0 +1,64 @@ +class GetMobileLoginInfoListModel { + int? iD; + int? employeeID; + int? channelID; + int? companyID; + String? deviceType; + String? deviceToken; + int? language; + int? gender; + int? loginType; + String? createdOn; + String? editedOn; + String? employeeName; + bool? businessCardPrivilege; + + GetMobileLoginInfoListModel( + {this.iD, + this.employeeID, + this.channelID, + this.companyID, + this.deviceType, + this.deviceToken, + this.language, + this.gender, + this.loginType, + this.createdOn, + this.editedOn, + this.employeeName, + this.businessCardPrivilege}); + + GetMobileLoginInfoListModel.fromJson(Map json) { + iD = json['ID']; + employeeID = json['EmployeeID']; + channelID = json['ChannelID']; + companyID = json['CompanyID']; + deviceType = json['DeviceType']; + deviceToken = json['DeviceToken']; + language = json['Language']; + gender = json['Gender']; + loginType = json['LoginType']; + createdOn = json['CreatedOn']; + editedOn = json['EditedOn']; + employeeName = json['EmployeeName']; + businessCardPrivilege = json['BusinessCardPrivilege']; + } + + Map toJson() { + final Map data = Map(); + data['ID'] = iD; + data['EmployeeID'] = employeeID; + data['ChannelID'] = channelID; + data['CompanyID'] = companyID; + data['DeviceType'] = deviceType; + data['DeviceToken'] = deviceToken; + data['Language'] = language; + data['Gender'] = gender; + data['LoginType'] = loginType; + data['CreatedOn'] = createdOn; + data['EditedOn'] = editedOn; + data['EmployeeName'] = employeeName; + data['BusinessCardPrivilege'] = businessCardPrivilege; + return data; + } +} diff --git a/lib/models/member_information_list_model.dart b/lib/models/member_information_list_model.dart index a3bc05f..dc64e53 100644 --- a/lib/models/member_information_list_model.dart +++ b/lib/models/member_information_list_model.dart @@ -1,3 +1,8 @@ +import 'dart:convert'; + +import 'package:mohem_flutter_app/classes/consts.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + class MemberInformationListModel { String? aCTUALTERMINATIONDATE; String? aSSIGNMENTENDDATE; @@ -27,7 +32,7 @@ class MemberInformationListModel { String? fREQUENCY; String? fREQUENCYMEANING; int? fROMROWNUM; - String? gRADEID; + int? gRADEID; String? gRADENAME; String? hIREDATE; int? jOBID; @@ -333,4 +338,16 @@ class MemberInformationListModel { data['USER_STATUS'] = this.uSERSTATUS; return data; } + + static Future> getFromPrefs() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + List encodedList = prefs.getStringList(SharedPrefsConsts.memberInformation) ?? []; + return encodedList.map((e) => MemberInformationListModel.fromJson(jsonDecode(e))).toList(); + } + + static void saveToPrefs(List list) async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + List encodedList = list.map((e) => jsonEncode(e.toJson())).toList(); + await prefs.setStringList(SharedPrefsConsts.memberInformation, encodedList); + } } \ No newline at end of file diff --git a/lib/models/privilege_list_model.dart b/lib/models/privilege_list_model.dart index 3ef3954..ad83500 100644 --- a/lib/models/privilege_list_model.dart +++ b/lib/models/privilege_list_model.dart @@ -1,3 +1,8 @@ +import 'dart:convert'; + +import 'package:mohem_flutter_app/classes/consts.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + class PrivilegeListModel { int? iD; String? serviceName; @@ -18,4 +23,16 @@ class PrivilegeListModel { data['Previlege'] = this.previlege; return data; } + + static Future> getFromPrefs() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + List encodedList = prefs.getStringList(SharedPrefsConsts.privilegeList) ?? []; + return encodedList.map((e) => PrivilegeListModel.fromJson(jsonDecode(e))).toList(); + } + + static void saveToPrefs(List list) async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + List encodedList = list.map((e) => jsonEncode(e.toJson())).toList(); + await prefs.setStringList(SharedPrefsConsts.privilegeList, encodedList); + } } diff --git a/lib/models/worklist_item_type_model.dart b/lib/models/worklist_item_type_model.dart new file mode 100644 index 0000000..49346c0 --- /dev/null +++ b/lib/models/worklist_item_type_model.dart @@ -0,0 +1,38 @@ +import 'dart:ui'; + +class WorkListItemTypeModelData { + late int value; + late String name; + late String fullName; + late bool active; + late List color; + late String icon; + late String key; + late bool disable; + + WorkListItemTypeModelData({required this.value, required this.name, required this.fullName, required this.active, required this.color, required this.icon, required this.key, required this.disable}); + + WorkListItemTypeModelData.fromJson(Map json) { + value = json['value']; + name = json['name']; + fullName = json['fullName']; + active = json['active']; + color = json['color']; + icon = json['icon']; + key = json['key']; + disable = json['disable']; + } + + Map toJson() { + final Map data = {}; + data['value'] = value; + data['name'] = name; + data['fullName'] = fullName; + data['active'] = active; + data['color'] = color; + data['icon'] = icon; + data['key'] = key; + data['disable'] = disable; + return data; + } +} diff --git a/lib/models/worklist_response_model.dart b/lib/models/worklist_response_model.dart new file mode 100644 index 0000000..4899d5a --- /dev/null +++ b/lib/models/worklist_response_model.dart @@ -0,0 +1,137 @@ + +class WorkListResponseModel { + String? bEGINDATE; + String? dUEDATE; + String? eNDDATE; + String? fROMROLE; + int? fROMROWNUM; + String? fROMUSER; + String? fUNCTIONNAME; + String? iTEMKEY; + String? iTEMTYPE; + String? iTEMTYPEDISPLAYNAME; + String? lANGUAGE; + String? mAILSTATUS; + String? mOREINFOROLE; + int? nOTIFICATIONID; + String? nOTIFICATIONNAME; + int? nOOFROWS; + String? oRIGINALRECIPIENT; + String? pONUMBER; + int? pRIORITY; + String? pRIORITYF; + String? pRNUMBER; + String? rECIPIENTROLE; + String? rEQUESTNUMBER; + String? rEQUESTTYPE; + String? rESPONDER; + int? rOWNUM; + String? sELECTEDEMPLOYEENUMBER; + String? sTATUS; + String? sUBJECT; + int? tOROWNUM; + String? tOUSER; + + WorkListResponseModel( + {this.bEGINDATE, + this.dUEDATE, + this.eNDDATE, + this.fROMROLE, + this.fROMROWNUM, + this.fROMUSER, + this.fUNCTIONNAME, + this.iTEMKEY, + this.iTEMTYPE, + this.iTEMTYPEDISPLAYNAME, + this.lANGUAGE, + this.mAILSTATUS, + this.mOREINFOROLE, + this.nOTIFICATIONID, + this.nOTIFICATIONNAME, + this.nOOFROWS, + this.oRIGINALRECIPIENT, + this.pONUMBER, + this.pRIORITY, + this.pRIORITYF, + this.pRNUMBER, + this.rECIPIENTROLE, + this.rEQUESTNUMBER, + this.rEQUESTTYPE, + this.rESPONDER, + this.rOWNUM, + this.sELECTEDEMPLOYEENUMBER, + this.sTATUS, + this.sUBJECT, + this.tOROWNUM, + this.tOUSER}); + + WorkListResponseModel.fromJson(Map json) { + bEGINDATE = json['BEGIN_DATE']; + dUEDATE = json['DUE_DATE']; + eNDDATE = json['END_DATE']; + fROMROLE = json['FROM_ROLE']; + fROMROWNUM = json['FROM_ROW_NUM']; + fROMUSER = json['FROM_USER']; + fUNCTIONNAME = json['FUNCTION_NAME']; + iTEMKEY = json['ITEM_KEY']; + iTEMTYPE = json['ITEM_TYPE']; + iTEMTYPEDISPLAYNAME = json['ITEM_TYPE_DISPLAY_NAME']; + lANGUAGE = json['LANGUAGE']; + mAILSTATUS = json['MAIL_STATUS']; + mOREINFOROLE = json['MORE_INFO_ROLE']; + nOTIFICATIONID = json['NOTIFICATION_ID']; + nOTIFICATIONNAME = json['NOTIFICATION_NAME']; + nOOFROWS = json['NO_OF_ROWS']; + oRIGINALRECIPIENT = json['ORIGINAL_RECIPIENT']; + pONUMBER = json['PO_NUMBER']; + pRIORITY = json['PRIORITY']; + pRIORITYF = json['PRIORITY_F']; + pRNUMBER = json['PR_NUMBER']; + rECIPIENTROLE = json['RECIPIENT_ROLE']; + rEQUESTNUMBER = json['REQUEST_NUMBER']; + rEQUESTTYPE = json['REQUEST_TYPE']; + rESPONDER = json['RESPONDER']; + rOWNUM = json['ROW_NUM']; + sELECTEDEMPLOYEENUMBER = json['SELECTED_EMPLOYEE_NUMBER']; + sTATUS = json['STATUS']; + sUBJECT = json['SUBJECT']; + tOROWNUM = json['TO_ROW_NUM']; + tOUSER = json['TO_USER']; + } + + Map toJson() { + final Map data = new Map(); + data['BEGIN_DATE'] = this.bEGINDATE; + data['DUE_DATE'] = this.dUEDATE; + data['END_DATE'] = this.eNDDATE; + data['FROM_ROLE'] = this.fROMROLE; + data['FROM_ROW_NUM'] = this.fROMROWNUM; + data['FROM_USER'] = this.fROMUSER; + data['FUNCTION_NAME'] = this.fUNCTIONNAME; + data['ITEM_KEY'] = this.iTEMKEY; + data['ITEM_TYPE'] = this.iTEMTYPE; + data['ITEM_TYPE_DISPLAY_NAME'] = this.iTEMTYPEDISPLAYNAME; + data['LANGUAGE'] = this.lANGUAGE; + data['MAIL_STATUS'] = this.mAILSTATUS; + data['MORE_INFO_ROLE'] = this.mOREINFOROLE; + data['NOTIFICATION_ID'] = this.nOTIFICATIONID; + data['NOTIFICATION_NAME'] = this.nOTIFICATIONNAME; + data['NO_OF_ROWS'] = this.nOOFROWS; + data['ORIGINAL_RECIPIENT'] = this.oRIGINALRECIPIENT; + data['PO_NUMBER'] = this.pONUMBER; + data['PRIORITY'] = this.pRIORITY; + data['PRIORITY_F'] = this.pRIORITYF; + data['PR_NUMBER'] = this.pRNUMBER; + data['RECIPIENT_ROLE'] = this.rECIPIENTROLE; + data['REQUEST_NUMBER'] = this.rEQUESTNUMBER; + data['REQUEST_TYPE'] = this.rEQUESTTYPE; + data['RESPONDER'] = this.rESPONDER; + data['ROW_NUM'] = this.rOWNUM; + data['SELECTED_EMPLOYEE_NUMBER'] = this.sELECTEDEMPLOYEENUMBER; + data['STATUS'] = this.sTATUS; + data['SUBJECT'] = this.sUBJECT; + data['TO_ROW_NUM'] = this.tOROWNUM; + data['TO_USER'] = this.tOUSER; + return data; + } +} \ No newline at end of file diff --git a/lib/provider/dashboard_provider_model.dart b/lib/provider/dashboard_provider_model.dart new file mode 100644 index 0000000..52fb6ad --- /dev/null +++ b/lib/provider/dashboard_provider_model.dart @@ -0,0 +1,190 @@ +import 'dart:convert'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:mohem_flutter_app/api/dashboard_api_client.dart'; +import 'package:mohem_flutter_app/classes/utils.dart'; +import 'package:mohem_flutter_app/main.dart'; +import 'package:mohem_flutter_app/models/dashboard/get_attendance_tracking_list_model.dart'; +import 'package:mohem_flutter_app/models/dashboard/get_open_notifications_list.dart'; +import 'package:mohem_flutter_app/models/dashboard/itg_forms_model.dart'; +import 'package:mohem_flutter_app/models/dashboard/menu_entries.dart'; +import 'package:mohem_flutter_app/models/dashboard/menus.dart'; +import 'package:mohem_flutter_app/models/generic_response_model.dart'; +import 'package:mohem_flutter_app/widgets/Updater.dart'; + +/// Mix-in [DiagnosticableTreeMixin] to have access to [debugFillProperties] for the devtool +// ignore: prefer_mixin +class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { + //Attendance Tracking + bool isAttendanceTrackingLoading = true; + int endTime = 0, isTimeRemainingInSeconds = 0; + double progress = 0.0; + GetAttendanceTracking? attendanceTracking; + + //Work List + bool isWorkListLoading = true; + int workListCounter = 0; + + //Misssing Swipe + bool isMissingSwipeLoading = true; + int missingSwipeCounter = 0; + + //Leave and Ticket Balance + bool isLeaveTicketBalanceLoading = true; + double leaveBalance = 0; + double ticketBalance = 0; + + //Menu Entries + bool isServicesMenusLoading = true; + List? homeMenus; + List? getMenuEntriesList; + + //Attendance Tracking API's & Methods + Future fetchAttendanceTracking() async { + try { + attendanceTracking = await DashboardApiClient().getAttendanceTracking(); + print("attendanceTracking:" + (attendanceTracking!.pRemainingHours).toString()); + isAttendanceTrackingLoading = false; + // isTimeRemainingInSeconds = calculateSeconds( "00:00:00"); + if (attendanceTracking?.pSwipeIn != null) { + isTimeRemainingInSeconds = calculateSeconds(attendanceTracking!.pRemainingHours ?? "00:00:00"); + int totalShiftTimeInSeconds = calculateSeconds(attendanceTracking!.pScheduledHours ?? "00:00:00"); + print("totalShiftTimeInSeconds: " + totalShiftTimeInSeconds.toString()); + print("isTimeRemainingInSeconds: " + isTimeRemainingInSeconds.toString()); + progress = (isTimeRemainingInSeconds / totalShiftTimeInSeconds); + endTime = DateTime.now().millisecondsSinceEpoch + Duration(seconds: isTimeRemainingInSeconds).inMilliseconds; + print("endTime " + endTime.toString()); + } + + notifyListeners(); + } catch (ex) { + Utils.handleException(ex, null); + } + return true; + } + + int calculateSeconds(String time) { + int hour = int.parse(time.split(":")[0]); + int mints = int.parse(time.split(":")[1]); + int seconds = int.parse(time.split(":")[2]); + return ((hour * 60 * 60) + (mints * 60) + seconds); + } + + update() { + fetchAttendanceTracking(); + // isAttendanceTrackingLoading = !isAttendanceTrackingLoading; + // isWorkListLoading = !isWorkListLoading; + // attendanceTracking?.pSwipeIn = "a"; + // isTimeRemainingInSeconds = calculateSeconds("00:10:30"); + // endTime = DateTime.now().millisecondsSinceEpoch + Duration(seconds: isTimeRemainingInSeconds).inMilliseconds; + // notifyListeners(); + } + + ItgFormsModel? itgFormsModel; + List? getOpenNotificationsList; + + //Work List API's & Methods + Future fetchWorkListCounter(context, {bool showLoading = false}) async { + try { + if (showLoading) Utils.showLoading(context); + GenericResponseModel? genericResponseModel = await DashboardApiClient().getOpenNotifications(); + isWorkListLoading = false; + getOpenNotificationsList = genericResponseModel?.getOpenNotificationsList; + workListCounter = genericResponseModel?.pOPENNTFNUMBER ?? 0; + itgFormsModel = await DashboardApiClient().getItgFormsPendingTask(); + workListCounter = workListCounter + (itgFormsModel?.totalCount ?? 0); + if (showLoading) Utils.hideLoading(context); + notifyListeners(); + } catch (ex) { + isWorkListLoading = false; + logger.wtf(ex); + if (showLoading) Utils.hideLoading(context); + notifyListeners(); + Utils.handleException(ex, null); + } + } + + //Missing Siwpe API's & Methods + Future fetchMissingSwipe() async { + try { + GenericResponseModel? genericResponseModel = await DashboardApiClient().getOpenMissingSwipes(); + isMissingSwipeLoading = false; + missingSwipeCounter = genericResponseModel!.getOpenMissingSwipesList!.pOpenMissingSwipes ?? 0; + notifyListeners(); + } catch (ex) { + isMissingSwipeLoading = false; + logger.wtf(ex); + notifyListeners(); + Utils.handleException(ex, null); + } + } + + //Leave and Ticket Balance API's & Methods + Future fetchLeaveTicketBalance() async { + try { + GenericResponseModel? genericResponseModel = await DashboardApiClient().getAccrualBalances(); + isLeaveTicketBalanceLoading = false; + leaveBalance = genericResponseModel?.getAccrualBalancesList![0].accrualNetEntitlement ?? 0.0; + ticketBalance = (genericResponseModel?.getAccrualBalancesList![1].accrualNetEntitlement ?? 0.0) + (genericResponseModel?.getAccrualBalancesList![2].accrualNetEntitlement ?? 0.0); + notifyListeners(); + } catch (ex) { + isLeaveTicketBalanceLoading = false; + logger.wtf(ex); + notifyListeners(); + Utils.handleException(ex, null); + } + } + + //List Menu API's & Methods + fetchListMenu() async { + try { + GenericResponseModel? genericResponseModel = await DashboardApiClient().getListMenu(); + Map map = {}; + print(jsonEncode(genericResponseModel!.listMenu)); + for (int i = 0; i < genericResponseModel.listMenu!.length; i++) { + print(genericResponseModel.listMenu![i].menuName ?? ""); + map[genericResponseModel.listMenu![i].menuName ?? ""] = i.toString(); + } + logger.i(map); + notifyListeners(); + } catch (ex) { + logger.wtf(ex); + notifyListeners(); + Utils.handleException(ex, null); + } + } + + //Menu Entries API's & Methods + fetchMenuEntries() async { + try { + GenericResponseModel? genericResponseModel = await DashboardApiClient().getGetMenuEntries(); + getMenuEntriesList = genericResponseModel!.getMenuEntriesList; + homeMenus = parseMenues(getMenuEntriesList ?? []); + isServicesMenusLoading = false; + notifyListeners(); + } catch (ex) { + logger.wtf(ex); + notifyListeners(); + Utils.handleException(ex, null); + } + } + + List parseMenues(List getMenuEntriesList) { + List menus = []; + for (int i = 0; i < getMenuEntriesList.length; i++) { + if (getMenuEntriesList[i].parentMenuName!.isEmpty) { + menus.add(Menus(getMenuEntriesList[i], getMenuEntriesList.where((element) => getMenuEntriesList[i].menuName == element.parentMenuName).toList())); + } + } + + // Verify Menus by printing in log + // for(int i=0;i { - @override - void initState() { - super.initState(); - DashbaordApiClient().getAttendanceTracking(); - } - - @override - void dispose() { - super.dispose(); - } - - @override - Widget build(BuildContext context) { - List names = [LocaleKeys.workList.tr(), LocaleKeys.missingSwipes.tr(), LocaleKeys.leaveBalance.tr(), LocaleKeys.ticketBalance.tr()]; - List namesInt = [118, 02, 18.5, 03]; - List namesColor = [0xff125765, 0xff239D8F, 0xff2BB8A8, 0xff1D92AA]; - - List namesT = [LocaleKeys.monthlyAttendance.tr(), LocaleKeys.workFromHome.tr(), LocaleKeys.ticketRequest.tr(), LocaleKeys.monthlyAttendance.tr()]; - List iconT = ["assets/images/monthly_attendance.svg", "assets/images/work_from_home.svg", "assets/images/ticket_request.svg", "assets/images/work_from_home.svg"]; - - List namesD = ["Nostalgia Perfume Perfume", "Al Nafoura", "AlJadi", "Nostalgia Perfume"]; - // DashbaordApiClient().getOpenNotifications(); - DashbaordApiClient().getOpenMissingSwipes(); - return Scaffold( - body: Column( - children: [ - Row( - children: [ - Row( - mainAxisSize: MainAxisSize.min, - children: [ - CircularAvatar( - width: 34, - height: 34, - url: "https://cdn4.iconfinder.com/data/icons/professions-2-2/151/89-512.png", - ), - 8.width, - SvgPicture.asset("assets/images/side_nav.svg"), - ], - ).onPress(() {}), - Expanded( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - //AppLogo(), - 8.width, - LocaleKeys.mohemm.tr().toText14() - ], - ), - ), - SizedBox( - width: 36, - height: 36, - child: Stack( - alignment: Alignment.centerLeft, - children: [ - SvgPicture.asset("assets/images/announcements.svg"), - Positioned( - right: 0, - top: 0, - child: Container( - padding: const EdgeInsets.only(left: 5, right: 5), - decoration: BoxDecoration(color: MyColors.redColor, borderRadius: BorderRadius.circular(17)), - child: "3".toText12(color: Colors.white), - ), - ) - ], - ), - ) - ], - ).paddingOnly(left: 21, right: 21, top: 48, bottom: 7), - Expanded( - child: ListView( - padding: EdgeInsets.zero, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - LocaleKeys.goodMorning.tr().toText14(color: MyColors.grey77Color), - "Mahmoud Shrouf".toText24(isBold: true), - 16.height, - Row( - children: [ - Expanded( - child: AspectRatio( - aspectRatio: 159 / 159, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(15), - gradient: const LinearGradient(transform: GradientRotation(.46), begin: Alignment.topRight, end: Alignment.bottomRight, colors: [ - MyColors.gradiantEndColor, - MyColors.gradiantStartColor, - ]), - ), - child: Stack( - alignment: Alignment.center, - children: [ - // SvgPicture.asset("assets/images/"), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - LocaleKeys.markAttendance.tr().toText14(color: Colors.white, isBold: true), - 9.height, - "07:55:12".toText14(color: Colors.white, isBold: true), - LocaleKeys.timeLeftToday.tr().toText12(color: Colors.white), - 9.height, - const ClipRRect( - borderRadius: BorderRadius.all( - Radius.circular(20), - ), - child: LinearProgressIndicator( - value: 0.7, - minHeight: 8, - valueColor: const AlwaysStoppedAnimation(Colors.white), - backgroundColor: const Color(0xff196D73), - ), - ), - ], - ).paddingOnly(top: 12, right: 15, left: 12), - ), - Row( - children: [ - Expanded( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [LocaleKeys.checkIn.tr().toText12(color: Colors.white), "09:00".toText14(color: Colors.white, isBold: true), 4.height], - ).paddingOnly(left: 12), - ), - Container( - width: 45, - height: 45, - padding: const EdgeInsets.only(left: 14, right: 14), - decoration: const BoxDecoration( - color: Color(0xff259EA4), - borderRadius: BorderRadius.only( - bottomRight: Radius.circular(15), - ), - ), - child: SvgPicture.asset("assets/images/stop.svg"), - ), - ], - ), - ], - ), - ], - ), - ).onPress(() { - Navigator.pushNamed(context, AppRoutes.todayAttendance); - }), - ), - ), - 9.width, - Expanded( - child: GridView.builder( - shrinkWrap: true, - primary: false, - physics: const NeverScrollableScrollPhysics(), - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2, childAspectRatio: 2 / 2, crossAxisSpacing: 9, mainAxisSpacing: 9), - padding: EdgeInsets.zero, - itemCount: 4, - itemBuilder: (BuildContext context, int index) { - return Container( - decoration: BoxDecoration( - color: Color(namesColor[index]), - borderRadius: BorderRadius.circular(10), - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - names[index].toText12(color: Colors.white), - Row( - children: [ - Expanded( - child: namesInt[index].toStringAsFixed(1).toText16(color: Colors.white, isBold: true), - ), - SvgPicture.asset("assets/images/arrow_next.svg", color: Colors.white) - ], - ) - ], - ).paddingOnly(left: 10, right: 10, bottom: 6, top: 6), - ).onPress(() { - Navigator.pushNamed(context, AppRoutes.workList); - }); - }, - ), - ), - ], - ), - 20.height, - Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - "Other".tr().toText12(), - LocaleKeys.services.tr().toText24(isBold: true), - ], - ), - ), - LocaleKeys.viewAllServices.tr().toText12(isUnderLine: true), - ], - ), - ], - ).paddingOnly(left: 21, right: 21, top: 7), - SizedBox( - height: 105 + 26, - child: ListView.separated( - shrinkWrap: true, - physics: const BouncingScrollPhysics(), - padding: const EdgeInsets.only(left: 21, right: 21, top: 13, bottom: 13), - scrollDirection: Axis.horizontal, - itemBuilder: (cxt, index) { - return AspectRatio( - aspectRatio: 105 / 105, - child: Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(15), - boxShadow: [ - BoxShadow( - color: const Color(0xff000000).withOpacity(.05), - blurRadius: 26, - offset: const Offset(0, -3), - ), - ], - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SvgPicture.asset(iconT[index]), - Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Expanded( - child: namesT[index].toText11(isBold: true), - ), - SvgPicture.asset("assets/images/arrow_next.svg").paddingOnly(bottom: 4) - ], - ) - ], - ).paddingOnly(left: 10, right: 10, bottom: 10, top: 12), - ), - ); - }, - separatorBuilder: (cxt, index) => 9.width, - itemCount: 4), - ), - 8.height, - Container( - width: double.infinity, - padding: EdgeInsets.only(top: 31), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.only(topRight: Radius.circular(50), topLeft: Radius.circular(50)), - border: Border.all(color: MyColors.lightGreyEDColor, width: 1), - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - LocaleKeys.offers.tr().toText12(), - Row( - children: [ - LocaleKeys.discounts.tr().toText24(isBold: true), - 6.width, - Container( - padding: const EdgeInsets.only(left: 8, right: 8), - decoration: BoxDecoration( - color: MyColors.yellowColor, - borderRadius: BorderRadius.circular(10), - ), - child: LocaleKeys.newString.tr().toText10(isBold: true)), - ], - ), - ], - ), - ), - LocaleKeys.viewAllOffers.tr().toText12(isUnderLine: true), - ], - ).paddingOnly(left: 21, right: 21), - SizedBox( - height: 103 + 33, - child: ListView.separated( - shrinkWrap: true, - physics: const BouncingScrollPhysics(), - padding: const EdgeInsets.only(left: 21, right: 21, top: 13), - scrollDirection: Axis.horizontal, - itemBuilder: (cxt, index) { - return SizedBox( - width: 73, - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Container( - width: 73, - height: 73, - decoration: BoxDecoration( - borderRadius: const BorderRadius.all( - Radius.circular(100), - ), - border: Border.all(color: MyColors.lightGreyEDColor, width: 1), - ), - child: ClipRRect( - borderRadius: const BorderRadius.all( - Radius.circular(50), - ), - child: Image.network( - "https://play-lh.googleusercontent.com/NPo88ojmhah4HDiposucJmfQIop4z4xc8kqJK9ITO9o-yCab2zxIp7PPB_XPj2iUojo", - fit: BoxFit.cover, - ), - ), - ), - 4.height, - Expanded( - child: namesD[6 % (index + 1)].toText12(isCenter: true, maxLine: 2), - ), - ], - ), - ); - }, - separatorBuilder: (cxt, index) => 8.width, - itemCount: 6), - ), - ], - ), - ) - ], - ), - ) - ], - ), - ); - } -} diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart new file mode 100644 index 0000000..c54dc05 --- /dev/null +++ b/lib/ui/landing/dashboard_screen.dart @@ -0,0 +1,390 @@ +import 'package:easy_localization/src/public_ext.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_countdown_timer/flutter_countdown_timer.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/config/routes.dart'; +import 'package:mohem_flutter_app/extensions/int_extensions.dart'; +import 'package:mohem_flutter_app/extensions/string_extensions.dart'; +import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; +import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; +import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; +import 'package:mohem_flutter_app/ui/landing/widget/menus_widget.dart'; +import 'package:mohem_flutter_app/ui/landing/widget/services_widget.dart'; +import 'package:mohem_flutter_app/widgets/circular_avatar.dart'; +import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart'; +import 'package:provider/provider.dart'; + +class DashboardScreen extends StatefulWidget { + DashboardScreen({Key? key}) : super(key: key); + + @override + _DashboardScreenState createState() { + return _DashboardScreenState(); + } +} + +class _DashboardScreenState extends State { + late DashboardProviderModel data; + + @override + void initState() { + super.initState(); + data = Provider.of(context, listen: false); + data.fetchAttendanceTracking(); + data.fetchWorkListCounter(context); + data.fetchMissingSwipe(); + data.fetchLeaveTicketBalance(); + data.fetchMenuEntries(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + List namesD = ["Nostalgia Perfume Perfume", "Al Nafoura", "AlJadi", "Nostalgia Perfume"]; + + return Scaffold( + body: Column( + children: [ + Row( + children: [ + Row( + mainAxisSize: MainAxisSize.min, + children: [ + CircularAvatar( + width: 34, + height: 34, + url: "https://cdn4.iconfinder.com/data/icons/professions-2-2/151/89-512.png", + ), + 8.width, + SvgPicture.asset("assets/images/side_nav.svg"), + ], + ).onPress(() {}), + Expanded( + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + //AppLogo(), + 8.width, + LocaleKeys.mohemm.tr().toText14() + ], + ), + ), + SizedBox( + width: 36, + height: 36, + child: Stack( + alignment: Alignment.centerLeft, + children: [ + SvgPicture.asset("assets/images/announcements.svg"), + Positioned( + right: 0, + top: 0, + child: Container( + padding: const EdgeInsets.only(left: 5, right: 5), + decoration: BoxDecoration(color: MyColors.redColor, borderRadius: BorderRadius.circular(17)), + child: "3".toText12(color: Colors.white), + ), + ) + ], + ), + ).onPress(() { + data.update(); + }) + ], + ).paddingOnly(left: 21, right: 21, top: 48, bottom: 7), + Expanded( + child: Column( + // padding: EdgeInsets.zero, + // physics: NeverScrollableScrollPhysics(), + children: [ + Expanded( + child: SingleChildScrollView( + child: Column( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.goodMorning.tr().toText14(color: MyColors.grey77Color), + "Mahmoud Shrouf".toText24(isBold: true), + 16.height, + Row( + children: [ + Expanded( + child: AspectRatio( + aspectRatio: 159 / 159, + child: Consumer( + builder: (context, model, child) { + return (model.isAttendanceTrackingLoading + ? GetAttendanceTrackingShimmer() + : Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(15), + gradient: const LinearGradient(transform: GradientRotation(.46), begin: Alignment.topRight, end: Alignment.bottomLeft, colors: [ + MyColors.gradiantEndColor, + MyColors.gradiantStartColor, + ]), + ), + child: Stack( + alignment: Alignment.center, + children: [ + if (model.isTimeRemainingInSeconds == 0) SvgPicture.asset("assets/images/thumb.svg"), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.markAttendance.tr().toText14(color: Colors.white, isBold: true), + if (model.isTimeRemainingInSeconds == 0) "01-02-2022".toText12(color: Colors.white), + if (model.isTimeRemainingInSeconds != 0) + Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + 9.height, + CountdownTimer( + endTime: model.endTime, + onEnd: null, + endWidget: "00:00:00".toText14(color: Colors.white, isBold: true), + textStyle: TextStyle(color: Colors.white, fontSize: 14, letterSpacing: -0.48, fontWeight: FontWeight.bold), + ), + LocaleKeys.timeLeftToday.tr().toText12(color: Colors.white), + 9.height, + ClipRRect( + borderRadius: BorderRadius.all( + Radius.circular(20), + ), + child: LinearProgressIndicator( + value: model.progress, + minHeight: 8, + valueColor: const AlwaysStoppedAnimation(Colors.white), + backgroundColor: const Color(0xff196D73), + ), + ), + ], + ), + ], + ).paddingOnly(top: 12, right: 15, left: 12), + ), + Row( + children: [ + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.checkIn.tr().toText12(color: Colors.white), + (model.attendanceTracking!.pSwipeIn == null ? "--:--" : model.attendanceTracking!.pSwipeIn) + .toString() + .toText14(color: Colors.white, isBold: true), + 4.height, + ], + ).paddingOnly(left: 12), + ), + Container( + width: 45, + height: 45, + padding: const EdgeInsets.only(left: 14, right: 14), + decoration: const BoxDecoration( + color: Color(0xff259EA4), + borderRadius: BorderRadius.only( + bottomRight: Radius.circular(15), + ), + ), + child: SvgPicture.asset(model.isTimeRemainingInSeconds == 0 ? "assets/images/play.svg" : "assets/images/stop.svg"), + ), + ], + ), + ], + ), + ], + ), + ).onPress(() { + Navigator.pushNamed(context, AppRoutes.todayAttendance); + })) + .animatedSwither(); + }, + ), + ), + ), + 9.width, + Expanded( + child: MenusWidget(), + ), + ], + ), + 20.height, + ], + ).paddingOnly(left: 21, right: 21, top: 7), + ServicesWidget(), + 8.height, + ], + ), + ), + ), + Container( + width: double.infinity, + padding: EdgeInsets.only(top: 31), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only(topRight: Radius.circular(50), topLeft: Radius.circular(50)), + border: Border.all(color: MyColors.lightGreyEDColor, width: 1), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + LocaleKeys.offers.tr().toText12(), + Row( + children: [ + LocaleKeys.discounts.tr().toText24(isBold: true), + 6.width, + Container( + padding: const EdgeInsets.only(left: 8, right: 8), + decoration: BoxDecoration( + color: MyColors.yellowColor, + borderRadius: BorderRadius.circular(10), + ), + child: LocaleKeys.newString.tr().toText10(isBold: true)), + ], + ), + ], + ), + ), + LocaleKeys.viewAllOffers.tr().toText12(isUnderLine: true), + ], + ).paddingOnly(left: 21, right: 21), + SizedBox( + height: 103 + 33, + child: ListView.separated( + shrinkWrap: true, + physics: const BouncingScrollPhysics(), + padding: const EdgeInsets.only(left: 21, right: 21, top: 13), + scrollDirection: Axis.horizontal, + itemBuilder: (cxt, index) { + return SizedBox( + width: 73, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + width: 73, + height: 73, + decoration: BoxDecoration( + borderRadius: const BorderRadius.all( + Radius.circular(100), + ), + border: Border.all(color: MyColors.lightGreyEDColor, width: 1), + ), + child: ClipRRect( + borderRadius: const BorderRadius.all( + Radius.circular(50), + ), + child: Image.network( + "https://play-lh.googleusercontent.com/NPo88ojmhah4HDiposucJmfQIop4z4xc8kqJK9ITO9o-yCab2zxIp7PPB_XPj2iUojo", + fit: BoxFit.cover, + ), + ), + ), + 4.height, + Expanded( + child: namesD[6 % (index + 1)].toText12(isCenter: true, maxLine: 2), + ), + ], + ), + ); + }, + separatorBuilder: (cxt, index) => 8.width, + itemCount: 6), + ), + ], + ), + ) + ], + ), + ) + ], + ), + bottomNavigationBar: BottomNavigationBar( + items: [ + BottomNavigationBarItem( + icon: Padding( + padding: const EdgeInsets.all(4.0), + child: SvgPicture.asset( + "assets/icons/home.svg", + width: 20, + height: 20, + ), + ), + label: 'Home', + ), + BottomNavigationBarItem( + icon: Padding( + padding: const EdgeInsets.all(4.0), + child: SvgPicture.asset( + "assets/icons/create_req.svg", + width: 20, + height: 20, + ), + ), + label: 'Create Request', + ), + BottomNavigationBarItem( + icon: Padding( + padding: const EdgeInsets.all(4.0), + child: SvgPicture.asset( + "assets/icons/work_list.svg", + width: 20, + height: 20, + ), + ), + label: 'Work List', + ), + BottomNavigationBarItem( + icon: Padding( + padding: const EdgeInsets.all(4.0), + child: SvgPicture.asset( + "assets/icons/item_for_sale.svg", + width: 20, + height: 20, + ), + ), + label: 'Items for Sale', + ), + ], + currentIndex: 0, + selectedLabelStyle: TextStyle( + fontSize: 8, + color: Color(0xff989898), + fontWeight: FontWeight.w600, + ), + unselectedLabelStyle: TextStyle( + fontSize: 8, + color: Color(0xff989898), + fontWeight: FontWeight.w600, + ), + type: BottomNavigationBarType.fixed, + selectedItemColor: Colors.black, + backgroundColor: Color(0xffF8F8F8), + onTap: (v) {}, + ), + ); + } +} diff --git a/lib/ui/landing/today_attendance_screen.dart b/lib/ui/landing/today_attendance_screen.dart index ac42dd1..2008484 100644 --- a/lib/ui/landing/today_attendance_screen.dart +++ b/lib/ui/landing/today_attendance_screen.dart @@ -1,12 +1,25 @@ import 'package:easy_localization/src/public_ext.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_countdown_timer/flutter_countdown_timer.dart'; import 'package:flutter_svg/flutter_svg.dart'; +import 'package:google_maps_flutter/google_maps_flutter.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/date_uitl.dart'; +import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/extensions/int_extensions.dart'; import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; +import 'package:mohem_flutter_app/models/generic_response_model.dart'; import 'package:mohem_flutter_app/widgets/circular_step_progress_bar.dart'; +import 'package:mohem_flutter_app/widgets/nfc/nfc_reader_sheet.dart'; +import 'package:nfc_manager/nfc_manager.dart'; +import 'package:provider/provider.dart'; + +import '../../provider/dashboard_provider_model.dart'; +import '../../widgets/location/Location.dart'; class TodayAttendanceScreen extends StatefulWidget { TodayAttendanceScreen({Key? key}) : super(key: key); @@ -18,14 +31,45 @@ class TodayAttendanceScreen extends StatefulWidget { } class _TodayAttendanceScreenState extends State { + ValueNotifier result = ValueNotifier(null); + late DashboardProviderModel data; + bool isNfcEnabled = false, isNfcLocationEnabled = false, isQrEnabled = false, isQrLocationEnabled = false, isWifiEnabled = false, isWifiLocationEnabled = false; + @override void initState() { super.initState(); + checkAttendanceAvailablity(); + data = Provider.of(context, listen: false); + } + + checkAttendanceAvailablity() async { + bool isAvailable = await NfcManager.instance.isAvailable(); + setState(() { + AppState().privilegeListModel!.forEach((element) { + // Check availability + if (isAvailable) if (element.serviceName == "enableNFC") { + // if (element.previlege ?? false) + isNfcEnabled = true; + } else if (element.serviceName == "enableQR") { + if (element.previlege ?? false) isQrEnabled = true; + } else if (element.serviceName == "enableWIFI") { + if (element.previlege ?? false) isWifiEnabled = true; + } else if (element.serviceName == "enableLocatoinNFC") { + if (element.previlege ?? false) isNfcLocationEnabled = true; + } else if (element.serviceName == "enableLocationQR") { + if (element.previlege ?? false) isQrLocationEnabled = true; + } else if (element.serviceName == "enableLocationWIFI") { + if (element.previlege ?? false) isWifiLocationEnabled = true; + } + }); + }); } @override void dispose() { super.dispose(); + // Stop Session + NfcManager.instance.stopSession(); } @override @@ -37,133 +81,197 @@ class _TodayAttendanceScreenState extends State { icon: const Icon(Icons.arrow_back_ios, color: Colors.white), onPressed: () => Navigator.pop(context), ), - ), - backgroundColor: Colors.white, - body: ListView( - children: [ - Container( - color: MyColors.backgroundBlackColor, - padding: EdgeInsets.only(top: 4,left: 21, right: 21, bottom: 21), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - "June 13, 2021".toText24(isBold: true, color: Colors.white), - LocaleKeys.timeLeftToday.tr().toText16(color: Color(0xffACACAC)), - 21.height, - Center( - child: CircularStepProgressBar( - totalSteps: 16 * 4, - currentStep: 16, - width: 216, - height: 216, - selectedColor: MyColors.gradiantEndColor, - unselectedColor: MyColors.grey70Color, - child: Center( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - "08:58:15".toText32(color: Colors.white, isBold: true), - 19.height, - "Shift Time".tr().toText12(color: MyColors.greyACColor), - "08:00 - 17:00".toText22(color: Colors.white, isBold: true), - ], - ), - ), - ), - ), - ], - ), - ), - Container( - color: MyColors.backgroundBlackColor, - child: Stack( - children: [ - Container( - height: 187, - padding: EdgeInsets.only(left: 31, right: 31, top: 31, bottom: 16), - decoration: BoxDecoration( - borderRadius: BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25)), - gradient: const LinearGradient(transform: GradientRotation(.64), begin: Alignment.topRight, end: Alignment.bottomRight, colors: [ - MyColors.gradiantEndColor, - MyColors.gradiantStartColor, - ]), - ), - child: Column( - children: [ - Row( - children: [commonStatusView("Check In", "09:27"), commonStatusView("Check Out", "- - : - -")], - ), - 21.height, - Row( - children: [commonStatusView("Late In", "00:27"), commonStatusView("Regular", "08:00")], - ), - ], - ), - ), - Container( - width: double.infinity, - decoration: BoxDecoration(borderRadius: BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25)), color: Colors.white), - margin: EdgeInsets.only(top: 187 - 31), - padding: EdgeInsets.only(left: 21, right: 21, top: 24, bottom: 24), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - "Mark".tr().toText12(), - "Attendance".tr().toText24(), - "Select the method to mark the attendance".tr().toText12(color: Color(0xff535353)), - 24.height, - GridView( - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - padding: EdgeInsets.zero, - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, childAspectRatio: 1 / 1, crossAxisSpacing: 8, mainAxisSpacing: 8), - children: [ - attendanceMethod("NFC", "assets/images/nfc.svg", () {}), - attendanceMethod("Wifi", "assets/images/wufu.svg", () {}), - ], - ) - ], - ), - ), - // Positioned( - // top: 187 - 21, - // child: Container( - // padding: EdgeInsets.only(left: 31, right: 31, top: 31, bottom: 16), - // decoration: BoxDecoration(borderRadius: BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25)), color: Colors.white), - // child: Column( - // children: [ - // Row( - // children: [commonStatusView("Check In", "09:27"), commonStatusView("Check Out", "- - : - -")], - // ), - // 21.height, - // Row( - // children: [commonStatusView("Late In", "00:27"), commonStatusView("Regular", "08:00")], - // ), - // ], - // ), - // ), - // ), - ], + actions: [ + IconButton( + onPressed: () { + data.fetchAttendanceTracking(); + }, + icon: Icon( + Icons.ac_unit, + color: Colors.white, ), ) ], ), + backgroundColor: MyColors.backgroundBlackColor, + body: Consumer( + builder: (context, model, child) { + return (model.isAttendanceTrackingLoading + ? Center(child: CircularProgressIndicator()) + : ListView( + children: [ + Container( + color: MyColors.backgroundBlackColor, + padding: EdgeInsets.only(top: 4, left: 21, right: 21, bottom: 21), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + DateUtil.getWeekDayMonthDayYearDateFormatted(DateTime.now(), "en").toText24(isBold: true, color: Colors.white), + LocaleKeys.timeLeftToday.tr().toText16(color: Color(0xffACACAC)), + 21.height, + Center( + child: CircularStepProgressBar( + totalSteps: 16 * 4, + currentStep: (model.progress * 100).toInt(), + width: 216, + height: 216, + selectedColor: MyColors.gradiantEndColor, + unselectedColor: MyColors.grey70Color, + child: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + CountdownTimer( + endTime: model.endTime, + onEnd: null, + endWidget: "00:00:00".toText32(color: Colors.white, isBold: true), + textStyle: TextStyle(color: Colors.white, fontSize: 32, letterSpacing: -1.92, fontWeight: FontWeight.bold, height: 1), + ), + 19.height, + "Shift Time".tr().toText12(color: MyColors.greyACColor), + (model.attendanceTracking!.pShtName ?? "00:00:00").toString().toText22(color: Colors.white, isBold: true), + ], + ), + ), + ), + ), + ], + ), + ), + Container( + color: MyColors.backgroundBlackColor, + child: Stack( + children: [ + Container( + height: 187, + padding: EdgeInsets.only(left: 31, right: 31, top: 31, bottom: 16), + decoration: BoxDecoration( + borderRadius: BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25)), + gradient: const LinearGradient(transform: GradientRotation(.64), begin: Alignment.topRight, end: Alignment.bottomLeft, colors: [ + MyColors.gradiantEndColor, + MyColors.gradiantStartColor, + ]), + ), + child: Column( + children: [ + Row( + children: [ + commonStatusView("Check In", (model.attendanceTracking!.pSwipeIn) ?? "- - : - -"), + commonStatusView("Check Out", (model.attendanceTracking!.pSwipeOut) ?? "- - : - -") + ], + ), + 21.height, + Row( + children: [ + commonStatusView("Late In", (model.attendanceTracking!.pLateInHours) ?? "- - : - -"), + commonStatusView("Regular", (model.attendanceTracking!.pScheduledHours) ?? "- - : - -") + ], + ), + ], + ), + ), + Container( + width: double.infinity, + decoration: BoxDecoration(borderRadius: BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25)), color: Colors.white), + margin: EdgeInsets.only(top: 187 - 31), + padding: EdgeInsets.only(left: 21, right: 21, top: 24, bottom: 24), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + "Mark".tr().toText12(), + "Attendance".tr().toText24(), + "Select the method to mark the attendance".tr().toText12(color: Color(0xff535353)), + 24.height, + GridView( + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + padding: EdgeInsets.zero, + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, childAspectRatio: 1 / 1, crossAxisSpacing: 8, mainAxisSpacing: 8), + children: [ + attendanceMethod("NFC", "assets/images/nfc.svg", isNfcEnabled, () { + showNfcReader(context, onNcfScan: (String? nfcId) async { + print(nfcId); + Utils.showLoading(context); + try { + GenericResponseModel? g = await DashboardApiClient().markAttendance(pointType: 2, nfcValue: nfcId ?? ""); + bool status = await model.fetchAttendanceTracking(); + Utils.hideLoading(context); + } catch (ex) { + print(ex); + Utils.hideLoading(context); + Utils.handleException(ex, (msg) { + Utils.confirmDialog(context, msg); + }); + } + }); + // Location.getCurrentLocation((LatLng? latlng) { + // print(latlng!.longitude.toString()); + // }); + }), + attendanceMethod("Wifi", "assets/images/wufu.svg", isWifiEnabled, () {}), + ], + ) + ], + ), + ), + // Positioned( + // top: 187 - 21, + // child: Container( + // padding: EdgeInsets.only(left: 31, right: 31, top: 31, bottom: 16), + // decoration: BoxDecoration(borderRadius: BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25)), color: Colors.white), + // child: Column( + // children: [ + // Row( + // children: [commonStatusView("Check In", "09:27"), commonStatusView("Check Out", "- - : - -")], + // ), + // 21.height, + // Row( + // children: [commonStatusView("Late In", "00:27"), commonStatusView("Regular", "08:00")], + // ), + // ], + // ), + // ), + // ), + ], + ), + ) + ], + )) + .animatedSwither(); + }, + ), ); } - Widget attendanceMethod(String title, String image, VoidCallback onPress) => Container( - padding: const EdgeInsets.only(left: 10, right: 10, top: 14, bottom: 14), + Widget attendanceMethod(String title, String image, bool isEnabled, VoidCallback onPress) => Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(15), - gradient: const LinearGradient(transform: GradientRotation(.64), begin: Alignment.topRight, end: Alignment.bottomRight, colors: [ + gradient: const LinearGradient(transform: GradientRotation(.64), begin: Alignment.topRight, end: Alignment.bottomLeft, colors: [ MyColors.gradiantEndColor, MyColors.gradiantStartColor, ]), ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [Expanded(child: SvgPicture.asset(image)), title.toText17(isBold: true, color: Colors.white)], + clipBehavior: Clip.antiAlias, + child: Stack( + children: [ + Container( + padding: const EdgeInsets.only(left: 10, right: 10, top: 14, bottom: 14), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded(child: SvgPicture.asset(image)), + title.toText17(isBold: true, color: Colors.white), + ], + ), + ), + if (!isEnabled) + Container( + width: double.infinity, + height: double.infinity, + color: Colors.grey.withOpacity(0.7), + ) + ], ), ).onPress(onPress); diff --git a/lib/ui/landing/widget/menus_widget.dart b/lib/ui/landing/widget/menus_widget.dart new file mode 100644 index 0000000..5d73f0a --- /dev/null +++ b/lib/ui/landing/widget/menus_widget.dart @@ -0,0 +1,138 @@ +import 'package:easy_localization/src/public_ext.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:mohem_flutter_app/config/routes.dart'; +import 'package:mohem_flutter_app/extensions/string_extensions.dart'; +import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; +import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; +import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; +import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart'; +import 'package:provider/provider.dart'; + +class MenusWidget extends StatelessWidget { + @override + Widget build(BuildContext context) { + List namesColor = [0xff125765, 0xff239D8F, 0xff2BB8A8, 0xff1D92AA]; + + return Consumer(builder: (cxt, data, child) { + return GridView( + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2, childAspectRatio: 2 / 2, crossAxisSpacing: 9, mainAxisSpacing: 9), + padding: EdgeInsets.zero, + shrinkWrap: true, + primary: false, + physics: const NeverScrollableScrollPhysics(), + children: [ + data.isWorkListLoading + ? MenuShimmer().onPress(() { + data.fetchWorkListCounter(context, showLoading: true); + }) + : Container( + decoration: BoxDecoration( + color: Color(namesColor[0]), + borderRadius: BorderRadius.circular(10), + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.workList.tr().toText12(color: Colors.white), + Row( + children: [ + Expanded( + child: data.workListCounter.toString().toText16(color: Colors.white, isBold: true), + ), + SvgPicture.asset("assets/images/arrow_next.svg", color: Colors.white) + ], + ) + ], + ).paddingOnly(left: 10, right: 10, bottom: 6, top: 6), + ).onPress(() async { + //await data.fetchWorkListCounter(context, showLoading: true); + Navigator.pushNamed(context, AppRoutes.workList); + }), + data.isMissingSwipeLoading + ? MenuShimmer().onPress(() { + data.fetchWorkListCounter(context); + }) + : Container( + decoration: BoxDecoration( + color: Color(namesColor[1]), + borderRadius: BorderRadius.circular(10), + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.missingSwipes.tr().toText12(color: Colors.white), + Row( + children: [ + Expanded( + child: data.missingSwipeCounter.toString().toText16(color: Colors.white, isBold: true), + ), + SvgPicture.asset("assets/images/arrow_next.svg", color: Colors.white) + ], + ) + ], + ).paddingOnly(left: 10, right: 10, bottom: 6, top: 6), + ).onPress(() { + Navigator.pushNamed(context, AppRoutes.workList); + }), + data.isLeaveTicketBalanceLoading + ? MenuShimmer().onPress(() { + data.fetchWorkListCounter(context); + }) + : Container( + decoration: BoxDecoration( + color: Color(namesColor[2]), + borderRadius: BorderRadius.circular(10), + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.leaveBalance.tr().toText12(color: Colors.white), + Row( + children: [ + Expanded( + child: data.leaveBalance.toString().toText16(color: Colors.white, isBold: true), + ), + SvgPicture.asset("assets/images/arrow_next.svg", color: Colors.white) + ], + ) + ], + ).paddingOnly(left: 10, right: 10, bottom: 6, top: 6), + ).onPress(() { + Navigator.pushNamed(context, AppRoutes.workList); + }), + data.isLeaveTicketBalanceLoading + ? MenuShimmer().onPress(() { + data.fetchWorkListCounter(context); + }) + : Container( + decoration: BoxDecoration( + color: Color(namesColor[3]), + borderRadius: BorderRadius.circular(10), + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.ticketBalance.tr().toText12(color: Colors.white), + Row( + children: [ + Expanded( + child: data.ticketBalance.toString().toText16(color: Colors.white, isBold: true), + ), + SvgPicture.asset("assets/images/arrow_next.svg", color: Colors.white) + ], + ) + ], + ).paddingOnly(left: 10, right: 10, bottom: 6, top: 6), + ).onPress(() { + Navigator.pushNamed(context, AppRoutes.workList); + }) + ], + ); + }); + } +} diff --git a/lib/ui/landing/widget/services_widget.dart b/lib/ui/landing/widget/services_widget.dart new file mode 100644 index 0000000..89a0aa6 --- /dev/null +++ b/lib/ui/landing/widget/services_widget.dart @@ -0,0 +1,148 @@ +import 'package:easy_localization/src/public_ext.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:mohem_flutter_app/extensions/int_extensions.dart'; +import 'package:mohem_flutter_app/extensions/string_extensions.dart'; +import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; +import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; +import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; +import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart'; +import 'package:provider/provider.dart'; + +class ServicesWidget extends StatelessWidget { + @override + Widget build(BuildContext context) { + List namesT = [LocaleKeys.monthlyAttendance.tr(), LocaleKeys.workFromHome.tr(), LocaleKeys.ticketRequest.tr(), LocaleKeys.monthlyAttendance.tr()]; + List iconT = [ + "assets/images/monthly_attendance.svg", + "assets/images/work_from_home.svg", + "assets/images/ticket_request.svg", + "assets/images/work_from_home.svg", + "assets/images/work_from_home.svg", + "assets/images/work_from_home.svg", + "assets/images/work_from_home.svg", + "assets/images/work_from_home.svg" + ]; + + return Consumer( + builder: (context, data, child) { + return data.isServicesMenusLoading + ? whileLoading() + : ListView.separated( + itemBuilder: (context, parentIndex) { + return Column( + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + firstWord(data.homeMenus![parentIndex].menuEntry.prompt!).toText12(), + lastWord(data.homeMenus![parentIndex].menuEntry.prompt!).toText24(isBold: true), + ], + ), + ), + LocaleKeys.viewAllServices.tr().toText12(isUnderLine: true), + ], + ).paddingOnly(left: 21, right: 21), + SizedBox( + height: 105 + 26, + child: ListView.separated( + shrinkWrap: true, + physics: const BouncingScrollPhysics(), + padding: const EdgeInsets.only(left: 21, right: 21, top: 13, bottom: 13), + scrollDirection: Axis.horizontal, + itemBuilder: (cxt, index) { + return AspectRatio( + aspectRatio: 105 / 105, + child: data.isServicesMenusLoading + ? ServicesMenuShimmer() + : Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(15), + boxShadow: [ + BoxShadow( + color: const Color(0xff000000).withOpacity(.05), + blurRadius: 26, + offset: const Offset(0, -3), + ), + ], + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SvgPicture.asset(iconT[index]), + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Expanded( + child: data.homeMenus![parentIndex].menuEntiesList[index].prompt!.toText11(isBold: true), + ), + SvgPicture.asset("assets/images/arrow_next.svg").paddingOnly(bottom: 4) + ], + ) + ], + ).paddingOnly(left: 10, right: 10, bottom: 10, top: 12), + ), + ); + }, + separatorBuilder: (cxt, index) => 9.width, + itemCount: data.homeMenus![parentIndex].menuEntiesList.length), + ), + ], + ); + }, + separatorBuilder: (context, index) { + return 12.height; + }, + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemCount: data.homeMenus!.length); + }, + ); + } + + String firstWord(String value) { + return value.split(" ").length > 1 ? value.split(" ")[0] : ""; + } + + String lastWord(String value) { + var parts = value.split(" "); + if (parts.length == 1) { + return value; + } else { + int i = value.indexOf(" "); + return value.substring(i + 1).toCamelCase; + } + } + + Widget whileLoading() { + return Column( + children: [ + ServicesHeaderShimmer().paddingOnly(left: 21, right: 21), + SizedBox( + height: 105 + 26, + child: ListView.separated( + shrinkWrap: true, + physics: const BouncingScrollPhysics(), + padding: const EdgeInsets.only(left: 21, right: 21, top: 13, bottom: 13), + scrollDirection: Axis.horizontal, + itemBuilder: (cxt, index) { + return AspectRatio( + aspectRatio: 105 / 105, + child: ServicesMenuShimmer(), + ); + }, + separatorBuilder: (cxt, index) => 9.width, + itemCount: 4, + ), + ), + ], + ); + } +} diff --git a/lib/ui/login/forgot_password_screen.dart b/lib/ui/login/forgot_password_screen.dart index 89bd66e..17b105f 100644 --- a/lib/ui/login/forgot_password_screen.dart +++ b/lib/ui/login/forgot_password_screen.dart @@ -37,24 +37,30 @@ class _ForgotPasswordScreenState extends State { super.dispose(); } - void performLogin() async { - // Utils.showLoading(context); + void performForgotPassword() async { + if (employeeId.text.isEmpty) { + return; + } + Utils.showLoading(context); try { _basicMemberInformation = await LoginApiClient().getBasicUserInformation("CS", employeeId.text); genericResponseModel = await LoginApiClient().sendPublicActivationCode(_basicMemberInformation?.pMOBILENUMBER, employeeId.text); + Utils.hideLoading(context); OtpDialog( context, 1, int.tryParse(_basicMemberInformation?.pMOBILENUMBER ?? ""), (value) async { + Utils.showLoading(context); GenericResponseModel? genericResponseModel = await LoginApiClient().checkPublicActivationCode(value, employeeId.text); if (genericResponseModel?.errorMessage != null) { Utils.showToast(genericResponseModel?.errorMessage ?? ""); return; } - - Navigator.pushNamed(context, AppRoutes.newPassword); - // this.checkActivationCode(value: value); + Utils.hideLoading(context); + await Navigator.pushNamed(context, AppRoutes.newPassword, arguments: employeeId.text); + Navigator.pop(context); + Navigator.pop(context); }, () => { Navigator.pop(context), @@ -62,8 +68,8 @@ class _ForgotPasswordScreenState extends State { ).displayDialog(context); } catch (ex) { print(ex); + Utils.hideLoading(context); Utils.handleException(ex, null); - // Utils.hideLoading(context); } } @@ -95,7 +101,14 @@ class _ForgotPasswordScreenState extends State { LocaleKeys.forgotPassword.tr().toText24(isBold: true), LocaleKeys.loginCodeWillSentToMobileNumber.tr().toText16(), 16.height, - InputWidget(LocaleKeys.employeeId.tr(), "123456", employeeId), + InputWidget( + LocaleKeys.employeeId.tr(), + "123456", + employeeId, + onChange: (value) { + setState(() {}); + }, + ), ], ), ) @@ -103,9 +116,13 @@ class _ForgotPasswordScreenState extends State { ), ), ), - DefaultButton(LocaleKeys.changePassword.tr(), () async { - //Navigator.pushNamed(context, AppRoutes.verifyLogin); - }) + DefaultButton( + LocaleKeys.changePassword.tr(), + employeeId.text.isEmpty + ? null + : () async { + performForgotPassword(); + }) .insideContainer ], ), diff --git a/lib/ui/login/login_screen.dart b/lib/ui/login/login_screen.dart index 2353f99..d5a6061 100644 --- a/lib/ui/login/login_screen.dart +++ b/lib/ui/login/login_screen.dart @@ -1,11 +1,15 @@ +import 'dart:io'; + import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/src/public_ext.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:mohem_flutter_app/api/login_api_client.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/classes/consts.dart'; import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/config/routes.dart'; import 'package:mohem_flutter_app/extensions/int_extensions.dart'; @@ -13,7 +17,10 @@ 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/check_mobile_app_version_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'; +import 'package:mohem_flutter_app/models/privilege_list_model.dart'; import 'package:mohem_flutter_app/widgets/button/default_button.dart'; import 'package:mohem_flutter_app/widgets/input_widget.dart'; @@ -33,9 +40,15 @@ class _LoginScreenState extends State { CheckMobileAppVersionModel? _checkMobileAppVersion; MemberLoginListModel? _memberLoginList; + final FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance; + + bool _autoLogin = false; + @override void initState() { super.initState(); + checkFirebaseToken(); + //checkPrefs(); } @override @@ -43,6 +56,48 @@ class _LoginScreenState extends State { super.dispose(); } + Future checkPrefs() async { + String username = await Utils.getStringFromPrefs(SharedPrefsConsts.username); + if (username.isNotEmpty) { + String password = await Utils.getStringFromPrefs(SharedPrefsConsts.password); + // String firebaseToken = await Utils.getStringFromPrefs(SharedPrefsConsts.firebaseToken); + // print("firebaseToken:$firebaseToken"); + this.username.text = username; + this.password.text = password; + _autoLogin = true; + } + } + + String? firebaseToken; + + Future checkFirebaseToken() async { + try { + Utils.showLoading(context); + firebaseToken = await _firebaseMessaging.getToken(); + GetMobileLoginInfoListModel? loginInfo = await LoginApiClient().getMobileLoginInfoNEW(firebaseToken ?? "", Platform.isAndroid ? "android" : "ios"); + if (loginInfo == null) { + Utils.hideLoading(context); + print("Device token not found"); + return; + } else { + await checkPrefs(); + Utils.hideLoading(context); + performLogin(); + } + } catch (ex) { + print(ex); + Utils.hideLoading(context); + Utils.handleException(ex, null); + } + } + + // Future getFirebaseToken() async { + // String? firebaseToken = await _firebaseMessaging.getToken(); + // if (firebaseToken != null) { + // await Utils.saveStringFromPrefs(SharedPrefsConsts.firebaseToken, firebaseToken); + // } + // } + void performLogin() async { Utils.showLoading(context); try { @@ -50,20 +105,30 @@ class _LoginScreenState extends State { _memberLoginList = await LoginApiClient().memberLogin(username.text, password.text); AppState().setMemberLoginListModel = _memberLoginList; AppState().setUserName = username.text; - print(_memberLoginList?.toJson()); + AppState().password = password.text; + if (_autoLogin) { + AppState().setMemberInformationListModel = (await MemberInformationListModel.getFromPrefs()).first; + AppState().setPrivilegeListModel = await PrivilegeListModel.getFromPrefs(); + } Utils.hideLoading(context); - Navigator.pushNamed(context, AppRoutes.verifyLogin); + if (_autoLogin) { + Navigator.pushNamed(context, AppRoutes.verifyLastLogin); + } else { + Navigator.pushNamed(context, AppRoutes.verifyLogin, arguments: "$firebaseToken"); + } } catch (ex) { print(ex); - Utils.handleException(ex, null); Utils.hideLoading(context); + Utils.handleException(ex, (msg) { + Utils.confirmDialog(context, msg); + }); } } @override Widget build(BuildContext context) { username.text="15153"; - password.text="e123e123e123"; + password.text="Xy12345@"; return Scaffold( body: Column( children: [ @@ -79,7 +144,7 @@ class _LoginScreenState extends State { Expanded(child: SizedBox()), Row( children: [ - LocaleKeys.english.tr().toText14(color: MyColors.textMixColor).onPress(() { + LocaleKeys.english.tr().toText14(color: AppState().isArabic(context) ? null : MyColors.textMixColor).onPress(() { context.setLocale(const Locale("en", "US")); }), Container( @@ -88,7 +153,7 @@ class _LoginScreenState extends State { height: 16, margin: const EdgeInsets.only(left: 10, right: 10), ), - LocaleKeys.arabic.tr().toText14().onPress(() { + LocaleKeys.arabic.tr().toText14(color: !AppState().isArabic(context) ? null : MyColors.textMixColor).onPress(() { context.setLocale(const Locale("ar", "SA")); }), ], diff --git a/lib/ui/login/new_password_screen.dart b/lib/ui/login/new_password_screen.dart index 3fc37f1..e0a8f94 100644 --- a/lib/ui/login/new_password_screen.dart +++ b/lib/ui/login/new_password_screen.dart @@ -1,7 +1,9 @@ import 'package:easy_localization/src/public_ext.dart'; import 'package:flutter/material.dart'; +import 'package:mohem_flutter_app/api/login_api_client.dart'; +import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; -import 'package:mohem_flutter_app/config/routes.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'; @@ -22,6 +24,8 @@ class _NewPasswordScreenState extends State { TextEditingController password = TextEditingController(); TextEditingController confirmPassword = TextEditingController(); + String? userName; + @override void initState() { super.initState(); @@ -32,8 +36,26 @@ class _NewPasswordScreenState extends State { super.dispose(); } + void setNewPassword() async { + Utils.showLoading(context); + try { + var genericResponseModel = await LoginApiClient().changePasswordForget(AppState().getForgetPasswordTokenID ?? "", password.text, confirmPassword.text, userName); + Utils.hideLoading(context); + Utils.showToast(LocaleKeys.passwordChangedSuccessfully.tr()); + Navigator.pop(context); + } catch (ex) { + print(ex); + Utils.hideLoading(context); + Utils.handleException(ex, (msg) { + Utils.confirmDialog(context, msg); + }); + } + } + @override Widget build(BuildContext context) { + userName ??= ModalRoute.of(context)!.settings.arguments as String; + return Scaffold( appBar: AppBar( backgroundColor: Colors.transparent, @@ -46,53 +68,125 @@ class _NewPasswordScreenState extends State { children: [ //const SizedBox(height: 23), Expanded( - child: Padding( - padding: const EdgeInsets.all(21.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Row( - // children: [ - // Expanded(child: SizedBox()), - // Row( - // children: [ - // LocaleKeys.english.tr().toText14(color: MyColors.textMixColor).onPress(() {}), - // Container( - // width: 1, - // color: MyColors.darkWhiteColor, - // height: 16, - // margin: const EdgeInsets.only(left: 10, right: 10), - // ), - // LocaleKeys.arabic.tr().toText14().onPress(() {}), - // ], - // ), - // ], - // ), - Expanded( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - LocaleKeys.setTheNewPassword.tr().toText24(isBold: true), - LocaleKeys.typeYourNewPasswordBelow.tr().toText16(), - 16.height, - InputWidget(LocaleKeys.password.tr(), "**********", password), - 12.height, - InputWidget(LocaleKeys.confirmPassword.tr(), "**********", confirmPassword, isObscureText: true) - ], - ), - ) - ], - ), - ), + child: ListView( + // mainAxisSize: MainAxisSize.min, + // crossAxisAlignment: CrossAxisAlignment.start, + // mainAxisAlignment: MainAxisAlignment.center, + children: [ + LocaleKeys.setTheNewPassword.tr().toText24(isBold: true), + LocaleKeys.typeYourNewPasswordBelow.tr().toText16(), + 16.height, + InputWidget( + LocaleKeys.password.tr(), + "**********", + password, + onChange: (value) { + setState(() {}); + }, + ), + 12.height, + InputWidget( + LocaleKeys.confirmPassword.tr(), + "**********", + confirmPassword, + isObscureText: true, + onChange: (value) { + setState(() {}); + }, + ), + 12.height, + passwordConstraintsUI(LocaleKeys.doNotUseRecentPassword.tr(), true), + 8.height, + passwordConstraintsUI(LocaleKeys.atLeastOneLowercase.tr(), checkRegEx(r'[a-z]')), + 8.height, + passwordConstraintsUI(LocaleKeys.atLeastOneUppercase.tr(), checkRegEx(r'[A-Z]')), + 8.height, + passwordConstraintsUI(LocaleKeys.atLeastOneNumeric.tr(), checkRegEx(r'[0-9]')), + 8.height, + 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.confirmPasswordMustMatch.tr(), password.text.isNotEmpty && password.text == confirmPassword.text), + 12.height, + ], + ).paddingAll(21), ), - DefaultButton(LocaleKeys.update.tr(), () async { - - // Navigator.pushNamed(context, AppRoutes.verifyLogin); - }).insideContainer + DefaultButton( + LocaleKeys.update.tr(), + (!isPasswordCompliant(password.text, 8)) + ? null + : () async { + setNewPassword(); + }) + .insideContainer ], ), ); } + + bool checkRegEx(String pattern) { + return RegExp(pattern).hasMatch(password.text); + } + + String recentPassword = ""; + + bool checkRepeatedCharacters(String value) { + if (value.isEmpty) { + return false; + } + for (int i = 0; i < value.length; i++) { + //if(i) + } + + return true; + } + + bool isPasswordCompliant(String? password, int minLength) { + if (password == null || password.isEmpty) { + return false; + } + + bool hasUppercase = password.contains(RegExp(r'[A-Z]')); + bool hasDigits = password.contains(RegExp(r'[0-9]')); + bool hasLowercase = password.contains(RegExp(r'[a-z]')); + bool hasSpecialCharacters = password.contains(RegExp(r'[!@#$%^&*(),.?":{}|<>]')); + bool hasMinLength = password.length >= minLength; + bool isMatched = password == confirmPassword.text; + + return hasDigits && hasUppercase && hasLowercase && hasSpecialCharacters && hasMinLength && isMatched && checkRepeatedChars(password); + } + + bool checkRepeatedChars(String password) { + bool isNonRepeatedLetters = true; + if (password.length > 2) { + for (int i = 0; i < password.length; i++) { + String char = password[i]; + try { + if (char == password[i + 1]) { + isNonRepeatedLetters = false; + break; + } + } catch (ex) {} + } + } + return isNonRepeatedLetters; + } + + Widget passwordConstraintsUI(String description, bool check) { + return Row( + children: [ + 4.width, + SizedBox( + width: 12, + height: 12, + child: Checkbox(fillColor: MaterialStateProperty.all(MyColors.gradiantEndColor), shape: const CircleBorder(), value: check, onChanged: null), + ), + 8.width, + description.toText14() + ], + ); + } } diff --git a/lib/ui/login/verify_last_login_screen.dart b/lib/ui/login/verify_last_login_screen.dart new file mode 100644 index 0000000..52ec751 --- /dev/null +++ b/lib/ui/login/verify_last_login_screen.dart @@ -0,0 +1,331 @@ +import 'package:easy_localization/src/public_ext.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:local_auth/auth_strings.dart'; +import 'package:local_auth/local_auth.dart'; +import 'package:mohem_flutter_app/api/login_api_client.dart'; +import 'package:mohem_flutter_app/app_state/app_state.dart'; +import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/classes/date_uitl.dart'; +import 'package:mohem_flutter_app/classes/utils.dart'; +import 'package:mohem_flutter_app/config/routes.dart'; +import 'package:mohem_flutter_app/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/generic_response_model.dart'; +import 'package:mohem_flutter_app/models/get_mobile_login_info_list_model.dart'; +import 'package:mohem_flutter_app/widgets/button/default_button.dart'; + +class VerifyLastLoginScreen extends StatefulWidget { + VerifyLastLoginScreen({Key? key}) : super(key: key); + + @override + _VerifyLastLoginScreenState createState() { + return _VerifyLastLoginScreenState(); + } +} + +class _VerifyLastLoginScreenState extends State { + final LocalAuthentication auth = LocalAuthentication(); + List _availableBioMetricType = []; + GetMobileLoginInfoListModel? mobileLoginInfoListModel; + + @override + void initState() { + _getAvailableBiometrics(); + // setDefault(); + super.initState(); + } + + @override + Widget build(BuildContext context) { + mobileLoginInfoListModel ??= ModalRoute.of(context)!.settings.arguments as GetMobileLoginInfoListModel; + String empName = AppState().isArabic(context) ? AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEAr! : AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEEn!; + return Scaffold( + appBar: AppBar( + backgroundColor: Colors.transparent, + leading: IconButton( + icon: const Icon(Icons.arrow_back_ios, color: MyColors.darkIconColor), + onPressed: () => Navigator.pop(context), + ), + actions: [Center(child: "Employee Digital ID".toText12(color: MyColors.textMixColor, isUnderLine: true).onPress(() {})), 21.width], + ), + body: Column( + children: [ + Expanded( + child: ListView( + padding: const EdgeInsets.all(21), + physics: const BouncingScrollPhysics(), + children: [ + //12.height, + if (true) + Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.welcomeBack.tr().toText12(), + mobileLoginInfoListModel!.employeeName!.toText24(isBold: true), + 10.height, + LocaleKeys.wouldYouLikeToLoginWithCurrentUsername.tr().toText16(), + Container( + height: 72, + margin: const EdgeInsets.only(top: 23, bottom: 23), + alignment: Alignment.center, + padding: const EdgeInsets.only(left: 17, right: 12), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: Colors.white, + border: Border.all( + color: const Color(0xffefefef), + width: 1, + ), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + LocaleKeys.lastLoginDetails.tr().toText16(), + DateUtil.formatDateToDate(DateUtil.convertStringToDate(mobileLoginInfoListModel!.editedOn!), false).toText12(), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + LocaleKeys.verificationType.tr().toText10(color: MyColors.grey57Color), + getVerificationType(mobileLoginInfoListModel!.loginType!).toText12(), + Expanded(child: SizedBox()), + DateUtil.formatDateToTime(DateUtil.convertStringToDate(mobileLoginInfoListModel!.editedOn!)).toText12(), + ], + ) + ], + ), + ), + LocaleKeys.pleaseVerify.tr().toText16(), + GridView( + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2, crossAxisSpacing: 13, mainAxisSpacing: 9), + physics: const NeverScrollableScrollPhysics(), + padding: const EdgeInsets.only(top: 9), + shrinkWrap: true, + children: [ + getButton(3), + getButton(2), + getButton(1), + getButton(4), + ], + ) + ], + ) + // else + // Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ + // Image.asset( + // 'assets/images/habib-logo.png', + // height: 90, + // width: 90, + // ), + // SizedBox(height: 23), + // this.onlySMSBox == false + // ? Text( + // TranslationBase.of(context).verifyLoginWith, + // style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Color(0xff2B353E), letterSpacing: -0.64, height: 25 / 16), + // ) + // : Text( + // TranslationBase.of(context).verifyFingerprint2, + // style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Color(0xff2B353E), letterSpacing: -0.64, height: 25 / 16), + // ), + // SizedBox(height: 23), + // Text( + // TranslationBase.of(context).pleaseVerify, + // style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Color(0xff2E303A), letterSpacing: -0.64), + // ), + // GridView( + // gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2, crossAxisSpacing: 13, mainAxisSpacing: 9), + // physics: NeverScrollableScrollPhysics(), + // padding: EdgeInsets.only(top: 9), + // shrinkWrap: true, + // children: [ + // if (onlySMSBox == false) getButton(3), + // if (onlySMSBox == false) getButton(2), + // getButton(1), + // getButton(4), + // ], + // ), + // ]), + ], + ), + ), + 12.height, + DefaultButton( + LocaleKeys.useAnotherAccount.tr(), + () => { + //Navigator.of(context).pushNamed(LOGIN_TYPE) + }, + ).insideContainer, + ], + ), + ); + } + + Future _getAvailableBiometrics() async { + try { + _availableBioMetricType = await auth.getAvailableBiometrics(); + } on PlatformException catch (e) { + // AppToast.showErrorToast(message: e.message); + print(e); + } + if (mounted) setState(() {}); + } + + String getVerificationType(int type) { + if (type == 1) { + LocaleKeys.sms.tr(); + } else if (type == 2) { + return LocaleKeys.fingerPrint.tr(); + } else if (type == 3) { + return LocaleKeys.face.tr(); + } else if (type == 4) { + return LocaleKeys.whatsapp.tr(); + } + return ""; + } + + Future loginWithFaceIDAndBiometrics() async { + IOSAuthMessages iosStrings = + const IOSAuthMessages(cancelButton: 'cancel', goToSettingsButton: 'settings', goToSettingsDescription: 'Please set up your Touch ID.', lockOut: 'Please reenable your Touch ID'); + bool authenticated = false; + try { + authenticated = await auth.authenticate(localizedReason: 'Scan your fingerprint to authenticate', useErrorDialogs: true, stickyAuth: true, iOSAuthStrings: iosStrings); + } on PlatformException catch (e) { + print(e); + Utils.hideLoading(context); + Utils.showToast("Please enable your Touch or Face ID"); + } + return authenticated; + } + + Widget _loginOptionButton(String _title, String _icon, int _flag, int? _loginIndex) { + bool isDisable = ((_flag == 3 && !checkBiometricIsAvailable(BiometricType.face)) || (_flag == 2 && !checkBiometricIsAvailable(BiometricType.fingerprint))); + print("$_title:$isDisable"); + return InkWell( + onTap: isDisable + ? null + : () async { + if (_flag == 0) { + setState(() { + // isMoreOption = true; + }); + } else { + Utils.showLoading(context); + if (_flag == 2 || _flag == 3) { + bool authenticateWithFaceAndTouchID = await loginWithFaceIDAndBiometrics(); + if (authenticateWithFaceAndTouchID) { + Navigator.pushNamedAndRemoveUntil(context, AppRoutes.dashboard, (Route route) => false); + return; + } else { + Utils.hideLoading(context); + return; + } + } + await LoginApiClient().checkMobileAppVersion(); + await LoginApiClient().memberLogin(AppState().getUserName!, AppState().password!); + BasicMemberInformationModel? memberInformationModel = await LoginApiClient().mohemmSendActivationCodeByOTPNotificationType( + checkBiometricIsAvailable(BiometricType.fingerprint) ? 1 : 0, AppState().memberLoginList?.pMOBILENUMBER, _flag, AppState().getUserName); + Utils.hideLoading(context); + OtpDialog( + context, + _flag, + int.tryParse(AppState().memberLoginList?.pMOBILENUMBER ?? ""), + (value) async { + Utils.showLoading(context); + try { + GenericResponseModel? genericResponseModel = await LoginApiClient().checkActivationCode(false, AppState().memberLoginList?.pMOBILENUMBER, value, AppState().getUserName); + if (genericResponseModel?.errorMessage != null) { + Utils.showToast(genericResponseModel?.errorMessage ?? ""); + // Navigator.pop(context); + } + Utils.hideLoading(context); + Navigator.pop(context); + Navigator.pushNamedAndRemoveUntil(context, AppRoutes.dashboard, (Route route) => false); + } catch (ex) { + print(ex); + Utils.hideLoading(context); + Utils.handleException(ex, null); + } + }, + () => { + Navigator.pop(context), + }, + ).displayDialog(context); + + // authenticateUser(_flag, isActive: _loginIndex); + } + }, + child: Container( + padding: const EdgeInsets.only(left: 20, right: 20, bottom: 15, top: 28), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(15), + color: isDisable ? Colors.grey.withOpacity(0.3) : Colors.white, + border: Border.all(color: MyColors.lightGreyEFColor, width: 1), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + SvgPicture.asset( + _icon, + height: 38, + width: 38, + color: isDisable ? MyColors.darkTextColor.withOpacity(0.7) : null, + ), + _title.toText16() + ], + ), + ), + ); + } + + Widget getButton(int flag) { + switch (flag) { + case 4: + return _loginOptionButton(LocaleKeys.verifyThroughWhatsapp.tr(), 'assets/images/login/verify_whatsapp.svg', flag, null); + case 1: + return _loginOptionButton(LocaleKeys.verifyThroughSMS.tr(), 'assets/images/login/verify_sms.svg', flag, null); + case 2: + return _loginOptionButton(LocaleKeys.verifyThroughFingerprint.tr(), 'assets/images/login/verify_thumb.svg', flag, BiometricType.fingerprint.index); + case 3: + return _loginOptionButton(LocaleKeys.verifyThroughFace.tr(), 'assets/images/login/verify_face.svg', flag, BiometricType.face.index); + default: + return const SizedBox(); + } + } + + bool checkBiometricIsAvailable(BiometricType biometricType) { + bool isAvailable = false; + for (int i = 0; i < _availableBioMetricType.length; i++) { + if (biometricType == _availableBioMetricType[i]) { + isAvailable = true; + break; + } + } + return isAvailable; + } +// +// formatDate(date) { +// return date; +// return DateFormat('MMM dd, yyy, kk:mm').format(date); +// } +// +// showLoader(bool isTrue) { +// setState(() { +// // isLoading = isTrue; +// }); +// } + +} diff --git a/lib/ui/login/verify_login_screen.dart b/lib/ui/login/verify_login_screen.dart index ba0eb98..8e9255f 100644 --- a/lib/ui/login/verify_login_screen.dart +++ b/lib/ui/login/verify_login_screen.dart @@ -1,20 +1,25 @@ +import 'dart:io'; + import 'package:easy_localization/src/public_ext.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:local_auth/auth_strings.dart'; import 'package:local_auth/local_auth.dart'; import 'package:mohem_flutter_app/api/login_api_client.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/classes/consts.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/generic_response_model.dart'; +import 'package:mohem_flutter_app/models/member_information_list_model.dart'; +import 'package:mohem_flutter_app/models/privilege_list_model.dart'; import 'package:mohem_flutter_app/widgets/button/default_button.dart'; class VerifyLoginScreen extends StatefulWidget { @@ -30,6 +35,8 @@ class _VerifyLoginScreenState extends State { final LocalAuthentication auth = LocalAuthentication(); List _availableBioMetricType = []; + String? firebaseToken; + @override void initState() { _getAvailableBiometrics(); @@ -39,6 +46,7 @@ class _VerifyLoginScreenState extends State { @override Widget build(BuildContext context) { + firebaseToken ??= ModalRoute.of(context)!.settings.arguments as String; return Scaffold( appBar: AppBar( backgroundColor: Colors.transparent, @@ -46,7 +54,7 @@ class _VerifyLoginScreenState extends State { icon: const Icon(Icons.arrow_back_ios, color: MyColors.darkIconColor), onPressed: () => Navigator.pop(context), ), - actions: [Center(child: "Employee Digital ID".toText12(color: MyColors.textMixColor, isUnderLine: true).onPress(() {})), 21.width], + // actions: [Center(child: "Employee Digital ID".toText12(color: MyColors.textMixColor, isUnderLine: true).onPress(() {})), 21.width], ), body: Column( children: [ @@ -61,69 +69,69 @@ class _VerifyLoginScreenState extends State { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - LocaleKeys.welcomeBack.tr().toText12(), - "Mohammad Hussain".toText24(isBold: true), - 10.height, - LocaleKeys.wouldYouLikeToLoginWithCurrentUsername.tr().toText16(), - Container( - height: 72, - margin: const EdgeInsets.only(top: 23, bottom: 23), - alignment: Alignment.center, - padding: EdgeInsets.only(left: 17, right: 12), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - color: Colors.white, - border: Border.all( - color: Color(0xffefefef), - width: 1, - ), - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - LocaleKeys.lastLoginDetails.tr().toText16(), - // Text( - // user.editedOn != null - // ? DateUtil.getDayMonthYearDateFormatted(DateUtil.convertStringToDate(user.editedOn)) - // : user.createdOn != null - // ? DateUtil.getDayMonthYearDateFormatted(DateUtil.convertStringToDate(user.createdOn)) - // : '--', - // style: TextStyle(fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xff2B353E), letterSpacing: -0.48), - // ), - ], - ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - LocaleKeys.verificationType.tr().toText10(color: MyColors.grey57Color), - Text( - "SMS", - // " " + getType(user.logInType, context), - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Color(0xff2B353E), - ), - ), - Expanded(child: SizedBox()), - // Text( - // user.editedOn != null - // ? DateUtil.formatDateToTimeLang(DateUtil.convertStringToDate(user.editedOn), false) - // : user.createdOn != null - // ? DateUtil.formatDateToTimeLang(DateUtil.convertStringToDate(user.createdOn), false) - // : '--', - // style: TextStyle(fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xff575757), letterSpacing: -0.48), - // ), - ], - ) - ], - ), - ), + // LocaleKeys.welcomeBack.tr().toText12(), + // "Mohammad Hussain".toText24(isBold: true), + // 10.height, + // LocaleKeys.wouldYouLikeToLoginWithCurrentUsername.tr().toText16(), + // Container( + // height: 72, + // margin: const EdgeInsets.only(top: 23, bottom: 23), + // alignment: Alignment.center, + // padding: EdgeInsets.only(left: 17, right: 12), + // decoration: BoxDecoration( + // borderRadius: BorderRadius.circular(10), + // color: Colors.white, + // border: Border.all( + // color: Color(0xffefefef), + // width: 1, + // ), + // ), + // child: Column( + // mainAxisSize: MainAxisSize.min, + // children: [ + // Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // crossAxisAlignment: CrossAxisAlignment.center, + // children: [ + // LocaleKeys.lastLoginDetails.tr().toText16(), + // // Text( + // // user.editedOn != null + // // ? DateUtil.getDayMonthYearDateFormatted(DateUtil.convertStringToDate(user.editedOn)) + // // : user.createdOn != null + // // ? DateUtil.getDayMonthYearDateFormatted(DateUtil.convertStringToDate(user.createdOn)) + // // : '--', + // // style: TextStyle(fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xff2B353E), letterSpacing: -0.48), + // // ), + // ], + // ), + // Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // crossAxisAlignment: CrossAxisAlignment.center, + // children: [ + // LocaleKeys.verificationType.tr().toText10(color: MyColors.grey57Color), + // Text( + // "SMS", + // // " " + getType(user.logInType, context), + // style: TextStyle( + // fontSize: 12, + // fontWeight: FontWeight.w600, + // color: Color(0xff2B353E), + // ), + // ), + // Expanded(child: SizedBox()), + // // Text( + // // user.editedOn != null + // // ? DateUtil.formatDateToTimeLang(DateUtil.convertStringToDate(user.editedOn), false) + // // : user.createdOn != null + // // ? DateUtil.formatDateToTimeLang(DateUtil.convertStringToDate(user.createdOn), false) + // // : '--', + // // style: TextStyle(fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xff575757), letterSpacing: -0.48), + // // ), + // ], + // ) + // ], + // ), + // ), LocaleKeys.pleaseVerify.tr().toText16(), GridView( gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2, crossAxisSpacing: 13, mainAxisSpacing: 9), @@ -612,9 +620,23 @@ class _VerifyLoginScreenState extends State { // // }); // } // + + Future loginWithFaceIDAndBiometrics() async { + IOSAuthMessages iosStrings = + const IOSAuthMessages(cancelButton: 'cancel', goToSettingsButton: 'settings', goToSettingsDescription: 'Please set up your Touch ID.', lockOut: 'Please reenable your Touch ID'); + bool authenticated = false; + try { + authenticated = await auth.authenticate(localizedReason: 'Scan your fingerprint to authenticate', useErrorDialogs: true, stickyAuth: true, iOSAuthStrings: iosStrings); + } on PlatformException catch (e) { + print(e); + Utils.hideLoading(context); + Utils.showToast("Please enable your Touch or Face ID"); + } + return authenticated; + } + Widget _loginOptionButton(String _title, String _icon, int _flag, int? _loginIndex) { bool isDisable = ((_flag == 3 && !checkBiometricIsAvailable(BiometricType.face)) || (_flag == 2 && !checkBiometricIsAvailable(BiometricType.fingerprint))); - print("$_title:$isDisable"); return InkWell( onTap: isDisable ? null @@ -624,37 +646,64 @@ class _VerifyLoginScreenState extends State { // isMoreOption = true; }); } else { - Utils.showLoading(context); - BasicMemberInformationModel? memberInformationModel = await LoginApiClient() - .mohemmSendActivationCodeByOTPNotificationType(checkBiometricIsAvailable(BiometricType.fingerprint) ? 1 : 0, AppState().memberLoginList?.pMOBILENUMBER, _flag, AppState().getUserName); - Utils.hideLoading(context); - OtpDialog( - context, - _flag, - int.tryParse(AppState().memberLoginList?.pMOBILENUMBER ?? ""), - (value) async { - Utils.showLoading(context); - try { - GenericResponseModel? genericResponseModel = await LoginApiClient().checkActivationCode(false, AppState().memberLoginList?.pMOBILENUMBER, value, AppState().getUserName); - if (genericResponseModel?.errorMessage != null) { - Utils.showToast(genericResponseModel?.errorMessage ?? ""); - // Navigator.pop(context); - } - Utils.hideLoading(context); - Navigator.pop(context); - Navigator.pushNamedAndRemoveUntil(context, AppRoutes.dashboard, (Route route) => false); - } catch (ex) { - print(ex); - Utils.hideLoading(context); - Utils.handleException(ex, null); + try { + Utils.showLoading(context); + if (_flag == 2 || _flag == 3) { + bool authenticateWithFaceAndTouchID = await loginWithFaceIDAndBiometrics(); + if (!authenticateWithFaceAndTouchID) { + return; } - }, - () => { - Navigator.pop(context), - }, - ).displayDialog(context); - - // authenticateUser(_flag, isActive: _loginIndex); + } + await LoginApiClient().checkMobileAppVersion(); + await LoginApiClient().memberLogin(AppState().getUserName!, AppState().password!); + BasicMemberInformationModel? memberInformationModel = await LoginApiClient().mohemmSendActivationCodeByOTPNotificationType( + checkBiometricIsAvailable(BiometricType.fingerprint) ? 1 : 0, AppState().memberLoginList?.pMOBILENUMBER, _flag, AppState().getUserName); + Utils.hideLoading(context); + OtpDialog( + context, + _flag, + int.tryParse(AppState().memberLoginList?.pMOBILENUMBER ?? ""), + (value) async { + Utils.showLoading(context); + try { + GenericResponseModel? genericResponseModel = await LoginApiClient().checkActivationCode(false, AppState().memberLoginList?.pMOBILENUMBER, value, AppState().getUserName); + GenericResponseModel? genericResponseModel1 = await LoginApiClient().insertMobileLoginInfoNEW( + AppState().memberLoginList?.pEMAILADDRESS ?? "", + genericResponseModel?.pSESSIONID ?? 0, + genericResponseModel?.memberInformationList![0].eMPLOYEENAME ?? "", + _flag, + AppState().memberLoginList?.pMOBILENUMBER ?? "", + AppState().getUserName!, + firebaseToken!, + Platform.isAndroid ? "android" : "ios"); + if (genericResponseModel?.errorMessage != null) { + Utils.showToast(genericResponseModel?.errorMessage ?? ""); + } else { + AppState().setPrivilegeListModel = genericResponseModel!.privilegeList ?? []; + AppState().setMemberInformationListModel = genericResponseModel.memberInformationList?.first; + MemberInformationListModel.saveToPrefs(genericResponseModel.memberInformationList ?? []); + PrivilegeListModel.saveToPrefs(genericResponseModel.privilegeList ?? []); + Utils.saveStringFromPrefs(SharedPrefsConsts.username, AppState().getUserName!); + Utils.saveStringFromPrefs(SharedPrefsConsts.password, AppState().password!); + } + Utils.hideLoading(context); + Navigator.pop(context); + Navigator.pushNamedAndRemoveUntil(context, AppRoutes.dashboard, (Route route) => false); + } catch (ex) { + print(ex); + Utils.hideLoading(context); + Utils.handleException(ex, null); + } + }, + () => { + Navigator.pop(context), + }, + ).displayDialog(context); + } catch (ex) { + print(ex); + Utils.hideLoading(context); + Utils.handleException(ex, null); + } } }, child: Container( diff --git a/lib/ui/work_list/missing_swipe/missing_swipe_screen.dart b/lib/ui/work_list/missing_swipe/missing_swipe_screen.dart index 4af620e..0a27afc 100644 --- a/lib/ui/work_list/missing_swipe/missing_swipe_screen.dart +++ b/lib/ui/work_list/missing_swipe/missing_swipe_screen.dart @@ -1,56 +1,85 @@ +import 'package:easy_localization/src/public_ext.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; -import 'package:mohem_flutter_app/ui/app_bar.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/ui/work_list/missing_swipe/fragments/actions_fragment.dart'; import 'package:mohem_flutter_app/ui/work_list/missing_swipe/fragments/attachments_fragment.dart'; import 'package:mohem_flutter_app/ui/work_list/missing_swipe/fragments/info_fragments.dart'; import 'package:mohem_flutter_app/ui/work_list/missing_swipe/fragments/request_fragment.dart'; +import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; import 'package:mohem_flutter_app/widgets/button/default_button.dart'; -import 'package:mohem_flutter_app/extensions/int_extensions.dart'; -class MissingSwipeScreen extends StatelessWidget { +class MissingSwipeScreen extends StatefulWidget { + MissingSwipeScreen({Key? key}) : super(key: key); + + @override + _MissingSwipeScreenState createState() { + return _MissingSwipeScreenState(); + } +} + +class _MissingSwipeScreenState extends State { + int tabIndex = 0; + PageController controller = PageController(); + bool showFabOptions = false; + + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + @override Widget build(BuildContext context) { - return DefaultTabController( - length: 4, - child: Scaffold( - appBar: appBar(context, title: "Missing Swipe Request"), - body: Container( - width: double.infinity, - height: double.infinity, - child: Column( + return Scaffold( + appBar: AppBarWidget(context, title: LocaleKeys.details.tr()), + backgroundColor: Colors.white, + body: Stack( + children: [ + Column( children: [ Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.only(bottomLeft: Radius.circular(20), bottomRight: Radius.circular(20)), - gradient: LinearGradient(transform: GradientRotation(.46), begin: Alignment.topRight, end: Alignment.bottomRight, colors: [ - MyColors.gradiantEndColor, - MyColors.gradiantStartColor, - ]), + padding: const EdgeInsets.only(left: 21, right: 21, top: 16, bottom: 16), + decoration: const BoxDecoration( + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(25), + bottomRight: Radius.circular(25), + ), + gradient: LinearGradient( + transform: GradientRotation(.83), + begin: Alignment.topRight, + end: Alignment.bottomLeft, + colors: [ + MyColors.gradiantEndColor, + MyColors.gradiantStartColor, + ], + ), ), - clipBehavior: Clip.antiAlias, - child: TabBar( - indicatorColor: Colors.white, - labelColor: Colors.white, - tabs: [ - Tab( - text: "Request", - ), - Tab( - text: "Actions", - ), - Tab( - text: "Attachments", - ), - Tab( - text: "Info.", - ), + child: Row( + children: [ + myTab("Request", 0), + myTab("Actions", 1), + myTab("Attachments", 2), + myTab("Info.", 3), ], ), ), Expanded( - child: TabBarView( + child: PageView( + controller: controller, + onPageChanged: (pageIndex) { + setState(() { + tabIndex = pageIndex; + }); + }, children: [ RequestFragment(), ActionsFragment(), @@ -60,39 +89,140 @@ class MissingSwipeScreen extends StatelessWidget { ), ), Container( - width: double.infinity, - height: 60, - padding: EdgeInsets.only(left: 21, right: 21), + padding: const EdgeInsets.only(top: 14, bottom: 14, left: 21, right: 21), + decoration: const BoxDecoration( + color: Colors.white, + border: Border( + top: BorderSide( + color: MyColors.lightGreyEFColor, + width: 1.0, + ), + ), + ), child: Row( children: [ - Expanded( - child: DefaultButton( - "Reject", - () {}, - colors: [ - Color(0xffEB8C90), - Color(0xffDE6C70), - ], - ), - ), - 12.width, - Expanded( - child: DefaultButton( - "Approve", - () {}, - colors: [ - Color(0xff32D892), - Color(0xff1AB170), - ], + DefaultButton( + LocaleKeys.reject.tr(), + () {}, + colors: const [ + Color(0xffEB8C90), + Color(0xffDE6C70), + ], + ).expanded, + 8.width, + DefaultButton( + LocaleKeys.approve.tr(), + () {}, + colors: const [ + Color(0xff32D892), + Color(0xff1AB170), + ], + ).expanded, + 8.width, + Container( + height: 43, + width: 43, + decoration: const BoxDecoration( + shape: BoxShape.circle, + color: MyColors.lightGreyE6Color, ), - ), + child: Icon(showFabOptions ? Icons.more_vert_rounded : Icons.more_horiz_rounded, color: MyColors.darkIconColor), + ).onPress(() { + setState(() { + showFabOptions = true; + }); + }) ], ), ) ], ), - ), + IgnorePointer( + ignoring: !showFabOptions, + child: AnimatedOpacity( + opacity: showFabOptions ? 1 : 0, + duration: const Duration(milliseconds: 250), + child: Container( + padding: const EdgeInsets.only(left: 21, right: 21, bottom: 75), + width: double.infinity, + height: double.infinity, + color: Colors.white.withOpacity(.67), + alignment: Alignment.bottomRight, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + myFab("Skip", "assets/images/skip.svg"), + 12.height, + myFab("Request Info", "assets/images/request_info.svg"), + 12.height, + myFab("Delegate", "assets/images/delegate.svg"), + ], + ), + ), + ).onPress(() { + setState(() { + showFabOptions = false; + }); + }), + ), + ], ), ); } + + Widget myTab(String title, int index) { + bool isSelected = (index == tabIndex); + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + title.toText12(color: isSelected ? Colors.white : Colors.white.withOpacity(.74), isCenter: true), + 4.height, + Container( + height: 8, + width: 8, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: isSelected ? Colors.white : Colors.transparent, + ), + ).onPress(() { + setState(() { + showFabOptions = true; + }); + }) + ], + ).onPress(() { + controller.jumpToPage(index); + }).expanded; + } + + Widget myFab(String title, String icon) { + return Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + title.toText16(), + 14.width, + Container( + height: 43, + width: 43, + padding: const EdgeInsets.all(12), + decoration: const BoxDecoration( + shape: BoxShape.circle, + gradient: LinearGradient( + transform: GradientRotation(.46), + begin: Alignment.topRight, + end: Alignment.bottomLeft, + colors: [ + MyColors.gradiantEndColor, + MyColors.gradiantStartColor, + ], + ), + ), + child: SvgPicture.asset(icon), + ) + ], + ); + } } diff --git a/lib/ui/work_list/work_list_screen.dart b/lib/ui/work_list/work_list_screen.dart index 06a545c..1e46783 100644 --- a/lib/ui/work_list/work_list_screen.dart +++ b/lib/ui/work_list/work_list_screen.dart @@ -1,29 +1,116 @@ import 'package:easy_localization/src/public_ext.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:mohem_flutter_app/api/worklist/worklist_api_client.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/classes/date_uitl.dart'; +import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/config/routes.dart'; -import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; -import 'package:mohem_flutter_app/ui/app_bar.dart'; -import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/extensions/int_extensions.dart'; +import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; +import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; +import 'package:mohem_flutter_app/models/dashboard/itg_forms_model.dart'; +import 'package:mohem_flutter_app/models/worklist_item_type_model.dart'; +import 'package:mohem_flutter_app/models/worklist_response_model.dart'; +import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; +import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; +import 'package:provider/provider.dart'; class WorkListScreen extends StatefulWidget { + WorkListScreen({Key? key}) : super(key: key); + @override - State createState() => _WorkListScreenState(); + _WorkListScreenState createState() { + return _WorkListScreenState(); + } } class _WorkListScreenState extends State { + List workListItemTypes = [ + WorkListItemTypeModelData( + value: 0, name: 'HR', fullName: 'Human Resource', active: false, color: [Color(0xff32D892), Color(0xff1AB170)], icon: "assets/images/miss_swipe.svg", key: 'HRSSA', disable: false), + WorkListItemTypeModelData( + value: 0, name: 'MO', fullName: 'Move Order', active: false, color: [Color(0xff58DCFA), Color(0xff3CB9D5)], icon: "assets/images/miss_swipe.svg", key: 'INVMOA', disable: false), + WorkListItemTypeModelData( + value: 0, name: 'PR', fullName: 'Purchase Requisition', active: false, color: [Color(0xff48EACF), Color(0xff3DCAB3)], icon: "assets/images/miss_swipe.svg", key: 'REQAPPRV', disable: false), + WorkListItemTypeModelData( + value: 0, name: 'PO', fullName: 'Purchase Order', active: false, color: [Color(0xff5099E3), Color(0xff3670AA)], icon: "assets/images/miss_swipe.svg", key: 'POAPPRV', disable: false), + WorkListItemTypeModelData( + value: 0, name: 'ITG', fullName: 'ITG Forms', active: false, color: [Color(0xffEB8C90), Color(0xffDE6C70)], icon: "assets/images/miss_swipe.svg", key: 'ITG', disable: false), + WorkListItemTypeModelData( + value: 0, name: 'IC', fullName: 'Item Creation', active: false, color: [Color(0xff32D892), Color(0xff1AB170)], icon: "assets/images/miss_swipe.svg", key: 'INVITEM', disable: false), + WorkListItemTypeModelData( + value: 0, name: 'STAMP', fullName: 'Stamp', active: false, color: [Color(0xff32D892), Color(0xff1AB170)], icon: "assets/images/miss_swipe.svg", key: 'STAMP', disable: false), + ]; + + int workListItemIndex = 0; + + List? workList; + int pageNumber = 1; + + late DashboardProviderModel providerData; + + @override + void initState() { + super.initState(); + + providerData = Provider.of(context, listen: false); + workListItemTypes.forEach((workListElement) { + if (workListElement.key == "ITG") { + workListElement.value = providerData.itgFormsModel?.totalCount ?? 0; + } else { + var tempList = providerData.getOpenNotificationsList?.where((notificationElement) => notificationElement.itemType == workListElement.key).toList(); + if (tempList!.isNotEmpty) { + workListElement.value = tempList.first.openNtfNumber ?? 0; + } + } + }); + getWorkList(); + } + + ItgFormsModel? itgFormsModel; + int? itgRequestTypeIndex; + + void getWorkList() async { + try { + Utils.showLoading(context); + if (workListItemTypes[workListItemIndex].key == "ITG") { + itgFormsModel = await WorkListApiClient().GetITGTaskCountRequestType(); + List requestAllList = []; + for (int i = 0; i < (itgFormsModel?.requestType!.length ?? 0); i++) { + requestAllList = requestAllList + (itgFormsModel?.requestType![i].requestDetails ?? []); + } + itgFormsModel?.requestType!.insert(0, RequestType(requestDetails: requestAllList, requestTypeCode: "all", requestTypeName: "All")); + if ((itgFormsModel?.requestType?.length ?? 0) > 0) { + itgRequestTypeIndex = 0; + } + } else { + itgRequestTypeIndex = null; + workList = await WorkListApiClient().getWorkList(pageNumber, workListItemTypes[workListItemIndex].key); + } + Utils.hideLoading(context); + setState(() {}); + } catch (ex) { + Utils.hideLoading(context); + Utils.handleException(ex, null); + } + } + + @override + void dispose() { + super.dispose(); + } + @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, - appBar: appBar( + appBar: AppBarWidget( context, title: LocaleKeys.workList.tr(), ), - body: Container( + body: SizedBox( width: double.infinity, height: double.infinity, child: Column( @@ -31,67 +118,151 @@ class _WorkListScreenState extends State { children: [ Container( width: double.infinity, - height: 2, - color: MyColors.darkWhiteColor, + height: 1, + color: MyColors.lightGreyEFColor, ), - Container( - width: double.infinity, + SizedBox( height: 40, - margin: EdgeInsets.only( - top: 21, - ), child: ListView.separated( itemBuilder: (context, index) { return Container( - padding: EdgeInsets.only( - left: 30, - right: 30, - ), + padding: const EdgeInsets.only(left: 21, right: 21, top: 8, bottom: 8), alignment: Alignment.center, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(6), - color: tabList[index].isSelected - ? MyColors.darkIconColor - : MyColors.lightGreyEAColor, - ), - child: tabList[index].title.toText12( - color: tabList[index].isSelected - ? MyColors.white - : MyColors.black, - ), - ); - }, - separatorBuilder: (context, index) { - return 8.width; + decoration: BoxDecoration(borderRadius: BorderRadius.circular(6), color: workListItemIndex == index ? MyColors.darkIconColor : MyColors.lightGreyEAColor), + child: ("${workListItemTypes[index].name} ${workListItemTypes[index].value > 0 ? "(${workListItemTypes[index].value})" : ""}") + .toText12(color: workListItemIndex == index ? MyColors.white : MyColors.black), + ).onPress(() { + if (workListItemIndex != index) { + workListItemIndex = index; + if (workListItemTypes[index].value == 0) { + workList = []; + } else { + workList = null; + } + setState(() {}); + if (workListItemTypes[index].value > 0) { + getWorkList(); + } + } + }); }, + separatorBuilder: (context, index) => 8.width, shrinkWrap: true, - itemCount: tabList.length, + itemCount: workListItemTypes.length, scrollDirection: Axis.horizontal, - padding: const EdgeInsets.only( - left: 21, - right: 21, + padding: const EdgeInsets.only(left: 21, right: 21), + ), + ).paddingOnly(top: 21, bottom: 21), + workListItemTypes[workListItemIndex].fullName.toSectionHeading().paddingOnly(left: 21, right: 21), + if (itgRequestTypeIndex != null) + SizedBox( + height: 40, + child: ListView.separated( + itemBuilder: (context, index) { + RequestType type = itgFormsModel!.requestType![index]; + return Container( + padding: const EdgeInsets.only(left: 21, right: 21, top: 8, bottom: 8), + alignment: Alignment.center, + decoration: BoxDecoration(borderRadius: BorderRadius.circular(30), color: itgRequestTypeIndex == index ? MyColors.darkIconColor : MyColors.lightGreyEAColor), + child: ("${type.requestTypeName}").toText12(color: itgRequestTypeIndex == index ? MyColors.white : MyColors.black), + ).onPress(() { + if (itgRequestTypeIndex != index) { + itgRequestTypeIndex = index; + setState(() {}); + } + }); + }, + separatorBuilder: (context, index) => 8.width, + shrinkWrap: true, + itemCount: itgFormsModel?.requestType?.length ?? 0, + scrollDirection: Axis.horizontal, + padding: const EdgeInsets.only(left: 21, right: 21), ), + ).paddingOnly(top: 16, bottom: 16), + itgRequestTypeIndex != null + ? Expanded( + child: ListView.separated( + physics: BouncingScrollPhysics(), + itemBuilder: (context, index) { + return itgRowItem(workListItemTypes[workListItemIndex], itgFormsModel!.requestType![itgRequestTypeIndex!].requestDetails![index]); + }, + separatorBuilder: (context, index) => 12.height, + itemCount: itgFormsModel!.requestType![itgRequestTypeIndex!].requestDetails?.length ?? 0, + padding: EdgeInsets.only(top: 16, left: 21, right: 21), + ), + ) + : Expanded( + child: workList != null + ? ((workList!).isEmpty + ? "No History Available".toText16().center + : ListView.separated( + physics: BouncingScrollPhysics(), + itemBuilder: (context, index) { + return rowItem(workListItemTypes[workListItemIndex], workList![index]); + }, + separatorBuilder: (context, index) => 12.height, + itemCount: workList?.length ?? 0, + padding: EdgeInsets.only(top: 21, left: 21, right: 21), + )) + : const SizedBox(), + ), + ], + ), + ), + ); + } + + Widget itgRowItem(WorkListItemTypeModelData data, RequestDetails requestDetails) { + return InkWell( + onTap: () { + Navigator.pushNamed(context, AppRoutes.missingSwipe); + }, + child: Container( + width: double.infinity, + padding: const EdgeInsets.only(left: 12, right: 12, top: 10, bottom: 10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: const Color(0xff000000).withOpacity(.05), + blurRadius: 26, + offset: const Offset(0, -3), + ), + ], + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(4), + gradient: LinearGradient(transform: GradientRotation(.218), begin: Alignment.topRight, end: Alignment.bottomRight, colors: data.color), ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [SvgPicture.asset("assets/images/miss_swipe.svg", width: 20, height: 20, color: Colors.white), 2.height, data.name.toText10(color: Colors.white)], + ).paddingAll(6), ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - LocaleKeys.human.toText12(), - LocaleKeys.resources.tr().toText24(isBold: true), - ], - ).paddingOnly(top: 24, left: 21, right: 21), - 24.height, + 8.width, Expanded( - child: ListView.separated( - itemBuilder: (context, index) { - return rowItem(typesList[index]); - }, - separatorBuilder: (context, index) { - return 12.height; - }, - itemCount: typesList.length, - padding: EdgeInsets.only(left: 21, right: 21), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + requestDetails.title!.toText12(color: MyColors.grey57Color), + 10.height, + Row( + children: [ + DateUtil.formatDateToDate(DateUtil.convertStringToDate(requestDetails.modifiedDate!), false).toText10(color: MyColors.lightTextColor).expanded, + SvgPicture.asset( + "assets/images/arrow_next.svg", + color: MyColors.darkIconColor, + ) + ], + ), + ], ), ), ], @@ -100,14 +271,14 @@ class _WorkListScreenState extends State { ); } - Widget rowItem(Types types) { + Widget rowItem(WorkListItemTypeModelData data, WorkListResponseModel workData) { return InkWell( - onTap: (){ + onTap: () { Navigator.pushNamed(context, AppRoutes.missingSwipe); }, child: Container( width: double.infinity, - padding: EdgeInsets.all(12), + padding: const EdgeInsets.only(left: 12, right: 12, top: 10, bottom: 10), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(10), @@ -126,39 +297,24 @@ class _WorkListScreenState extends State { Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(4), - gradient: LinearGradient( - transform: GradientRotation(.46), - begin: Alignment.topRight, - end: Alignment.bottomRight, - colors: types.colors), + gradient: LinearGradient(transform: GradientRotation(.218), begin: Alignment.topRight, end: Alignment.bottomRight, colors: data.color), ), child: Column( crossAxisAlignment: CrossAxisAlignment.center, - children: [ - SvgPicture.asset( - "assets/images/miss_swipe.svg", - color: Colors.white, - ), - 2.height, - types.title.toText10(color: Colors.white) - ], + children: [SvgPicture.asset("assets/images/miss_swipe.svg", width: 20, height: 20, color: Colors.white), 2.height, data.name.toText10(color: Colors.white)], ).paddingAll(6), ), - 12.width, + 8.width, Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, children: [ - "Missing Swipe Request".toText16(), - "Missing Swipe Request for Hussain, Mohammad has been approved" - .toText10(), - 12.height, + workData.sUBJECT!.toText12(color: MyColors.grey57Color), + 10.height, Row( children: [ - Expanded( - child: "07 Jan 2021" - .toText10(color: MyColors.lightTextColor)), + DateUtil.formatDateToDate(DateUtil.convertSimpleStringDateToDate(workData.bEGINDATE!), false).toText10(color: MyColors.lightTextColor).expanded, SvgPicture.asset( "assets/images/arrow_next.svg", color: MyColors.darkIconColor, @@ -174,33 +330,3 @@ class _WorkListScreenState extends State { ); } } - -class Tabs { - String title; - bool isSelected; - - Tabs(this.title, this.isSelected); -} - -List tabList = [ - Tabs("All", true), - Tabs("HR", false), - Tabs("MO", false), - Tabs("PR", false), - Tabs("PO", false), -]; - -class Types { - String title; - List colors; - - Types(this.title, this.colors); -} - -List typesList = [ - Types("HR", [Color(0xff32D892), Color(0xff1AB170)]), - Types("ITG", [Color(0xffEB8C90), Color(0xffDE6C70)]), - Types("PO", [Color(0xff5099E3), Color(0xff3670AA)]), - Types("PR", [Color(0xff48EACF), Color(0xff3DCAB3)]), - Types("MO", [Color(0xff58DCFA), Color(0xff3CB9D5)]), -]; diff --git a/lib/widgets/Updater.dart b/lib/widgets/Updater.dart new file mode 100644 index 0000000..154173d --- /dev/null +++ b/lib/widgets/Updater.dart @@ -0,0 +1,39 @@ +/* ZiK */ + +import 'dart:async'; +import 'package:flutter/cupertino.dart'; + +typedef ChildProvider = Widget Function(BuildContext context, E? data); + +class Updater extends StatelessWidget{ + final ChildProvider childProvider; + StreamController? sink; + T? initialData; + List _history = []; + + Stream? _stream; + Updater({T? initialData, required this.childProvider}){ + this.sink = StreamController(); + this.initialData = initialData; + _stream = this.sink?.stream; + } + + @override + Widget build(BuildContext context) { + return StreamBuilder( + initialData: this.initialData, + stream: _stream, + builder: (ctx, snapshot){ + return childProvider(context, snapshot.data); + }); + } + + pushData(T? data) { + _history.add(data); + sink?.sink.add(data); + } + + List getDataHistory() => _history; + T? getLatestData() => _history.last; + +} \ No newline at end of file diff --git a/lib/widgets/app_bar_widget.dart b/lib/widgets/app_bar_widget.dart new file mode 100644 index 0000000..f079f7f --- /dev/null +++ b/lib/widgets/app_bar_widget.dart @@ -0,0 +1,44 @@ +import 'package:flutter/material.dart'; +import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/extensions/int_extensions.dart'; +import 'package:mohem_flutter_app/extensions/string_extensions.dart'; +import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; + +AppBar AppBarWidget(BuildContext context, {required String title, bool showHomeButton = false}) { + return AppBar( + leadingWidth: 0, + // leading: GestureDetector( + // behavior: HitTestBehavior.opaque, + // onTap: Feedback.wrapForTap(() => Navigator.maybePop(context), context), + // child: const Icon(Icons.arrow_back_ios, color: MyColors.darkIconColor), + // ), + //titleSpacing: -1.44, + title: Row( + children: [ + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: Feedback.wrapForTap(() => Navigator.maybePop(context), context), + child: const Icon(Icons.arrow_back_ios, color: MyColors.darkIconColor), + ), + 4.width, + title.toText24(color: MyColors.darkTextColor, isBold: true, considerHeight: false).expanded, + ], + ), + centerTitle: false, + elevation: 0, + backgroundColor: Colors.white, + actions: [ + if (showHomeButton) + IconButton( + onPressed: () { + // Navigator.pushAndRemoveUntil( + // context, + // MaterialPageRoute(builder: (context) => LandingPage()), + // (Route route) => false, + // ); + }, + icon: const Icon(Icons.home, color: MyColors.darkIconColor), + ), + ], + ); +} diff --git a/lib/widgets/dialogs/confirm_dialog.dart b/lib/widgets/dialogs/confirm_dialog.dart new file mode 100644 index 0000000..7264a9b --- /dev/null +++ b/lib/widgets/dialogs/confirm_dialog.dart @@ -0,0 +1,66 @@ +import 'package:easy_localization/src/public_ext.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; +import 'package:mohem_flutter_app/widgets/button/default_button.dart'; + +class ConfirmDialog extends StatelessWidget { + final String? title; + final String? message; + final String? okTitle; + final VoidCallback? onTap; + + const ConfirmDialog({Key? key, this.title, @required this.message, this.okTitle, this.onTap}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Dialog( + backgroundColor: Colors.white, + shape: RoundedRectangleBorder(), + insetPadding: EdgeInsets.only(left: 21, right: 21), + child: Padding( + padding: EdgeInsets.only(left: 20, right: 20, top: 18, bottom: 28), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.only(top: 16.0), + child: Text( + title ?? LocaleKeys.confirm.tr(), + style: TextStyle(fontSize: 24, fontWeight: FontWeight.w600, color: Color(0xff2B353E), height: 35 / 24, letterSpacing: -0.96), + ), + ), + ), + IconButton( + padding: EdgeInsets.zero, + icon: Icon(Icons.close), + color: Color(0xff2B353E), + constraints: BoxConstraints(), + onPressed: () { + Navigator.pop(context); + }, + ) + ], + ), + Text( + message ?? "", + style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Color(0xff808080), letterSpacing: -0.48), + ), + SizedBox(height: 28), + DefaultButton( + okTitle ?? LocaleKeys.ok.tr(), + onTap == null ? () => Navigator.pop(context) : onTap, + textColor: Colors.white, + //color: Ap.green, + ), + ], + ), + ), + ); + } +} diff --git a/lib/widgets/input_widget.dart b/lib/widgets/input_widget.dart index 8b248e4..7761816 100644 --- a/lib/widgets/input_widget.dart +++ b/lib/widgets/input_widget.dart @@ -12,15 +12,10 @@ class InputWidget extends StatelessWidget { final bool isInputTypeNum; final bool isObscureText; final bool isBackgroundEnable; + final Function(String)? onChange; InputWidget(this.labelText, this.hintText, this.controller, - {this.isObscureText = false, - this.suffixTap, - this.isEnable = true, - this.hasSelection = false, - this.lines = 1, - this.isInputTypeNum = false, - this.isBackgroundEnable = false}); + {this.isObscureText = false, this.suffixTap, this.isEnable = true, this.hasSelection = false, this.lines = 1, this.onChange, this.isInputTypeNum = false, this.isBackgroundEnable = false}); @override Widget build(BuildContext context) { @@ -56,14 +51,12 @@ class InputWidget extends StatelessWidget { TextField( enabled: isEnable, scrollPadding: EdgeInsets.zero, - keyboardType: isInputTypeNum - ? TextInputType.number - : TextInputType.text, + keyboardType: isInputTypeNum ? TextInputType.number : TextInputType.text, controller: controller, maxLines: lines, obscuringCharacter: "*", obscureText: isObscureText, - onChanged: (value) => {}, + onChanged: onChange, style: const TextStyle( fontSize: 14, height: 21 / 14, @@ -82,12 +75,7 @@ class InputWidget extends StatelessWidget { letterSpacing: -0.56, ), suffixIconConstraints: const BoxConstraints(minWidth: 50), - suffixIcon: suffixTap == null - ? null - : IconButton( - icon: const Icon(Icons.mic, - color: MyColors.darkTextColor), - onPressed: suffixTap), + suffixIcon: suffixTap == null ? null : IconButton(icon: const Icon(Icons.mic, color: MyColors.darkTextColor), onPressed: suffixTap), contentPadding: EdgeInsets.zero, border: InputBorder.none, focusedBorder: InputBorder.none, diff --git a/lib/widgets/location/Location.dart b/lib/widgets/location/Location.dart new file mode 100644 index 0000000..bd39e2e --- /dev/null +++ b/lib/widgets/location/Location.dart @@ -0,0 +1,249 @@ +import 'dart:async'; +import 'dart:math'; +import 'dart:ui'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:geolocator/geolocator.dart'; +import 'package:google_directions_api/google_directions_api.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:mohem_flutter_app/classes/utils.dart'; +// import 'package:geodesy/geodesy.dart' as geodesy; + +import '../../classes/app_permissions.dart'; +import '../../theme/colors.dart'; + + +//Created By Mr.Zohaib +class Location { + static _Map map = _Map(); + + static havePermission(Function(bool) callback) { + Geolocator.checkPermission().then((value) async { + if (value == LocationPermission.denied) { + value = await Geolocator.requestPermission(); + callback(![LocationPermission.denied, LocationPermission.deniedForever].contains(value)); + } else { + callback(true); + } + }); + } + + static isEnabled(Function(bool) callback) { + Geolocator.isLocationServiceEnabled().then((value) => callback(value)); + } + + static bool _listeningSettingChange = true; + + static listenGPS({bool change = true, Function(bool)? onChange}) async { + _listeningSettingChange = change; + if (change == false) return; + + Future.doWhile(() async { + await Utils.delay(1000); + var enable = await Geolocator.isLocationServiceEnabled(); + onChange!(enable); + return _listeningSettingChange; + }); + } + + static getCurrentLocation(Function(LatLng?) callback) { + done(Position position) { + //AppStorage.sp.saveLocation(position); + + LatLng? myCurrentLocation = LatLng(position.latitude, position.longitude); + callback(myCurrentLocation); + } + + AppPermissions.location((granted) { + + if (granted) + Geolocator.getLastKnownPosition(forceAndroidLocationManager: true).then((value) { + if (value == null) { + Geolocator.getCurrentPosition().then((value) { + done(value); + }); + } else { + done(value); + } + }); + }); + } + + // static LatLng locationAwayFrom( + // {required LatLng loc1, num distanceMeters = 200.0, num bearing = 270.0}) { + // geodesy.LatLng l1 = geodesy.LatLng(loc1.latitude, loc1.longitude); + // geodesy.LatLng destinationPoint = geodesy.Geodesy() + // .destinationPointByDistanceAndBearing(l1, distanceMeters, bearing); + // return LatLng(destinationPoint.latitude, destinationPoint.longitude); + // } + + static Future distanceTo(LatLng destination) async { + var myLoc = await Geolocator.getLastKnownPosition(); + var distance = 0.0; + if (myLoc != null) { + distance = Geolocator.distanceBetween(destination.latitude, destination.longitude, myLoc.latitude, myLoc.longitude); + } + return distance; + } +} + +class _Map { + Marker createMarker( + String id, { + required LatLng coordinates, + BitmapDescriptor? icon, + VoidCallback? onTap, + }) { + final MarkerId markerId = MarkerId(id); + return Marker( + icon: icon ?? BitmapDescriptor.defaultMarker, + markerId: markerId, + position: coordinates, + flat: false, + // infoWindow: InfoWindow(title: id, snippet: '*'), + onTap: onTap, + ); + } + + CameraPosition initialCamera({required Completer mapController, LatLng? position, double zoom = 12}) { + position = position ?? LatLng(24.7249303, 46.5416656); + CameraPosition riyadhEye = CameraPosition( + target: position, + zoom: zoom, + ); + mapController.future.then((controller) { + controller.animateCamera(CameraUpdate.newCameraPosition(riyadhEye)); + }); + return riyadhEye; + } + + CameraPosition moveTo(LatLng location, {double zoom = 12, double direction = 0.0, required Completer mapController, bool? animation}) { + var camera = CameraPosition(target: location, zoom: zoom, bearing: direction); + mapController.future.then((controller) { + animation ?? false ? controller.animateCamera(CameraUpdate.newCameraPosition(camera)) : controller.moveCamera(CameraUpdate.newCameraPosition(camera)); + }); + return camera; + } + + moveCamera(CameraPosition camera, @required Completer mapController, bool animation) { + mapController.future.then((controller) { + animation ? controller.animateCamera(CameraUpdate.newCameraPosition(camera)) : controller.moveCamera(CameraUpdate.newCameraPosition(camera)); + }); + } + + scrollBy({double x = 0, double y = 0, required Completer mapController, bool animation = true}) { + var camera = CameraUpdate.scrollBy(x, y); + mapController.future.then((controller) { + animation ? controller.animateCamera(camera) : controller.moveCamera(camera); + }); + } + + goToCurrentLocation({Completer? mapController, double? direction = 0.0, bool? animation}) { + Location.getCurrentLocation((location) { + moveTo(location!, zoom: 17, mapController: mapController!, animation: animation, direction: direction!); + }); + } + + var routes = Map(); + + setRoutePolylines(LatLng? source, LatLng? destination, Set polylines, Completer mapController, Function(DirectionsRoute?) completion) { + if (source == null || destination == null) { + completion(null); + return; + } + + var origin = '${source.latitude},${source.longitude}'; + var destin = '${destination.latitude},${destination.longitude}'; + var routeId = '$origin->$destination'; + + createPolyline(DirectionsRoute results) { + List polylineCoordinates = results.overviewPath!.map((e) => LatLng(e.latitude, e.longitude)).toList(); + PolylineId id = PolylineId("route"); + Polyline polyline = Polyline( + polylineId: id, + color: accentColor, + width: 5, + jointType: JointType.round, + startCap: Cap.roundCap, + endCap: Cap.roundCap, + points: polylineCoordinates, + ); + + polylines.removeWhere((element) => true); + polylines.add(polyline); + + LatLngBounds bound = getBounds(coordinates: polylineCoordinates); + focusCameraToLatLngBounds(bound: bound, mapController: mapController, padding: 100); + completion(routes[routeId]); + } + + var availableRoute = routes[routeId]; + if (availableRoute == null) { + var request = DirectionsRequest(origin: origin, destination: destin); + DirectionsService().route(request, (response, status) { + if (status == DirectionsStatus.ok && response.routes!.isNotEmpty) { + routes[routeId] = response.routes!.first; + createPolyline(response.routes!.first); + } + }); + } else { + createPolyline(availableRoute); + } + } + + LatLngBounds getBounds({required List coordinates}) { + var lngs = coordinates.map((c) => c.longitude).toList(); + var lats = coordinates.map((c) => c.latitude).toList(); + + double bottomMost = lngs.reduce(min); + double topMost = lngs.reduce(max); + double leftMost = lats.reduce(min); + double rightMost = lats.reduce(max); + + LatLngBounds bounds = LatLngBounds( + northeast: LatLng(rightMost, topMost), + southwest: LatLng(leftMost, bottomMost), + ); + return bounds; + + double? x0, x1, y0, y1; + for (LatLng latLng in coordinates) { + if (x0 == null) { + x0 = x1 = latLng.latitude; + y0 = y1 = latLng.longitude; + } else { + if (latLng.latitude > x1!) x1 = latLng.latitude; + if (latLng.latitude < x0) x0 = latLng.latitude; + if (latLng.longitude > y1!) y1 = latLng.longitude; + if (latLng.longitude < y0!) y0 = latLng.longitude; + } + } + return LatLngBounds(northeast: LatLng(x1!, y1!), southwest: LatLng(x0!, y0!)); + } + + focusCameraToLatLngBounds({LatLngBounds? bound, Completer? mapController, double? padding}) async { + if (bound == null) return; + + CameraUpdate camera = CameraUpdate.newLatLngBounds(bound, padding!); + final GoogleMapController controller = await mapController!.future; + controller.animateCamera(camera); + } + + focusCameraTo2Points({LatLng? point1, LatLng? point2, Completer? mapController, double? padding}) async { + var source = point1; + var destination = point2; + if (source != null && destination != null) { + // 'package:google_maps_flutter_platform_interface/src/types/location.dart': Failed assertion: line 72 pos 16: 'southwest.latitude <= northeast.latitude': is not true. + LatLngBounds bound; + if (source.latitude <= destination.latitude) { + bound = LatLngBounds(southwest: source, northeast: destination); + } else { + bound = LatLngBounds(southwest: destination, northeast: source); + } + + if (bound == null) return; + + focusCameraToLatLngBounds(bound: bound, mapController: mapController, padding: padding); + } + } +} diff --git a/lib/widgets/nfc/nfc_reader_sheet.dart b/lib/widgets/nfc/nfc_reader_sheet.dart new file mode 100644 index 0000000..84397ba --- /dev/null +++ b/lib/widgets/nfc/nfc_reader_sheet.dart @@ -0,0 +1,187 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:nfc_manager/nfc_manager.dart'; +import 'package:nfc_manager/platform_tags.dart'; + +void showNfcReader(BuildContext context, {required Function(String? nfcId) onNcfScan}) { + showModalBottomSheet( + context: context, + enableDrag: false, + isDismissible: false, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only(topLeft: Radius.circular(12), topRight: Radius.circular(12)), + ), + backgroundColor: Colors.white, + builder: (context) { + return NfcLayout( + onNcfScan: onNcfScan, + ); + }, + ); +} + +class NfcLayout extends StatefulWidget { + Function(String? nfcId) onNcfScan; + + NfcLayout({required this.onNcfScan}); + + @override + _NfcLayoutState createState() => _NfcLayoutState(); +} + +class _NfcLayoutState extends State { + bool _reading = false; + Widget? mainWidget; + String? nfcId; + + @override + void initState() { + super.initState(); + + NfcManager.instance.startSession(onDiscovered: (NfcTag tag) async { + print(tag.data); + var f = MifareUltralight(tag: tag, identifier: tag.data["nfca"]["identifier"], type: 2, maxTransceiveLength: 252, timeout: 22); + final String identifier = f.identifier.map((e) => e.toRadixString(16).padLeft(2, '0')).join(''); + // print(identifier); // => 0428fcf2255e81 + nfcId = identifier; + + setState(() { + _reading = true; + mainWidget = doneNfc(); + }); + + Future.delayed(const Duration(seconds: 1), () { + NfcManager.instance.stopSession(); + Navigator.pop(context); + widget.onNcfScan(nfcId); + }); + }); + } + + @override + Widget build(BuildContext context) { + (mainWidget == null && !_reading) ? mainWidget = scanNfc() : mainWidget = doneNfc(); + return AnimatedSwitcher(duration: Duration(milliseconds: 500), child: mainWidget); + } + + Widget scanNfc() { + return Container( + key: ValueKey(1), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + height: 30, + ), + Text( + "Ready To Scan", + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 24, + ), + ), + SizedBox( + height: 30, + ), + Image.asset( + "assets/icons/nfc/ic_nfc.png", + height: MediaQuery.of(context).size.width / 3, + ), + SizedBox( + height: 30, + ), + Text( + "Approach an NFC Tag", + style: TextStyle( + fontSize: 18, + ), + ), + SizedBox( + height: 30, + ), + ButtonTheme( + minWidth: MediaQuery.of(context).size.width / 1.2, + height: 45.0, + buttonColor: Colors.grey[300], + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6), + ), + child: RaisedButton( + onPressed: () { + NfcManager.instance.stopSession(); + Navigator.pop(context); + }, + elevation: 0, + child: Text("CANCEL"), + ), + ), + SizedBox( + height: 30, + ), + ], + ), + ); + } + + Widget doneNfc() { + return Container( + key: ValueKey(2), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + height: 30, + ), + Text( + "Successfully Scanned", + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 24, + ), + ), + SizedBox( + height: 30, + ), + Image.asset( + "assets/icons/nfc/ic_done.png", + height: MediaQuery.of(context).size.width / 3, + ), + SizedBox( + height: 30, + ), + Text( + "Approach an NFC Tag", + style: TextStyle( + fontSize: 18, + ), + ), + SizedBox( + height: 30, + ), + ButtonTheme( + minWidth: MediaQuery.of(context).size.width / 1.2, + height: 45.0, + buttonColor: Colors.grey[300], + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6), + ), + child: RaisedButton( + // onPressed: () { + // _stream?.cancel(); + // widget.onNcfScan(nfcId); + // Navigator.pop(context); + // }, + onPressed: null, + elevation: 0, + child: Text("DONE"), + ), + ), + SizedBox( + height: 30, + ), + ], + ), + ); + } +} diff --git a/lib/widgets/shimmer/dashboard_shimmer_widget.dart b/lib/widgets/shimmer/dashboard_shimmer_widget.dart new file mode 100644 index 0000000..5b5bd60 --- /dev/null +++ b/lib/widgets/shimmer/dashboard_shimmer_widget.dart @@ -0,0 +1,189 @@ +import 'package:easy_localization/src/public_ext.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:mohem_flutter_app/extensions/int_extensions.dart'; +import 'package:mohem_flutter_app/extensions/string_extensions.dart'; +import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; +import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; +import 'package:shimmer/shimmer.dart'; + +class GetAttendanceTrackingShimmer extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + width: double.infinity, + height: double.infinity, + clipBehavior: Clip.antiAlias, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(15), + boxShadow: [ + BoxShadow( + color: const Color(0xff000000).withOpacity(.05), + blurRadius: 26, + offset: const Offset(0, -3), + ), + ], + ), + child: Stack( + alignment: Alignment.center, + children: [ + // SvgPicture.asset("assets/images/"), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.markAttendance.tr().toText14(color: Colors.white, isBold: true).toShimmer(), + 16.height, + "07:55:12".toText10(color: Colors.white, isBold: true).toShimmer(), + 3.height, + LocaleKeys.timeLeftToday.tr().toText10(color: Colors.white).toShimmer(), + 9.height, + const ClipRRect( + borderRadius: BorderRadius.all( + Radius.circular(20), + ), + child: LinearProgressIndicator( + value: 0.7, + minHeight: 8, + valueColor: const AlwaysStoppedAnimation(Colors.white), + backgroundColor: const Color(0xff196D73), + ), + ).toShimmer(), + ], + ).paddingOnly(top: 12, right: 15, left: 12), + ), + Row( + children: [ + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.checkIn.tr().toText12(color: Colors.white).toShimmer(), + ], + ).paddingOnly(left: 12), + ), + Container( + width: 45, + height: 45, + // color: Colors.blue, + padding: const EdgeInsets.only(left: 14, right: 14), + ).toShimmer(), + ], + ), + ], + ), + ], + ), + ); + } +} + +class MenuShimmer extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + clipBehavior: Clip.antiAlias, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(15), + boxShadow: [ + BoxShadow( + color: const Color(0xff000000).withOpacity(.05), + blurRadius: 26, + offset: const Offset(0, -3), + ), + ], + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.workList.tr().toText12(color: Colors.white).toShimmer(), + Row( + children: [ + Expanded( + flex: 3, + child: 123.toString().toText10(color: Colors.white, isBold: true).toShimmer(), + ), + 12.width, + SvgPicture.asset("assets/images/arrow_next.svg", color: Colors.white).toShimmer() + ], + ) + ], + ).paddingOnly(left: 10, right: 10, bottom: 6, top: 6), + ); + } +} + +class ServicesHeaderShimmer extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + "Other".tr().toText10().toShimmer(), + 6.height, + LocaleKeys.services.tr().toText12(isBold: true).toShimmer(), + ], + ), + ), + LocaleKeys.viewAllServices.tr().toText12(isUnderLine: true).toShimmer(), + ], + ); + } +} + +class ServicesMenuShimmer extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(15), + boxShadow: [ + BoxShadow( + color: const Color(0xff000000).withOpacity(.05), + blurRadius: 26, + offset: const Offset(0, -3), + ), + ], + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SvgPicture.asset("assets/images/monthly_attendance.svg").toShimmer(), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + "Attendan".toText11(isBold: false).toShimmer(), + 5.height, + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Expanded( + child: "Attendance".toText11(isBold: false).toShimmer(), + ), + 6.width, + SvgPicture.asset("assets/images/arrow_next.svg").paddingOnly(bottom: 4).toShimmer() + ], + ), + ], + ) + ], + ).paddingOnly(left: 10, right: 10, bottom: 10, top: 12), + ); + } +} diff --git a/lib/widgets/swipe/nfc_reader_sheet.dart b/lib/widgets/swipe/nfc_reader_sheet.dart new file mode 100644 index 0000000..3dc357d --- /dev/null +++ b/lib/widgets/swipe/nfc_reader_sheet.dart @@ -0,0 +1,194 @@ +// import 'dart:async'; +// +// import 'package:flutter/material.dart'; +// +// +// void showNfcReader(BuildContext context, {Function onNcfScan}) { +// showModalBottomSheet( +// context: context, +// enableDrag: false, +// isDismissible: false, +// shape: RoundedRectangleBorder( +// borderRadius: BorderRadius.only(topLeft: Radius.circular(12), topRight: Radius.circular(12)), +// ), +// backgroundColor: Colors.white, +// builder: (context) { +// return NfcLayout( +// onNcfScan: onNcfScan, +// ); +// }); +// } +// +// class NfcLayout extends StatefulWidget { +// Function onNcfScan; +// +// NfcLayout({this.onNcfScan}); +// +// @override +// _NfcLayoutState createState() => _NfcLayoutState(); +// } +// +// class _NfcLayoutState extends State { +// StreamSubscription _stream; +// bool _reading = false; +// Widget mainWidget; +// String nfcId; +// +// @override +// void initState() { +// super.initState(); +// +// setState(() { +// // _reading = true; +// // Start reading using NFC.readNDEF() +// _stream = NFC.readNDEF(once: false, throwOnUserCancel: false, readerMode: NFCDispatchReaderMode()).listen((NDEFMessage message) { +// setState(() { +// _reading = true; +// mainWidget = doneNfc(); +// }); +// Future.delayed(const Duration(milliseconds: 500), () { +// _stream?.cancel(); +// widget.onNcfScan(nfcId); +// Navigator.pop(context); +// }); +// print("read NDEF id: ${message.id}"); +// print("NFC Record " + message.payload); +// print("NFC Record Lenght " + message.records.length.toString()); +// print("NFC Record " + message.records.first.id); +// print("NFC Record " + message.records.first.payload); +// print("NFC Record " + message.records.first.data); +// print("NFC Record " + message.records.first.type); +// // widget.onNcfScan(message.id); +// nfcId = message.id; +// }, onError: (e) { +// // Check error handling guide below +// }); +// }); +// } +// +// @override +// Widget build(BuildContext context) { +// (mainWidget == null && !_reading) ? mainWidget = scanNfc() : mainWidget = doneNfc(); +// return AnimatedSwitcher(duration: Duration(milliseconds: 500), child: mainWidget); +// } +// +// Widget scanNfc() { +// return Container( +// key: ValueKey(1), +// child: Column( +// mainAxisSize: MainAxisSize.min, +// children: [ +// SizedBox( +// height: 30, +// ), +// Text( +// "Ready To Scan", +// style: TextStyle( +// fontWeight: FontWeight.bold, +// fontSize: 24, +// ), +// ), +// SizedBox( +// height: 30, +// ), +// Image.asset( +// "assets/images/nfc/ic_nfc.png", +// height: MediaQuery.of(context).size.width / 3, +// ), +// SizedBox( +// height: 30, +// ), +// Text( +// "Approach an NFC Tag", +// style: TextStyle( +// fontSize: 18, +// ), +// ), +// SizedBox( +// height: 30, +// ), +// ButtonTheme( +// minWidth: MediaQuery.of(context).size.width / 1.2, +// height: 45.0, +// buttonColor: Colors.grey[300], +// shape: RoundedRectangleBorder( +// borderRadius: BorderRadius.circular(6), +// ), +// child: RaisedButton( +// onPressed: () { +// _stream?.cancel(); +// Navigator.pop(context); +// }, +// elevation: 0, +// child: Text("CANCEL"), +// ), +// ), +// SizedBox( +// height: 30, +// ), +// ], +// ), +// ); +// } +// +// Widget doneNfc() { +// return Container( +// key: ValueKey(2), +// child: Column( +// mainAxisSize: MainAxisSize.min, +// children: [ +// SizedBox( +// height: 30, +// ), +// Text( +// "Successfully Scanned", +// style: TextStyle( +// fontWeight: FontWeight.bold, +// fontSize: 24, +// ), +// ), +// SizedBox( +// height: 30, +// ), +// Image.asset( +// "assets/images/nfc/ic_done.png", +// height: MediaQuery.of(context).size.width / 3, +// ), +// SizedBox( +// height: 30, +// ), +// Text( +// "Approach an NFC Tag", +// style: TextStyle( +// fontSize: 18, +// ), +// ), +// SizedBox( +// height: 30, +// ), +// ButtonTheme( +// minWidth: MediaQuery.of(context).size.width / 1.2, +// height: 45.0, +// buttonColor: Colors.grey[300], +// shape: RoundedRectangleBorder( +// borderRadius: BorderRadius.circular(6), +// ), +// child: RaisedButton( +// // onPressed: () { +// // _stream?.cancel(); +// // widget.onNcfScan(nfcId); +// // Navigator.pop(context); +// // }, +// onPressed: null, +// elevation: 0, +// child: Text("DONE"), +// ), +// ), +// SizedBox( +// height: 30, +// ), +// ], +// ), +// ); +// } +// } diff --git a/pubspec.lock b/pubspec.lock deleted file mode 100644 index 1ae9d08..0000000 --- a/pubspec.lock +++ /dev/null @@ -1,500 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - args: - dependency: transitive - description: - name: args - url: "https://pub.dartlang.org" - source: hosted - version: "2.3.0" - async: - dependency: transitive - description: - name: async - url: "https://pub.dartlang.org" - source: hosted - version: "2.8.2" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - characters: - dependency: transitive - description: - name: characters - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.1" - clock: - dependency: transitive - description: - name: clock - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - collection: - dependency: transitive - description: - name: collection - url: "https://pub.dartlang.org" - source: hosted - version: "1.15.0" - crypto: - dependency: transitive - description: - name: crypto - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.1" - cupertino_icons: - dependency: "direct main" - description: - name: cupertino_icons - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.4" - easy_localization: - dependency: "direct main" - description: - name: easy_localization - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.0" - easy_logger: - dependency: transitive - description: - name: easy_logger - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.2" - fake_async: - dependency: transitive - description: - name: fake_async - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - ffi: - dependency: transitive - description: - name: ffi - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.2" - file: - dependency: transitive - description: - name: file - url: "https://pub.dartlang.org" - source: hosted - version: "6.1.2" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.4" - flutter_localizations: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - flutter_plugin_android_lifecycle: - dependency: transitive - description: - name: flutter_plugin_android_lifecycle - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.5" - flutter_svg: - dependency: "direct main" - description: - name: flutter_svg - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - flutter_web_plugins: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - fluttertoast: - dependency: "direct main" - description: - name: fluttertoast - url: "https://pub.dartlang.org" - source: hosted - version: "8.0.8" - http: - dependency: "direct main" - description: - name: http - url: "https://pub.dartlang.org" - source: hosted - version: "0.13.4" - http_parser: - dependency: transitive - description: - name: http_parser - url: "https://pub.dartlang.org" - source: hosted - version: "4.0.0" - injector: - dependency: "direct main" - description: - name: injector - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - intl: - dependency: transitive - description: - name: intl - url: "https://pub.dartlang.org" - source: hosted - version: "0.17.0" - js: - dependency: transitive - description: - name: js - url: "https://pub.dartlang.org" - source: hosted - version: "0.6.3" - lints: - dependency: transitive - description: - name: lints - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" - local_auth: - dependency: "direct main" - description: - name: local_auth - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.9" - matcher: - dependency: transitive - description: - name: matcher - url: "https://pub.dartlang.org" - source: hosted - version: "0.12.11" - meta: - dependency: transitive - description: - name: meta - url: "https://pub.dartlang.org" - source: hosted - version: "1.7.0" - nested: - dependency: transitive - description: - name: nested - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - path: - dependency: transitive - description: - name: path - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.0" - path_drawing: - dependency: transitive - description: - name: path_drawing - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - path_parsing: - dependency: transitive - description: - name: path_parsing - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - path_provider: - dependency: "direct main" - description: - name: path_provider - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.8" - path_provider_android: - dependency: transitive - description: - name: path_provider_android - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.9" - path_provider_ios: - dependency: transitive - description: - name: path_provider_ios - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.7" - path_provider_linux: - dependency: transitive - description: - name: path_provider_linux - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.4" - path_provider_macos: - dependency: transitive - description: - name: path_provider_macos - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.4" - path_provider_platform_interface: - dependency: transitive - description: - name: path_provider_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.1" - path_provider_windows: - dependency: transitive - description: - name: path_provider_windows - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.4" - permission_handler: - dependency: "direct main" - description: - name: permission_handler - url: "https://pub.dartlang.org" - source: hosted - version: "8.3.0" - permission_handler_platform_interface: - dependency: transitive - description: - name: permission_handler_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "3.7.0" - petitparser: - dependency: transitive - description: - name: petitparser - url: "https://pub.dartlang.org" - source: hosted - version: "4.4.0" - platform: - dependency: transitive - description: - name: platform - url: "https://pub.dartlang.org" - source: hosted - version: "3.1.0" - plugin_platform_interface: - dependency: transitive - description: - name: plugin_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.2" - process: - dependency: transitive - description: - name: process - url: "https://pub.dartlang.org" - source: hosted - version: "4.2.4" - provider: - dependency: "direct main" - description: - name: provider - url: "https://pub.dartlang.org" - source: hosted - version: "6.0.1" - shared_preferences: - dependency: transitive - description: - name: shared_preferences - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.11" - shared_preferences_android: - dependency: transitive - description: - name: shared_preferences_android - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.9" - shared_preferences_ios: - dependency: transitive - description: - name: shared_preferences_ios - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.8" - shared_preferences_linux: - dependency: transitive - description: - name: shared_preferences_linux - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.3" - shared_preferences_macos: - dependency: transitive - description: - name: shared_preferences_macos - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.2" - shared_preferences_platform_interface: - dependency: transitive - description: - name: shared_preferences_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - shared_preferences_web: - dependency: transitive - description: - name: shared_preferences_web - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.2" - shared_preferences_windows: - dependency: transitive - description: - name: shared_preferences_windows - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.3" - shimmer: - dependency: "direct main" - description: - name: shimmer - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - sizer: - dependency: "direct main" - description: - name: sizer - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.15" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.99" - source_span: - dependency: transitive - description: - name: source_span - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.1" - stack_trace: - dependency: transitive - description: - name: stack_trace - url: "https://pub.dartlang.org" - source: hosted - version: "1.10.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - string_scanner: - dependency: transitive - description: - name: string_scanner - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - term_glyph: - dependency: transitive - description: - name: term_glyph - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - test_api: - dependency: transitive - description: - name: test_api - url: "https://pub.dartlang.org" - source: hosted - version: "0.4.3" - typed_data: - dependency: transitive - description: - name: typed_data - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.0" - universal_io: - dependency: transitive - description: - name: universal_io - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.4" - vector_math: - dependency: transitive - description: - name: vector_math - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.1" - win32: - dependency: transitive - description: - name: win32 - url: "https://pub.dartlang.org" - source: hosted - version: "2.3.1" - xdg_directories: - dependency: transitive - description: - name: xdg_directories - url: "https://pub.dartlang.org" - source: hosted - version: "0.2.0" - xml: - dependency: transitive - description: - name: xml - url: "https://pub.dartlang.org" - source: hosted - version: "5.3.1" -sdks: - dart: ">=2.14.0 <3.0.0" - flutter: ">=2.5.0" diff --git a/pubspec.yaml b/pubspec.yaml index 868012d..d38cc5a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -18,7 +18,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: - sdk: ">=2.12.0 <3.0.0" + sdk: ">=2.16.0 <3.0.0" # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions @@ -39,12 +39,26 @@ dependencies: provider: ^6.0.1 easy_localization: ^3.0.0 http: ^0.13.4 - permission_handler: ^8.3.0 + permission_handler: ^9.2.0 flutter_svg: ^1.0.0 sizer: ^2.0.15 local_auth: ^1.1.9 fluttertoast: ^8.0.8 + shared_preferences: ^2.0.12 + firebase_messaging: ^11.2.8 shimmer: ^2.0.0 + logger: ^1.1.0 + flutter_countdown_timer: ^4.1.0 + nfc_manager: ^3.1.1 + uuid: ^3.0.6 + + # maps + google_maps_flutter: ^2.0.2 + google_maps_utils: ^1.4.0+1 + google_directions_api: ^0.9.0 + geolocator: any + # flutter_compass: ^0.6.1 + google_maps_flutter_web: ^0.3.2 dev_dependencies: @@ -80,6 +94,8 @@ flutter: - assets/images/ - assets/images/login/ - assets/images/logos/ + - assets/icons/nfc/ic_nfc.png + - assets/icons/nfc/ic_done.png # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware.