diff --git a/android/app/agconnect-services.json b/android/app/agconnect-services.json new file mode 100644 index 0000000..20a7546 --- /dev/null +++ b/android/app/agconnect-services.json @@ -0,0 +1,57 @@ +{ + "agcgw_all":{ + "CN":"connect-drcn.dbankcloud.cn", + "CN_back":"connect-drcn.hispace.hicloud.com", + "DE":"connect-dre.dbankcloud.cn", + "DE_back":"connect-dre.hispace.hicloud.com", + "RU":"connect-drru.hispace.dbankcloud.ru", + "RU_back":"connect-drru.hispace.dbankcloud.cn", + "SG":"connect-dra.dbankcloud.cn", + "SG_back":"connect-dra.hispace.hicloud.com" + }, + "websocketgw_all":{ + "CN":"connect-ws-drcn.hispace.dbankcloud.cn", + "CN_back":"connect-ws-drcn.hispace.dbankcloud.com", + "DE":"connect-ws-dre.hispace.dbankcloud.cn", + "DE_back":"connect-ws-dre.hispace.dbankcloud.com", + "RU":"connect-ws-drru.hispace.dbankcloud.ru", + "RU_back":"connect-ws-drru.hispace.dbankcloud.cn", + "SG":"connect-ws-dra.hispace.dbankcloud.cn", + "SG_back":"connect-ws-dra.hispace.dbankcloud.com" + }, + "client":{ + "cp_id":"2640966000002322881", + "product_id":"737518067793559971", + "client_id":"715996003571874624", + "client_secret":"B5B89A56A53847C6BB9D216A8747E75952760DF9A8232239D8744CD847A8FFDA", + "project_id":"737518067793559971", + "app_id":"104737117", + "api_key":"DAEDACKDrYgyco9mjPV9ZUjCSh1kCr/GBV0nseHH0z2mnxlZ41RksOKmyTi+PUTwmGEPK+VxCup4F9oUf4VbDnCsjB7aNBShYcjR+g==", + "package_name":"hmg.cloudSolutions.mohem" + }, + "oauth_client":{ + "client_id":"104737117", + "client_type":1 + }, + "app_info":{ + "app_id":"104737117", + "package_name":"hmg.cloudSolutions.mohem" + }, + "configuration_version":"3.0", + "appInfos":[ + { + "package_name":"hmg.cloudSolutions.mohem", + "client":{ + "app_id":"104737117" + }, + "app_info":{ + "package_name":"hmg.cloudSolutions.mohem", + "app_id":"104737117" + }, + "oauth_client":{ + "client_type":1, + "client_id":"104737117" + } + } + ] +} \ No newline at end of file diff --git a/android/app/build.gradle b/android/app/build.gradle index 198bc87..5279c1f 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -31,6 +31,7 @@ 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" +apply plugin: 'com.huawei.agconnect' android { compileSdkVersion 33 @@ -51,7 +52,7 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "hmg.cloudSolutions.mohem" - minSdkVersion 21 + minSdkVersion 28 targetSdkVersion 33 versionCode flutterVersionCode.toInteger() versionName flutterVersionName @@ -66,8 +67,14 @@ android { } } buildTypes { + debug { + signingConfig signingConfigs.debug + } release { signingConfig signingConfigs.release + minifyEnabled true + shrinkResources true + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index f187ebd..3f5e424 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -7,12 +7,21 @@ - + + + + + + + + + postParams = { - "UID": uuid.v4(), //Mobile Id + "UID": await PlatformDeviceId.getDeviceId, //uuid.v4(), //Mobile Id + // "UID": uuid.v4(), //Mobile Id "Latitude": lat, "Longitude": long, "QRValue": QRValue, @@ -199,17 +201,18 @@ class DashboardApiClient { }, url, postParams); } -// Future setAdvertisementViewed(String masterID, int advertisementId) async { -// String url = "${ApiConsts.cocRest}Mohemm_ITG_UpdateAdvertisementAsViewed"; -// -// Map postParams = { -// "ItgNotificationMasterId": masterID, -// "ItgAdvertisement": {"advertisementId": advertisementId, "acknowledgment": true} //Mobile Id -// }; -// postParams.addAll(AppState().postParamsJson); -// return await ApiClient().postJsonForObject((json) { -// // ItgMainRes responseData = ItgMainRes.fromJson(json); -// return json; -// }, url, postParams); -// } + Future setAdvertisementViewed(String masterID, int advertisementId) async { + String url = "${ApiConsts.cocRest}Mohemm_ITG_UpdateAdvertisementAsViewed"; + + Map postParams = { + "ItgNotificationMasterId": masterID, + "EmployeeNumber": AppState().memberInformationList!.eMPLOYEENUMBER.toString(), + "ItgAdvertisement": {"advertisementId": advertisementId, "acknowledgment": true} //Mobile Id + }; + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject((json) { + // ItgMainRes responseData = ItgMainRes.fromJson(json); + return json; + }, url, postParams); + } } diff --git a/lib/api/login_api_client.dart b/lib/api/login_api_client.dart index 7da7754..1b6b19e 100644 --- a/lib/api/login_api_client.dart +++ b/lib/api/login_api_client.dart @@ -145,4 +145,15 @@ class LoginApiClient { return responseData; }, url, postParams); } + + Future changePasswordFromActiveDirectorySession(String password, String email) async { + String url = "${ApiConsts.authenticationRest}SetPassword"; + Map postParams = {"EmailAddress": email, "Password": password, "generalid": "Cs2020@2016\$2958"}; + postParams.addAll(AppState().postParamsJson); + postParams["LogInTokenID"] = "@acT!V3D!r3Ct0rY"; // hard code token for active directory + return await ApiClient().postJsonForObject((json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData; + }, url, postParams); + } } diff --git a/lib/api/marathon/marathon_api_client.dart b/lib/api/marathon/marathon_api_client.dart index ee3810f..3d75d87 100644 --- a/lib/api/marathon/marathon_api_client.dart +++ b/lib/api/marathon/marathon_api_client.dart @@ -34,6 +34,20 @@ class MarathonApiClient { ); } + Future getMarathonersCount({required String marathonId}) async { + Response response = await ApiClient().getJsonForResponse( + ApiConsts.marathonGetMarathonersCount + '?marathonId=$marathonId', + token: AppState().getMarathonToken == null || AppState().getMarathonToken == "" ? await getMarathonToken() : AppState().getMarathonToken, + ); + + var json = jsonDecode(response.body); + logger.i("json in getMarathonersCount: $json"); + + MarathonGenericModel marathonGenericModel = MarathonGenericModel.fromJson(json); + + return marathonGenericModel.data as int; + } + Future getProjectId() async { return await ApiClient().postJsonForObject( (json) { @@ -73,8 +87,8 @@ class MarathonApiClient { Future joinMarathonAsParticipant() async { Map jsonObject = { "employeeNumber": AppState().memberInformationList!.eMPLOYEENUMBER ?? "", - "employeeNameAr": AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEAr ?? "", - "employeeNameEn": AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEEn ?? "", + "employeeNameAr": AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEAr ?? AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEEn ?? "", + "employeeNameEn": AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEEn ?? AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEAr ?? "", "marathonId": AppState().getMarathonProjectId!, }; diff --git a/lib/api/worklist/worklist_api_client.dart b/lib/api/worklist/worklist_api_client.dart index 82b865c..628701f 100644 --- a/lib/api/worklist/worklist_api_client.dart +++ b/lib/api/worklist/worklist_api_client.dart @@ -14,6 +14,8 @@ import 'package:mohem_flutter_app/models/get_mo_notification_body_list_model.dar import 'package:mohem_flutter_app/models/get_notification_buttons_list_model.dart'; import 'package:mohem_flutter_app/models/get_po_Item_history_list_model.dart'; import 'package:mohem_flutter_app/models/get_po_notification_body_list_model.dart'; +import 'package:mohem_flutter_app/models/get_pr_action_history_list_model.dart'; +import 'package:mohem_flutter_app/models/get_pr_information_list.dart'; import 'package:mohem_flutter_app/models/get_pr_notification_body_list_model.dart'; import 'package:mohem_flutter_app/models/get_quotation_analysis_list_model.dart'; import 'package:mohem_flutter_app/models/get_stamp_ms_notification_body_list_model.dart'; @@ -46,7 +48,7 @@ class WorkListApiClient { Map postParams = { "P_NOTIFICATION_TYPE": pNotificationType, "P_PAGE_NUM": pPageNum, - "P_PAGE_LIMIT": 25, + "P_PAGE_LIMIT": 20, "P_ITEM_TYPE": pItemType, "P_SEARCH_FROM_USER": pSearchUser, "P_SEARCH_ITEM_TYPE_DSP_NAME": pSearchItemType, @@ -90,6 +92,16 @@ class WorkListApiClient { }, url, postParams); } + Future> getPRAttachments(String pOLineID) async { + String url = "${ApiConsts.erpRest}GET_PR_ATTACHMENTS"; + Map postParams = {"P_PO_LINE_ID": pOLineID}; + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject((json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getPRAttachmentList ?? []; + }, url, postParams); + } + Future> getRFCEmployeeeList(int pNotificationID) async { String url = "${ApiConsts.erpRest}GET_RFC_EMPLOYEE_LIST"; Map postParams = {"P_NOTIFICATION_ID": pNotificationID, "P_PAGE_NUM": 1, "P_PAGE_LIMIT": 10}; @@ -114,6 +126,20 @@ class WorkListApiClient { }, url, postParams); } + Future> getActionHistoryForPR(String pOLineID) async { + String url = "${ApiConsts.erpRest}GET_PR_ACTION_HISTORY"; + Map postParams = { + "P_PO_LINE_ID": pOLineID, + "P_PAGE_LIMIT": 100, + "P_PAGE_NUM": 1, + }; + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject((json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getPRActionHistoryList?.reversed.toList() ?? []; + }, url, postParams); + } + Future> getNotificationButtons(int pNotificationID) async { String url = "${ApiConsts.erpRest}GET_NOTIFICATION_BUTTONS"; Map postParams = {"P_NOTIFICATION_ID": pNotificationID}; @@ -413,7 +439,7 @@ class WorkListApiClient { "EmployeeNumber": employeeNumber, "Comments": "", "AdditionalFields": null, - "NewUserEMPId":newUserEMPId + "NewUserEMPId": newUserEMPId }; postParams.addAll(AppState().postParamsJson); return await ApiClient().postJsonForObject((json) { @@ -589,7 +615,8 @@ class WorkListApiClient { }, url, postParams); } - Future submitComment({String? comment, String? email, String? userId, int? notificationId, required String apiMode, int? approverIndex = null}) async { + Future submitComment( + {String? comment, String? email, String? userId, int? notificationId, required String apiMode, int? approverIndex = null, List>? attributeData = const []}) async { String url = "${ApiConsts.erpRest}NOTIFICATION_ACTIONS"; Map postParams = { "P_COMMENTS": comment, @@ -598,7 +625,7 @@ class WorkListApiClient { "P_FORWARD_TO_USER_NAME": userId, "P_NOTIFICATION_ID": notificationId, "P_APPROVER_INDEX": approverIndex, - "RespondAttributeList": [] + "RespondAttributeList": attributeData }; postParams.addAll(AppState().postParamsJson); return await ApiClient().postJsonForObject((json) { @@ -626,4 +653,18 @@ class WorkListApiClient { return responseData.updateUserItemTypesList; }, url, postParams); } + + Future getPRDetailsForPO(String poLineID) async { + String url = "${ApiConsts.erpRest}GET_PR_INFORMATION"; + Map postParams = { + "P_PO_LINE_ID": poLineID, + "P_PAGE_LIMIT": 100, + "P_PAGE_NUM": 1, + }; + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject((json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData.getPRInformationList; + }, url, postParams); + } } diff --git a/lib/app_state/app_state.dart b/lib/app_state/app_state.dart index 708091e..7ccdd4f 100644 --- a/lib/app_state/app_state.dart +++ b/lib/app_state/app_state.dart @@ -1,7 +1,6 @@ import 'dart:io'; import 'package:easy_localization/easy_localization.dart'; -import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart'; import 'package:mohem_flutter_app/models/itg_forms_models/request_detail_model.dart'; import 'package:mohem_flutter_app/models/member_information_list_model.dart'; @@ -79,7 +78,19 @@ class AppState { bool get getIsDemoMarathon => _isDemoMarathon; - final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 4.1, mobileType: Platform.isAndroid ? "android" : "ios"); + bool _isHuawei = false; + + set setIsHuawei(bool value) => _isHuawei = value; + + bool get getIsHuawei => _isHuawei; + + String _huaweiPushToken = ""; + + set setHuaweiPushToken(String value) => _huaweiPushToken = value; + + String get getHuaweiPushToken => _huaweiPushToken; + + final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 4.8, mobileType: Platform.isAndroid ? "android" : "ios"); void setPostParamsInitConfig() { isAuthenticated = false; diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 0559996..32b3fc7 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -8,6 +8,7 @@ class ApiConsts { 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 authenticationRest = baseUrlServices + "Authentication.svc/REST/"; static String erpRest = baseUrlServices + "ERP.svc/REST/"; static String swpRest = baseUrlServices + "SWP.svc/REST/"; static String user = baseUrlServices + "api/User/"; @@ -37,6 +38,7 @@ class ApiConsts { static String marathonSubmitAnswerUrl = marathonBaseUrl + "question/submit"; static String marathonQualifiersUrl = marathonBaseUrl + "winner/getWinner/"; static String marathonSelectedWinner = marathonBaseUrl + "winner/getSelectedWinner/"; + static String marathonGetMarathonersCount = marathonBaseUrl + "Participant/GetRemainingParticipants"; //DummyCards for the UI static CardContent dummyQuestion = const CardContent(); diff --git a/lib/classes/lottie_consts.dart b/lib/classes/lottie_consts.dart index bcc7149..e112243 100644 --- a/lib/classes/lottie_consts.dart +++ b/lib/classes/lottie_consts.dart @@ -9,4 +9,5 @@ class MyLottieConsts { static const String congratsGif = "assets/images/congrats.gif"; static const String loadingLottie = "assets/lottie/loading_lottie.json"; static const String noWinnerLottie = "assets/lottie/no_winner.json"; + static const String audioPlaybackLottie = "assets/lottie/audio_playback.json"; } diff --git a/lib/classes/my_custom_stream.dart b/lib/classes/my_custom_stream.dart new file mode 100644 index 0000000..2a0927f --- /dev/null +++ b/lib/classes/my_custom_stream.dart @@ -0,0 +1,21 @@ +import 'package:flutter/foundation.dart'; +import 'package:just_audio/just_audio.dart'; + +class MyCustomStream extends StreamAudioSource { + final Uint8List bytes; + + MyCustomStream(this.bytes); + + @override + Future request([int? start, int? end]) async { + start ??= 0; + end ??= bytes.length; + return StreamAudioResponse( + sourceLength: bytes.length, + contentLength: end - start, + offset: start, + stream: Stream.value(bytes.sublist(start, end)), + contentType: 'audio/aac', + ); + } +} \ No newline at end of file diff --git a/lib/classes/notifications.dart b/lib/classes/notifications.dart index 0773575..9528616 100644 --- a/lib/classes/notifications.dart +++ b/lib/classes/notifications.dart @@ -1,13 +1,15 @@ -import 'dart:convert'; import 'dart:io'; + +import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; + +// import 'package:huawei_hmsavailability/huawei_hmsavailability.dart'; +import 'package:huawei_push/huawei_push.dart' as huawei_push; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/utils.dart'; -import 'package:mohem_flutter_app/main.dart'; import 'package:permission_handler/permission_handler.dart'; -import 'package:firebase_core/firebase_core.dart'; final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); @@ -18,6 +20,10 @@ class AppNotifications { factory AppNotifications() => _instance; + // late HmsApiAvailability hmsApiAvailability; + + String _huaweiToken = ''; + Future requestPermissions() async { if (Platform.isIOS) { await flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation()?.requestPermissions(alert: true, badge: true, sound: true); @@ -35,6 +41,10 @@ class AppNotifications { } void init(String? firebaseToken) async { + // if (Platform.isAndroid) { + // hmsApiAvailability = HmsApiAvailability(); + // } + await requestPermissions(); AppState().setDeviceToken = firebaseToken; await Permission.notification.isDenied.then((bool value) { @@ -57,6 +67,48 @@ class AppNotifications { FirebaseMessaging.instance.onTokenRefresh.listen((String token) { AppState().setDeviceToken = token; }); + + if (Platform.isAndroid) { + // await hmsApiAvailability.isHMSAvailable().then((value) async { + if (!(await Utils.isGoogleServicesAvailable())) { + huawei_push.Push.enableLogger(); + var result = await huawei_push.Push.setAutoInitEnabled(true); + + huawei_push.Push.onNotificationOpenedApp.listen((message) { + // newMessage(toFirebaseRemoteMessage(message)); + }, onError: (e) => print(e.toString())); + + huawei_push.Push.onMessageReceivedStream.listen((message) { + // newMessage(toFirebaseRemoteMessage(message)); + }, onError: (e) => print(e.toString())); + } + // }).catchError((err) { + // print(err); + // }); + } + } + + void initHuaweiPush(Function loginCallback) { + AppState().setIsHuawei = true; + initTokenStream(loginCallback); + huawei_push.Push.getToken(""); + } + + // HUAWEI PUSH TOKEN IMPLEMENTATION + void _onTokenEvent(String event) { + _huaweiToken = event; + AppState().setHuaweiPushToken = _huaweiToken; + debugPrint("HUAWEI PUSH TOKEN: $_huaweiToken"); + } + + void _onTokenError(Object error) {} + + Future initTokenStream(Function loginCallback) async { + huawei_push.Push.getTokenStream.listen(_onTokenEvent, onError: _onTokenError).onData((data) { + AppState().setHuaweiPushToken = data; + debugPrint("HUAWEI PUSH TOKEN: $data"); + loginCallback(); + }); } void _handleMessage(RemoteMessage message) { @@ -64,8 +116,10 @@ class AppNotifications { } void _handleOpenApp(RemoteMessage message) { - Utils.saveStringFromPrefs("isAppOpendByChat", "true"); - Utils.saveStringFromPrefs("notificationData", message.data["user_chat_history_response"].toString()); + if (message.data.isNotEmpty && message.data["type"] == 'chat') { + Utils.saveStringFromPrefs("isAppOpendByChat", "true"); + Utils.saveStringFromPrefs("notificationData", message.data["user_chat_history_response"].toString()); + } } } @@ -79,4 +133,7 @@ Future backgroundMessageHandler(RemoteMessage message) async { await Firebase.initializeApp(); Utils.saveStringFromPrefs("isAppOpendByChat", "false"); Utils.saveStringFromPrefs("notificationData", message.data["user_chat_history_response"].toString()); + if (message.data.isNotEmpty && message.data["type"] == 'call') { + // ChatVoipCall().showCallkitIncoming(uuid: const Uuid().v4(), data: message); + } } diff --git a/lib/classes/utils.dart b/lib/classes/utils.dart index 3368f83..34831c2 100644 --- a/lib/classes/utils.dart +++ b/lib/classes/utils.dart @@ -7,6 +7,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:fluttertoast/fluttertoast.dart'; +import 'package:google_api_availability/google_api_availability.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'; @@ -390,4 +391,14 @@ class Utils { print(err); }); } + + //HUAWEI DECISION MAKING + static Future isGoogleServicesAvailable() async { + GooglePlayServicesAvailability availability = await GoogleApiAvailability.instance.checkGooglePlayServicesAvailability(); + String status = availability.toString().split('.').last; + if (status == "success") { + return true; + } + return false; + } } diff --git a/lib/config/routes.dart b/lib/config/routes.dart index 947bbcd..7ccb6ce 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -8,6 +8,7 @@ import 'package:mohem_flutter_app/ui/chat/chat_detailed_screen.dart'; import 'package:mohem_flutter_app/ui/chat/chat_home.dart'; import 'package:mohem_flutter_app/ui/chat/favorite_users_screen.dart'; import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart'; +import 'package:mohem_flutter_app/ui/landing/itg/change_itg_ad_password_screen.dart'; import 'package:mohem_flutter_app/ui/landing/itg/its_add_screen_video_image.dart'; import 'package:mohem_flutter_app/ui/landing/itg/survey_screen.dart'; import 'package:mohem_flutter_app/ui/landing/today_attendance_screen2.dart'; @@ -177,6 +178,7 @@ class AppRoutes { static const String subordinateLeave = "/subordinateLeave"; static const String changePassword = "/changePassword"; + static const String changeItgAdPasswordScreen = "/changeItgAdPasswordScreen"; //Chat static const String chat = "/chat"; @@ -289,7 +291,7 @@ class AppRoutes { subordinateLeave: (BuildContext context) => SubordinateLeave(), changePassword: (BuildContext context) => ChangePasswordScreen(), - + changeItgAdPasswordScreen: (BuildContext context) => ChangeItgAdPasswordScreen(), //Chat chat: (BuildContext context) => ChatHome(), chatDetailed: (BuildContext context) => ChatDetailScreen(), diff --git a/lib/dialogs/otp_dialog.dart b/lib/dialogs/otp_dialog.dart index 9158b94..9f7c82e 100644 --- a/lib/dialogs/otp_dialog.dart +++ b/lib/dialogs/otp_dialog.dart @@ -9,7 +9,6 @@ import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; import 'package:mohem_flutter_app/widgets/button/default_button.dart'; import 'package:mohem_flutter_app/widgets/otp_widget.dart'; -import 'package:sizer/sizer.dart'; final ValueNotifier otpFieldClear = ValueNotifier(""); diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index 54ffe20..45cfc05 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -22,6 +22,17 @@ extension TrimString on String { } } +String displayLocalizedContent({required bool isPhoneLangArabic, required int selectedLanguage, required String englishContent, required String arabicContent}) { + if (selectedLanguage == 1) { + return englishContent; + } else if (selectedLanguage == 2) { + return arabicContent; + } else if (selectedLanguage == 3) { + return isPhoneLangArabic ? arabicContent : englishContent; + } + return englishContent; +} + extension EmailValidator on String { Widget get toWidget => Text(this); @@ -111,9 +122,10 @@ extension EmailValidator on String { decoration: isUnderLine ? TextDecoration.underline : null), ); - Widget toText16({Color? color, bool isUnderLine = false, bool isBold = false, int? maxlines, double? height}) => Text( + Widget toText16({Color? color, bool isUnderLine = false, bool isBold = false, int? maxlines, double? height, bool isCentered = false}) => Text( this, maxLines: maxlines, + textAlign: isCentered ? TextAlign.center : null, style: TextStyle( color: color ?? MyColors.darkTextColor, fontSize: 16, diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index 7895c62..ba21c29 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -59,6 +59,7 @@ class CodegenLoader extends AssetLoader{ "newString": "جديد", "setTheNewPassword": "قم بتعيين كلمة المرور الجديدة", "typeYourNewPasswordBelow": "اكتب كلمة المرور الجديدة أدناه", + "typeYourNewActiveDirectoryPasswordBelow": "اكتب كلمة مرور الدليل النشط الجديدة أدناه", "confirmPassword": "تأكيد كلمة المرور", "update": "تحديث", "title": "عنوان", @@ -420,7 +421,8 @@ class CodegenLoader extends AssetLoader{ "stamp": "ختم", "addFavoriteList": "هل تريد اضافة {name} لقائمة المفضله", "feedbackUserExperience": "هذا للحصول على تعليقات حول تجربة المستخدم", - "rateUI": ".1 كيف تريد تقييم التطبيق", + "rateUI": "كيف تريد أن تقيم", + "rateUI2": "ما مدى رضائك عن هذا التطبيق", "submitSurvey": "ارسال الاستبيان", "typeHere": "اكتب هنا", "infoDetail": "تفاصيل المعلومات", @@ -542,9 +544,9 @@ class CodegenLoader extends AssetLoader{ "myTeam": "فريقي", "youCanPlayDemo": "لكن يمكنك لعب العرض", "connectHmgWifi": "قم بتوصيل HMG WIFI", - "connectedHmgWifi": "افصل HMG WIFI", - "networkMustHMG": "يجب أن تكون الشبكة متصلة بـ HMG", - "connectedWithHmg": "تم الاتصال بنجاح مع HMG WIFI" + "connectedHmgWifi": "اتصال HMG WIFI", + "itgForms": "نماذج (ITG)", + "resetAdPassword": "إعادة تعيين كلمة مرور AD" }; static const Map en_US = { "mohemm": "Mohemm", @@ -591,6 +593,7 @@ static const Map en_US = { "newString": "New", "setTheNewPassword": "Set the new password", "typeYourNewPasswordBelow": "Type your new password below", + "typeYourNewActiveDirectoryPasswordBelow": "Type new active directory password below", "confirmPassword": "Confirm Password", "update": "Update", "title": "Title", @@ -952,7 +955,8 @@ static const Map en_US = { "stamp": "Stamp", "addFavoriteList": "Do you want to add {name} in your favorite list", "feedbackUserExperience": "This is to get the feedback about the user experience", - "rateUI": "1. How would you rate this UI?", + "rateUI": "How would you like to rate", + "rateUI2": "How do you satisfied with this application", "submitSurvey": "Submit Survey", "typeHere": "Type here", "infoDetail": "Info Detail", @@ -1074,9 +1078,9 @@ static const Map en_US = { "myTeam": "My Team", "youCanPlayDemo": "But you can play demo", "connectHmgWifi": "Connect HMG WIFI", - "connectedHmgWifi": "Disconnect HMG WIFI", - "networkMustHMG": "Network must be connected with HMG", - "connectedWithHmg": "Successfully Connected with HMG WIFI" + "connectedHmgWifi": "Connected HMG WIFI", + "itgForms": "ITG Forms", + "resetAdPassword": "Reset AD Password" }; 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 f59476d..343bf38 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -44,6 +44,7 @@ abstract class LocaleKeys { static const newString = 'newString'; static const setTheNewPassword = 'setTheNewPassword'; static const typeYourNewPasswordBelow = 'typeYourNewPasswordBelow'; + static const typeYourNewActiveDirectoryPasswordBelow = 'typeYourNewActiveDirectoryPasswordBelow'; static const confirmPassword = 'confirmPassword'; static const update = 'update'; static const title = 'title'; @@ -406,6 +407,7 @@ abstract class LocaleKeys { static const addFavoriteList = 'addFavoriteList'; static const feedbackUserExperience = 'feedbackUserExperience'; static const rateUI = 'rateUI'; + static const rateUI2 = 'rateUI2'; static const submitSurvey = 'submitSurvey'; static const typeHere = 'typeHere'; static const infoDetail = 'infoDetail'; @@ -513,7 +515,7 @@ abstract class LocaleKeys { static const youCanPlayDemo = 'youCanPlayDemo'; static const connectHmgWifi = 'connectHmgWifi'; static const connectedHmgWifi = 'connectedHmgWifi'; - static const networkMustHMG = 'networkMustHMG'; - static const connectedWithHmg = 'connectedWithHmg'; + static const itgForms = 'itgForms'; + static const resetAdPassword = 'resetAdPassword'; } diff --git a/lib/main.dart b/lib/main.dart index ae2d367..07590f3 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -9,10 +9,10 @@ import 'package:mohem_flutter_app/classes/consts.dart'; import 'package:mohem_flutter_app/config/routes.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/chat_call_provider.dart'; import 'package:mohem_flutter_app/provider/chat_provider_model.dart'; import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; import 'package:mohem_flutter_app/provider/eit_provider_model.dart'; -import 'package:mohem_flutter_app/provider/hmg_connection_provider.dart'; import 'package:mohem_flutter_app/theme/app_theme.dart'; import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart'; import 'package:month_year_picker/month_year_picker.dart'; @@ -28,7 +28,6 @@ Logger logger = Logger( // output: null, // U ); - class MyHttpOverrides extends HttpOverrides { @override HttpClient createHttpClient(SecurityContext? context) { @@ -71,9 +70,9 @@ Future main() async { ChangeNotifierProvider( create: (_) => MarathonProvider(), ), - ChangeNotifierProvider( - create: (_) => HmgConnectionProvider(), - ) + // ChangeNotifierProvider( + // create: (_) => ChatCallProvider(), + // ), ], child: const MyApp(), ), @@ -265,4 +264,3 @@ class MyApp extends StatelessWidget { // }); // } // } - diff --git a/lib/models/chat/call.dart b/lib/models/chat/call.dart index 7f8f6eb..ce58ae3 100644 --- a/lib/models/chat/call.dart +++ b/lib/models/chat/call.dart @@ -7,127 +7,191 @@ import 'dart:convert'; class CallDataModel { CallDataModel({ this.callerId, - this.callReceiverID, - this.notificationForeground, - this.message, + this.callerDetails, + this.receiverId, + this.receiverDetails, this.title, - this.type, - this.identity, - this.name, - this.isCall, - this.isWebrtc, - this.contant, - this.contantNo, - this.chatEventId, - this.fileTypeId, - this.currentUserId, - this.chatSource, - this.userChatHistoryLineRequestList, - this.server, + this.calltype, }); String? callerId; - String? callReceiverID; - String? notificationForeground; - String? message; - String? title; - String? type; - String? identity; - String? name; - String? isCall; - String? isWebrtc; - String? contant; - String? contantNo; - String? chatEventId; - dynamic? fileTypeId; - String? currentUserId; - String? chatSource; - List? userChatHistoryLineRequestList; - String? server; + CallerDetails? callerDetails; + String? receiverId; + ReceiverDetails? receiverDetails; + dynamic title; + String? calltype; factory CallDataModel.fromRawJson(String str) => CallDataModel.fromJson(json.decode(str)); String toRawJson() => json.encode(toJson()); factory CallDataModel.fromJson(Map json) => CallDataModel( - callerId: json["callerID"] == null ? null : json["callerID"], - callReceiverID: json["callReceiverID"] == null ? null : json["callReceiverID"], - notificationForeground: json["notification_foreground"] == null ? null : json["notification_foreground"], - message: json["message"] == null ? null : json["message"], - title: json["title"] == null ? null : json["title"], - type: json["type"] == null ? null : json["type"], - identity: json["identity"] == null ? null : json["identity"], - name: json["name"] == null ? null : json["name"], - isCall: json["is_call"] == null ? null : json["is_call"], - isWebrtc: json["is_webrtc"] == null ? null : json["is_webrtc"], - contant: json["contant"] == null ? null : json["contant"], - contantNo: json["contantNo"] == null ? null : json["contantNo"], - chatEventId: json["chatEventId"] == null ? null : json["chatEventId"], - fileTypeId: json["fileTypeId"], - currentUserId: json["currentUserId"] == null ? null : json["currentUserId"], - chatSource: json["chatSource"] == null ? null : json["chatSource"], - userChatHistoryLineRequestList: json["userChatHistoryLineRequestList"] == null - ? null - : List.from( - json["userChatHistoryLineRequestList"].map( - (x) => UserChatHistoryLineRequestList.fromJson(x), - ), - ), - server: json["server"] == null ? null : json["server"], - ); + callerId: json["callerID"], + callerDetails: json["callerDetails"] == null ? null : CallerDetails.fromJson(json["callerDetails"]), + receiverId: json["receiverID"], + receiverDetails: json["receiverDetails"] == null ? null : ReceiverDetails.fromJson(json["receiverDetails"]), + title: json["title"], + calltype: json["calltype"], + ); + + Map toJson() => { + "callerID": callerId, + "callerDetails": callerDetails?.toJson(), + "receiverID": receiverId, + "receiverDetails": receiverDetails?.toJson(), + "title": title, + "calltype": calltype, + }; +} + +class CallerDetails { + CallerDetails({ + this.response, + this.errorResponses, + }); + + Response? response; + dynamic errorResponses; + + factory CallerDetails.fromRawJson(String str) => CallerDetails.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory CallerDetails.fromJson(Map json) => CallerDetails( + response: json["response"] == null ? null : Response.fromJson(json["response"]), + errorResponses: json["errorResponses"], + ); Map toJson() => { - "callerID": callerId == null ? null : callerId, - "callReceiverID": callReceiverID == null ? null : callReceiverID, - "notification_foreground": notificationForeground == null ? null : notificationForeground, - "message": message == null ? null : message, - "title": title == null ? null : title, - "type": type == null ? null : type, - "identity": identity == null ? null : identity, - "name": name == null ? null : name, - "is_call": isCall == null ? null : isCall, - "is_webrtc": isWebrtc == null ? null : isWebrtc, - "contant": contant == null ? null : contant, - "contantNo": contantNo == null ? null : contantNo, - "chatEventId": chatEventId == null ? null : chatEventId, - "fileTypeId": fileTypeId, - "currentUserId": currentUserId == null ? null : currentUserId, - "chatSource": chatSource == null ? null : chatSource, - "userChatHistoryLineRequestList": userChatHistoryLineRequestList == null - ? null - : List.from( - userChatHistoryLineRequestList!.map( - (x) => x.toJson(), - ), - ), - "server": server == null ? null : server, - }; + "response": response?.toJson(), + "errorResponses": errorResponses, + }; } -class UserChatHistoryLineRequestList { - UserChatHistoryLineRequestList({ - this.isSeen, - this.isDelivered, - this.targetUserId, - this.targetUserStatus, +class Response { + Response({ + this.id, + this.userName, + this.email, + this.phone, + this.title, + this.token, + this.isDomainUser, + this.isActiveCode, + this.encryptedUserId, + this.encryptedUserName, }); - bool? isSeen; - bool? isDelivered; - int? targetUserId; - int? targetUserStatus; + int? id; + String? userName; + String? email; + dynamic phone; + String? title; + String? token; + bool? isDomainUser; + bool? isActiveCode; + String? encryptedUserId; + String? encryptedUserName; + + factory Response.fromRawJson(String str) => Response.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory Response.fromJson(Map json) => Response( + id: json["id"], + userName: json["userName"], + email: json["email"], + phone: json["phone"], + title: json["title"], + token: json["token"], + isDomainUser: json["isDomainUser"], + isActiveCode: json["isActiveCode"], + encryptedUserId: json["encryptedUserId"], + encryptedUserName: json["encryptedUserName"], + ); + + Map toJson() => { + "id": id, + "userName": userName, + "email": email, + "phone": phone, + "title": title, + "token": token, + "isDomainUser": isDomainUser, + "isActiveCode": isActiveCode, + "encryptedUserId": encryptedUserId, + "encryptedUserName": encryptedUserName, + }; +} + +class ReceiverDetails { + ReceiverDetails({ + this.id, + this.userName, + this.email, + this.phone, + this.title, + this.userStatus, + this.image, + this.unreadMessageCount, + this.userAction, + this.isPin, + this.isFav, + this.isAdmin, + this.rKey, + this.totalCount, + }); + + int? id; + String? userName; + String? email; + dynamic phone; + dynamic title; + int? userStatus; + String? image; + int? unreadMessageCount; + dynamic userAction; + bool? isPin; + bool? isFav; + bool? isAdmin; + String? rKey; + int? totalCount; + + factory ReceiverDetails.fromRawJson(String str) => ReceiverDetails.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); - factory UserChatHistoryLineRequestList.fromJson(Map json) => UserChatHistoryLineRequestList( - isSeen: json["isSeen"] == null ? null : json["isSeen"], - isDelivered: json["isDelivered"] == null ? null : json["isDelivered"], - targetUserId: json["targetUserId"] == null ? null : json["targetUserId"], - targetUserStatus: json["targetUserStatus"] == null ? null : json["targetUserStatus"], - ); + factory ReceiverDetails.fromJson(Map json) => ReceiverDetails( + id: json["id"], + userName: json["userName"], + email: json["email"], + phone: json["phone"], + title: json["title"], + userStatus: json["userStatus"], + image: json["image"], + unreadMessageCount: json["unreadMessageCount"], + userAction: json["userAction"], + isPin: json["isPin"], + isFav: json["isFav"], + isAdmin: json["isAdmin"], + rKey: json["rKey"], + totalCount: json["totalCount"], + ); Map toJson() => { - "isSeen": isSeen == null ? null : isSeen, - "isDelivered": isDelivered == null ? null : isDelivered, - "targetUserId": targetUserId == null ? null : targetUserId, - "targetUserStatus": targetUserStatus == null ? null : targetUserStatus, - }; + "id": id, + "userName": userName, + "email": email, + "phone": phone, + "title": title, + "userStatus": userStatus, + "image": image, + "unreadMessageCount": unreadMessageCount, + "userAction": userAction, + "isPin": isPin, + "isFav": isFav, + "isAdmin": isAdmin, + "rKey": rKey, + "totalCount": totalCount, + }; } diff --git a/lib/models/generic_response_model.dart b/lib/models/generic_response_model.dart index ed00de4..a9006eb 100644 --- a/lib/models/generic_response_model.dart +++ b/lib/models/generic_response_model.dart @@ -28,6 +28,8 @@ import 'package:mohem_flutter_app/models/get_mobile_login_info_list_model.dart'; import 'package:mohem_flutter_app/models/get_notification_buttons_list_model.dart'; import 'package:mohem_flutter_app/models/get_po_Item_history_list_model.dart'; import 'package:mohem_flutter_app/models/get_po_notification_body_list_model.dart'; +import 'package:mohem_flutter_app/models/get_pr_action_history_list_model.dart'; +import 'package:mohem_flutter_app/models/get_pr_information_list.dart'; import 'package:mohem_flutter_app/models/get_pr_notification_body_list_model.dart'; import 'package:mohem_flutter_app/models/get_quotation_analysis_list_model.dart'; import 'package:mohem_flutter_app/models/get_schedule_shifts_details_list_model.dart'; @@ -169,9 +171,11 @@ class GenericResponseModel { List? getAbsenceTransactionList; List? getAccrualBalancesList; List? getActionHistoryList; + List? getPRActionHistoryList; List? getAddressDffStructureList; List? getApprovesList; List? getAttachementList; + List? getPRAttachmentList; GetAttendanceTracking? getAttendanceTrackingList; List? getBasicDetColsStructureList; List? getBasicDetDffStructureList; @@ -226,6 +230,7 @@ class GenericResponseModel { List? getPoItemHistoryList; GetPoNotificationBodyList? getPoNotificationBodyList; GetPrNotificationBodyList? getPrNotificationBodyList; + GetPRInformationList? getPRInformationList; List? getQuotationAnalysisList; List? getRFCEmployeeListList; List? getRespondAttributeValueList; @@ -434,10 +439,12 @@ class GenericResponseModel { this.getAbsenceTransactionList, this.getAccrualBalancesList, this.getActionHistoryList, + this.getPRActionHistoryList, this.getAddressDffStructureList, this.getAddressNotificationBodyList, this.getApprovesList, this.getAttachementList, + this.getPRAttachmentList, this.getAttendanceTrackingList, this.getBasicDetColsStructureList, this.getBasicDetDffStructureList, @@ -490,6 +497,7 @@ class GenericResponseModel { this.getPoItemHistoryList, this.getPoNotificationBodyList, this.getPrNotificationBodyList, + this.getPRInformationList, this.getQuotationAnalysisList, this.getRFCEmployeeListList, this.getRespondAttributeValueList, @@ -748,6 +756,13 @@ class GenericResponseModel { }); } + if (json['PR_Action_History_List'] != null) { + getPRActionHistoryList = []; + json['PR_Action_History_List'].forEach((v) { + getPRActionHistoryList!.add(GetPRActionHistoryList.fromJson(v)); + }); + } + if (json['GetAddressDffStructureList'] != null) { getAddressDffStructureList = []; json['GetAddressDffStructureList'].forEach((v) { @@ -769,6 +784,14 @@ class GenericResponseModel { getAttachementList!.add(GetAttachementList.fromJson(v)); }); } + + if (json['PR_Attachments_List'] != null) { + getPRAttachmentList = []; + json['PR_Attachments_List'].forEach((v) { + getPRAttachmentList!.add(GetAttachementList.fromJson(v)); + }); + } + getAttendanceTrackingList = json["GetAttendanceTrackingList"] == null ? null : GetAttendanceTracking.fromMap(json["GetAttendanceTrackingList"]); if (json['GetBasicDetColsStructureList'] != null) { getBasicDetColsStructureList = []; @@ -979,6 +1002,7 @@ class GenericResponseModel { } getPoNotificationBodyList = json['GetPoNotificationBodyList'] != null ? GetPoNotificationBodyList.fromJson(json['GetPoNotificationBodyList']) : null; getPrNotificationBodyList = json['GetPrNotificationBodyList'] != null ? GetPrNotificationBodyList.fromJson(json['GetPrNotificationBodyList']) : null; + getPRInformationList = json['PR_Information_List'] != null ? GetPRInformationList.fromJson(json['PR_Information_List']) : null; if (json['GetQuotationAnalysisList'] != null) { getQuotationAnalysisList = []; json['GetQuotationAnalysisList'].forEach((v) { @@ -1602,6 +1626,10 @@ class GenericResponseModel { data['GetPrNotificationBodyList'] = this.getPrNotificationBodyList!.toJson(); } + if (this.getPRInformationList != null) { + data['PR_Information_List'] = this.getPRInformationList!.toJson(); + } + if (this.getQuotationAnalysisList != null) { data['GetQuotationAnalysisList'] = this.getQuotationAnalysisList!.map((v) => v.toJson()).toList(); } diff --git a/lib/models/get_po_notification_body_list_model.dart b/lib/models/get_po_notification_body_list_model.dart index d0473dc..a1a56e6 100644 --- a/lib/models/get_po_notification_body_list_model.dart +++ b/lib/models/get_po_notification_body_list_model.dart @@ -158,6 +158,7 @@ class POLines { String? nEEDBYDATE; int? nOOFROWS; int? pOHEADERID; + int? pOLINEID; String? pROMISEDDATE; String? pRNUM; num? qUANTITY; @@ -181,6 +182,7 @@ class POLines { this.nEEDBYDATE, this.nOOFROWS, this.pOHEADERID, + this.pOLINEID, this.pROMISEDDATE, this.pRNUM, this.qUANTITY, @@ -204,6 +206,7 @@ class POLines { nEEDBYDATE = json['NEED_BY_DATE']; nOOFROWS = json['NO_OF_ROWS']; pOHEADERID = json['PO_HEADER_ID']; + pOLINEID = json['PO_LINE_ID']; pROMISEDDATE = json['PROMISED_DATE']; pRNUM = json['PR_NUM']; qUANTITY = json['QUANTITY']; @@ -229,6 +232,7 @@ class POLines { data['NEED_BY_DATE'] = this.nEEDBYDATE; data['NO_OF_ROWS'] = this.nOOFROWS; data['PO_HEADER_ID'] = this.pOHEADERID; + data['PO_LINE_ID'] = this.pOLINEID; data['PROMISED_DATE'] = this.pROMISEDDATE; data['PR_NUM'] = this.pRNUM; data['QUANTITY'] = this.qUANTITY; diff --git a/lib/models/get_pr_action_history_list_model.dart b/lib/models/get_pr_action_history_list_model.dart new file mode 100644 index 0000000..d57668d --- /dev/null +++ b/lib/models/get_pr_action_history_list_model.dart @@ -0,0 +1,68 @@ +class GetPRActionHistoryList { + String? aCTION; + String? aCTIONCODE; + String? aPPROVALDATE; + String? eMAILADDRESS; + String? eMPLOYEEIMAGE; + int? fROMROWNUM; + String? nAME; + String? nOTE; + int? nOOFROWS; + String? pOSITIONTITLE; + int? rOWNUM; + int? sEQUENCE; + int? tOROWNUM; + Null? uSERNAME; + + GetPRActionHistoryList( + {this.aCTION, + this.aCTIONCODE, + this.aPPROVALDATE, + this.eMAILADDRESS, + this.eMPLOYEEIMAGE, + this.fROMROWNUM, + this.nAME, + this.nOTE, + this.nOOFROWS, + this.pOSITIONTITLE, + this.rOWNUM, + this.sEQUENCE, + this.tOROWNUM, + this.uSERNAME}); + + GetPRActionHistoryList.fromJson(Map json) { + aCTION = json['ACTION']; + aCTIONCODE = json['ACTION_CODE']; + aPPROVALDATE = json['APPROVAL_DATE']; + eMAILADDRESS = json['EMAIL_ADDRESS']; + eMPLOYEEIMAGE = json['EMPLOYEE_IMAGE']; + fROMROWNUM = json['FROM_ROW_NUM']; + nAME = json['NAME']; + nOTE = json['NOTE']; + nOOFROWS = json['NO_OF_ROWS']; + pOSITIONTITLE = json['POSITION_TITLE']; + rOWNUM = json['ROW_NUM']; + sEQUENCE = json['SEQUENCE']; + tOROWNUM = json['TO_ROW_NUM']; + uSERNAME = json['USER_NAME']; + } + + Map toJson() { + Map data = new Map(); + data['ACTION'] = this.aCTION; + data['ACTION_CODE'] = this.aCTIONCODE; + data['APPROVAL_DATE'] = this.aPPROVALDATE; + data['EMAIL_ADDRESS'] = this.eMAILADDRESS; + data['EMPLOYEE_IMAGE'] = this.eMPLOYEEIMAGE; + data['FROM_ROW_NUM'] = this.fROMROWNUM; + data['NAME'] = this.nAME; + data['NOTE'] = this.nOTE; + data['NO_OF_ROWS'] = this.nOOFROWS; + data['POSITION_TITLE'] = this.pOSITIONTITLE; + data['ROW_NUM'] = this.rOWNUM; + data['SEQUENCE'] = this.sEQUENCE; + data['TO_ROW_NUM'] = this.tOROWNUM; + data['USER_NAME'] = this.uSERNAME; + return data; + } +} diff --git a/lib/models/get_pr_information_list.dart b/lib/models/get_pr_information_list.dart new file mode 100644 index 0000000..33ede12 --- /dev/null +++ b/lib/models/get_pr_information_list.dart @@ -0,0 +1,125 @@ +class GetPRInformationList { + List? pRHeader; + List? pRLines; + String? pCURRENCYCODE; + + GetPRInformationList({this.pRHeader, this.pRLines, this.pCURRENCYCODE}); + + GetPRInformationList.fromJson(Map json) { + if (json['PRHeader'] != null) { + pRHeader = []; + json['PRHeader'].forEach((v) { + pRHeader!.add(new PRHeader.fromJson(v)); + }); + } + if (json['PRLines'] != null) { + pRLines = []; + json['PRLines'].forEach((v) { + pRLines!.add(new PRLines.fromJson(v)); + }); + } + pCURRENCYCODE = json['P_CURRENCY_CODE']; + } + + Map toJson() { + Map data = new Map(); + if (this.pRHeader != null) { + data['PRHeader'] = this.pRHeader!.map((v) => v.toJson()).toList(); + } + if (this.pRLines != null) { + data['PRLines'] = this.pRLines!.map((v) => v.toJson()).toList(); + } + data['P_CURRENCY_CODE'] = this.pCURRENCYCODE; + return data; + } +} + +class PRHeader { + String? dESCRIPTION; + String? pRNUMBER; + String? rEQUISITIONTOTAL; + String? tAXTOTAL; + + PRHeader({this.dESCRIPTION, this.pRNUMBER, this.rEQUISITIONTOTAL, this.tAXTOTAL}); + + PRHeader.fromJson(Map json) { + dESCRIPTION = json['DESCRIPTION']; + pRNUMBER = json['PR_NUMBER']; + rEQUISITIONTOTAL = json['REQUISITION_TOTAL']; + tAXTOTAL = json['TAX_TOTAL']; + } + + Map toJson() { + Map data = new Map(); + data['DESCRIPTION'] = this.dESCRIPTION; + data['PR_NUMBER'] = this.pRNUMBER; + data['REQUISITION_TOTAL'] = this.rEQUISITIONTOTAL; + data['TAX_TOTAL'] = this.tAXTOTAL; + return data; + } +} + +class PRLines { + String? cOSTCENTER; + String? dESCRIPTION; + int? fROMROWNUM; + int? iTEMAMU; + String? iTEMCODE; + int? lINEAMOUNT; + int? lINENUM; + int? nOOFROWS; + int? qUANTITY; + int? rOWNUM; + int? tOROWNUM; + int? uNITPRICE; + String? uOM; + + PRLines( + {this.cOSTCENTER, + this.dESCRIPTION, + this.fROMROWNUM, + this.iTEMAMU, + this.iTEMCODE, + this.lINEAMOUNT, + this.lINENUM, + this.nOOFROWS, + this.qUANTITY, + this.rOWNUM, + this.tOROWNUM, + this.uNITPRICE, + this.uOM}); + + PRLines.fromJson(Map json) { + cOSTCENTER = json['COST_CENTER']; + dESCRIPTION = json['DESCRIPTION']; + fROMROWNUM = json['FROM_ROW_NUM']; + iTEMAMU = json['ITEM_AMU']; + iTEMCODE = json['ITEM_CODE']; + lINEAMOUNT = json['LINE_AMOUNT']; + lINENUM = json['LINE_NUM']; + nOOFROWS = json['NO_OF_ROWS']; + qUANTITY = json['QUANTITY']; + rOWNUM = json['ROW_NUM']; + tOROWNUM = json['TO_ROW_NUM']; + uNITPRICE = json['UNIT_PRICE']; + uOM = json['UOM']; + } + + Map toJson() { + Map data = new Map(); + data['COST_CENTER'] = this.cOSTCENTER; + data['DESCRIPTION'] = this.dESCRIPTION; + data['FROM_ROW_NUM'] = this.fROMROWNUM; + data['ITEM_AMU'] = this.iTEMAMU; + data['ITEM_CODE'] = this.iTEMCODE; + data['LINE_AMOUNT'] = this.lINEAMOUNT; + data['LINE_NUM'] = this.lINENUM; + data['NO_OF_ROWS'] = this.nOOFROWS; + data['QUANTITY'] = this.qUANTITY; + data['ROW_NUM'] = this.rOWNUM; + data['TO_ROW_NUM'] = this.tOROWNUM; + data['UNIT_PRICE'] = this.uNITPRICE; + data['UOM'] = this.uOM; + return data; + } +} diff --git a/lib/models/itg/itg_response_model.dart b/lib/models/itg/itg_response_model.dart index 4dff106..dff7869 100644 --- a/lib/models/itg/itg_response_model.dart +++ b/lib/models/itg/itg_response_model.dart @@ -5,6 +5,7 @@ import 'dart:convert'; import 'package:mohem_flutter_app/models/itg/advertisement.dart'; +import 'package:mohem_flutter_app/models/itg/survey_model.dart'; MohemmItgResponseItem mohemmItgResponseItemFromJson(String str) => MohemmItgResponseItem.fromJson(json.decode(str)); @@ -103,7 +104,7 @@ class ItgResponseData { final bool? isDeleted; final bool? showDelete; final Advertisement? advertisement; - final dynamic survey; + final SurveyModel? survey; final dynamic isActive; final dynamic pageSize; final dynamic pageNo; @@ -126,7 +127,7 @@ class ItgResponseData { isDeleted: json["isDeleted"] == null ? null : json["isDeleted"], showDelete: json["showDelete"] == null ? null : json["showDelete"], advertisement: json["advertisement"] == null ? null : Advertisement.fromJson(json["advertisement"]), - survey: json["survey"], + survey: json["survey"] == null ? null : SurveyModel.fromJson(json["survey"]), isActive: json["isActive"], pageSize: json["pageSize"], pageNo: json["pageNo"], diff --git a/lib/models/itg/survey_model.dart b/lib/models/itg/survey_model.dart new file mode 100644 index 0000000..7cdbbdd --- /dev/null +++ b/lib/models/itg/survey_model.dart @@ -0,0 +1,148 @@ +class SurveyModel { + int? surveyId; + String? referenceNo; + String? title; + String? description; + List? questions; + bool? isActive; + Null? pageSize; + Null? pageNo; + Null? languageId; + + SurveyModel({this.surveyId, this.referenceNo, this.title, this.description, this.questions, this.isActive, this.pageSize, this.pageNo, this.languageId}); + + SurveyModel.fromJson(Map json) { + surveyId = json['surveyId']; + referenceNo = json['referenceNo']; + title = json['title']; + description = json['description']; + if (json['questions'] != null) { + questions = []; + json['questions'].forEach((v) { + questions!.add(new Questions.fromJson(v)); + }); + } + isActive = json['isActive']; + pageSize = json['pageSize']; + pageNo = json['pageNo']; + languageId = json['languageId']; + } + + Map toJson() { + Map data = new Map(); + data['surveyId'] = this.surveyId; + data['referenceNo'] = this.referenceNo; + data['title'] = this.title; + data['description'] = this.description; + if (this.questions != null) { + data['questions'] = this.questions!.map((v) => v.toJson()).toList(); + } + data['isActive'] = this.isActive; + data['pageSize'] = this.pageSize; + data['pageNo'] = this.pageNo; + data['languageId'] = this.languageId; + return data; + } +} + +class Questions { + int? questionId; + String? title; + bool? isRequired; + String? type; + int? sequenceNo; + Null? surveyId; + List? options; + Null? rspPercentage; + Null? isActive; + Null? pageSize; + Null? pageNo; + Null? languageId; + + Questions({this.questionId, this.title, this.isRequired, this.type, this.sequenceNo, this.surveyId, this.options, this.rspPercentage, this.isActive, this.pageSize, this.pageNo, this.languageId}); + + Questions.fromJson(Map json) { + questionId = json['questionId']; + title = json['title']; + isRequired = json['isRequired']; + type = json['type']; + sequenceNo = json['sequenceNo']; + surveyId = json['surveyId']; + if (json['options'] != null) { + options = []; + json['options'].forEach((v) { + options!.add(new Options.fromJson(v)); + }); + } + rspPercentage = json['rspPercentage']; + isActive = json['isActive']; + pageSize = json['pageSize']; + pageNo = json['pageNo']; + languageId = json['languageId']; + } + + Map toJson() { + Map data = new Map(); + data['questionId'] = this.questionId; + data['title'] = this.title; + data['isRequired'] = this.isRequired; + data['type'] = this.type; + data['sequenceNo'] = this.sequenceNo; + data['surveyId'] = this.surveyId; + if (this.options != null) { + data['options'] = this.options!.map((v) => v.toJson()).toList(); + } + data['rspPercentage'] = this.rspPercentage; + data['isActive'] = this.isActive; + data['pageSize'] = this.pageSize; + data['pageNo'] = this.pageNo; + data['languageId'] = this.languageId; + return data; + } +} + +class Options { + int? optionId; + String? title; + bool? isCommentsRequired; + int? sequenceNo; + int? questionId; + Null? rspPercentage; + Null? count; + Null? isActive; + Null? pageSize; + Null? pageNo; + Null? languageId; + + Options({this.optionId, this.title, this.isCommentsRequired, this.sequenceNo, this.questionId, this.rspPercentage, this.count, this.isActive, this.pageSize, this.pageNo, this.languageId}); + + Options.fromJson(Map json) { + optionId = json['optionId']; + title = json['title']; + isCommentsRequired = json['isCommentsRequired']; + sequenceNo = json['sequenceNo']; + questionId = json['questionId']; + rspPercentage = json['rspPercentage']; + count = json['count']; + isActive = json['isActive']; + pageSize = json['pageSize']; + pageNo = json['pageNo']; + languageId = json['languageId']; + } + + Map toJson() { + Map data = new Map(); + data['optionId'] = this.optionId; + data['title'] = this.title; + data['isCommentsRequired'] = this.isCommentsRequired; + data['sequenceNo'] = this.sequenceNo; + data['questionId'] = this.questionId; + data['rspPercentage'] = this.rspPercentage; + data['count'] = this.count; + data['isActive'] = this.isActive; + data['pageSize'] = this.pageSize; + data['pageNo'] = this.pageNo; + data['languageId'] = this.languageId; + return data; + } +} diff --git a/lib/provider/chat_call_provider.dart b/lib/provider/chat_call_provider.dart new file mode 100644 index 0000000..45205df --- /dev/null +++ b/lib/provider/chat_call_provider.dart @@ -0,0 +1,187 @@ +import 'dart:convert'; +import 'dart:ui'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter_webrtc/flutter_webrtc.dart'; +import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart'; + +class ChatCallProvider with ChangeNotifier, DiagnosticableTreeMixin { + ///////////////////// Web RTC Video Calling ////////////////////// + // Video Call + late RTCPeerConnection _peerConnection; + RTCVideoRenderer _localVideoRenderer = RTCVideoRenderer(); + final RTCVideoRenderer _remoteRenderer = RTCVideoRenderer(); + + MediaStream? _localStream; + MediaStream? _remoteStream; + + void initCallListeners() { + chatHubConnection.on("OnCallAcceptedAsync", onCallAcceptedAsync); + chatHubConnection.on("OnIceCandidateAsync", onIceCandidateAsync); + chatHubConnection.on("OnOfferAsync", onOfferAsync); + chatHubConnection.on("OnAnswerOffer", onAnswerOffer); + chatHubConnection.on("OnHangUpAsync", onHangUpAsync); + chatHubConnection.on("OnCallDeclinedAsync", onCallDeclinedAsync); + } + + //Video Constraints + var videoConstraints = { + "video": { + "mandatory": { + "width": {"min": 320}, + "height": {"min": 180} + }, + "optional": [ + { + "width": {"max": 1280} + }, + {"frameRate": 25}, + {"facingMode": "user"} + ] + }, + "frameRate": 25, + "width": 420, //420,//640,//1280, + "height": 240 //240//480//720 + }; + + // Audio Constraints + var audioConstraints = { + "sampleRate": 8000, + "sampleSize": 16, + "channelCount": 2, + "echoCancellation": true, + "audio": true, + }; + + Future _createPeerConnection() async { + // {"url": "stun:stun.l.google.com:19302"}, + Map configuration = { + "iceServers": [ + {"urls": 'stun:15.185.116.59:3478'}, + {"urls": "turn:15.185.116.59:3479", "username": "admin", "credential": "admin"} + ] + }; + + Map offerSdpConstraints = { + "mandatory": { + "OfferToReceiveAudio": true, + "OfferToReceiveVideo": true, + }, + "optional": [], + }; + + RTCPeerConnection pc = await createPeerConnection(configuration, offerSdpConstraints); + // if (pc != null) print(pc); + //pc.addStream(widget.localStream); + + pc.onIceCandidate = (e) { + if (e.candidate != null) { + print(json.encode({ + 'candidate': e.candidate.toString(), + 'sdpMid': e.sdpMid.toString(), + 'sdpMlineIndex': e.sdpMLineIndex, + })); + } + }; + pc.onIceConnectionState = (e) { + print(e); + }; + pc.onAddStream = (stream) { + print('addStream: ' + stream.id); + _remoteRenderer.srcObject = stream; + }; + return pc; + } + + void init() { + initRenderers(); + _createPeerConnection().then((pc) { + _peerConnection = pc; + // _setRemoteDescription(widget.info); + }); + } + + void initRenderers() { + _localVideoRenderer.initialize(); + _remoteRenderer.initialize(); + initLocalCamera(); + } + + void initLocalCamera() async { + _localStream = await navigator.mediaDevices.getUserMedia({'video': true, 'audio': true}); + _localVideoRenderer.srcObject = _localStream; + // _localVideoRenderer.srcObject = await navigator.mediaDevices + // .getUserMedia({'video': true, 'audio': true}); + print('this source Object'); + print('this suarce ${_localVideoRenderer.srcObject != null}'); + notifyListeners(); + } + + void startCall({required String callType}) {} + + void endCall() {} + + void checkCall(Map message) { + switch (message["callStatus"]) { + case 'connected': + {} + break; + case 'offer': + {} + break; + case 'accept': + {} + break; + case 'candidate': + {} + break; + case 'bye': + {} + break; + case 'leave': + {} + break; + } + } + + //// Listeners Methods //// + + void onCallAcceptedAsync(List? params) {} + + void onIceCandidateAsync(List? params) {} + + void onOfferAsync(List? params) {} + + void onAnswerOffer(List? params) {} + + void onHangUpAsync(List? params) {} + + void onCallDeclinedAsync(List? params) {} + + //// Invoke Methods + + Future invoke({required String invokeMethod, required String currentUserID, required String targetUserID, bool isVideoCall = false, var data}) async { + List args = []; + if (invokeMethod == "answerCallAsync") { + args = [currentUserID, targetUserID]; + } else if (invokeMethod == "CallUserAsync") { + args = [currentUserID, targetUserID, isVideoCall]; + } else if (invokeMethod == "IceCandidateAsync") { + args = [targetUserID, data]; + } else if (invokeMethod == "OfferAsync") { + args = [targetUserID, data]; + } else if (invokeMethod == "AnswerOfferAsync") { + args = [targetUserID, data]; + //json In Data + } + await chatHubConnection.invoke(invokeMethod, args: args); + } + + void stopListeners() async { + chatHubConnection.off('OnCallDeclinedAsync'); + chatHubConnection.off('OnCallAcceptedAsync'); + chatHubConnection.off('OnIceCandidateAsync'); + chatHubConnection.off('OnAnswerOffer'); + } +} diff --git a/lib/provider/chat_provider_model.dart b/lib/provider/chat_provider_model.dart index 3e7bc4b..d374114 100644 --- a/lib/provider/chat_provider_model.dart +++ b/lib/provider/chat_provider_model.dart @@ -69,6 +69,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { List teamMembersList = []; Material.TextDirection textDirection = Material.TextDirection.ltr; + bool isRTL = false; + String msgText = ""; //Chat Home Page Counter int chatUConvCounter = 0; @@ -77,6 +79,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { List? chatUsersList = []; int pageNo = 1; + bool disbaleChatForThisUser = false; + Future getUserAutoLoginToken() async { userLoginToken.UserAutoLoginModel userLoginResponse = await ChatApiClient().getUserLoginToken(); if (userLoginResponse.response != null) { @@ -86,6 +90,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { Utils.showToast( userLoginResponse.errorResponses!.first.fieldName.toString() + " Erorr", ); + disbaleChatForThisUser = true; + notifyListeners(); } } @@ -117,6 +123,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { // chatHubConnection.on("OnUpdateUserChatHistoryWindowsAsync", updateChatHistoryWindow); chatHubConnection.on("OnGetUserChatHistoryNotDeliveredAsync", chatNotDelivered); chatHubConnection.on("OnUpdateUserChatHistoryStatusAsync", updateUserChatStatus); + if (kDebugMode) { logger.i("All listeners registered"); } @@ -1007,23 +1014,25 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } void disposeData() { - search.clear(); - isChatScreenActive = false; - receiverID = 0; - paginationVal = 0; - message.text = ''; - isTextMsg = false; - isAttachmentMsg = false; - isVoiceMsg = false; - isReplyMsg = false; - repliedMsg = []; - sFileType = ""; - deleteData(); - favUsersList.clear(); - searchedChats?.clear(); - pChatHistory?.clear(); - chatHubConnection.stop(); - AppState().chatDetails = null; + if (!disbaleChatForThisUser) { + search.clear(); + isChatScreenActive = false; + receiverID = 0; + paginationVal = 0; + message.text = ''; + isTextMsg = false; + isAttachmentMsg = false; + isVoiceMsg = false; + isReplyMsg = false; + repliedMsg = []; + sFileType = ""; + deleteData(); + favUsersList.clear(); + searchedChats?.clear(); + pChatHistory?.clear(); + chatHubConnection.stop(); + AppState().chatDetails = null; + } } void deleteData() { @@ -1407,17 +1416,16 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { void inputBoxDirection(String val) { if (val.isNotEmpty) { isTextMsg = true; - RegExp exp = RegExp("[a-zA-Z]"); - if (exp.hasMatch(val.substring(val.length - 1)) && val.substring(val.length - 1) != " ") { - textDirection = Material.TextDirection.ltr; - notifyListeners(); - } else if (val.substring(val.length - 1) != " " && !exp.hasMatch(val.substring(val.length - 1))) { - textDirection = Material.TextDirection.rtl; - notifyListeners(); - } } else { isTextMsg = false; } + msgText = val; + notifyListeners(); + } + + void onDirectionChange(bool val) { + isRTL = val; + notifyListeners(); } Material.TextDirection getTextDirection(String v) { @@ -1451,18 +1459,19 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } void openChatByNoti(BuildContext context) async { + SingleUserChatModel nUser = SingleUserChatModel(); Utils.saveStringFromPrefs("isAppOpendByChat", "false"); - SingleUserChatModel nUser = SingleUserChatModel.fromJson(jsonDecode(await Utils.getStringFromPrefs("notificationData"))); - Utils.saveStringFromPrefs("notificationData", "null"); - logger.w(jsonEncode(nUser)); - Future.delayed(const Duration(seconds: 2)); - for (ChatUser user in searchedChats!) { - if (user.id == nUser.targetUserId) { - Navigator.pushNamed(context, AppRoutes.chatDetailed, arguments: ChatDetailedScreenParams(user, false)); - return; - } else { - openChatByNoti(context); + if (await Utils.getStringFromPrefs("notificationData") != "null") { + nUser = SingleUserChatModel.fromJson(jsonDecode(await Utils.getStringFromPrefs("notificationData"))); + Utils.saveStringFromPrefs("notificationData", "null"); + Future.delayed(const Duration(seconds: 2)); + for (ChatUser user in searchedChats!) { + if (user.id == nUser.targetUserId) { + Navigator.pushNamed(context, AppRoutes.chatDetailed, arguments: ChatDetailedScreenParams(user, false)); + return; + } } } + Utils.saveStringFromPrefs("notificationData", "null"); } } diff --git a/lib/provider/dashboard_provider_model.dart b/lib/provider/dashboard_provider_model.dart index 644453f..0e18544 100644 --- a/lib/provider/dashboard_provider_model.dart +++ b/lib/provider/dashboard_provider_model.dart @@ -66,7 +66,11 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { if (attendanceTracking?.pSwipeIn != null) { isTimeRemainingInSeconds = calculateSeconds(attendanceTracking!.pRemainingHours ?? "00:00:00"); int totalShiftTimeInSeconds = calculateSeconds(attendanceTracking!.pScheduledHours ?? "00:00:00"); - progress = (isTimeRemainingInSeconds / totalShiftTimeInSeconds); + if (isTimeRemainingInSeconds == 0 || totalShiftTimeInSeconds == 0) { + progress = 0; + } else { + progress = (isTimeRemainingInSeconds / totalShiftTimeInSeconds); + } endTime = DateTime.now().millisecondsSinceEpoch + Duration(seconds: isTimeRemainingInSeconds).inMilliseconds; } notifyListeners(); @@ -258,7 +262,25 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { 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())); + GetMenuEntriesList abc = GetMenuEntriesList(requestType: "itg_forms", prompt: LocaleKeys.itgForms.tr()); + List list = getMenuEntriesList.where((element) => getMenuEntriesList[i].menuName == element.parentMenuName).toList(); + + if (getMenuEntriesList[i].menuName == "MBL_E_PROFESSIONALS_01") { + // hard coding this check to add change password for Active Directory + + GetMenuEntriesList activeDirectoryEntry = GetMenuEntriesList( + requestType: "RESET_ITG_AD_PASSWORD", + prompt: LocaleKeys.resetAdPassword.tr(), + parentMenuName: 'ITG_FORMS', + menuName: LocaleKeys.itgForms.tr(), + menuEntryType: "FUNCTION", //Reset AD Password + ); + getMenuEntriesList.add(activeDirectoryEntry); + + list.add(GetMenuEntriesList(requestType: "ITG_FORMS", prompt: LocaleKeys.itgForms.tr(), menuName: 'ITG_FORMS')); + } + + menus.add(Menus(getMenuEntriesList[i], list)); } } return menus; @@ -268,6 +290,7 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { MohemmItgResponseItem? res = await DashboardApiClient().getITGPageNotification(); return res; } + void notify() { notifyListeners(); } diff --git a/lib/ui/chat/call/chat_outgoing_call_screen.dart b/lib/ui/chat/call/chat_outgoing_call_screen.dart index 627c24a..2356e10 100644 --- a/lib/ui/chat/call/chat_outgoing_call_screen.dart +++ b/lib/ui/chat/call/chat_outgoing_call_screen.dart @@ -10,12 +10,14 @@ import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/extensions/int_extensions.dart'; import 'package:mohem_flutter_app/main.dart'; import 'package:mohem_flutter_app/models/chat/call.dart'; +import 'package:mohem_flutter_app/provider/chat_call_provider.dart'; +import 'package:provider/provider.dart'; class OutGoingCall extends StatefulWidget { - CallDataModel OutGoingCallData; - bool? isVideoCall; + CallDataModel outGoingCallData; + bool isVideoCall; - OutGoingCall({Key? key, required this.OutGoingCallData, this.isVideoCall}) : super(key: key); + OutGoingCall({Key? key, required this.outGoingCallData, required this.isVideoCall}) : super(key: key); @override _OutGoingCallState createState() => _OutGoingCallState(); @@ -23,23 +25,25 @@ class OutGoingCall extends StatefulWidget { class _OutGoingCallState extends State with SingleTickerProviderStateMixin { AnimationController? _animationController; - CameraController? _controller; + late CameraController controller; + late List _cameras; Future? _initializeControllerFuture; bool isCameraReady = false; bool isMicOff = false; bool isLoudSpeaker = false; bool isCamOff = false; + late ChatCallProvider callProviderd; @override void initState() { + callProviderd = Provider.of(context, listen: false); _animationController = AnimationController( vsync: this, duration: const Duration( milliseconds: 500, ), ); - logger.d(jsonEncode(widget.OutGoingCallData)); - //_runAnimation(); + // _runAnimation(); // connectSignaling(); WidgetsBinding.instance.addPostFrameCallback( (_) => _runAnimation(), @@ -58,13 +62,10 @@ class _OutGoingCallState extends State with SingleTickerProviderSt return Stack( alignment: FractionalOffset.center, children: [ - if (widget.isVideoCall!) + if (widget.isVideoCall) Positioned.fill( - child: AspectRatio( - aspectRatio: _controller!.value.aspectRatio, - child: CameraPreview( - _controller!, - ), + child: CameraPreview( + controller, ), ), Positioned.fill( @@ -74,7 +75,7 @@ class _OutGoingCallState extends State with SingleTickerProviderSt child: Container( decoration: BoxDecoration( color: MyColors.grey57Color.withOpacity( - 0.7, + 0.3, ), ), child: Column( @@ -105,9 +106,9 @@ class _OutGoingCallState extends State with SingleTickerProviderSt fit: BoxFit.cover, ), 10.height, - const Text( - "Aamir Saleem Ahmad", - style: TextStyle( + Text( + widget.outGoingCallData.title, + style: const TextStyle( fontSize: 21, fontWeight: FontWeight.bold, color: MyColors.white, @@ -179,7 +180,7 @@ class _OutGoingCallState extends State with SingleTickerProviderSt mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - if (widget.isVideoCall!) + if (widget.isVideoCall) RawMaterialButton( onPressed: () { _camOff(); @@ -267,13 +268,10 @@ class _OutGoingCallState extends State with SingleTickerProviderSt } void _runAnimation() async { - List cameras = await availableCameras(); - CameraDescription firstCamera = cameras[1]; - _controller = CameraController( - firstCamera, - ResolutionPreset.medium, - ); - _initializeControllerFuture = _controller!.initialize(); + _cameras = await availableCameras(); + CameraDescription firstCamera = _cameras[1]; + controller = CameraController(firstCamera, ResolutionPreset.medium); + _initializeControllerFuture = controller.initialize(); setState(() {}); // setAudioFile(); for (int i = 0; i < 100; i++) { @@ -304,7 +302,7 @@ class _OutGoingCallState extends State with SingleTickerProviderSt try { // backToHome(); // final roomModel = RoomModel(name: widget.OutGoingCallData.name, token: widget.OutGoingCallData.sessionId, identity: widget.OutGoingCallData.identity); - await _controller?.dispose(); + await controller?.dispose(); // changeCallStatusAPI(4); diff --git a/lib/ui/chat/chat_bubble.dart b/lib/ui/chat/chat_bubble.dart index 1e91a79..d6483dc 100644 --- a/lib/ui/chat/chat_bubble.dart +++ b/lib/ui/chat/chat_bubble.dart @@ -8,6 +8,7 @@ import 'package:just_audio/just_audio.dart'; import 'package:mohem_flutter_app/api/chat/chat_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/my_custom_stream.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'; @@ -429,7 +430,7 @@ class ChatBubble extends StatelessWidget { Widget getPlayer({required AudioPlayer player, required SingleUserChatModel modelData}) { return StreamBuilder( - stream: player!.playerStateStream, + stream: player.playerStateStream, builder: (BuildContext context, AsyncSnapshot snapshot) { PlayerState? playerState = snapshot.data; ProcessingState? processingState = playerState?.processingState; @@ -442,7 +443,7 @@ class ChatBubble extends StatelessWidget { child: const CircularProgressIndicator(), ); } else if (playing != true) { - return Icon( + return const Icon( Icons.play_arrow, size: 30, color: MyColors.lightGreenColor, @@ -470,22 +471,3 @@ class ChatBubble extends StatelessWidget { ); } } - -class MyCustomStream extends StreamAudioSource { - final Uint8List bytes; - - MyCustomStream(this.bytes); - - @override - Future request([int? start, int? end]) async { - start ??= 0; - end ??= bytes.length; - return StreamAudioResponse( - sourceLength: bytes.length, - contentLength: end - start, - offset: start, - stream: Stream.value(bytes.sublist(start, end)), - contentType: 'audio/aac', - ); - } -} diff --git a/lib/ui/chat/chat_detailed_screen.dart b/lib/ui/chat/chat_detailed_screen.dart index a72e12b..421eb91 100644 --- a/lib/ui/chat/chat_detailed_screen.dart +++ b/lib/ui/chat/chat_detailed_screen.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:convert'; import 'package:audio_waveforms/audio_waveforms.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; @@ -13,7 +14,10 @@ import 'package:mohem_flutter_app/main.dart'; import 'package:mohem_flutter_app/models/chat/call.dart'; import 'package:mohem_flutter_app/models/chat/get_search_user_chat_model.dart'; import 'package:mohem_flutter_app/models/chat/get_single_user_chat_list_model.dart'; +import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart'; +import 'package:mohem_flutter_app/provider/chat_call_provider.dart'; import 'package:mohem_flutter_app/provider/chat_provider_model.dart'; +import 'package:mohem_flutter_app/ui/chat/custom_auto_direction.dart'; import 'package:mohem_flutter_app/ui/chat/call/chat_outgoing_call_screen.dart'; import 'package:mohem_flutter_app/ui/chat/chat_bubble.dart'; import 'package:mohem_flutter_app/ui/chat/common.dart'; @@ -41,8 +45,10 @@ class ChatDetailScreen extends StatefulWidget { class _ChatDetailScreenState extends State { final RefreshController _rc = RefreshController(initialRefresh: false); late ChatProviderModel data; + late ChatCallProvider callPro; ChatDetailedScreenParams? params; - var textDirection = TextDirection.RTL; + + // var textDirection = TextDirection.RTL; void getMoreChat() async { if (params != null) { @@ -72,6 +78,7 @@ class _ChatDetailScreenState extends State { Widget build(BuildContext context) { params = ModalRoute.of(context)!.settings.arguments as ChatDetailedScreenParams; data = Provider.of(context, listen: false); + // callPro = Provider.of(context, listen: false); if (params != null) { data.getSingleUserChatHistory( senderUID: AppState().chatDetails!.response!.id!.toInt(), @@ -92,11 +99,11 @@ class _ChatDetailScreenState extends State { chatUser: params!.chatUser, actions: [ // SvgPicture.asset("assets/icons/chat/call.svg", width: 21, height: 23).onPress(() { - // // makeCall(callType: "AUDIO", con: hubConnection); + // makeCall(callType: "AUDIO"); // }), // 24.width, // SvgPicture.asset("assets/icons/chat/video_call.svg", width: 21, height: 18).onPress(() { - // // makeCall(callType: "VIDEO", con: hubConnection); + // makeCall(callType: "VIDEO"); // }), // 21.width, ], @@ -252,37 +259,39 @@ class _ChatDetailScreenState extends State { if (!m.isRecoding) Row( children: [ - TextField( - textDirection: m.textDirection, - controller: m.message, - decoration: InputDecoration( - hintTextDirection: m.textDirection, - hintText: m.isAttachmentMsg - ? m.selectedFile.path.split("/").last - : m.textDirection.name == "rtl" ? "اكتب هنا للرد" :LocaleKeys.typeheretoreply.tr(), - hintStyle: TextStyle(color: m.isAttachmentMsg ? MyColors.darkTextColor : MyColors.grey98Color, fontSize: 14), - border: InputBorder.none, - focusedBorder: InputBorder.none, - enabledBorder: InputBorder.none, - errorBorder: InputBorder.none, - disabledBorder: InputBorder.none, - filled: true, - fillColor: MyColors.white, - contentPadding: const EdgeInsets.only( - left: 21, - top: 20, - bottom: 20, + CustomAutoDirection( + onDirectionChange: (bool isRTL) => m.onDirectionChange(isRTL), + text: m.msgText, + child: TextField( + // textDirection: m.textDirection, + controller: m.message, + decoration: InputDecoration( + hintTextDirection: m.textDirection, + hintText: m.isAttachmentMsg ? m.selectedFile.path.split("/").last : LocaleKeys.typeheretoreply.tr(), + hintStyle: TextStyle(color: m.isAttachmentMsg ? MyColors.darkTextColor : MyColors.grey98Color, fontSize: 14), + border: InputBorder.none, + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + errorBorder: InputBorder.none, + disabledBorder: InputBorder.none, + filled: true, + fillColor: MyColors.white, + contentPadding: const EdgeInsets.only( + left: 21, + top: 20, + bottom: 20, + ), + prefixIconConstraints: const BoxConstraints(), + prefixIcon: m.sFileType.isNotEmpty + ? SvgPicture.asset(m.getType(m.sFileType), height: 30, width: 22, alignment: Alignment.center, fit: BoxFit.cover).paddingOnly(left: 21, right: 15) + : null, ), - prefixIconConstraints: const BoxConstraints(), - prefixIcon: m.sFileType.isNotEmpty - ? SvgPicture.asset(m.getType(m.sFileType), height: 30, width: 22, alignment: Alignment.center, fit: BoxFit.cover).paddingOnly(left: 21, right: 15) - : null, - ), - onChanged: (String val) { - m.inputBoxDirection(val); - m.userTypingInvoke(currentUser: AppState().chatDetails!.response!.id!, reciptUser: params!.chatUser!.id!); - }, - ).expanded, + onChanged: (String val) { + m.inputBoxDirection(val); + m.userTypingInvoke(currentUser: AppState().chatDetails!.response!.id!, reciptUser: params!.chatUser!.id!); + }, + ).expanded, + ), if (m.sFileType.isNotEmpty) Row( children: [ @@ -342,45 +351,30 @@ class _ChatDetailScreenState extends State { } } - void makeCall({required String callType, required HubConnection con}) async { + void makeCall({required String callType}) async { + callPro.initCallListeners(); print("================== Make call Triggered ============================"); Map json = { "callerID": AppState().chatDetails!.response!.id!.toString(), - "callReceiverID": params!.chatUser!.id.toString(), - "notification_foreground": "true", - "message": "Aamir is calling", - "title": "Video Call", - "type": callType == "VIDEO" ? "Video" : "Audio", - "identity": AppState().chatDetails!.response!.userName, - "name": AppState().chatDetails!.response!.title, - "is_call": "true", - "is_webrtc": "true", - "contant": "Start video Call ${AppState().chatDetails!.response!.userName}", - "contantNo": "775d1f11-62d9-6fcc-91f6-21f8c14559fb", - "chatEventId": "3", - "fileTypeId": null, - "currentUserId": AppState().chatDetails!.response!.id!.toString(), - "chatSource": "1", - "userChatHistoryLineRequestList": [ - { - "isSeen": false, - "isDelivered": false, - "targetUserId": params!.chatUser!.id!, - "targetUserStatus": 4, - } - ], - // "server": "https://192.168.8.163:8086", - "server": "https://livecareturn.hmg.com:8086", + "callerDetails": AppState().chatDetails!.toJson(), + "receiverID": params!.chatUser!.id.toString(), + "receiverDetails": params!.chatUser!.toJson(), + "title": params!.chatUser!.userName!.replaceAll(".", " "), + "calltype": callType == "VIDEO" ? "Video" : "Audio", }; + logger.w(json); CallDataModel callData = CallDataModel.fromJson(json); await Navigator.push( context, MaterialPageRoute( builder: (BuildContext context) => OutGoingCall( isVideoCall: callType == "VIDEO" ? true : false, - OutGoingCallData: callData, + outGoingCallData: callData, ), ), - ); + ).then((value) { + print("then"); + callPro.stopListeners(); + }); } } diff --git a/lib/ui/chat/chat_home.dart b/lib/ui/chat/chat_home.dart index 2e23254..9c5f216 100644 --- a/lib/ui/chat/chat_home.dart +++ b/lib/ui/chat/chat_home.dart @@ -52,11 +52,11 @@ class _ChatHomeState extends State { if (data.searchedChats == null || data.searchedChats!.isEmpty) { data.isLoading = true; data.getUserRecentChats().whenComplete(() async { - String isAppOpendByChat = await Utils.getStringFromPrefs("isAppOpendByChat"); - String notificationData = await Utils.getStringFromPrefs("notificationData"); - if (isAppOpendByChat != "null" || isAppOpendByChat == "true" && notificationData != "null") { - data.openChatByNoti(context); - } + // String isAppOpendByChat = await Utils.getStringFromPrefs("isAppOpendByChat"); + // String notificationData = await Utils.getStringFromPrefs("notificationData"); + // if (isAppOpendByChat != "null" || isAppOpendByChat == "true" && notificationData != "null") { + // data.openChatByNoti(context); + // } }); } } diff --git a/lib/ui/chat/custom_auto_direction.dart b/lib/ui/chat/custom_auto_direction.dart new file mode 100644 index 0000000..7e40644 --- /dev/null +++ b/lib/ui/chat/custom_auto_direction.dart @@ -0,0 +1,38 @@ +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart' as intl; + +class CustomAutoDirection extends StatefulWidget { + final String text; + final Widget child; + final void Function(bool isRTL)? onDirectionChange; + + const CustomAutoDirection({Key? key, required this.text, required this.child, this.onDirectionChange}) : super(key: key); + + @override + _CustomAutoDirectionState createState() => _CustomAutoDirectionState(); +} + +class _CustomAutoDirectionState extends State { + late String text; + late Widget childWidget; + + @override + Widget build(BuildContext context) { + text = widget.text; + childWidget = widget.child; + return Directionality(textDirection: isRTL(text) ? TextDirection.rtl : TextDirection.ltr, child: childWidget); + } + + @override + void didUpdateWidget(CustomAutoDirection oldWidget) { + if (isRTL(oldWidget.text) != isRTL(widget.text)) { + WidgetsBinding.instance.addPostFrameCallback((_) => widget.onDirectionChange?.call(isRTL(widget.text))); + } + super.didUpdateWidget(oldWidget); + } + + bool isRTL(String text) { + if (text.isEmpty) return Directionality.of(context) == TextDirection.rtl; + return intl.Bidi.detectRtlDirectionality(text); + } +} diff --git a/lib/ui/dialogs/id/employee_digital_id_dialog.dart b/lib/ui/dialogs/id/employee_digital_id_dialog.dart index 0e672f8..63a5e29 100644 --- a/lib/ui/dialogs/id/employee_digital_id_dialog.dart +++ b/lib/ui/dialogs/id/employee_digital_id_dialog.dart @@ -6,10 +6,8 @@ import 'package:mohem_flutter_app/extensions/int_extensions.dart'; import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; import 'package:mohem_flutter_app/widgets/button/default_button.dart'; -import 'package:qr_flutter/qr_flutter.dart'; import 'package:mohem_flutter_app/classes/utils.dart'; -import 'package:mohem_flutter_app/main.dart'; class EmployeeDigitialIdDialog extends StatelessWidget { @override diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index 3801e02..6070b90 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -16,8 +16,8 @@ import 'package:mohem_flutter_app/extensions/int_extensions.dart'; import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; -import 'package:mohem_flutter_app/main.dart'; import 'package:mohem_flutter_app/models/offers_and_discounts/get_offers_list.dart'; +import 'package:mohem_flutter_app/models/privilege_list_model.dart'; import 'package:mohem_flutter_app/provider/chat_provider_model.dart'; import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; import 'package:mohem_flutter_app/ui/landing/widget/app_drawer.dart'; @@ -63,7 +63,9 @@ class _DashboardScreenState extends State with WidgetsBindingOb data = Provider.of(context, listen: false); marathonProvider = Provider.of(context, listen: false); cProvider = Provider.of(context, listen: false); - _bHubCon(); + if (checkIfPrivilegedForChat()) { + _bHubCon(); + } _onRefresh(true); }); } @@ -87,24 +89,28 @@ class _DashboardScreenState extends State with WidgetsBindingOb void dispose() { WidgetsBinding.instance.removeObserver(this); super.dispose(); - chatHubConnection.stop(); + if (!cProvider.disbaleChatForThisUser) { + chatHubConnection.stop(); + } } void _bHubCon() { cProvider.getUserAutoLoginToken().whenComplete(() async { - String isAppOpendByChat = await Utils.getStringFromPrefs("isAppOpendByChat"); - if (isAppOpendByChat != null && isAppOpendByChat == "true") { - Utils.showLoading(context); - cProvider.buildHubConnection(); - Future.delayed(const Duration(seconds: 2), () async { - cProvider.invokeChatCounter(userId: AppState().chatDetails!.response!.id!); - gotoChat(context); - }); - } else { - cProvider.buildHubConnection(); - Future.delayed(const Duration(seconds: 2), () { - cProvider.invokeChatCounter(userId: AppState().chatDetails!.response!.id!); - }); + if (!cProvider.disbaleChatForThisUser) { + String isAppOpendByChat = await Utils.getStringFromPrefs("isAppOpendByChat"); + if (isAppOpendByChat != "null" && isAppOpendByChat == "true") { + Utils.showLoading(context); + cProvider.buildHubConnection(); + Future.delayed(const Duration(seconds: 2), () async { + cProvider.invokeChatCounter(userId: AppState().chatDetails!.response!.id!); + gotoChat(context); + }); + } else { + cProvider.buildHubConnection(); + Future.delayed(const Duration(seconds: 2), () { + cProvider.invokeChatCounter(userId: AppState().chatDetails!.response!.id!); + }); + } } }); } @@ -122,6 +128,11 @@ class _DashboardScreenState extends State with WidgetsBindingOb if (chatHubConnection.state == HubConnectionState.Connected) { Utils.hideLoading(context); Navigator.pushNamed(context, AppRoutes.chat); + String isAppOpendByChat = await Utils.getStringFromPrefs("isAppOpendByChat"); + if (isAppOpendByChat != "null" || isAppOpendByChat == "true") { + Utils.saveStringFromPrefs("isAppOpendByChat", "false"); + Utils.saveStringFromPrefs("notificationData", "null"); + } } } @@ -140,54 +151,55 @@ class _DashboardScreenState extends State with WidgetsBindingOb data.fetchMenuEntries(); data.getCategoryOffersListAPI(context); marathonProvider.getMarathonDetailsFromApi(); - if (!isFromInit) checkHubCon(); + if (isFromInit) { + checkERMChannel(); + } + if (!cProvider.disbaleChatForThisUser && !isFromInit) checkHubCon(); _refreshController.refreshCompleted(); } + void checkERMChannel() { + data.getITGNotification().then((val) { + if (val!.result!.data != null) { + print("-------------------- Survey ----------------------------"); + if (val.result!.data!.notificationType == "Survey") { + DashboardApiClient().getAdvertisementDetail(val.result!.data!.notificationMasterId ?? "").then( + (value) { + if (value!.mohemmItgResponseItem!.statusCode == 200) { + if (value.mohemmItgResponseItem!.result!.data != null) { + // Navigator.pushNamed(context, AppRoutes.survey, arguments: val.result!.data); + Navigator.pushNamed(context, AppRoutes.survey, arguments: value.mohemmItgResponseItem!.result!.data); + // Navigator.pushNamed(context, AppRoutes.advertisement, arguments: { + // "masterId": val.result!.data!.notificationMasterId, + // "advertisement": value.mohemmItgResponseItem!.result!.data!.advertisement, + // }); + } + } + }, + ); + } else { + print("------------------------------------------- Ads --------------------"); + DashboardApiClient().getAdvertisementDetail(val.result!.data!.notificationMasterId ?? "").then( + (value) { + if (value!.mohemmItgResponseItem!.statusCode == 200) { + if (value.mohemmItgResponseItem!.result!.data != null) { + Navigator.pushNamed(context, AppRoutes.advertisement, arguments: { + "masterId": val.result!.data!.notificationMasterId, + "advertisement": value.mohemmItgResponseItem!.result!.data!.advertisement, + }); + } + } + }, + ); + } + } + }); + } + @override Widget build(BuildContext context) { return Scaffold( key: _scaffoldState, - // appBar: AppBar( - // actions: [ - // IconButton( - // onPressed: () { - // data.getITGNotification().then((val) { - // if (val!.result!.data != null) { - // print("-------------------- Survey ----------------------------"); - // if (val.result!.data!.notificationType == "Survey") { - // Navigator.pushNamed(context, AppRoutes.survey, arguments: val.result!.data); - // } else { - // print("------------------------------------------- Ads --------------------"); - // DashboardApiClient().getAdvertisementDetail(val.result!.data!.notificationMasterId ?? "").then( - // (value) { - // if (value!.mohemmItgResponseItem!.statusCode == 200) { - // if (value.mohemmItgResponseItem!.result!.data != null) { - // Navigator.pushNamed(context, AppRoutes.advertisement, arguments: { - // "masterId": val.result!.data!.notificationMasterId, - // "advertisement": value.mohemmItgResponseItem!.result!.data!.advertisement, - // }); - // - // // Navigator.push( - // // context, - // // MaterialPageRoute( - // // builder: (BuildContext context) => ITGAdsScreen( - // // addMasterId: val.result!.data!.notificationMasterId!, - // // advertisement: value.mohemmItgResponseItem!.result!.data!.advertisement!, - // // ), - // // ), - // // ); - // } - // } - // }, - // ); - // } - // } - // }); - // }, - // icon: Icon(Icons.add)) - // ], - // ), body: Column( children: [ Row( @@ -248,7 +260,7 @@ class _DashboardScreenState extends State with WidgetsBindingOb children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [ + children: [ LocaleKeys.welcomeBack.tr().toText14(color: MyColors.grey77Color), (AppState().memberInformationList!.eMPLOYEENAME ?? "").toText24(isBold: true), 16.height, @@ -341,7 +353,7 @@ class _DashboardScreenState extends State with WidgetsBindingOb bottomLeft: AppState().isArabic(context) ? Radius.circular(15) : Radius.circular(0), ), ), - child: SvgPicture.asset(model.isTimeRemainingInSeconds == 0 ? "assets/images/attendance.svg" : "assets/images/attendance.svg"), + child: SvgPicture.asset(model.isTimeRemainingInSeconds == 0 ? "assets/images/biometrics.svg" : "assets/images/biometrics.svg"), ).onPress(() { showMyBottomSheet( context, @@ -454,7 +466,7 @@ class _DashboardScreenState extends State with WidgetsBindingOb tag: "ItemImage" + data.getOffersList[index].offersDiscountId.toString()!, transitionOnUserGestures: true, child: Image.network( - data.getOffersList[index].logo!, + data.getOffersList[index].logo ?? "", fit: BoxFit.contain, ), ), @@ -564,20 +576,28 @@ class _DashboardScreenState extends State with WidgetsBindingOb children: [ SvgPicture.asset( "assets/icons/chat/chat.svg", - color: currentIndex == 4 ? MyColors.grey3AColor : MyColors.grey98Color, + color: !checkIfPrivilegedForChat() + ? MyColors.lightGreyE3Color + : currentIndex == 4 + ? MyColors.grey3AColor + : cProvider.disbaleChatForThisUser + ? MyColors.lightGreyE3Color + : MyColors.grey98Color, ).paddingAll(4), Consumer( builder: (BuildContext cxt, ChatProviderModel data, Widget? child) { - return Positioned( - right: 0, - top: 0, - child: Container( - padding: const EdgeInsets.only(left: 4, right: 4), - alignment: Alignment.center, - decoration: BoxDecoration(color: MyColors.redColor, borderRadius: BorderRadius.circular(17)), - child: data.chatUConvCounter.toString().toText10(color: Colors.white), - ), - ); + return !checkIfPrivilegedForChat() + ? const SizedBox() + : Positioned( + right: 0, + top: 0, + child: Container( + padding: const EdgeInsets.only(left: 4, right: 4), + alignment: Alignment.center, + decoration: BoxDecoration(color: cProvider.disbaleChatForThisUser ? MyColors.pinkDarkColor : MyColors.redColor, borderRadius: BorderRadius.circular(17)), + child: data.chatUConvCounter.toString().toText10(color: Colors.white), + ), + ); }, ), ], @@ -601,7 +621,9 @@ class _DashboardScreenState extends State with WidgetsBindingOb } else if (index == 3) { Navigator.pushNamed(context, AppRoutes.itemsForSale); } else if (index == 4) { - Navigator.pushNamed(context, AppRoutes.chat); + if (!cProvider.disbaleChatForThisUser && checkIfPrivilegedForChat()) { + Navigator.pushNamed(context, AppRoutes.chat); + } } }, ), @@ -624,7 +646,17 @@ class _DashboardScreenState extends State with WidgetsBindingOb } } }); - Navigator.pushNamed(context, AppRoutes.offersAndDiscountsDetails, arguments: getOffersDetailList); } + + bool checkIfPrivilegedForChat() { + for (PrivilegeListModel element in AppState().privilegeListModel!) { + if (element.serviceName?.toLowerCase() == "chat") { + if (element.previlege != null) { + return element.previlege!; + } + } + } + return false; + } } diff --git a/lib/ui/landing/itg/change_itg_ad_password_screen.dart b/lib/ui/landing/itg/change_itg_ad_password_screen.dart new file mode 100644 index 0000000..cc84f96 --- /dev/null +++ b/lib/ui/landing/itg/change_itg_ad_password_screen.dart @@ -0,0 +1,166 @@ +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/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/button/default_button.dart'; +import 'package:mohem_flutter_app/widgets/input_widget.dart'; + +class ChangeItgAdPasswordScreen extends StatefulWidget { + ChangeItgAdPasswordScreen({Key? key}) : super(key: key); + + @override + _ChangeItgAdPasswordScreenState createState() { + return _ChangeItgAdPasswordScreenState(); + } +} + +class _ChangeItgAdPasswordScreenState extends State { + TextEditingController password = TextEditingController(); + TextEditingController confirmPassword = TextEditingController(); + + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + void setNewPassword() async { + Utils.showLoading(context); + try { + GenericResponseModel response = await LoginApiClient().changePasswordFromActiveDirectorySession(password.text, AppState().memberInformationList!.eMPLOYEEEMAILADDRESS!); + Utils.hideLoading(context); + if ((response.messageStatus ?? 0) == 1) { + Utils.showToast(LocaleKeys.passwordChangedSuccessfully.tr()); + Navigator.pop(context); + } + } catch (ex) { + Utils.hideLoading(context); + Utils.handleException(ex, context, (msg) { + Utils.confirmDialog(context, msg); + }); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: Colors.transparent, + leading: IconButton( + icon: const Icon(Icons.arrow_back_ios, color: MyColors.darkIconColor), + onPressed: () => Navigator.pop(context), + ), + ), + body: Column( + children: [ + ListView( + padding: const EdgeInsets.all(21), + children: [ + LocaleKeys.changePassword.tr().toText24(isBold: true), + LocaleKeys.typeYourNewActiveDirectoryPasswordBelow.tr().toText16(), + 16.height, + InputWidget( + LocaleKeys.password.tr(), + "**********", + password, + onChange: (value) { + setState(() {}); + }, + ), + 12.height, + InputWidget( + LocaleKeys.confirmPassword.tr(), + "**********", + confirmPassword, + isTextIsPassword: true, + onChange: (value) { + setState(() {}); + }, + ), + 16.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), + ], + ).expanded, + DefaultButton(LocaleKeys.changePassword.tr(), (!isPasswordCompliant(password.text, 8)) ? null : setNewPassword).insideContainer + ], + ), + ); + } + + bool checkRegEx(String pattern) { + return RegExp(pattern).hasMatch(password.text); + } + + String recentPassword = ""; + + 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 && hasLowercase && 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/landing/itg/its_add_screen_video_image.dart b/lib/ui/landing/itg/its_add_screen_video_image.dart index bcb9ed4..61b2766 100644 --- a/lib/ui/landing/itg/its_add_screen_video_image.dart +++ b/lib/ui/landing/itg/its_add_screen_video_image.dart @@ -2,10 +2,17 @@ import 'dart:convert'; import 'dart:io' as Io; import 'dart:io'; import 'dart:typed_data'; + import 'package:flutter/material.dart'; -import 'package:just_audio/just_audio.dart'; +import 'package:flutter_countdown_timer/index.dart'; +import 'package:lottie/lottie.dart'; import 'package:mohem_flutter_app/api/dashboard_api_client.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/classes/lottie_consts.dart'; +import 'package:mohem_flutter_app/classes/utils.dart'; +import 'package:mohem_flutter_app/extensions/int_extensions.dart'; +import 'package:mohem_flutter_app/extensions/string_extensions.dart'; +import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; import 'package:mohem_flutter_app/main.dart'; import 'package:mohem_flutter_app/models/itg/advertisement.dart' as ads; import 'package:path_provider/path_provider.dart'; @@ -24,11 +31,13 @@ class _ITGAdsScreenState extends State { bool skip = false; bool isVideo = false; bool isImage = false; + bool isAudio = false; String ext = ''; late File imageFile; ads.Advertisement? advertisementData; dynamic data; String? masterID; + int videoDuration = 0; void checkFileType() async { String? rFile = advertisementData!.viewAttachFileColl!.first.base64String; @@ -38,11 +47,13 @@ class _ITGAdsScreenState extends State { await processImage(rFile!); isImage = true; } else { + if (ext == ".aac") { + isAudio = true; + } isVideo = true; _futureController = createVideoPlayer(rFile!); } setState(() {}); - initTimer(); } Future processImage(String encodedBytes) async { @@ -76,26 +87,29 @@ class _ITGAdsScreenState extends State { void initTimer() { Future.delayed(const Duration(seconds: 5), () { skip = true; - setState(() {}); + // setState(() {}); }); } @override void dispose() { - _controller.dispose(); + if (_controller != null) _controller.dispose(); + // player.stop(); + // player.dispose(); super.dispose(); } @override Widget build(BuildContext context) { data = ModalRoute.of(context)!.settings.arguments; - if (advertisementData == null) advertisementData = data["advertisement"] as ads.Advertisement; - if (masterID == null) masterID = data["masterId"]; + advertisementData ??= data["advertisement"] as ads.Advertisement; + masterID ??= data["masterId"]; if (advertisementData != null) { checkFileType(); + videoDuration = advertisementData?.durationInSeconds ?? 0; } - // double height = MediaQuery.of(context).size.height * .25; return Scaffold( + backgroundColor: Colors.black, body: Stack( children: [ if (isVideo) @@ -104,11 +118,52 @@ class _ITGAdsScreenState extends State { builder: (BuildContext context, AsyncSnapshot snapshot) { if (snapshot.connectionState == ConnectionState.done && snapshot.data != null) { _controller = snapshot.data as VideoPlayerController; - return Positioned.fill( - child: AspectRatio( - aspectRatio: _controller.value.aspectRatio, - child: VideoPlayer(_controller), - ), + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Center( + child: isAudio + ? Lottie.asset(MyLottieConsts.audioPlaybackLottie) + : AspectRatio( + aspectRatio: _controller.value.aspectRatio, + child: VideoPlayer(_controller), + ), + ), + 30.height, + CountdownTimer( + endTime: DateTime.now().millisecondsSinceEpoch + 1000 * videoDuration, + onEnd: null, + endWidget: "00:00:00".toText14(color: Colors.white, isBold: true), + textStyle: const TextStyle(color: Colors.white, fontSize: 16, letterSpacing: -0.48, fontWeight: FontWeight.bold), + ), + 50.height, + Container(padding: const EdgeInsets.all(16), decoration: Utils.containerRadius(MyColors.white, 10), child: const Icon(Icons.thumb_up, color: MyColors.gradiantEndColor)) + .onPress(() { + try { + DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!).then((value) { + logger.d(value); + Navigator.pop(context); + }); + } catch (ex) { + logger.wtf(ex); + Utils.handleException(ex, context, null); + } + }), + // DefaultButton(LocaleKeys.home.tr(), () async { + // DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!).then((value) { + // logger.d(value); + // }); + // }).paddingOnly(left: 50, right: 50) + + // ElevatedButton( + // onPressed: () async { + // // DashboardApiClient().setAdvertisementViewed(widget.addMasterId, widget.advertisement!.advertisementId!).then((value) { + // // logger.d(value); + // // }); + // }, + // child: const Text("Go To Dashboard"), + // ) + ], ); } else { return const Center( @@ -117,16 +172,28 @@ class _ITGAdsScreenState extends State { } }, ), - if (isImage) Image.file(imageFile), - if (skip) - ElevatedButton( - onPressed: () async { - // DashboardApiClient().setAdvertisementViewed(widget.addMasterId, widget.advertisement!.advertisementId!).then((value) { - // logger.d(value); - // }); - }, - child: const Text("Go To Dashboard"), - ) + if (isImage) + Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.file(imageFile), + 50.height, + Container(padding: const EdgeInsets.all(16), decoration: Utils.containerRadius(MyColors.white, 10), child: const Icon(Icons.thumb_up, color: MyColors.gradiantEndColor)).onPress( + () { + try { + DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!).then((value) { + logger.d(value); + Navigator.pop(context); + }); + } catch (ex) { + logger.wtf(ex); + Utils.handleException(ex, context, null); + } + }, + ), + ], + ), ], ), ); diff --git a/lib/ui/landing/itg/survey_screen.dart b/lib/ui/landing/itg/survey_screen.dart index ec79d0f..59f3c14 100644 --- a/lib/ui/landing/itg/survey_screen.dart +++ b/lib/ui/landing/itg/survey_screen.dart @@ -1,5 +1,3 @@ -import 'dart:convert'; - import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_rating_bar/flutter_rating_bar.dart'; @@ -7,15 +5,14 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:mohem_flutter_app/api/dashboard_api_client.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; import 'package:mohem_flutter_app/classes/utils.dart'; -import 'package:mohem_flutter_app/config/routes.dart'; import 'package:mohem_flutter_app/extensions/int_extensions.dart'; import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; import 'package:mohem_flutter_app/models/itg/itg_main_response.dart'; import 'package:mohem_flutter_app/models/itg/itg_response_model.dart'; +import 'package:mohem_flutter_app/models/itg/survey_model.dart'; import 'package:mohem_flutter_app/widgets/button/default_button.dart'; -import 'package:mohem_flutter_app/widgets/dynamic_forms/dynamic_textfield_widget.dart'; class SurveyScreen extends StatefulWidget { const SurveyScreen({Key? key}) : super(key: key); @@ -27,78 +24,50 @@ class SurveyScreen extends StatefulWidget { class _SurveyScreenState extends State { String reviewText = ""; double starRating = 1; - int _selectedIndex = 5; + int _selectedIndex = 0; ItgResponseData? itgResponseData; + List answeredQuestions = []; + + @override + void initState() { + WidgetsBinding.instance.addPostFrameCallback( + (_) => initAnswersList(), + ); + super.initState(); + } + @override Widget build(BuildContext context) { - if (itgResponseData == null) itgResponseData = ModalRoute.of(context)!.settings.arguments as ItgResponseData; + itgResponseData ??= ModalRoute.of(context)!.settings.arguments as ItgResponseData; return Scaffold( backgroundColor: MyColors.backgroundColor, body: Column( children: [ Expanded( child: ListView( - scrollDirection: Axis.vertical, children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - 124.height, - LocaleKeys.feedbackUserExperience.tr().toText19(), - 27.height, - LocaleKeys.rateUI.tr().toText16(), - 22.height, - Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - RatingBar.builder( - initialRating: 3, - minRating: starRating, - direction: Axis.horizontal, - allowHalfRating: false, - itemCount: 5, - itemPadding: EdgeInsets.symmetric(horizontal: 8), - itemBuilder: (context, _) => Icon( - Icons.star, - color: Colors.amber, - ), - onRatingUpdate: (rating) { - starRating = rating; - }, - ) - ], - ).paddingOnly(left: 22, right: 22, top: 12, bottom: 12).objectContainerView(disablePadding: true), - 39.height, - LocaleKeys.rateUI.tr().toText16(), - 10.height, - GridView( - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 5, crossAxisSpacing: 7, mainAxisSpacing: 7), - physics: const NeverScrollableScrollPhysics(), - padding: const EdgeInsets.only(top: 0), - shrinkWrap: true, - children: [ - optionUI("poor.svg", 1), - optionUI("bad.svg", 2), - optionUI("normal.svg", 3), - optionUI("good.svg", 4), - optionUI("xcellent.svg", 5), - ], - ), - 27.height, - DynamicTextFieldWidget( - LocaleKeys.description.tr(), - LocaleKeys.typeHere.tr(), - lines: 3, - onChange: (v) { - reviewText = v; - }, - ), - 150.height - ], - ).paddingOnly(left: 21, right: 21), + Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + children: [ + 32.height, + itgResponseData?.survey?.title?.toText24() ?? const Text(""), + 8.height, + itgResponseData?.survey?.description?.toText16() ?? const Text(""), + ListView.builder( + padding: EdgeInsets.zero, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: itgResponseData?.survey?.questions?.length, + itemBuilder: (cxt, index) { + return answeredQuestions.isNotEmpty ? getSurveyWidget(itgResponseData?.survey?.questions![index], index) : Container(); + }, + ), + ], + ).paddingOnly(left: 21, right: 21), + ), ], )), DefaultButton( @@ -111,7 +80,7 @@ class _SurveyScreenState extends State { )); } - Widget optionUI(String icon, int index) { + Widget optionUI(String icon, int? index, int answerIndex) { return (_selectedIndex == index ? SvgPicture.asset( 'assets/images/' + icon, @@ -126,33 +95,129 @@ class _SurveyScreenState extends State { disablePadding: true, )) .onPress(() { - _selectedIndex = index; + _selectedIndex = index!; + answeredQuestions[answerIndex] = _selectedIndex.toString(); setState(() {}); }); } + void initAnswersList() { + answeredQuestions.clear(); + itgResponseData?.survey?.questions?.forEach((element) { + if (element.type != "Stars") { + if(element.type == "Faces") { + _selectedIndex = element.options![0].optionId!; + } + answeredQuestions.add(element.options![0].optionId.toString()); + } else { + answeredQuestions.add("4"); + } + }); + setState(() {}); + } + + Widget getSurveyWidget(Questions? question, int parentIndex) { + if (question?.type == "Expressions") { + // Expressions = radio buttons + return Column( + children: [ + 24.height, + question?.title?.toText18() ?? const Text(""), + 16.height, + GridView.builder( + padding: EdgeInsets.zero, + itemCount: question?.options?.length, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (context, index) { + return radioOption(question?.options?[index].title ?? "", question?.options?[index].optionId.toString() ?? "", answeredQuestions[parentIndex], parentIndex); + }, + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + childAspectRatio: (4.0), + ), + ).paddingOnly(left: 22, right: 22, top: 12, bottom: 12).objectContainerView(disablePadding: true), + ], + ); + } else if (question?.type == "Stars") { + // Stars = star rating + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + 24.height, + question?.title?.toText18() ?? Text(""), + 16.height, + RatingBar.builder( + initialRating: 3, + minRating: starRating, + direction: Axis.horizontal, + allowHalfRating: false, + itemCount: 5, + itemPadding: const EdgeInsets.symmetric(horizontal: 8), + itemBuilder: (context, _) => const Icon( + Icons.star, + color: Colors.amber, + ), + onRatingUpdate: (rating) { + starRating = rating; + answeredQuestions[parentIndex] = rating.toInt().toString(); + }, + ).paddingOnly(left: 22, right: 22, top: 12, bottom: 12).objectContainerView(disablePadding: true), + ], + ); + } else if (question?.type == "Faces") { + // Faces = face rating + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + 24.height, + question?.title?.toText18() ?? Text("asdasdasdasd"), + 16.height, + GridView( + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 5, crossAxisSpacing: 7, mainAxisSpacing: 7), + physics: const NeverScrollableScrollPhysics(), + padding: const EdgeInsets.only(top: 0), + shrinkWrap: true, + children: [ + optionUI("poor.svg", question?.options?[0].optionId, parentIndex), + optionUI("bad.svg", question?.options?[1].optionId, parentIndex), + optionUI("normal.svg", question?.options?[2].optionId, parentIndex), + optionUI("good.svg", question?.options?[3].optionId, parentIndex), + optionUI("xcellent.svg", question?.options?[4].optionId, parentIndex), + ], + ), + ], + ); + } else { + return Container(); + } + return Container(); + } + void performAPI() async { Utils.showLoading(context); + List> itgAnswersList = []; + int index = 0; try { - ItgMainRes? res= await DashboardApiClient().submitItgForm( - comment: reviewText, - masterId: itgResponseData!.notificationMasterId ?? "", - itgList: [ - {"questionId": "1", "optionId": null, "starRating": starRating}, - {"questionId": "2", "optionId": "4", "starRating": _selectedIndex} - ], - serviceId: itgResponseData!.serviceId ?? 0); - Utils.hideLoading(context); + answeredQuestions.forEach((element) { + itgAnswersList.add({ + "questionId": itgResponseData?.survey?.questions![index].questionId, + "optionId": itgResponseData?.survey?.questions![index].type != "Stars" ? answeredQuestions[index] : null, + "starRating": itgResponseData?.survey?.questions![index].type == "Stars" ? answeredQuestions[index] : null + }); + index++; + }); + ItgMainRes? res = await DashboardApiClient() + .submitItgForm(comment: reviewText, masterId: itgResponseData!.notificationMasterId ?? "", itgList: itgAnswersList, serviceId: itgResponseData!.survey!.surveyId ?? 0); + Utils.hideLoading(context); - - if(res!.mohemmItgResponseItem!.statusCode==200){ + if (res!.mohemmItgResponseItem!.statusCode == 200) { Utils.showToast("Survey has been submitted successfully"); Navigator.pop(context); - }else{ + } else { Utils.showToast(res.mohemmItgResponseItem!.message.toString()); } - } catch (ex) { Utils.hideLoading(context); Utils.handleException(ex, context, (msg) { @@ -160,4 +225,41 @@ class _SurveyScreenState extends State { }); } } + + Widget radioOption(String title, String value, String groupValue, int answerIndex) { + return Row( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Container( + width: 24, + height: 24, + decoration: BoxDecoration( + color: Colors.transparent, + border: Border.all(color: MyColors.borderColor, width: 1), + borderRadius: const BorderRadius.all( + Radius.circular(100), + ), + ), + padding: const EdgeInsets.all(4), + child: Container( + width: double.infinity, + height: double.infinity, + decoration: BoxDecoration( + color: value == answeredQuestions[answerIndex] ? MyColors.greenColor : Colors.transparent, + borderRadius: const BorderRadius.all( + Radius.circular(100), + ), + ), + ), + ), + 6.width, + title.toText12(color: MyColors.grey57Color), + 12.width + ], + ).onPress(() { + answeredQuestions[answerIndex] = value; + setState(() {}); + }); + } } diff --git a/lib/ui/login/login_screen.dart b/lib/ui/login/login_screen.dart index d0dbb28..8d8e7c2 100644 --- a/lib/ui/login/login_screen.dart +++ b/lib/ui/login/login_screen.dart @@ -3,11 +3,13 @@ import 'dart:io'; import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/src/public_ext.dart'; import 'package:firebase_core/firebase_core.dart'; +import 'package:firebase_crashlytics/firebase_crashlytics.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; + +// import 'package:huawei_hmsavailability/huawei_hmsavailability.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'; @@ -19,7 +21,6 @@ import 'package:mohem_flutter_app/extensions/int_extensions.dart'; import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; -import 'package:mohem_flutter_app/main.dart'; import 'package:mohem_flutter_app/models/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'; @@ -28,8 +29,8 @@ 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/button/hmg_connectivity_button.dart'; import 'package:mohem_flutter_app/widgets/input_widget.dart'; -import 'package:permission_handler/permission_handler.dart'; -import 'package:safe_device/safe_device.dart'; + +// import 'package:safe_device/safe_device.dart'; import 'package:wifi_iot/wifi_iot.dart'; class LoginScreen extends StatefulWidget { @@ -59,30 +60,33 @@ class _LoginScreenState extends State { bool isOnExternalStorage = false; bool isDevelopmentModeEnable = false; + // late HmsApiAvailability hmsApiAvailability; + @override void initState() { super.initState(); + // hmsApiAvailability = HmsApiAvailability(); // checkFirebaseToken(); // if (kReleaseMode) { // checkDeviceSafety(); // } } - void checkDeviceSafety() async { - try { - isJailBroken = await SafeDevice.isJailBroken; - isRealDevice = await SafeDevice.isRealDevice; - if (Platform.isAndroid) { - isOnExternalStorage = await SafeDevice.isOnExternalStorage; - isDevelopmentModeEnable = await SafeDevice.isDevelopmentModeEnable; - } - if (isJailBroken || !isRealDevice || isOnExternalStorage || isDevelopmentModeEnable) { - Navigator.pushNamedAndRemoveUntil(context, AppRoutes.unsafeDeviceScreen, (_) => false); - } - } catch (error) { - print(error); - } - } + // void checkDeviceSafety() async { + // try { + // isJailBroken = await SafeDevice.isJailBroken; + // isRealDevice = await SafeDevice.isRealDevice; + // if (Platform.isAndroid) { + // isOnExternalStorage = await SafeDevice.isOnExternalStorage; + // isDevelopmentModeEnable = await SafeDevice.isDevelopmentModeEnable; + // } + // if (isJailBroken || !isRealDevice || isOnExternalStorage || isDevelopmentModeEnable) { + // Navigator.pushNamedAndRemoveUntil(context, AppRoutes.unsafeDeviceScreen, (_) => false); + // } + // } catch (error) { + // print(error); + // } + // } @override void dispose() { @@ -95,31 +99,50 @@ class _LoginScreenState extends State { Future checkFirebaseToken() async { try { Utils.showLoading(context); - await Firebase.initializeApp(); - // await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions( - // alert: true, - // badge: true, - // sound: true, - // ); - // await FirebaseMessaging.instance.requestPermission(); - _firebaseMessaging = FirebaseMessaging.instance; - firebaseToken = await _firebaseMessaging.getToken(); - AppNotifications().init(firebaseToken); - loginInfo = await LoginApiClient().getMobileLoginInfoNEW(firebaseToken ?? "", Platform.isAndroid ? "android" : "ios"); - if (loginInfo == null) { - await checkPrefs(); - _autoLogin = false; - Utils.hideLoading(context); - return; + if (Platform.isAndroid) { + try { + if (!(await Utils.isGoogleServicesAvailable())) { + print("HUAWEI APPPP GALLERYYYY!!!!"); + AppState().setIsHuawei = true; + AppNotifications().initHuaweiPush(checkLoginInfo); + } else { + print("GOOGLE PLAY STOREEEE!!!!"); + await Firebase.initializeApp(); + _firebaseMessaging = FirebaseMessaging.instance; + firebaseToken = await _firebaseMessaging.getToken(); + AppNotifications().init(firebaseToken); + checkLoginInfo(); + await FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(true); + } + // }); + } catch (ex) {} } else { - loginInfo!.deviceToken = firebaseToken; - await checkPrefs(); - Utils.hideLoading(context); - performLogin(); + await Firebase.initializeApp(); + _firebaseMessaging = FirebaseMessaging.instance; + firebaseToken = await _firebaseMessaging.getToken(); + AppNotifications().init(firebaseToken); + checkLoginInfo(); + await FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(true); } } catch (ex) { Utils.hideLoading(context); Utils.handleException(ex, context, null); + await FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(true); + } + } + + void checkLoginInfo() async { + loginInfo = await LoginApiClient().getMobileLoginInfoNEW(AppState().getIsHuawei ? AppState().getHuaweiPushToken : firebaseToken ?? "", Platform.isAndroid ? "android" : "ios"); + if (loginInfo == null) { + await checkPrefs(); + _autoLogin = false; + Utils.hideLoading(context); + return; + } else { + loginInfo!.deviceToken = firebaseToken; + await checkPrefs(); + Utils.hideLoading(context); + performLogin(); } } @@ -172,8 +195,8 @@ class _LoginScreenState extends State { isAppOpenBySystem = (ModalRoute.of(context)!.settings.arguments ?? true) as bool; if (!kReleaseMode) { // username.text = "15444"; // Maha User - username.text = "15153"; // Tamer User - password.text = "Abcd@1234"; + // username.text = "15153"; // Tamer User + // password.text = "Abcd@12345"; // username.text = "206535"; // Hashim User // password.text = "Namira786"; @@ -185,7 +208,8 @@ class _LoginScreenState extends State { } // username.text = "15444"; - return Scaffold( + + return Scaffold( body: Column( children: [ const SizedBox(height: 23), @@ -197,11 +221,9 @@ class _LoginScreenState extends State { children: [ Row( children: [ - const Expanded( - child: SizedBox( - child: HmgConnectivityButton(), - ), - ), + // Expanded( + // child:SizedBox(child: HmgConnectivityButton(),), + // ), Row( children: [ LocaleKeys.english.tr().toText14(color: AppState().isArabic(context) ? null : MyColors.textMixColor).onPress(() { @@ -262,4 +284,30 @@ class _LoginScreenState extends State { ), ); } + + void connectWithHmgNetwork() async { + try { + bool isConnected = await WiFiForIoTPlugin.connect("MOHEMM-CONNECT", password: "0987654321", joinOnce: Platform.isIOS ? false : true, security: NetworkSecurity.WPA, withInternet: false); + + if (isConnected) { + await WiFiForIoTPlugin.forceWifiUsage(true); + // if (Platform.isIOS) { + // await closeWifiRequest(); + // await Future.delayed(Duration(seconds: 6)); + // } else { + // await WiFiForIoTPlugin.forceWifiUsage(true); + // } + } + } catch (e) { + print("----------------o----"); + print(e); + } + } + + Future closeWifiRequest() async { + if (Platform.isAndroid) { + await WiFiForIoTPlugin.forceWifiUsage(false); + } + return await WiFiForIoTPlugin.disconnect(); + } } diff --git a/lib/ui/login/verify_last_login_screen.dart b/lib/ui/login/verify_last_login_screen.dart index 6892dd1..c48d1f3 100644 --- a/lib/ui/login/verify_last_login_screen.dart +++ b/lib/ui/login/verify_last_login_screen.dart @@ -372,7 +372,7 @@ class _VerifyLastLoginScreenState extends State { _flag, AppState().memberLoginList?.pMOBILENUMBER ?? "", AppState().getUserName!, - mobileLoginInfoListModel!.deviceToken!, + AppState().getIsHuawei ? AppState().getHuaweiPushToken : mobileLoginInfoListModel!.deviceToken!, Platform.isAndroid ? "android" : "ios"); AppState().setMemberInformationListModel = genericResponseModel!.memberInformationList?.first; AppState().setPrivilegeListModel = genericResponseModel!.privilegeList ?? []; diff --git a/lib/ui/login/verify_login_screen.dart b/lib/ui/login/verify_login_screen.dart index 0ba486b..0147472 100644 --- a/lib/ui/login/verify_login_screen.dart +++ b/lib/ui/login/verify_login_screen.dart @@ -628,7 +628,7 @@ class _VerifyLoginScreenState extends State { _flag, AppState().memberLoginList?.pMOBILENUMBER ?? "", AppState().getUserName!, - firebaseToken!, + AppState().getIsHuawei ? AppState().getHuaweiPushToken : firebaseToken!, Platform.isAndroid ? "android" : "ios"); if (genericResponseModel?.errorMessage != null) { Utils.showToast(genericResponseModel?.errorMessage ?? ""); diff --git a/lib/ui/marathon/marathon_intro_screen.dart b/lib/ui/marathon/marathon_intro_screen.dart index 9d4f81d..de1c356 100644 --- a/lib/ui/marathon/marathon_intro_screen.dart +++ b/lib/ui/marathon/marathon_intro_screen.dart @@ -17,7 +17,18 @@ class MarathonIntroScreen extends StatelessWidget { Widget build(BuildContext context) { MarathonProvider provider = context.watch(); return Scaffold( - appBar: AppBarWidget(context, title: LocaleKeys.brainMarathon.tr()), + appBar: AppBarWidget( + context, + title: LocaleKeys.brainMarathon.tr(), + onHomeTapped: () { + Navigator.pop(context); + context.setLocale(provider.savedLocale); + }, + onBackTapped: () { + Navigator.pop(context); + context.setLocale(provider.savedLocale); + }, + ), body: Column( children: [ ListView( diff --git a/lib/ui/marathon/marathon_provider.dart b/lib/ui/marathon/marathon_provider.dart index 34d8cc9..b88f54b 100644 --- a/lib/ui/marathon/marathon_provider.dart +++ b/lib/ui/marathon/marathon_provider.dart @@ -1,7 +1,7 @@ import 'dart:async'; -import 'dart:developer'; import 'package:appinio_swiper/appinio_swiper.dart'; +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:mohem_flutter_app/api/marathon/demo_marathon_repo.dart'; @@ -32,7 +32,7 @@ class MarathonProvider extends ChangeNotifier { int? selectedOptionIndex; String? selectedOptionId; int? totalQualifiers; - + Locale savedLocale = const Locale("en", "US"); String? gapTimeImage; String? gapTimeText; int? gapTimeType; @@ -135,7 +135,6 @@ class MarathonProvider extends ChangeNotifier { late VideoPlayerController videoController; Future initializeVideoPlayer() async { - log("VIDEO PLAYER INITIALIZED!!!"); videoController = VideoPlayerController.network(ApiConsts.marathonBaseUrlServices + marathonDetailModel.sponsors!.first.video!); await videoController.initialize(); await videoController.play(); @@ -220,7 +219,7 @@ class MarathonProvider extends ChangeNotifier { oneSec, (Timer timer) async { // This 1 is just to show the color of answer tile for 1 and then update card status - if (totalCurrentQuestionTime - currentGapTime == 1) { + if (totalCurrentQuestionTime - currentGapTime == 0) { if (callCountThreshold == 0) { getCorrectAnswerAndUpdateAnswerColor(); } @@ -280,8 +279,8 @@ class MarathonProvider extends ChangeNotifier { oneSec, (Timer timer) async { if (totalSecondsToWaitForWinner == 1) { - await callGetSelectedWinnersApi().whenComplete(() => updateQuestionCardStatus(QuestionCardStatus.winnerFound)); timer.cancel(); + await callGetSelectedWinnersApi().whenComplete(() => updateQuestionCardStatus(QuestionCardStatus.winnerFound)); return; } else if (totalSecondsToWaitForWinner == 15) { totalSecondsToWaitForWinner--; @@ -297,6 +296,18 @@ class MarathonProvider extends ChangeNotifier { //************************************************ FUNCTIONS ********************************************************** + void updateLanguageAsPerMarathon(BuildContext context, MarathonDetailModel detailModel) { + savedLocale = context.locale; + if (detailModel.selectedLanguage == 1) { + context.setLocale(const Locale("en", "US")); + } else if (detailModel.selectedLanguage == 2) { + context.setLocale(const Locale("ar", "SA")); + } else if (detailModel.selectedLanguage == 3) { + } else { + context.setLocale(const Locale("en", "US")); + } + } + Future callSubmitOptionApi() async { return await MarathonApiClient().submitSelectedOption(marathonId: marathonDetailModel.id!, questionId: currentQuestion.id, selectedAnswerId: selectedOptionId); } @@ -342,11 +353,15 @@ class MarathonProvider extends ChangeNotifier { gapTimeImage = currentQuestion.gapImage; gapTimeText = currentQuestion.gapText; gapTimeType = currentQuestion.gapType; + + startTimerForQuestion(); + updateCardData(); if (Utils.isLoading) { Utils.hideLoading(AppRoutes.navigatorKey.currentContext!); } - startTimerForQuestion(); - updateCardData(); + if (!AppState().getIsDemoMarathon) { + totalMarathoners = await MarathonApiClient().getMarathonersCount(marathonId: marathonDetailModel.id!); + } Navigator.pushReplacementNamed(AppRoutes.navigatorKey.currentContext!, AppRoutes.marathonScreen); } else { currentQuestion = AppState().getIsDemoMarathon @@ -512,6 +527,7 @@ class MarathonProvider extends ChangeNotifier { answerStatusesList[i] = QuestionCardStatus.question; } } + AppRoutes.navigatorKey.currentContext!.setLocale(savedLocale); notifyListeners(); } diff --git a/lib/ui/marathon/marathon_screen.dart b/lib/ui/marathon/marathon_screen.dart index e5da2c1..6dbbd18 100644 --- a/lib/ui/marathon/marathon_screen.dart +++ b/lib/ui/marathon/marathon_screen.dart @@ -78,7 +78,12 @@ class MarathonScreen extends StatelessWidget { 16.height, Column( children: [ - (AppState().isArabic(context) ? AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEAr : AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEEn)!.toText22( + displayLocalizedContent( + isPhoneLangArabic: AppState().isArabic(context), + selectedLanguage: provider.demoMarathonDetailModel.selectedLanguage!, + arabicContent: AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEAr!, + englishContent: AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEEn!, + ).toText22( color: MyColors.grey3AColor, isCentered: true, ), @@ -92,7 +97,12 @@ class MarathonScreen extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ "${LocaleKeys.sponsoredBy.tr()} ".toText14(color: MyColors.grey77Color), - (AppState().isArabic(context) ? provider.demoMarathonDetailModel.sponsors!.first.nameAr ?? "" : provider.demoMarathonDetailModel.sponsors!.first.nameEn ?? "").toText14( + displayLocalizedContent( + isPhoneLangArabic: AppState().isArabic(context), + selectedLanguage: provider.demoMarathonDetailModel.selectedLanguage!, + englishContent: provider.demoMarathonDetailModel.sponsors!.first.nameEn!, + arabicContent: provider.demoMarathonDetailModel.sponsors!.first.nameAr!, + ).toText14( color: MyColors.darkTextColor, isBold: true, ), @@ -160,7 +170,12 @@ class MarathonScreen extends StatelessWidget { provider.iAmWinner ? Column( children: [ - (AppState().isArabic(context) ? AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEAr : AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEEn)!.toText22( + displayLocalizedContent( + isPhoneLangArabic: AppState().isArabic(context), + selectedLanguage: provider.marathonDetailModel.selectedLanguage ?? 0, + arabicContent: AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEAr ?? "", + englishContent: AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEEn ?? "", + ).toText24( color: MyColors.grey3AColor, isCentered: true, ), @@ -169,12 +184,16 @@ class MarathonScreen extends StatelessWidget { ], ) : const SizedBox(), - 34.height, if (provider.selectedWinners != null) ...[ - provider.selectedWinners!.length == 1 + provider.selectedWinners!.length == 1 && !provider.iAmWinner ? Column( children: [ - (AppState().isArabic(context) ? provider.selectedWinners![0].nameEn : provider.selectedWinners![0].nameEn)!.toText24( + displayLocalizedContent( + isPhoneLangArabic: AppState().isArabic(context), + selectedLanguage: provider.marathonDetailModel.selectedLanguage ?? 0, + arabicContent: provider.selectedWinners![0].nameAr ?? "", + englishContent: provider.selectedWinners![0].nameEn ?? "", + ).toText24( color: MyColors.grey3AColor, isCentered: true, ), @@ -192,10 +211,15 @@ class MarathonScreen extends StatelessWidget { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - (AppState().isArabic(context) ? provider.selectedWinners![index].nameEn : provider.selectedWinners![index].nameEn)!.toText16( + displayLocalizedContent( + isPhoneLangArabic: AppState().isArabic(context), + selectedLanguage: provider.marathonDetailModel.selectedLanguage ?? 0, + arabicContent: provider.selectedWinners![index].nameAr ?? "", + englishContent: provider.selectedWinners![index].nameEn ?? "", + ).toText16( color: MyColors.grey3AColor, ), - provider.selectedWinners!.first.employeeId!.toText16(color: MyColors.grey57Color), + provider.selectedWinners![index].employeeId!.toText16(color: MyColors.grey57Color), ], ); }, @@ -207,7 +231,12 @@ class MarathonScreen extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ "${LocaleKeys.sponsoredBy.tr()} ".toText14(color: MyColors.grey77Color), - (AppState().isArabic(context) ? provider.marathonDetailModel.sponsors!.first.nameAr ?? "" : provider.marathonDetailModel.sponsors!.first.nameEn ?? "").toText14( + displayLocalizedContent( + isPhoneLangArabic: AppState().isArabic(context), + selectedLanguage: provider.marathonDetailModel.selectedLanguage!, + arabicContent: provider.marathonDetailModel.sponsors!.first.nameAr ?? "", + englishContent: provider.marathonDetailModel.sponsors!.first.nameEn ?? "", + ).toText14( color: MyColors.darkTextColor, isBold: true, ), @@ -232,7 +261,7 @@ class MarathonScreen extends StatelessWidget { ); } - Widget getNameContainer(BuildContext context) { + Widget getNameContainer(BuildContext context, MarathonProvider provider) { return Container( height: 50, padding: const EdgeInsets.symmetric(horizontal: 20), @@ -244,8 +273,12 @@ class MarathonScreen extends StatelessWidget { child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - (AppState().isArabic(context) ? AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEAr! : AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEEn!) - .toText17(isBold: true, color: MyColors.white), + displayLocalizedContent( + isPhoneLangArabic: AppState().isArabic(context), + selectedLanguage: (!AppState().getIsDemoMarathon ? provider.marathonDetailModel.selectedLanguage : provider.demoMarathonDetailModel.selectedLanguage) ?? 0, + arabicContent: AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEAr ?? "", + englishContent: AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEEn ?? "", + ).toText17(isBold: true, color: MyColors.white), AppState().memberInformationList!.eMPLOYEENUMBER!.toText17(isBold: true, color: MyColors.white), ], ), @@ -310,8 +343,8 @@ class MarathonScreen extends StatelessWidget { else ...[ MarathonProgressContainer(provider: provider).paddingOnly(left: 21, right: 21), ], - if (provider.questionCardStatus == QuestionCardStatus.findingWinner) ...[ - getNameContainer(context), + if (provider.questionCardStatus == QuestionCardStatus.findingWinner && !provider.isUserOutOfGame) ...[ + getNameContainer(context, provider), ], QuestionCardBuilder( onQuestion: (BuildContext context) => const QuestionCard(), @@ -337,7 +370,7 @@ class MarathonScreen extends StatelessWidget { subTitle: LocaleKeys.youMissedTheQuestion.tr().toText18(color: MyColors.darkTextColor, isCentered: true), ), onFindingWinner: (BuildContext context) => CustomStatusWidget( - asset: Lottie.asset(MyLottieConsts.winnerLottie, height: 168, reverse: false), + asset: Lottie.asset(MyLottieConsts.winnerLottie, height: 168, reverse: false, repeat: true), title: LocaleKeys.fingersCrossed.tr().toText22(color: MyColors.greenColor), subTitle: LocaleKeys.winnerSelectedRandomly.tr().toText18(color: MyColors.darkTextColor, isCentered: true), ), diff --git a/lib/ui/marathon/widgets/marathon_banner.dart b/lib/ui/marathon/widgets/marathon_banner.dart index ecce777..536af9b 100644 --- a/lib/ui/marathon/widgets/marathon_banner.dart +++ b/lib/ui/marathon/widgets/marathon_banner.dart @@ -434,7 +434,12 @@ class MarathonBanner extends StatelessWidget { ), Flexible( child: Text( - (AppState().isArabic(context) ? provider.marathonDetailModel.titleAr ?? "" : provider.marathonDetailModel.titleEn ?? "").trimString(isTablet ? 25 : 15), + displayLocalizedContent( + isPhoneLangArabic: AppState().isArabic(context), + selectedLanguage: provider.marathonDetailModel.selectedLanguage ?? 0, + englishContent: provider.marathonDetailModel.titleEn ?? "", + arabicContent: provider.marathonDetailModel.titleAr ?? "", + ), overflow: TextOverflow.ellipsis, style: TextStyle( fontStyle: FontStyle.italic, @@ -525,10 +530,7 @@ class MarathonBanner extends StatelessWidget { ], ).onPress(() async { int remainingTimeInMinutes = DateTime.parse(provider.marathonDetailModel.startTime!).difference(DateTime.now()).inMinutes; - if (remainingTimeInMinutes > 5 && provider.marathonDetailModel.sponsors != null && provider.marathonDetailModel.sponsors!.isNotEmpty) { - log("IF CALLED!!!"); - log("Remaining Time: $remainingTimeInMinutes"); Utils.showLoading(context); try { await provider.initializeVideoPlayer().then((_) { @@ -537,20 +539,16 @@ class MarathonBanner extends StatelessWidget { Navigator.pushNamed(context, AppRoutes.marathonSponsorVideoScreen); }); } catch (e) { - // if (kDebugMode) { + if (kDebugMode) { log("Error in VideoPlayer: ${e.toString()}"); - // } + } Utils.hideLoading(context); - Navigator.pushNamed(context, AppRoutes.marathonIntroScreen).then((value) { - print("Back to home!!!"); - }); + Navigator.pushNamed(context, AppRoutes.marathonIntroScreen); } } else { - log("ELSE CALLED!!!"); - Navigator.pushNamed(context, AppRoutes.marathonIntroScreen).then((value) { - print("Back to home!!!"); - }); + Navigator.pushNamed(context, AppRoutes.marathonIntroScreen); } + provider.updateLanguageAsPerMarathon(context, provider.isUpComingMarathon ? provider.marathonDetailModel : provider.demoMarathonDetailModel); }), ) : getNoUpcomingMarathonWidget(context); diff --git a/lib/ui/marathon/widgets/marathon_details_card.dart b/lib/ui/marathon/widgets/marathon_details_card.dart index 11a3d84..65d6716 100644 --- a/lib/ui/marathon/widgets/marathon_details_card.dart +++ b/lib/ui/marathon/widgets/marathon_details_card.dart @@ -39,11 +39,23 @@ class MarathonDetailsCard extends StatelessWidget { ), 7.height, LocaleKeys.contestTopicAbout.tr().toText16(color: MyColors.grey77Color), - "${AppState().isArabic(context) ? marathonDetailModel.titleAr : marathonDetailModel.titleEn}".toText20(color: MyColors.textMixColor, isBold: true), + displayLocalizedContent( + isPhoneLangArabic: AppState().isArabic(context), + selectedLanguage: marathonDetailModel.selectedLanguage ?? 0, + englishContent: marathonDetailModel.titleEn ?? "", + arabicContent: marathonDetailModel.titleAr ?? "", + ).toText20(color: MyColors.textMixColor, isBold: true), Row( children: [ Flexible( - child: "${AppState().isArabic(context) ? marathonDetailModel.descAr : marathonDetailModel.descEn}".toText14(color: MyColors.grey77Color), + child: displayLocalizedContent( + isPhoneLangArabic: AppState().isArabic(context), + selectedLanguage: marathonDetailModel.selectedLanguage ?? 0, + englishContent: marathonDetailModel.descEn ?? "", + arabicContent: marathonDetailModel.descAr ?? "", + ).toText14( + color: MyColors.grey77Color, + ), ) ], ), @@ -57,18 +69,22 @@ class MarathonDetailsCard extends StatelessWidget { child: SizedBox( height: 30, child: ListView.builder( - scrollDirection: Axis.horizontal, - shrinkWrap: true, - itemCount: marathonDetailModel.sponsors!.first.sponsorPrizes!.length, - itemBuilder: (BuildContext context, int index) { - SponsorPrizes prizes = marathonDetailModel.sponsors!.first.sponsorPrizes![index]; - return Container( - decoration: BoxDecoration(color: MyColors.backgroundColor, borderRadius: BorderRadius.circular(100), border: Border.all(color: MyColors.grey57Color.withOpacity(0.1))), - child: "${AppState().isArabic(context) ? prizes.marathonPrizeAr : prizes.marathonPrizeEn}" - .toText16(color: MyColors.greenColor, isBold: true) - .paddingOnly(left: 5, right: 5), - ).paddingOnly(left: 5); - }), + scrollDirection: Axis.horizontal, + shrinkWrap: true, + itemCount: marathonDetailModel.sponsors!.first.sponsorPrizes!.length, + itemBuilder: (BuildContext context, int index) { + SponsorPrizes prizes = marathonDetailModel.sponsors!.first.sponsorPrizes![index]; + return Container( + decoration: BoxDecoration(color: MyColors.backgroundColor, borderRadius: BorderRadius.circular(100), border: Border.all(color: MyColors.grey57Color.withOpacity(0.1))), + child: displayLocalizedContent( + isPhoneLangArabic: AppState().isArabic(context), + selectedLanguage: marathonDetailModel.selectedLanguage ?? 0, + englishContent: prizes.marathonPrizeEn ?? "", + arabicContent: prizes.marathonPrizeAr ?? "", + ).toText16(color: MyColors.greenColor, isBold: true).paddingOnly(left: 5, right: 5), + ).paddingOnly(left: 5); + }, + ), ), ) ], @@ -77,7 +93,12 @@ class MarathonDetailsCard extends StatelessWidget { Row( children: [ "${LocaleKeys.sponsoredBy.tr()} ".toText16(color: MyColors.grey77Color), - "${AppState().isArabic(context) ? marathonDetailModel.sponsors?.first.nameAr : marathonDetailModel.sponsors?.first.nameEn}".toText16(color: MyColors.darkTextColor, isBold: true), + displayLocalizedContent( + isPhoneLangArabic: AppState().isArabic(context), + selectedLanguage: marathonDetailModel.selectedLanguage ?? 0, + englishContent: marathonDetailModel.sponsors?.first.nameEn ?? "", + arabicContent: marathonDetailModel.sponsors?.first.nameAr ?? "", + ).toText16(color: MyColors.darkTextColor, isBold: true), ], ), 10.height, diff --git a/lib/ui/marathon/widgets/marathon_header.dart b/lib/ui/marathon/widgets/marathon_header.dart index fed6caa..58820c1 100644 --- a/lib/ui/marathon/widgets/marathon_header.dart +++ b/lib/ui/marathon/widgets/marathon_header.dart @@ -3,8 +3,6 @@ import 'package:flutter/material.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; -import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart'; -import 'package:provider/provider.dart'; class MarathonHeader extends StatelessWidget { const MarathonHeader({Key? key}) : super(key: key); diff --git a/lib/ui/marathon/widgets/question_card.dart b/lib/ui/marathon/widgets/question_card.dart index 5246426..8aa76bd 100644 --- a/lib/ui/marathon/widgets/question_card.dart +++ b/lib/ui/marathon/widgets/question_card.dart @@ -85,7 +85,12 @@ class CardContent extends StatelessWidget { child: Padding( padding: const EdgeInsets.symmetric(horizontal: 13, vertical: 15), child: Text( - AppState().isArabic(context) ? "${provider.currentQuestion.titleAr}" ?? "" : provider.currentQuestion.titleEn ?? "", + displayLocalizedContent( + isPhoneLangArabic: AppState().isArabic(context), + selectedLanguage: (AppState().getIsDemoMarathon ? provider.demoMarathonDetailModel.selectedLanguage : provider.marathonDetailModel.selectedLanguage) ?? 0, + englishContent: provider.currentQuestion.titleEn ?? "", + arabicContent: provider.currentQuestion.titleAr ?? "", + ), style: const TextStyle( color: MyColors.white, fontSize: 16, @@ -125,7 +130,7 @@ class AnswerContent extends StatelessWidget { return AnswerTileForText( index: index, onAnswerTapped: () { - if (provider.totalCurrentQuestionTime - provider.currentGapTime <= 1) { + if (provider.totalCurrentQuestionTime - provider.currentGapTime <= 0) { null; } else { provider.updateCurrentQuestionOptionStatus(QuestionsOptionStatus.selected, index); @@ -170,9 +175,12 @@ class AnswerTileForText extends StatelessWidget { alignment: Alignment.centerLeft, decoration: MyDecorations.getAnswersContainerColor(provider.currentQuestion.questionOptions![index].optionStatus!), child: Center( - child: (AppState().isArabic(context) ? provider.currentQuestion.questionOptions![index].titleAr! : provider.currentQuestion.questionOptions![index].titleEn!) - .toText16(color: provider.isUserOutOfGame ? MyColors.darkTextColor : getAnswerTextColor(provider.currentQuestion.questionOptions![index].optionStatus!)) - .paddingOnly(top: 13, bottom: 13), + child: displayLocalizedContent( + isPhoneLangArabic: AppState().isArabic(context), + selectedLanguage: (AppState().getIsDemoMarathon ? provider.demoMarathonDetailModel.selectedLanguage : provider.marathonDetailModel.selectedLanguage) ?? 0, + englishContent: provider.currentQuestion.questionOptions![index].titleEn ?? "", + arabicContent: provider.currentQuestion.questionOptions![index].titleAr ?? "", + ).toText16(color: provider.isUserOutOfGame ? MyColors.darkTextColor : getAnswerTextColor(provider.currentQuestion.questionOptions![index].optionStatus!)).paddingOnly(top: 13, bottom: 13), ), ), ); diff --git a/lib/ui/misc/request_submit_screen.dart b/lib/ui/misc/request_submit_screen.dart index d1264fd..3611241 100644 --- a/lib/ui/misc/request_submit_screen.dart +++ b/lib/ui/misc/request_submit_screen.dart @@ -1,3 +1,4 @@ +import 'dart:convert'; import 'dart:io'; import 'package:easy_localization/easy_localization.dart'; @@ -71,27 +72,31 @@ class _RequestSubmitScreenState extends State { } } + Future>> addAttachments() async { + List> list = []; + if (attachmentFiles.isNotEmpty) { + attachmentFiles.asMap().forEach((index, value) { + String type = attachmentFiles[index].path.split('.').last; + String name = attachmentFiles[index].path.split('/').last; + List fileContent = value.readAsBytesSync(); + String encodedFile = base64Encode(fileContent); + list.add(AttachmentModel( + attachmentID: index, + pFILECONTENTTYPE: type, + pFILENAME: name, + pFILEDATA: encodedFile, + pTRANSACTIONID: params!.transactionId, + ).toJson()); + }); + } + return list; + } + void submitRequest() async { try { Utils.showLoading(context); - List> list = []; - if (attachmentFiles.isNotEmpty) { - attachments.asMap().forEach((index, value) async { - String type = attachmentFiles[index].path.split('.').last; - String name = attachmentFiles[index].path.split('/').last; - // List fileContent = await value.readAsBytes(); - // String encodedFile = base64Encode(fileContent); - list.add(AttachmentModel( - attachmentID: index, - pFILECONTENTTYPE: type, - pFILENAME: name, - pFILEDATA: value, - pTRANSACTIONID: params!.transactionId, - ).toJson()); - }); - } + List> list = await addAttachments(); await MyAttendanceApiClient().addAttachment(list); - if (params!.approvalFlag == 'phone_numbers') { await ProfileApiClient().startPhoneApprovalProcess( "SUBMIT", diff --git a/lib/ui/my_attendance/services_menu_list_screen.dart b/lib/ui/my_attendance/services_menu_list_screen.dart index 8e44324..44aac6a 100644 --- a/lib/ui/my_attendance/services_menu_list_screen.dart +++ b/lib/ui/my_attendance/services_menu_list_screen.dart @@ -57,6 +57,9 @@ class ServicesMenuListScreen extends StatelessWidget { } else if (servicesMenuData.list[index].requestType == "ABSENCE") { Navigator.pushNamed(context, AppRoutes.leaveBalance, arguments: servicesMenuData.selectedEmp); return; + } else if (servicesMenuData.list[index].requestType == "RESET_ITG_AD_PASSWORD") { + Navigator.pushNamed(context, AppRoutes.changeItgAdPasswordScreen); + return; } if (servicesMenuData.list[index].requestType == "EIT") { Navigator.pushNamed(context, AppRoutes.dynamicScreen, diff --git a/lib/ui/screens/items_for_sale/fragments/add_details_fragment.dart b/lib/ui/screens/items_for_sale/fragments/add_details_fragment.dart index 5e3f749..75d1da2 100644 --- a/lib/ui/screens/items_for_sale/fragments/add_details_fragment.dart +++ b/lib/ui/screens/items_for_sale/fragments/add_details_fragment.dart @@ -18,7 +18,7 @@ import 'package:mohem_flutter_app/ui/screens/items_for_sale/fragments/select_cat import 'package:mohem_flutter_app/widgets/button/default_button.dart'; import 'package:mohem_flutter_app/widgets/button/simple_button.dart'; import 'package:mohem_flutter_app/widgets/dynamic_forms/dynamic_textfield_widget.dart'; -import 'package:mohem_flutter_app/widgets/image_picker.dart'; +import 'package:mohem_flutter_app/widgets/image_picker.dart' as imagePicker; import 'package:mohem_flutter_app/widgets/radio/show_radio.dart'; class AddItemDetailsFragment extends StatefulWidget { @@ -200,14 +200,22 @@ class _AddItemDetailsFragmentState extends State { children: [ title.toText16().expanded, 6.width, - SimpleButton(LocaleKeys.add.tr(), () { - ImageOptions.showImageOptionsNew(context, false, (String image, File file) { - setState(() { - images.add(image); - Navigator.of(context).pop(); - }); - }); - }, fontSize: 14), + SimpleButton( + LocaleKeys.add.tr(), + () { + if (images.length < 3) { + imagePicker.ImageOptions.showImageOptionsNew(context, false, (String image, File file) { + setState(() { + images.add(image); + Navigator.of(context).pop(); + }); + }); + } else { + Utils.showToast("The maximum no. of images allowed is 3."); + } + }, + fontSize: 14, + ), ], ), if (images.isNotEmpty) 12.height, diff --git a/lib/ui/screens/items_for_sale/fragments/items_for_sale.dart b/lib/ui/screens/items_for_sale/fragments/items_for_sale.dart index ae715fe..1ecd0c9 100644 --- a/lib/ui/screens/items_for_sale/fragments/items_for_sale.dart +++ b/lib/ui/screens/items_for_sale/fragments/items_for_sale.dart @@ -1,5 +1,3 @@ -import 'dart:convert'; - import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; @@ -98,9 +96,7 @@ class _ItemsForSaleFragmentState extends State { currentCategoryID == getSaleCategoriesList[index].categoryID ? const Icon(Icons.check_circle_rounded, color: MyColors.greenColor, size: 16.0) : Container(), ], ).expanded, - AppState().isArabic(context) - ?getSaleCategoriesList[index].titleAr!.toText10() - :getSaleCategoriesList[index].title!.toText10() + AppState().isArabic(context) ? getSaleCategoriesList[index].titleAr!.toText10() : getSaleCategoriesList[index].title!.toText10() ], ).paddingOnly(left: 10, right: 10, bottom: 10, top: 12).expanded.objectContainerView(disablePadding: true), ), @@ -163,8 +159,8 @@ class _ItemsForSaleFragmentState extends State { aspectRatio: 148 / 127, child: ClipRRect( borderRadius: BorderRadius.circular(6), - child: Image.memory( - base64Decode(getItemsForSaleList.itemAttachments![0].content!), + child: Image.network( + getItemsForSaleList.itemAttachments![0].filePath!, fit: BoxFit.cover, ), ), diff --git a/lib/ui/screens/items_for_sale/item_for_sale_detail.dart b/lib/ui/screens/items_for_sale/item_for_sale_detail.dart index ee76943..a853e1a 100644 --- a/lib/ui/screens/items_for_sale/item_for_sale_detail.dart +++ b/lib/ui/screens/items_for_sale/item_for_sale_detail.dart @@ -1,5 +1,4 @@ -import 'dart:convert'; - +import 'package:carousel_slider/carousel_slider.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; @@ -24,6 +23,7 @@ class ItemForSaleDetailPage extends StatefulWidget { class _ItemForSaleDetailPageState extends State { late GetItemsForSaleList getItemsForSaleList; + int _current = 0; @override Widget build(BuildContext context) { @@ -46,15 +46,32 @@ class _ItemForSaleDetailPageState extends State { transitionOnUserGestures: true, child: AspectRatio( aspectRatio: 322 / 261, - child: ClipRRect( - borderRadius: BorderRadius.circular(6), - child: Image.memory( - base64Decode(getItemsForSaleList.itemAttachments![0].content!), - fit: BoxFit.cover, - ), + child: CarouselSlider( + items: getItemImages(), + options: CarouselOptions( + enableInfiniteScroll: false, + onPageChanged: (index, reason) { + setState(() { + _current = index; + }); + }), ), ), ).paddingAll(8), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: getItemImages().asMap().entries.map((entry) { + return Container( + width: 8.0, + height: 8.0, + margin: const EdgeInsets.symmetric(horizontal: 4.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + color: (Theme.of(context).brightness == Brightness.dark ? Colors.white : Colors.black).withOpacity(_current == entry.key ? 0.9 : 0.4), + ), + ); + }).toList(), + ), Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, @@ -88,22 +105,34 @@ class _ItemForSaleDetailPageState extends State { ).expanded, Row( children: [ - DefaultButton("Email", () async { - Uri emailLaunchUri = Uri( - scheme: 'mailto', - path: getItemsForSaleList.emailAddress, - ); - launchUrl(emailLaunchUri); - }, iconData: Icons.email_sharp, isTextExpanded: false) + DefaultButton( + "Email", + getItemsForSaleList.status == 'Approved' + ? () async { + Uri emailLaunchUri = Uri( + scheme: 'mailto', + path: getItemsForSaleList.emailAddress, + ); + launchUrl(emailLaunchUri); + } + : null, + iconData: Icons.email_sharp, + isTextExpanded: false) .expanded, 8.width, - DefaultButton("Call", () async { - Uri callLaunchUri = Uri( - scheme: 'tel', - path: getItemsForSaleList.mobileNumber, - ); - launchUrl(callLaunchUri); - }, iconData: Icons.call_sharp, isTextExpanded: false) + DefaultButton( + "Call", + getItemsForSaleList.status == 'Approved' + ? () async { + Uri callLaunchUri = Uri( + scheme: 'tel', + path: getItemsForSaleList.mobileNumber, + ); + launchUrl(callLaunchUri); + } + : null, + iconData: Icons.call_sharp, + isTextExpanded: false) .expanded, ], ).insideContainer, @@ -111,4 +140,25 @@ class _ItemForSaleDetailPageState extends State { ), ); } + + List getItemImages() { + int index = 0; + List itemImages = []; + getItemsForSaleList.itemAttachments!.forEach((element) { + itemImages.add( + Padding( + padding: const EdgeInsets.only(left: 8.0, right: 8.0), + child: ClipRRect( + borderRadius: BorderRadius.circular(6), + child: Image.network( + getItemsForSaleList.itemAttachments![index].filePath!, + fit: BoxFit.cover, + ), + ), + ), + ); + index++; + }); + return itemImages; + } } diff --git a/lib/ui/work_list/item_history_screen.dart b/lib/ui/work_list/item_history_screen.dart index a3c34a9..88abf06 100644 --- a/lib/ui/work_list/item_history_screen.dart +++ b/lib/ui/work_list/item_history_screen.dart @@ -1,15 +1,29 @@ +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; + import 'package:easy_localization/src/public_ext.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_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/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/get_attachement_list_model.dart'; import 'package:mohem_flutter_app/models/get_mo_Item_history_list_model.dart'; import 'package:mohem_flutter_app/models/get_po_Item_history_list_model.dart'; +import 'package:mohem_flutter_app/models/get_pr_action_history_list_model.dart'; +import 'package:mohem_flutter_app/models/get_pr_information_list.dart'; import 'package:mohem_flutter_app/models/get_quotation_analysis_list_model.dart'; import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; +import 'package:mohem_flutter_app/widgets/circular_avatar.dart'; import 'package:mohem_flutter_app/widgets/item_detail_view_widget.dart'; +import 'package:open_file/open_file.dart'; +import 'package:path_provider/path_provider.dart'; class ItemHistoryScreenParams { String? title; @@ -18,8 +32,12 @@ class ItemHistoryScreenParams { int? pItemId; int? pPoHeaderId; int? pOrgId; + bool isPRInfo; + GetPRInformationList? getPRInformationList; + String pOLineID; - ItemHistoryScreenParams({@required this.title, this.isItemHistory = true, this.isMO = true, this.pItemId, this.pPoHeaderId, this.pOrgId}); + ItemHistoryScreenParams( + {@required this.title, this.isItemHistory = true, this.isMO = true, this.isPRInfo = false, this.getPRInformationList, this.pItemId, this.pPoHeaderId, this.pOrgId, this.pOLineID = ""}); } class ItemHistoryScreen extends StatefulWidget { @@ -37,6 +55,9 @@ class _ItemHistoryScreenState extends State { List moItemHistoryList = []; List poItemHistoryList = []; List quotationAnalysisList = []; + List actionHistoryList = []; + List getAttachmentList = []; + int tabIndex = 0; @override void initState() { @@ -46,12 +67,43 @@ class _ItemHistoryScreenState extends State { @override void dispose() { super.dispose(); + actionHistoryList.clear(); } void loadData() { if (_screenParams == null) { _screenParams = ModalRoute.of(context)!.settings.arguments as ItemHistoryScreenParams; - getDataFromApi(); + if (!_screenParams!.isPRInfo) { + getDataFromApi(); + } + } + } + + void getActionsDataFromApi() async { + if (actionHistoryList.isEmpty) { + try { + Utils.showLoading(context); + actionHistoryList = await WorkListApiClient().getActionHistoryForPR(_screenParams!.pOLineID); + Utils.hideLoading(context); + setState(() {}); + } catch (ex) { + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + } + } + } + + void getAttachmentsDataFromApi() async { + if (getAttachmentList.isEmpty) { + try { + Utils.showLoading(context); + getAttachmentList = await WorkListApiClient().getPRAttachments(_screenParams!.pOLineID!); + Utils.hideLoading(context); + setState(() {}); + } catch (ex) { + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + } } } @@ -83,18 +135,259 @@ class _ItemHistoryScreenState extends State { appBar: AppBarWidget(context, title: _screenParams?.title ?? ""), backgroundColor: Colors.white, body: ListView( - padding: const EdgeInsets.all(21), + padding: _screenParams!.isPRInfo ? const EdgeInsets.all(0) : const EdgeInsets.all(21), physics: const BouncingScrollPhysics(), children: [ + if (_screenParams!.isPRInfo) prLinesDataView(), if (moItemHistoryList.isNotEmpty) loadMoItemHistoryData(), if (poItemHistoryList.isNotEmpty) loadPoItemHistoryData(), if (quotationAnalysisList.isNotEmpty) loadQuotationAnalysisData(), - if (moItemHistoryList.isEmpty && poItemHistoryList.isEmpty && quotationAnalysisList.isEmpty) Utils.getNoDataWidget(context), + if (moItemHistoryList.isEmpty && poItemHistoryList.isEmpty && quotationAnalysisList.isEmpty && !_screenParams!.isPRInfo) Utils.getNoDataWidget(context), + ], + ), + ); + } + + Widget prLinesDataView() { + return Column( + children: [ + Container( + 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, + ], + ), + ), + child: Row( + children: [ + myTab(LocaleKeys.info.tr(), 0), + myTab(LocaleKeys.actions.tr(), 1), + myTab(LocaleKeys.attachments.tr(), 2), + ], + ), + ), + if (tabIndex == 0) _screenParams!.getPRInformationList!.pRHeader![0].dESCRIPTION!.toText14().paddingOnly(top: 20, right: 21, left: 21), + if (tabIndex == 0) + ListView.separated( + padding: const EdgeInsets.all(21), + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (cxt, index) => Column( + children: [ + ItemDetailGrid( + ItemDetailViewCol("Cost Center", _screenParams!.getPRInformationList!.pRLines![index].cOSTCENTER ?? ""), + ItemDetailViewCol("Code", _screenParams!.getPRInformationList!.pRLines![index].iTEMCODE ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol("Unit", _screenParams!.getPRInformationList!.pRLines![index].uOM ?? ""), + ItemDetailViewCol("Price (SAR)", _screenParams!.getPRInformationList!.pRLines![index].uNITPRICE.toString() ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol("Amount (SAR)", _screenParams!.getPRInformationList!.pRLines![index].lINEAMOUNT.toString() ?? ""), + ItemDetailViewCol("Quantity", _screenParams!.getPRInformationList!.pRLines![index].qUANTITY.toString() ?? ""), + ), + ItemDetailGrid( + ItemDetailViewCol("AMU (Last 3 months)", _screenParams!.getPRInformationList!.pRLines![index].iTEMAMU.toString() ?? ""), + ItemDetailViewCol("PR Number", _screenParams!.getPRInformationList!.pRHeader![0].pRNUMBER!.toString() ?? ""), + isItLast: true, + ), + ], + ).objectContainerView(), + separatorBuilder: (cxt, index) => 12.height, + itemCount: _screenParams!.getPRInformationList!.pRLines!.length), + if (tabIndex == 1) getPRActionsHistory(), //"ACTIONS".toText14().paddingOnly(top: 20, right: 21, left: 21), + if (tabIndex == 2) getPRAttachments(), + ], + ); + } + + String determineFileIcon(String fileContentType) { + String icon = ""; + switch (fileContentType) { + case "pdf": + icon = "assets/images/pdf.svg"; + break; + case "xls": + icon = "assets/images/xls.svg"; + break; + case "xlsx": + icon = "assets/images/xls.svg"; + break; + case "png": + icon = "assets/images/png.svg"; + break; + case "jpg": + icon = "assets/images/jpg.svg"; + break; + case "jpeg": + icon = "assets/images/jpg.svg"; + break; + } + return icon; + } + + Future _createFileFromString(String encodedStr, String ext) async { + Uint8List bytes = base64.decode(encodedStr); + String dir = (await getApplicationDocumentsDirectory()).path; + File file = File("$dir/" + DateTime.now().millisecondsSinceEpoch.toString() + "." + ext); + await file.writeAsBytes(bytes); + return file.path; + } + + Widget getPRAttachments() { + return ListView.separated( + itemCount: getAttachmentList.length, + shrinkWrap: true, + itemBuilder: (context, index) { + return Row( + children: [ + SvgPicture.asset(determineFileIcon(getAttachmentList[index].fILECONTENTTYPE ?? "")), + 12.width, + (getAttachmentList[index].fILENAME ?? "").toText16().expanded, + ], + ).objectContainerView().onPress(() async { + try { + String path = await _createFileFromString(getAttachmentList[index].fILEDATA ?? "", getAttachmentList[index].fILECONTENTTYPE ?? ""); + OpenFile.open(path); + } catch (ex) { + Utils.showToast("Cannot open file."); + } + }); + }, + separatorBuilder: (BuildContext context, int index) => 12.height, + ).paddingAll(21); + } + + Widget getPRActionsHistory() { + return SingleChildScrollView( + child: ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: actionHistoryList.length, + padding: EdgeInsets.all(21), + itemBuilder: (context, index) { + return showItem(context, actionHistoryList[index], index); + }, + separatorBuilder: (BuildContext context, int index) { + return 12.height; + }, + ), + ); + } + + Widget showItem(BuildContext context, GetPRActionHistoryList actionHistory, int index) { + return Container( + width: double.infinity, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: const Color(0xff000000).withOpacity(.05), + blurRadius: 26, + offset: const Offset(0, -3), + ), + ], + ), + clipBehavior: Clip.antiAlias, + child: Stack( + clipBehavior: Clip.antiAlias, + children: [ + Positioned( + left: -20, + top: -10, + child: Transform.rotate( + angle: 15, + child: Container( + width: 50, + height: 30, + color: getStatusColor(actionHistory.aCTIONCODE!), + ), + ), + ), + Column( + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + actionHistory.eMPLOYEEIMAGE != null + ? CircularAvatar(url: actionHistory.eMPLOYEEIMAGE ?? "", isImageBase64: true, height: 34, width: 34) + : CircularAvatar(url: "https://cdn4.iconfinder.com/data/icons/professions-2-2/151/89-512.png", isImageBase64: false, height: 34, width: 34), + 9.width, + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + actionHistory.nAME!.toText16(), + if ((actionHistory.nOTE ?? "").isNotEmpty) + SelectableText( + actionHistory.nOTE!, + style: const TextStyle( + fontSize: 12, + fontWeight: FontWeight.w600, + color: MyColors.grey57Color, + letterSpacing: -0.72, + ), + ), + + // "Note: ${actionHistory.nOTE!}".toText12(color: MyColors.grey57Color), + 4.height, + Row( + children: [ + actionHistory.aCTION!.toText10(color: getStatusColor(actionHistory.aCTIONCODE!)), + 8.width, + if (actionHistory.aPPROVALDATE!.isNotEmpty) + DateUtil.formatDateToDate(DateUtil.convertSimpleStringDateToDateddMMyyyy(actionHistory.aPPROVALDATE!), false).toText12(color: MyColors.lightTextColor), + ], + ), + 10.height, + // getActionDuration(index).toText11(maxLine: 1, color: const Color(0xff1FA269)) + ], + ), + ) + ], + ).paddingOnly(top: 19, left: 16, right: 16, bottom: 12), + ], + ), ], ), ); } + Color getStatusColor(String code) { + if (code == "SUBMIT") { + return const Color(0xff2E303A); + } else if (code == "REJECTED") { + return MyColors.redColor; + } else if (code == "REJECT") { + return MyColors.redColor; + } else if (code == "PENDING") { + return MyColors.orange; + } else if (code == "APPROVED" || code == "APPROVE" || code == "ANSWER_INFO") { + return const Color(0xff1FA269); + } else if (code == "REQUEST_INFO" || code == "FORWARD") { + return const Color(0xff2E303A); + } else if (code != "SUBMIT" && code != "REJECT" && code != "PENDING") { + return MyColors.orange; + } else { + return const Color(0xff2E303A); + } + } + + Widget getActionHistory() { + return Container(); + } + Widget loadMoItemHistoryData() { return ListView.separated( shrinkWrap: true, @@ -231,4 +524,34 @@ class _ItemHistoryScreenState extends State { separatorBuilder: (cxt, index) => 12.height, itemCount: quotationAnalysisList.length); } + + 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(() { + if (index == 1) { + getActionsDataFromApi(); + } + if (index == 2) { + getAttachmentsDataFromApi(); + } + tabIndex = index; + }); + }).expanded; + } } diff --git a/lib/ui/work_list/sheets/delegate_sheet.dart b/lib/ui/work_list/sheets/delegate_sheet.dart index 2a5f453..d505099 100644 --- a/lib/ui/work_list/sheets/delegate_sheet.dart +++ b/lib/ui/work_list/sheets/delegate_sheet.dart @@ -13,6 +13,7 @@ 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/models/get_action_history_list_model.dart'; import 'package:mohem_flutter_app/models/itg_forms_models/wf_history_model.dart'; +import 'package:mohem_flutter_app/models/notification_get_respond_attributes_list_model.dart'; import 'package:mohem_flutter_app/models/worklist/get_favorite_replacements_model.dart'; import 'package:mohem_flutter_app/models/worklist/replacement_list_model.dart'; import 'package:mohem_flutter_app/ui/work_list/sheets/search_options_sheet.dart'; @@ -29,8 +30,10 @@ class DelegateSheet extends StatefulWidget { List? actionHistoryList; List? wFHistory; VoidCallback callBackFunc; + List getNotificationRespondAttributes; - DelegateSheet({required this.title, required this.apiMode, this.notificationID, this.actionHistoryList, this.wFHistory, required this.callBackFunc}); + DelegateSheet( + {required this.title, required this.apiMode, this.notificationID, this.actionHistoryList, this.wFHistory, required this.callBackFunc, this.getNotificationRespondAttributes = const []}); @override State createState() => _DelegateSheetState(); @@ -415,6 +418,7 @@ class _DelegateSheetState extends State { actionHistoryList: actionHistory, notificationID: widget.notificationID, isITGRequest: widget.wFHistory != null, + getNotificationRespondAttributes: widget.getNotificationRespondAttributes, )); }, child: Row( @@ -489,6 +493,7 @@ class _DelegateSheetState extends State { favoriteReplacements: actionHistory, notificationID: widget.notificationID, isITGRequest: widget.wFHistory != null, + getNotificationRespondAttributes: widget.getNotificationRespondAttributes, )); }, child: Row( @@ -555,6 +560,7 @@ class _DelegateSheetState extends State { replacementList: actionHistory, notificationID: widget.notificationID, isITGRequest: widget.wFHistory != null, + getNotificationRespondAttributes: widget.getNotificationRespondAttributes, )); }, child: Row( diff --git a/lib/ui/work_list/sheets/selected_item_sheet.dart b/lib/ui/work_list/sheets/selected_item_sheet.dart index 54f87d0..85395a6 100644 --- a/lib/ui/work_list/sheets/selected_item_sheet.dart +++ b/lib/ui/work_list/sheets/selected_item_sheet.dart @@ -6,14 +6,15 @@ import 'package:mohem_flutter_app/classes/colors.dart'; import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/extensions/int_extensions.dart'; 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/get_action_history_list_model.dart'; import 'package:mohem_flutter_app/models/member_information_list_model.dart'; +import 'package:mohem_flutter_app/models/notification_get_respond_attributes_list_model.dart'; import 'package:mohem_flutter_app/models/worklist/get_favorite_replacements_model.dart'; import 'package:mohem_flutter_app/models/worklist/replacement_list_model.dart'; import 'package:mohem_flutter_app/widgets/button/default_button.dart'; import 'package:mohem_flutter_app/widgets/circular_avatar.dart'; +import 'package:mohem_flutter_app/widgets/dialogs/accept_reject_input_dialog.dart'; import 'package:mohem_flutter_app/widgets/input_widget.dart'; class SelectedItemSheet extends StatelessWidget { @@ -23,10 +24,18 @@ class SelectedItemSheet extends StatelessWidget { GetFavoriteReplacements? favoriteReplacements; ReplacementList? replacementList; MemberInformationListModel? memberInformationListModel; + List getNotificationRespondAttributes; bool isITGRequest; - SelectedItemSheet(this.title, {required this.apiMode, this.notificationID, this.actionHistoryList, this.favoriteReplacements, this.replacementList, this.isITGRequest = false}); + SelectedItemSheet(this.title, + {required this.apiMode, + this.notificationID, + this.actionHistoryList, + this.favoriteReplacements, + this.replacementList, + this.isITGRequest = false, + this.getNotificationRespondAttributes = const []}); TextEditingController username = TextEditingController(); String comment = ""; @@ -103,7 +112,7 @@ class SelectedItemSheet extends StatelessWidget { email = replacementList!.emailAddress; userId = replacementList!.userName; } - isITGRequest ? performITGNetworkCall(context, email: email ?? "", userId: userId ?? "") : performNetworkCall(context, email: email ?? "", userId: userId ?? ""); + isITGRequest ? performITGNetworkCall(context, email: email ?? "", userId: userId ?? "") : askForConfirmation(context, email: email ?? "", userId: userId ?? ""); } else { Utils.showToast("Please enter comments"); } @@ -121,6 +130,45 @@ class SelectedItemSheet extends StatelessWidget { ); } + void askForConfirmation(BuildContext context, {String? email, String? userId}) { + NotificationGetRespondAttributesList? notificationNoteInput; + NotificationGetRespondAttributesList? forwardToUser; + List filtered = getNotificationRespondAttributes.where((element) => element.attributeName == "NOTE" || element.attributeName == "WF_NOTE").toList(); + if (filtered.isNotEmpty) { + notificationNoteInput = filtered.first; + } + + filtered = getNotificationRespondAttributes.where((element) => element.attributeName == "FORWARD_TO_USERNAME_RESPONSE").toList(); + if (filtered.isNotEmpty) { + forwardToUser = filtered.first; + } + + if (notificationNoteInput == null) { + performNetworkCall(context, email: email ?? "", userId: userId ?? "", attributeData: []); + } else { + showDialog( + context: context, + builder: (cxt) => AcceptRejectInputDialog( + message: title != null ? null : LocaleKeys.requestedItems.tr(), + // title: title, + notificationGetRespond: notificationNoteInput, + actionMode: apiMode, + onTap: (note) { + performNetworkCall(context, email: email ?? "", userId: userId ?? "", attributeData: [ + if ((apiMode == "FORWARD" || apiMode == "APPROVE_AND_FORWARD") && forwardToUser != null) + {"ATTRIBUTE_NAME": "FORWARD_TO_USERNAME_RESPONSE", "ATTRIBUTE_TEXT_VALUE": actionHistoryList?.uSERNAME}, + if (notificationNoteInput != null) + { + "ATTRIBUTE_NAME": notificationNoteInput.attributeName, + if (notificationNoteInput.attributeType == "number") "ATTRIBUTE_NUMBER_VALUE": note else if (notificationNoteInput.attributeType == "VARCHAR2") "ATTRIBUTE_TEXT_VALUE": note + } + ]); + }, + ), + ); + } + } + void getUserInformation(BuildContext context) async { String? empID = ""; if (actionHistoryList != null) empID = actionHistoryList!.uSERNAME; @@ -137,10 +185,17 @@ class SelectedItemSheet extends StatelessWidget { } } - Future performNetworkCall(BuildContext context, {String? email, String? userId}) async { + Future performNetworkCall(BuildContext context, {String? email, String? userId, List>? attributeData = const []}) async { Utils.showLoading(context); try { - await WorkListApiClient().submitComment(comment: comment, email: email, userId: userId, notificationId: notificationID, apiMode: apiMode, approverIndex: actionHistoryList != null ? actionHistoryList!.sEQUENCE : null); + await WorkListApiClient().submitComment( + comment: comment, + email: email, + userId: userId, + notificationId: notificationID, + apiMode: apiMode, + approverIndex: actionHistoryList != null ? actionHistoryList!.sEQUENCE : null, + attributeData: attributeData); Utils.hideLoading(context); // Navigator.pop(context); // Navigator.pop(context); diff --git a/lib/ui/work_list/work_list_screen.dart b/lib/ui/work_list/work_list_screen.dart index 485921d..9dea0a1 100644 --- a/lib/ui/work_list/work_list_screen.dart +++ b/lib/ui/work_list/work_list_screen.dart @@ -93,10 +93,12 @@ class _WorkListScreenState extends State { final ScrollController _controller = ScrollController(); int pNotificationType = 1; + ScrollController? _scrollController; @override void initState() { super.initState(); + _scrollController = ScrollController()..addListener(_scrollListener); providerData = Provider.of(context, listen: false); calculateCounter(); if (workListItemIndex != null) getWorkList(); @@ -154,7 +156,7 @@ class _WorkListScreenState extends State { ItgFormsModel? itgFormsModel; int? itgRequestTypeIndex; - Future getWorkList({bool showLoading = true}) async { + Future getWorkList({bool showLoading = true, bool isCallingFromRefresh = false}) async { try { if (showLoading) Utils.showLoading(context); if (workListItemTypes[workListItemIndex!].key == "ITG") { @@ -173,7 +175,12 @@ class _WorkListScreenState extends State { } } else { itgRequestTypeIndex = null; - workList = await WorkListApiClient().getWorkList(pageNumber, workListItemTypes[workListItemIndex!].key, pNotificationType.toString()); + List? _list = await WorkListApiClient().getWorkList(pageNumber, workListItemTypes[workListItemIndex!].key, pNotificationType.toString()); + if (workList != null && _list != null && !isCallingFromRefresh) { + workList!.addAll(_list); + } else { + workList = _list; + } AppState().setWorkList = workList; } if (showLoading) Utils.hideLoading(context); @@ -188,9 +195,10 @@ class _WorkListScreenState extends State { try { _refreshController.refreshCompleted(); Utils.showLoading(context); + pageNumber = 1; List dataOnRefresh = await Future.wait([ providerData.fetchWorkListCounter(context, showLoading: false), - getWorkList(showLoading: false), + getWorkList(showLoading: false, isCallingFromRefresh: true), ]); calculateCounter(); Utils.hideLoading(context); @@ -203,9 +211,19 @@ class _WorkListScreenState extends State { @override void dispose() { + _scrollController?.dispose(); super.dispose(); } + void _scrollListener() { + if (_scrollController!.position.pixels == _scrollController!.position.maxScrollExtent) { + pageNumber = pageNumber + 1; + if (itgRequestTypeIndex == null && workListItemTypes[workListItemIndex!].value != workList!.length) { + getWorkList(); + } + } + } + @override Widget build(BuildContext context) { return Scaffold( @@ -236,6 +254,7 @@ class _WorkListScreenState extends State { } if (workListItemIndex != index && !workListItemTypes[index].disable) { workListItemIndex = index; + pageNumber = 1; if (workListItemTypes[index].value == 0) { workList = []; itgRequestTypeIndex = null; @@ -273,6 +292,7 @@ class _WorkListScreenState extends State { ), controller: _refreshController, onRefresh: _onRefresh, + scrollController: _scrollController, child: SingleChildScrollView( physics: const BouncingScrollPhysics(), child: itgRequestTypeIndex != null @@ -354,7 +374,6 @@ class _WorkListScreenState extends State { setState(() {}); } } - } else { verifyWorkListCounter(); if (mounted) setState(() {}); diff --git a/lib/ui/work_list/worklist_detail_screen.dart b/lib/ui/work_list/worklist_detail_screen.dart index 9bc0222..0a4f8cc 100644 --- a/lib/ui/work_list/worklist_detail_screen.dart +++ b/lib/ui/work_list/worklist_detail_screen.dart @@ -148,9 +148,6 @@ class _WorkListDetailScreenState extends State { } else if (workListData!.rEQUESTTYPE == "ADDRESS") { getAddressNotificationBody(); } - // getBasicNTFBody = await WorkListApiClient().getBasicDetNTFBody(workListData!.nOTIFICATIONID!, -999); - // getAbsenceCollectionNotifications = await WorkListApiClient().getAbsenceNotificationBody(workListData!.nOTIFICATIONID!, -999); - // subordinatesLeavesModel = await WorkListApiClient().getSubordinatesLeaves("", ""); } if (workListData!.iTEMTYPE == "STAMP") { getStampNotificationBody(); @@ -449,7 +446,6 @@ class _WorkListDetailScreenState extends State { } void handleFabAction(GetNotificationButtonsList notificationButton) { - print("notificationButton:${notificationButton.bUTTONACTION}"); switch (notificationButton.bUTTONACTION) { case "DELEGATE": showMyBottomSheet(context, @@ -526,6 +522,7 @@ class _WorkListDetailScreenState extends State { notificationID: workListData!.nOTIFICATIONID, actionHistoryList: actionHistoryList, callBackFunc: reloadWorkList, + getNotificationRespondAttributes: getNotificationRespondAttributes, )); break; case "FORWARD": @@ -537,8 +534,12 @@ class _WorkListDetailScreenState extends State { notificationID: workListData!.nOTIFICATIONID, actionHistoryList: actionHistoryList, callBackFunc: reloadWorkList, + getNotificationRespondAttributes: getNotificationRespondAttributes, )); break; + case "DEL": + performAction(notificationButton.bUTTONACTION!); + break; case "REJECT": performAction(notificationButton.bUTTONACTION!); break; @@ -565,6 +566,7 @@ class _WorkListDetailScreenState extends State { actionHistoryList: actionHistoryList.last, notificationID: workListData!.nOTIFICATIONID, isITGRequest: false, + getNotificationRespondAttributes: getNotificationRespondAttributes, )); setState(() {}); } catch (ex) { @@ -656,7 +658,6 @@ class _WorkListDetailScreenState extends State { } void performAction(String actionMode, {String? title}) { - print(actionMode); showDialog( context: context, builder: (cxt) => AcceptRejectInputDialog( @@ -1003,19 +1004,11 @@ class _WorkListDetailScreenState extends State { try { isActionHistoryLoaded = false; actionHistoryList.clear(); - // if (apiCallCount == 0) Utils.showLoading(context); - // apiCallCount++; actionHistoryList = await WorkListApiClient().getActionHistory(workListData!.nOTIFICATIONID!); - // apiCallCount--; - // if (apiCallCount == 0) { - // Utils.hideLoading(context); setState(() { isActionHistoryLoaded = true; }); - // } } catch (ex) { - // apiCallCount--; - // Utils.hideLoading(context); Utils.handleException(ex, context, null); } } @@ -1024,88 +1017,15 @@ class _WorkListDetailScreenState extends State { try { isAttachmentLoaded = false; getAttachmentList.clear(); - // if (apiCallCount == 0) Utils.showLoading(context); - // apiCallCount++; getAttachmentList = await WorkListApiClient().getAttachments(workListData!.nOTIFICATIONID!); - // apiCallCount--; - // if (apiCallCount == 0) { - // Utils.hideLoading(context); setState(() { isAttachmentLoaded = true; }); - // } } catch (ex) { - // apiCallCount--; - // Utils.hideLoading(context); Utils.handleException(ex, context, null); } } - // Widget showUpdateContinueSheet(List list) { - // double itemHeight = 0; - // double itemWidth = 0; - // var size = MediaQuery.of(context).size; - // itemHeight = (size.height - kToolbarHeight - 24) / 9; - // itemWidth = size.width / 2; - // return Column( - // children: [ - // if ((workListData?.sUBJECT ?? "").isNotEmpty) workListData!.sUBJECT!.toText14().paddingOnly(top: 10, right: 21, left: 21, bottom: 21), - // ListView.separated( - // shrinkWrap: true, - // physics: const NeverScrollableScrollPhysics(), - // itemBuilder: (cxt, index) { - // List dataList = list.isEmpty ? [] : (list[index].collectionNotification ?? []); - // dataList = dataList.where((o) => o.displayFlag == "Y").toList(); - // bool isOdd = false; - // if (dataList.length % 2 != 0) { - // isOdd = true; - // dataList.add(new CollectionNotificationEit()); - // } - // return GridView.builder( - // itemCount: dataList.length, - // shrinkWrap: true, - // physics: const NeverScrollableScrollPhysics(), - // itemBuilder: (context, index) => ItemDetailViewGridItem( - // index, - // dataList[index].segmentPrompt, - // dataList[index].segmentValueDsp, - // isNeedToShowEmptyDivider: (dataList.length == index + 1) - // ? isOdd - // ? true - // : false - // : false, - // ), - // gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - // crossAxisCount: 2, - // childAspectRatio: (itemWidth / itemHeight), - // ), - // ).objectContainerView(); - // }, - // separatorBuilder: (cxt, index) => 12.height, - // itemCount: list.length, - // ), - // Padding( - // padding: const EdgeInsets.only(right: 21, left: 21, bottom: 21), - // child: Row( - // children: [ - // DefaultButton( - // LocaleKeys.edit.tr(), - // () => performEditAction(), - // colors: const [Color(0xffE47A7E), Color(0xffDE6D71)], - // ).expanded, - // 8.width, - // DefaultButton( - // LocaleKeys.next.tr(), - // () => performNextAction(), - // colors: const [Color(0xff28C884), Color(0xff1BB271)], - // ).expanded, - // ], - // ), - // ), - // ], - // ); - // } - Widget showLoadingAnimation() { return Lottie.asset( 'assets/lottie/loading.json', diff --git a/lib/ui/work_list/worklist_fragments/actions_fragment.dart b/lib/ui/work_list/worklist_fragments/actions_fragment.dart index 98b5b72..1d88129 100644 --- a/lib/ui/work_list/worklist_fragments/actions_fragment.dart +++ b/lib/ui/work_list/worklist_fragments/actions_fragment.dart @@ -82,7 +82,20 @@ class ActionsFragment extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ actionHistory.nAME!.toText16(), - if ((actionHistory.nOTE ?? "").isNotEmpty) "Note: ${actionHistory.nOTE!}".toText12(color: MyColors.grey57Color), + + if ((actionHistory.nOTE ?? "").isNotEmpty) + SelectableText( + actionHistory.nOTE!, + style: const TextStyle( + fontSize: 12, + fontWeight: FontWeight.w600, + color: MyColors.grey57Color, + letterSpacing: -0.72, + ), + ), + + // if ((actionHistory.nOTE ?? "").isNotEmpty) "Note: ${actionHistory.nOTE!}".toText12(color: MyColors.grey57Color), + 4.height, Row( children: [ diff --git a/lib/ui/work_list/worklist_fragments/attachments_fragment.dart b/lib/ui/work_list/worklist_fragments/attachments_fragment.dart index b351683..bc1bde6 100644 --- a/lib/ui/work_list/worklist_fragments/attachments_fragment.dart +++ b/lib/ui/work_list/worklist_fragments/attachments_fragment.dart @@ -22,7 +22,6 @@ class AttachmentsFragment extends StatelessWidget { return ListView.separated( itemCount: getAttachmentList.length, itemBuilder: (context, index) { - return Row( children: [ SvgPicture.asset(determineFileIcon(getAttachmentList[index].fILECONTENTTYPE ?? "")), diff --git a/lib/ui/work_list/worklist_fragments/request_fragment.dart b/lib/ui/work_list/worklist_fragments/request_fragment.dart index a13f91f..b2bc0b6 100644 --- a/lib/ui/work_list/worklist_fragments/request_fragment.dart +++ b/lib/ui/work_list/worklist_fragments/request_fragment.dart @@ -1,7 +1,9 @@ import 'package:easy_localization/src/public_ext.dart'; import 'package:expandable/expandable.dart'; import 'package:flutter/material.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/utils.dart'; import 'package:mohem_flutter_app/config/routes.dart'; import 'package:mohem_flutter_app/extensions/int_extensions.dart'; import 'package:mohem_flutter_app/extensions/string_extensions.dart'; @@ -10,7 +12,8 @@ import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; import 'package:mohem_flutter_app/models/get_item_creation_ntf_body_list_model.dart'; import 'package:mohem_flutter_app/models/get_mo_notification_body_list_model.dart'; import 'package:mohem_flutter_app/models/get_po_notification_body_list_model.dart'; -import 'package:mohem_flutter_app/models/get_pr_notification_body_list_model.dart'; +import 'package:mohem_flutter_app/models/get_pr_information_list.dart'; +import 'package:mohem_flutter_app/models/get_pr_notification_body_list_model.dart' as get_pr_notification_body_list_model; import 'package:mohem_flutter_app/ui/work_list/item_history_screen.dart'; import 'package:mohem_flutter_app/widgets/button/default_button.dart'; import 'package:mohem_flutter_app/widgets/item_detail_view_widget.dart'; @@ -19,14 +22,14 @@ class RequestFragment extends StatelessWidget { final List moNotificationBodyList; final List itemCreationLines; final List poLinesList; - final List prLinesList; + final List prLinesList; RequestFragment({ Key? key, this.moNotificationBodyList = const [], this.itemCreationLines = const [], this.poLinesList = const [], - this.prLinesList = const [], + this.prLinesList = const [], }) : super(key: key); @override @@ -37,7 +40,7 @@ class RequestFragment extends StatelessWidget { padding: const EdgeInsets.all(21), children: [ if (moNotificationBodyList.isNotEmpty) moNotificationDataView(), - if (poLinesList.isNotEmpty) poLinesDataView(), + if (poLinesList.isNotEmpty) poLinesDataView(context), if (itemCreationLines.isNotEmpty) itemCreationLinesView(), if (prLinesList.isNotEmpty) prLinesDataView(), ], @@ -45,7 +48,7 @@ class RequestFragment extends StatelessWidget { ); } - Widget poLinesDataView() { + Widget poLinesDataView(BuildContext context) { return ExpandableNotifier( child: ListView.separated( shrinkWrap: true, @@ -87,22 +90,38 @@ class RequestFragment extends StatelessWidget { 12.height, Row( children: [ - DefaultButton(LocaleKeys.itemHistory.tr(), () { - Navigator.pushNamed( - cxt, - AppRoutes.itemHistory, - arguments: ItemHistoryScreenParams(title: LocaleKeys.itemHistory.tr(), isMO: false, pItemId: poLinesList[index].iTEMID), - ); - }).expanded, + DefaultButton( + LocaleKeys.itemHistory.tr(), + () { + Navigator.pushNamed( + cxt, + AppRoutes.itemHistory, + arguments: ItemHistoryScreenParams(title: LocaleKeys.itemHistory.tr(), isMO: false, pItemId: poLinesList[index].iTEMID), + ); + }, + fontSize: 13, + ).expanded, 12.width, - DefaultButton(LocaleKeys.quotationAnalysis.tr(), () { - Navigator.pushNamed( - cxt, - AppRoutes.itemHistory, - arguments: ItemHistoryScreenParams( - isItemHistory: false, isMO: false, title: LocaleKeys.quotationAnalysis.tr(), pItemId: poLinesList[index].iTEMID, pPoHeaderId: poLinesList[index].pOHEADERID), - ); - }).expanded, + DefaultButton( + LocaleKeys.quotationAnalysis.tr(), + () { + Navigator.pushNamed( + cxt, + AppRoutes.itemHistory, + arguments: ItemHistoryScreenParams( + isItemHistory: false, isMO: false, title: LocaleKeys.quotationAnalysis.tr(), pItemId: poLinesList[index].iTEMID, pPoHeaderId: poLinesList[index].pOHEADERID), + ); + }, + fontSize: 13, + ).expanded, + 12.width, + DefaultButton( + "PR Details", + () { + getPRDetails(context, poLinesList[index].pOLINEID.toString()); + }, + fontSize: 13, + ).expanded, ], ) ], @@ -263,4 +282,23 @@ class RequestFragment extends StatelessWidget { separatorBuilder: (cxt, index) => 12.height, itemCount: itemCreationLines.length); } + + void getPRDetails(BuildContext context, String poLineID) async { + try { + Utils.showLoading(context); + GetPRInformationList? getPRInformationList = GetPRInformationList(); + getPRInformationList = await WorkListApiClient().getPRDetailsForPO(poLineID); + Utils.hideLoading(context); + + Navigator.pushNamed( + context, + AppRoutes.itemHistory, + arguments: ItemHistoryScreenParams( + isItemHistory: false, isMO: false, isPRInfo: true, getPRInformationList: getPRInformationList, title: "PR Details", pItemId: 0, pPoHeaderId: 0, pOLineID: poLineID), + ); + } catch (ex) { + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + } + } } diff --git a/lib/widgets/Updater.dart b/lib/widgets/Updater.dart index 82cc172..3042dbb 100644 --- a/lib/widgets/Updater.dart +++ b/lib/widgets/Updater.dart @@ -1,18 +1,20 @@ /* ZiK */ import 'dart:async'; + import 'package:flutter/cupertino.dart'; typedef ChildProvider = Widget Function(BuildContext context, E? data); -class Updater extends StatelessWidget{ +class Updater extends StatelessWidget { final ChildProvider childProvider; StreamController? sink; T? initialData; List _history = []; Stream? _stream; - Updater({T? initialData, required this.childProvider}){ + + Updater({T? initialData, required this.childProvider}) { this.sink = StreamController(); this.initialData = initialData; _stream = this.sink?.stream; @@ -23,17 +25,17 @@ class Updater extends StatelessWidget{ return StreamBuilder( initialData: this.initialData, stream: _stream, - builder: (ctx, snapshot){ - return childProvider(context, snapshot.data); - }); + builder: (ctx, snapshot) { + return childProvider(context, snapshot.data); + }); } void pushData(T? data) { _history.add(data); sink?.sink.add(data); } - + List getDataHistory() => _history; - T? getLatestData() => _history.last; -} \ No newline at end of file + T? getLatestData() => _history.last; +} diff --git a/lib/widgets/app_bar_widget.dart b/lib/widgets/app_bar_widget.dart index 1096f24..6f9898e 100644 --- a/lib/widgets/app_bar_widget.dart +++ b/lib/widgets/app_bar_widget.dart @@ -1,13 +1,9 @@ import 'package:flutter/material.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/provider/chat_provider_model.dart'; -import 'package:mohem_flutter_app/widgets/circular_avatar.dart'; -import 'package:provider/provider.dart'; AppBar AppBarWidget(BuildContext context, {required String title, diff --git a/lib/widgets/bottom_sheets/search_employee_bottom_sheet.dart b/lib/widgets/bottom_sheets/search_employee_bottom_sheet.dart index b20674e..d810457 100644 --- a/lib/widgets/bottom_sheets/search_employee_bottom_sheet.dart +++ b/lib/widgets/bottom_sheets/search_employee_bottom_sheet.dart @@ -1,5 +1,3 @@ -import 'dart:convert'; - import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -26,7 +24,6 @@ import 'package:mohem_flutter_app/widgets/button/default_button.dart'; import 'package:mohem_flutter_app/widgets/circular_avatar.dart'; import 'package:mohem_flutter_app/widgets/dynamic_forms/dynamic_textfield_widget.dart'; import 'package:provider/provider.dart'; -import 'package:pull_to_refresh/pull_to_refresh.dart'; class SearchEmployeeBottomSheet extends StatefulWidget { int? notificationID; @@ -243,11 +240,11 @@ class _SearchEmployeeBottomSheetState extends State { children: [ Stack( children: [ - SvgPicture.asset( - "assets/images/user.svg", - height: 48, - width: 48, - ), + SvgPicture.asset( + "assets/images/user.svg", + height: 48, + width: 48, + ), Positioned( right: 5, bottom: 1, @@ -307,13 +304,7 @@ class _SearchEmployeeBottomSheetState extends State { ).onPress( () { if (provider.chatUsersList![index].isFav == null || provider.chatUsersList![index].isFav == false) { - provider - .favoriteUser( - userID: AppState().chatDetails!.response!.id!, - targetUserID: provider.chatUsersList![index].id!, - fromSearch: true - ) - .then((value) { + provider.favoriteUser(userID: AppState().chatDetails!.response!.id!, targetUserID: provider.chatUsersList![index].id!, fromSearch: true).then((value) { setState(() {}); }); } else if (provider.chatUsersList![index].isFav == true) { @@ -326,13 +317,7 @@ class _SearchEmployeeBottomSheetState extends State { setState(() {}); }); } else { - provider - .favoriteUser( - userID: AppState().chatDetails!.response!.id!, - targetUserID: provider.chatUsersList![index].id!, - fromSearch: true - ) - .then((value) { + provider.favoriteUser(userID: AppState().chatDetails!.response!.id!, targetUserID: provider.chatUsersList![index].id!, fromSearch: true).then((value) { setState(() {}); }); } diff --git a/lib/widgets/button/default_button.dart b/lib/widgets/button/default_button.dart index 71de642..338a13d 100644 --- a/lib/widgets/button/default_button.dart +++ b/lib/widgets/button/default_button.dart @@ -5,8 +5,7 @@ import 'package:mohem_flutter_app/classes/colors.dart'; extension WithContainer on Widget { Widget get insideContainer => Container( color: Colors.white, - padding: - const EdgeInsets.only(top: 16, bottom: 16, right: 21, left: 21), + padding: const EdgeInsets.only(top: 16, bottom: 16, right: 21, left: 21), child: this, ); } @@ -76,8 +75,7 @@ class DefaultButton extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ if (iconData != null) Icon(iconData, color: textColor), - if (svgIcon != null) - SvgPicture.asset(svgIcon ?? "", color: textColor), + if (svgIcon != null) SvgPicture.asset(svgIcon ?? "", color: textColor), if (!isTextExpanded) Padding( padding: EdgeInsets.only( diff --git a/lib/widgets/chat_app_bar_widge.dart b/lib/widgets/chat_app_bar_widge.dart index 25ed34c..cc252ec 100644 --- a/lib/widgets/chat_app_bar_widge.dart +++ b/lib/widgets/chat_app_bar_widge.dart @@ -7,7 +7,6 @@ import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; import 'package:mohem_flutter_app/models/chat/get_search_user_chat_model.dart'; import 'package:mohem_flutter_app/provider/chat_provider_model.dart'; -import 'package:mohem_flutter_app/widgets/circular_avatar.dart'; import 'package:provider/provider.dart'; AppBar ChatAppBarWidget(BuildContext context, diff --git a/lib/widgets/dialogs/dialogs.dart b/lib/widgets/dialogs/dialogs.dart index debb147..6765e38 100644 --- a/lib/widgets/dialogs/dialogs.dart +++ b/lib/widgets/dialogs/dialogs.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -void showMDialog(context, {Widget? child,Color? backgroundColor,bool isDismissable=true}) async { +void showMDialog(context, {Widget? child, Color? backgroundColor, bool isDismissable = true}) async { return showDialog( context: context, barrierDismissible: isDismissable, diff --git a/lib/widgets/dynamic_forms/dynamic_textfield_widget.dart b/lib/widgets/dynamic_forms/dynamic_textfield_widget.dart index ec4146b..0630e44 100644 --- a/lib/widgets/dynamic_forms/dynamic_textfield_widget.dart +++ b/lib/widgets/dynamic_forms/dynamic_textfield_widget.dart @@ -55,20 +55,23 @@ class DynamicTextFieldWidget extends StatelessWidget { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - labelText, - style: const TextStyle( - fontSize: 11, - fontWeight: FontWeight.w600, - color: Color(0xff2B353E), - letterSpacing: -0.44, + if (labelText.isNotEmpty) + Text( + labelText, + style: const TextStyle( + fontSize: 11, + fontWeight: FontWeight.w600, + color: Color(0xff2B353E), + letterSpacing: -0.44, + ), ), - ), TextField( enabled: isEnable, scrollPadding: EdgeInsets.zero, readOnly: isReadOnly, - keyboardType: (isInputTypeNum) ? (isInputTypeNumSigned ? const TextInputType.numberWithOptions(signed: true, decimal: true) : TextInputType.numberWithOptions(signed: true, decimal: true)) : TextInputType.text, + keyboardType: (isInputTypeNum) + ? (isInputTypeNumSigned ? const TextInputType.numberWithOptions(signed: true, decimal: true) : TextInputType.numberWithOptions(signed: true, decimal: true)) + : TextInputType.text, textInputAction: TextInputAction.done, //controller: controller, maxLines: lines, diff --git a/lib/widgets/image_picker.dart b/lib/widgets/image_picker.dart index 834695b..ef04f84 100644 --- a/lib/widgets/image_picker.dart +++ b/lib/widgets/image_picker.dart @@ -45,7 +45,19 @@ class ImageOptions { onFilesTap: () async { FilePickerResult? result = await FilePicker.platform.pickFiles( type: FileType.custom, - allowedExtensions: ['jpg', 'jpeg ', 'pdf', 'txt', 'docx', 'doc', 'pptx', 'xlsx', 'png', 'rar', 'zip',], + allowedExtensions: [ + 'jpg', + 'jpeg ', + 'pdf', + 'txt', + 'docx', + 'doc', + 'pptx', + 'xlsx', + 'png', + 'rar', + 'zip', + ], ); List files = result!.paths.map((path) => File(path!)).toList(); image(result.files.first.path.toString(), files.first); @@ -54,67 +66,68 @@ class ImageOptions { ); } - static void showImageOptions(BuildContext context, Function(String, File) image) { - showModalBottomSheet( - backgroundColor: Colors.transparent, - context: context, - builder: (BuildContext bc) { - return _BottomSheet( - children: [ - _BottomSheetItem( - title: "Select File Source", - onTap: () {}, - icon: Icons.file_present, - color: MyColors.black, - ), - _BottomSheetItem( - title: "Gallery", - icon: Icons.image, - onTap: () async { - if (Platform.isAndroid) { - galleryImageAndroid(image); - } else { - File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.gallery, imageQuality: 10))?.path ?? ""); - String fileName = _image.path; - var bytes = File(fileName).readAsBytesSync(); - String base64Encode = base64.encode(bytes); - if (base64Encode != null) { - image(base64Encode, _image); - } - } - }, - ), - _BottomSheetItem( - title: "Camera", - icon: Icons.camera_alt, - onTap: () async { - if (Platform.isAndroid) { - cameraImageAndroid(image); - } else { - File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.camera, imageQuality: 10))?.path ?? ""); - String fileName = _image.path; - var bytes = File(fileName).readAsBytesSync(); - String base64Encode = base64.encode(bytes); - if (base64Encode != null) { - image(base64Encode, _image); - } - } - }, - ), - _BottomSheetItem( - title: "Cancel", - onTap: () {}, - icon: Icons.cancel, - color: MyColors.redColor, - ) - ], - ); - }); - } +// static void showImageOptions(BuildContext context, Function(String, File) image) { +// showModalBottomSheet( +// backgroundColor: Colors.transparent, +// context: context, +// builder: (BuildContext bc) { +// return _BottomSheet( +// children: [ +// _BottomSheetItem( +// title: "Select File Source", +// onTap: () {}, +// icon: Icons.file_present, +// color: MyColors.black, +// ), +// _BottomSheetItem( +// title: "Gallery", +// icon: Icons.image, +// onTap: () async { +// if (Platform.isAndroid) { +// galleryImageAndroid(image); +// } else { +// File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.gallery, imageQuality: 10))?.path ?? ""); +// String fileName = _image.path; +// var bytes = File(fileName).readAsBytesSync(); +// String base64Encode = base64.encode(bytes); +// if (base64Encode != null) { +// image(base64Encode, _image); +// } +// } +// }, +// ), +// _BottomSheetItem( +// title: "Camera", +// icon: Icons.camera_alt, +// onTap: () async { +// if (Platform.isAndroid) { +// cameraImageAndroid(image); +// } else { +// File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.camera, imageQuality: 10))?.path ?? ""); +// String fileName = _image.path; +// var bytes = File(fileName).readAsBytesSync(); +// String base64Encode = base64.encode(bytes); +// if (base64Encode != null) { +// image(base64Encode, _image); +// } +// } +// }, +// ), +// _BottomSheetItem( +// title: "Cancel", +// onTap: () {}, +// icon: Icons.cancel, +// color: MyColors.redColor, +// ) +// ], +// ); +// }); +// } } void galleryImageAndroid(Function(String, File) image) async { File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.gallery, imageQuality: 20))?.path ?? ""); + String fileName = _image.path; var bytes = File(fileName).readAsBytesSync(); String base64Encode = base64.encode(bytes); diff --git a/lib/widgets/location/Location.dart b/lib/widgets/location/Location.dart index d407c1c..62bd016 100644 --- a/lib/widgets/location/Location.dart +++ b/lib/widgets/location/Location.dart @@ -1,22 +1,11 @@ import 'dart:async'; -import 'dart:math'; -import 'dart:ui'; -import 'package:mohem_flutter_app/classes/utils.dart'; 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/app_permissions.dart'; import 'package:mohem_flutter_app/classes/utils.dart'; -import 'package:mohem_flutter_app/theme/colors.dart'; -// import 'package:geodesy/geodesy.dart' as geodesy; -//Created By Mr.Zohaib class Location { - static _Map map = _Map(); - static void havePermission(Function(bool) callback) { Geolocator.checkPermission().then((value) async { if (value == LocationPermission.denied) { @@ -46,206 +35,30 @@ class Location { }); } - static void getCurrentLocation(Function(LatLng?, bool isMocked) callback, BuildContext context) { + static void getCurrentLocation(Function(Position position, bool isMocked) callback, BuildContext context) { void done(Position position) { //AppStorage.sp.saveLocation(position); bool isMocked = position.isMocked; - LatLng? myCurrentLocation = LatLng(position.latitude, position.longitude); - callback(myCurrentLocation, isMocked); + callback(position, isMocked); } AppPermissions.location((granted) { if (granted) { - Geolocator.getLastKnownPosition(forceAndroidLocationManager: true).then((value) { - if (value == null) { - Geolocator.getCurrentPosition().then((value) { - done(value); - }); - } else { - done(value); - } + Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.medium, timeLimit: const Duration(seconds: 5)).then((value) { + done(value); }); + // Geolocator.getLastKnownPosition(forceAndroidLocationManager: true).then((value) { + // if (value == null) { + // Geolocator.getCurrentPosition().then((value) { + // done(value); + // }); + // } else { + // done(value); + // } + // }); } else { // AppPermissions } }, context); } - - // 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, - }) { - 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; - } - - void moveCamera(CameraPosition camera, @required Completer mapController, bool animation) { - mapController.future.then((controller) { - animation ? controller.animateCamera(CameraUpdate.newCameraPosition(camera)) : controller.moveCamera(CameraUpdate.newCameraPosition(camera)); - }); - } - - void 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); - }); - } - - // void 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(); - - void 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'; - - void 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!)); - } - - void focusCameraToLatLngBounds({LatLngBounds? bound, Completer? mapController, double? padding}) async { - if (bound == null) return; - - CameraUpdate camera = CameraUpdate.newLatLngBounds(bound, padding!); - GoogleMapController controller = await mapController!.future; - controller.animateCamera(camera); - } - - void 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/otp_widget.dart b/lib/widgets/otp_widget.dart index e90308d..7994b1e 100644 --- a/lib/widgets/otp_widget.dart +++ b/lib/widgets/otp_widget.dart @@ -108,7 +108,7 @@ class OTPWidgetState extends State with SingleTickerProviderStateMixi } } - void calculateStrList() { + void calculateStrList() { if (strList.length > widget.maxLength) { strList.length = widget.maxLength; } diff --git a/lib/widgets/qr_scanner_dialog.dart b/lib/widgets/qr_scanner_dialog.dart index 6082d4c..11e2601 100644 --- a/lib/widgets/qr_scanner_dialog.dart +++ b/lib/widgets/qr_scanner_dialog.dart @@ -1,9 +1,8 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; -import 'package:qr_code_scanner/qr_code_scanner.dart'; - import 'package:mohem_flutter_app/widgets/button/default_button.dart'; +import 'package:qr_code_scanner/qr_code_scanner.dart'; class QrScannerDialog extends StatefulWidget { @override @@ -68,6 +67,8 @@ class _QrScannerDialogState extends State { } }); }); + controller.pauseCamera(); + controller.resumeCamera(); } @override diff --git a/pubspec.yaml b/pubspec.yaml index 13ca645..bc70be9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 3.6.4+2 +version: 3.2.93+300032 environment: sdk: ">=2.16.0 <3.0.0" @@ -46,7 +46,7 @@ dependencies: local_auth: ^1.1.9 fluttertoast: ^8.0.8 syncfusion_flutter_calendar: ^19.4.48 - flutter_calendar_carousel: ^2.1.0 +# flutter_calendar_carousel: ^2.1.0 pie_chart: ^5.1.0 shared_preferences: ^2.0.12 firebase_messaging: ^13.0.4 @@ -54,24 +54,21 @@ dependencies: logger: ^1.1.0 flutter_countdown_timer: ^4.1.0 nfc_manager: ^3.2.0 - uuid: ^3.0.6 +# uuid: ^3.0.6 +# device_info_plus: ^4.0.0 +# android_id: ^0.1.3+1 + platform_device_id: ^1.0.1 image_picker: ^0.8.5+3 file_picker: ^4.6.1 - # maps - google_maps_flutter: ^2.0.2 - google_maps_utils: ^1.4.0+1 - google_directions_api: ^0.9.0 geolocator: ^9.0.2 - # flutter_compass: ^0.6.1 - google_maps_flutter_web: ^0.3.2 month_year_picker: ^0.2.0+1 month_picker_dialog_2: 0.5.5 open_file: ^3.2.1 wifi_iot: ^0.3.18 flutter_html: ^3.0.0-alpha.6 # flutter_barcode_scanner: ^2.0.0 - qr_code_scanner: ^1.0.0 - qr_flutter: ^4.0.0 + qr_code_scanner: ^1.0.1 +# qr_flutter: ^4.0.0 url_launcher: ^6.0.15 share: 2.0.4 flutter_rating_bar: ^4.0.1 @@ -91,8 +88,8 @@ dependencies: logging: ^1.0.1 swipe_to: ^1.0.2 flutter_webrtc: ^0.9.16 - camera: ^0.10.0+4 - flutter_local_notifications: any + camera: ^0.10.3 + flutter_local_notifications: ^10.0.0 #firebase_analytics: any #Chat Voice Message Recoding & Play @@ -104,9 +101,22 @@ dependencies: video_player: ^2.5.1 just_audio: ^0.9.30 - safe_device: ^1.1.2 +# safe_device: ^1.1.2 flutter_layout_grid: ^2.0.1 + #Huawei Dependencies +# huawei_hmsavailability: ^6.6.0+300 + huawei_location: 6.0.0+302 + huawei_push: ^6.7.0+300 + firebase_crashlytics: ^2.9.0 + + #Items for sale Image Carousel Slider + carousel_slider: ^4.2.1 + + #Huawei Specified +# store_checker: ^1.1.0 + google_api_availability: ^3.0.1 + dependency_overrides: firebase_core_platform_interface: 4.5.1