From d971f4a6510ac5c9a65c5c11ee5fec6a22639fcb Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Sun, 12 Mar 2023 16:04:24 +0300 Subject: [PATCH 1/3] po worklist forward & approve and forward RespondAttributeList payload improvement. --- android/app/build.gradle | 9 +-- lib/api/worklist/worklist_api_client.dart | 8 +-- lib/classes/consts.dart | 4 +- lib/ui/landing/dashboard_screen.dart | 2 +- lib/ui/login/login_screen.dart | 30 +++++----- lib/ui/work_list/sheets/delegate_sheet.dart | 8 ++- .../work_list/sheets/selected_item_sheet.dart | 60 +++++++++++++++++-- lib/ui/work_list/worklist_detail_screen.dart | 7 ++- pubspec.yaml | 2 +- 9 files changed, 93 insertions(+), 37 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 5590740..5279c1f 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -59,12 +59,6 @@ android { } signingConfigs { - debug { - keyAlias keystoreProperties['keyAlias'] - keyPassword keystoreProperties['keyPassword'] - storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null - storePassword keystoreProperties['storePassword'] - } release { keyAlias keystoreProperties['keyAlias'] keyPassword keystoreProperties['keyPassword'] @@ -73,6 +67,9 @@ android { } } buildTypes { + debug { + signingConfig signingConfigs.debug + } release { signingConfig signingConfigs.release minifyEnabled true diff --git a/lib/api/worklist/worklist_api_client.dart b/lib/api/worklist/worklist_api_client.dart index f0d3d80..8765ddd 100644 --- a/lib/api/worklist/worklist_api_client.dart +++ b/lib/api/worklist/worklist_api_client.dart @@ -414,7 +414,7 @@ class WorkListApiClient { "EmployeeNumber": employeeNumber, "Comments": "", "AdditionalFields": null, - "NewUserEMPId":newUserEMPId + "NewUserEMPId": newUserEMPId }; postParams.addAll(AppState().postParamsJson); return await ApiClient().postJsonForObject((json) { @@ -590,7 +590,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, @@ -599,7 +600,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) { @@ -641,5 +642,4 @@ class WorkListApiClient { return responseData.getPRInformationList; }, url, postParams); } - } diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 688fd70..4d3025e 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -3,8 +3,8 @@ import 'package:mohem_flutter_app/ui/marathon/widgets/question_card.dart'; class ApiConsts { //static String baseUrl = "http://10.200.204.20:2801/"; // Local server // static String baseUrl = "https://erptstapp.srca.org.sa"; // SRCA server - // static String baseUrl = "https://uat.hmgwebservices.com"; // UAT server - static String baseUrl = "https://hmgwebservices.com"; // Live server + static String baseUrl = "https://uat.hmgwebservices.com"; // UAT server + // static String baseUrl = "https://hmgwebservices.com"; // Live server static String baseUrlServices = baseUrl + "/Services/"; // server // static String baseUrlServices = "https://api.cssynapses.com/tangheem/"; // Live server static String utilitiesRest = baseUrlServices + "Utilities.svc/REST/"; diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index 8b78974..817d4b5 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -440,7 +440,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, ), ), diff --git a/lib/ui/login/login_screen.dart b/lib/ui/login/login_screen.dart index 0fc3aa9..8d8e7c2 100644 --- a/lib/ui/login/login_screen.dart +++ b/lib/ui/login/login_screen.dart @@ -8,6 +8,7 @@ import 'package:firebase_messaging/firebase_messaging.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'; @@ -92,9 +93,6 @@ class _LoginScreenState extends State { super.dispose(); } - - - String? firebaseToken; GetMobileLoginInfoListModel? loginInfo; @@ -103,19 +101,19 @@ class _LoginScreenState extends State { Utils.showLoading(context); 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); - } + 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 { 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..3953ccb 100644 --- a/lib/ui/work_list/sheets/selected_item_sheet.dart +++ b/lib/ui/work_list/sheets/selected_item_sheet.dart @@ -10,10 +10,12 @@ 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 +25,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 +113,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 +131,41 @@ class SelectedItemSheet extends StatelessWidget { ); } + void askForConfirmation(BuildContext context, {String? email, String? userId}) { + NotificationGetRespondAttributesList? notificationNoteInput; + NotificationGetRespondAttributesList? forwardToUser; + List filtered = getNotificationRespondAttributes.where((element) => element.attributeName == "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; + } + + 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 +182,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/worklist_detail_screen.dart b/lib/ui/work_list/worklist_detail_screen.dart index 7a489c3..feadb6d 100644 --- a/lib/ui/work_list/worklist_detail_screen.dart +++ b/lib/ui/work_list/worklist_detail_screen.dart @@ -449,7 +449,6 @@ class _WorkListDetailScreenState extends State { } void handleFabAction(GetNotificationButtonsList notificationButton) { - print("notificationButton:${notificationButton.bUTTONACTION}"); switch (notificationButton.bUTTONACTION) { case "DELEGATE": showMyBottomSheet(context, @@ -526,6 +525,7 @@ class _WorkListDetailScreenState extends State { notificationID: workListData!.nOTIFICATIONID, actionHistoryList: actionHistoryList, callBackFunc: reloadWorkList, + getNotificationRespondAttributes: getNotificationRespondAttributes, )); break; case "FORWARD": @@ -537,8 +537,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; @@ -656,7 +660,6 @@ class _WorkListDetailScreenState extends State { } void performAction(String actionMode, {String? title}) { - print(actionMode); showDialog( context: context, builder: (cxt) => AcceptRejectInputDialog( diff --git a/pubspec.yaml b/pubspec.yaml index cd1ef74..bc70be9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -89,7 +89,7 @@ dependencies: swipe_to: ^1.0.2 flutter_webrtc: ^0.9.16 camera: ^0.10.3 - flutter_local_notifications: any + flutter_local_notifications: ^10.0.0 #firebase_analytics: any #Chat Voice Message Recoding & Play From 227855a6a5b995fe0b03c719d0a2c41fe15487f3 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Sun, 12 Mar 2023 17:03:23 +0300 Subject: [PATCH 2/3] dynamic text field improvement. --- .../dynamic_forms/dynamic_textfield_widget.dart | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/lib/widgets/dynamic_forms/dynamic_textfield_widget.dart b/lib/widgets/dynamic_forms/dynamic_textfield_widget.dart index cc710fe..0630e44 100644 --- a/lib/widgets/dynamic_forms/dynamic_textfield_widget.dart +++ b/lib/widgets/dynamic_forms/dynamic_textfield_widget.dart @@ -55,15 +55,16 @@ 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, From cd091b696ae5389aa3f771900e5ee04d0ab8fc2e Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Mon, 13 Mar 2023 16:12:26 +0300 Subject: [PATCH 3/3] worklist pagination added. --- lib/api/worklist/worklist_api_client.dart | 2 +- lib/ui/work_list/work_list_screen.dart | 27 +++++++++++++++++++---- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/lib/api/worklist/worklist_api_client.dart b/lib/api/worklist/worklist_api_client.dart index 8765ddd..51e5c80 100644 --- a/lib/api/worklist/worklist_api_client.dart +++ b/lib/api/worklist/worklist_api_client.dart @@ -47,7 +47,7 @@ class WorkListApiClient { Map postParams = { "P_NOTIFICATION_TYPE": pNotificationType, "P_PAGE_NUM": pPageNum, - "P_PAGE_LIMIT": 50, + "P_PAGE_LIMIT": 20, "P_ITEM_TYPE": pItemType, "P_SEARCH_FROM_USER": pSearchUser, "P_SEARCH_ITEM_TYPE_DSP_NAME": pSearchItemType, 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(() {});