From d614532956eb6e89907cb3e605014fc8a30f2b52 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Thu, 23 Jun 2022 12:07:25 +0300 Subject: [PATCH 1/8] Announcements implemented --- lib/models/get_announcement_details.dart | 4 +- .../announcements/announcement_details.dart | 89 +++++++++++-------- .../screens/announcements/announcements.dart | 15 +++- pubspec.yaml | 1 + 4 files changed, 68 insertions(+), 41 deletions(-) diff --git a/lib/models/get_announcement_details.dart b/lib/models/get_announcement_details.dart index 33628ce..9414c9f 100644 --- a/lib/models/get_announcement_details.dart +++ b/lib/models/get_announcement_details.dart @@ -3,8 +3,8 @@ class GetAnnouncementDetails { String? titleAR; String? emailBodyEN; String? emailBodyAR; - String? bodyEN; - String? bodyAR; + String? bodyEN = ""; + String? bodyAR = ""; String? bannerImage; String? rowID; String? awarenessName; diff --git a/lib/ui/screens/announcements/announcement_details.dart b/lib/ui/screens/announcements/announcement_details.dart index a3de742..a2f1f99 100644 --- a/lib/ui/screens/announcements/announcement_details.dart +++ b/lib/ui/screens/announcements/announcement_details.dart @@ -3,9 +3,13 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter_html/flutter_html.dart'; import 'package:mohem_flutter_app/api/pending_transactions_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/models/get_announcement_details.dart'; import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; +import 'package:url_launcher/url_launcher.dart'; class AnnouncementDetails extends StatefulWidget { const AnnouncementDetails({Key? key}) : super(key: key); @@ -36,59 +40,68 @@ class _AnnouncementDetailsState extends State { title: "Announcements", ), body: SingleChildScrollView( - child: Container( - width: double.infinity, - padding: const EdgeInsets.all(10.0), - margin: const EdgeInsets.all(12.0), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(10), - boxShadow: [ - BoxShadow( - color: const Color(0xff000000).withOpacity(.05), - blurRadius: 26, - offset: const Offset(0, -3), - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - SizedBox( + child: getAnnouncementDetailsObj != null + ? Container( width: double.infinity, - height: 150.0, - child: ClipRRect( + padding: const EdgeInsets.all(10.0), + margin: const EdgeInsets.all(12.0), + decoration: BoxDecoration( + color: Colors.white, borderRadius: BorderRadius.circular(10), - child: Image.memory( - base64Decode(Utils.getBase64FromJpeg(getAnnouncementDetailsObj?.bannerImage)), - fit: BoxFit.cover, - ), + boxShadow: [ + BoxShadow( + color: const Color(0xff000000).withOpacity(.05), + blurRadius: 26, + offset: const Offset(0, -3), + ), + ], ), - ), - Container( - margin: const EdgeInsets.only(top: 12.0), - child: Html( - data: getAnnouncementDetailsObj?.bodyEN, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + 12.height, + AppState().isArabic(context) + ? Text(getAnnouncementDetailsObj?.titleAR ?? "", style: const TextStyle(color: MyColors.darkTextColor, fontSize: 16, letterSpacing: -0.64, fontWeight: FontWeight.w600)) + : Text(getAnnouncementDetailsObj?.titleEN ?? "", style: const TextStyle(color: MyColors.darkTextColor, fontSize: 16, letterSpacing: -0.64, fontWeight: FontWeight.w600)), + 12.height, + SizedBox( + width: double.infinity, + height: 150.0, + child: ClipRRect( + borderRadius: BorderRadius.circular(10), + child: Image.memory( + base64Decode(Utils.getBase64FromJpeg(getAnnouncementDetailsObj?.bannerImage)), + fit: BoxFit.cover, + ), + ), + ), + Container( + margin: const EdgeInsets.only(top: 12.0), + child: Html( + data: AppState().isArabic(context) ? getAnnouncementDetailsObj?.bodyAR : getAnnouncementDetailsObj?.bodyEN ?? "", + onLinkTap: (String? url, RenderContext context, Map attributes, _) { + launchUrl(Uri.parse(url!)); + }), + ), + ], ), - ), - ], - ), - ), + ) + : Utils.getNoDataWidget(context), ), ); } - getRequestID() { + getRequestID() async { if (currentPageNo == 0) { final arguments = (ModalRoute.of(context)?.settings.arguments ?? {}) as Map; currentPageNo = arguments["currentPageNo"]; rowID = arguments["rowID"]; - getAnnouncementDetails(0, rowID); + await getAnnouncementDetails(0, rowID); } } - void getAnnouncementDetails(int itgAwarenessID, int itgRowID) async { + Future getAnnouncementDetails(int itgAwarenessID, int itgRowID) async { try { Utils.showLoading(context); jsonResponse = await PendingTransactionsApiClient().getAnnouncements(itgAwarenessID, currentPageNo, itgRowID); diff --git a/lib/ui/screens/announcements/announcements.dart b/lib/ui/screens/announcements/announcements.dart index cad3a9a..61ebde4 100644 --- a/lib/ui/screens/announcements/announcements.dart +++ b/lib/ui/screens/announcements/announcements.dart @@ -27,11 +27,22 @@ class _AnnouncementsState extends State { List getAnnouncementsObject = []; List _foundAnnouncements = []; TextEditingController searchController = TextEditingController(); + final ScrollController _controller = ScrollController(); @override void initState() { getAnnouncements(0, 0); super.initState(); + _controller.addListener(() { + if (_controller.position.atEdge) { + bool isTop = _controller.position.pixels == 0; + if (!isTop) { + print('At the bottom'); + currentPageNo++; + getAnnouncements(0, 0); + } + } + }); } @override @@ -71,6 +82,7 @@ class _AnnouncementsState extends State { child: ListView.separated( physics: const BouncingScrollPhysics(), shrinkWrap: true, + controller: _controller, itemBuilder: (BuildContext context, int index) { return InkWell( onTap: () { @@ -125,7 +137,8 @@ class _AnnouncementsState extends State { ); }, separatorBuilder: (BuildContext context, int index) => 1.height, - itemCount: _foundAnnouncements.length ?? 0)) + itemCount: _foundAnnouncements.length ?? 0)), + 20.height, ], ), ) diff --git a/pubspec.yaml b/pubspec.yaml index 365819d..6601587 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -68,6 +68,7 @@ dependencies: open_file: ^3.2.1 wifi_iot: ^0.3.16 flutter_html: ^2.2.1 + url_launcher: ^6.0.15 dev_dependencies: flutter_test: From c63844dcf75cf569fc164efdee13dcfc1c8a76e5 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Mon, 8 Aug 2022 15:41:27 +0300 Subject: [PATCH 2/8] My requests & CCP --- lib/api/my_requests_api_client.dart | 62 +++ lib/classes/file_process.dart | 40 ++ lib/config/routes.dart | 9 + lib/models/generic_response_model.dart | 80 ++-- .../get_ccp_dff_structure_model.dart | 220 +++++++++ .../my_requests/get_ccp_output_model.dart | 21 + .../get_ccp_transactions_model.dart | 32 ++ .../get_concurrent_programs_model.dart | 24 + lib/ui/landing/widget/app_drawer.dart | 10 + lib/ui/screens/my_requests/my_requests.dart | 218 +++++++++ lib/ui/screens/my_requests/new_request.dart | 423 ++++++++++++++++++ 11 files changed, 1108 insertions(+), 31 deletions(-) create mode 100644 lib/api/my_requests_api_client.dart create mode 100644 lib/classes/file_process.dart create mode 100644 lib/models/my_requests/get_ccp_dff_structure_model.dart create mode 100644 lib/models/my_requests/get_ccp_output_model.dart create mode 100644 lib/models/my_requests/get_ccp_transactions_model.dart create mode 100644 lib/models/my_requests/get_concurrent_programs_model.dart create mode 100644 lib/ui/screens/my_requests/my_requests.dart create mode 100644 lib/ui/screens/my_requests/new_request.dart diff --git a/lib/api/my_requests_api_client.dart b/lib/api/my_requests_api_client.dart new file mode 100644 index 0000000..391e297 --- /dev/null +++ b/lib/api/my_requests_api_client.dart @@ -0,0 +1,62 @@ +import 'package:mohem_flutter_app/api/api_client.dart'; +import 'package:mohem_flutter_app/app_state/app_state.dart'; +import 'package:mohem_flutter_app/classes/consts.dart'; +import 'package:mohem_flutter_app/models/generic_response_model.dart'; +import 'package:mohem_flutter_app/models/get_eit_dff_structure_list_model.dart'; +import 'package:mohem_flutter_app/models/my_requests/get_ccp_dff_structure_model.dart'; +import 'package:mohem_flutter_app/models/my_requests/get_ccp_output_model.dart'; +import 'package:mohem_flutter_app/models/my_requests/get_ccp_transactions_model.dart'; +import 'package:mohem_flutter_app/models/my_requests/get_concurrent_programs_model.dart'; + +class MyRequestsApiClient { + static final MyRequestsApiClient _instance = MyRequestsApiClient._internal(); + + MyRequestsApiClient._internal(); + + factory MyRequestsApiClient() => _instance; + + Future> getConcurrentPrograms() async { + String url = "${ApiConsts.erpRest}GET_CONCURRENT_PROGRAMS"; + Map postParams = {"P_REQUEST_GROUP_ID": 3290}; + + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject((json) { + GenericResponseModel? responseData = GenericResponseModel.fromJson(json); + return responseData.getConcurrentProgramsModel ?? []; + }, url, postParams); + } + + Future> getCCPTransactions(String? templateName) async { + String url = "${ApiConsts.erpRest}GET_CCP_TRANSACTIONS"; + Map postParams = {"P_DESC_FLEX_NAME": templateName}; + + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject((json) { + GenericResponseModel? responseData = GenericResponseModel.fromJson(json); + return responseData.getCCPTransactionsModel ?? []; + }, url, postParams); + } + + Future getCCPOutput(String? requestID) async { + String url = "${ApiConsts.erpRest}GET_CCP_OUTPUT"; + Map postParams = {"P_REQUEST_ID": requestID}; + + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject((json) { + GenericResponseModel? responseData = GenericResponseModel.fromJson(json); + return responseData.getCCPOutputModel!; + }, url, postParams); + } + + Future> getCCPDFFStructure(String? templateName) async { + String url = "${ApiConsts.erpRest}GET_CCP_DFF_STRUCTURE"; + Map postParams = {"P_DESC_FLEX_NAME": templateName}; + + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject((json) { + GenericResponseModel? responseData = GenericResponseModel.fromJson(json); + return responseData.getEITDFFStructureList ?? []; + }, url, postParams); + } + +} diff --git a/lib/classes/file_process.dart b/lib/classes/file_process.dart new file mode 100644 index 0000000..29f24c8 --- /dev/null +++ b/lib/classes/file_process.dart @@ -0,0 +1,40 @@ +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:open_file/open_file.dart'; +import 'package:path_provider/path_provider.dart'; + +class FileProcess { + static bool isFolderCreated = false; + static Directory? directory; + + static checkDocumentFolder() async { + try { + if (!isFolderCreated) { + directory = await getApplicationDocumentsDirectory(); + await directory!.exists().then((value) { + if (value) directory!.create(); + isFolderCreated = true; + }); + } + } catch (e) { + print(e.toString()); + } + } + + static void openFile(String fileName) { + String dir = directory!.path + "/${fileName}.pdf"; + OpenFile.open(dir); + } + + static Future downloadFile(String base64Content, String fileName) async { + Uint8List bytes = base64.decode(base64Content); + await checkDocumentFolder(); + String dir = directory!.path + "/" + fileName + ".pdf"; + File file = File(dir); + if (!file.existsSync()) file.create(); + await file.writeAsBytes(bytes); + return file; + } +} diff --git a/lib/config/routes.dart b/lib/config/routes.dart index 502d852..509f6f8 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -25,6 +25,8 @@ import 'package:mohem_flutter_app/ui/screens/announcements/announcements.dart'; import 'package:mohem_flutter_app/ui/screens/eit/add_eit.dart'; import 'package:mohem_flutter_app/ui/screens/mowadhafhi/mowadhafhi_hr_request.dart'; import 'package:mohem_flutter_app/ui/screens/mowadhafhi/request_details.dart'; +import 'package:mohem_flutter_app/ui/screens/my_requests/my_requests.dart'; +import 'package:mohem_flutter_app/ui/screens/my_requests/new_request.dart'; import 'package:mohem_flutter_app/ui/screens/pending_transactions/pending_transactions.dart'; import 'package:mohem_flutter_app/ui/screens/pending_transactions/pending_transactions_details.dart'; import 'package:mohem_flutter_app/ui/screens/profile/profile_screen.dart'; @@ -95,6 +97,10 @@ class AppRoutes { static const String announcements = "/announcements"; static const String announcementsDetails = "/announcementsDetails"; + // My Requests + static const String myRequests = "/myRequests"; + static const String newRequest = "/newRequests"; + static final Map routes = { @@ -151,6 +157,9 @@ class AppRoutes { announcements: (context) => Announcements(), announcementsDetails: (context) => AnnouncementDetails(), + //My Requests + myRequests: (context) => MyRequests(), + newRequest: (context) => NewRequest(), }; } diff --git a/lib/models/generic_response_model.dart b/lib/models/generic_response_model.dart index 00404f4..a550e9d 100644 --- a/lib/models/generic_response_model.dart +++ b/lib/models/generic_response_model.dart @@ -32,6 +32,10 @@ import 'package:mohem_flutter_app/models/mowadhafhi/get_ticket_details.dart'; import 'package:mohem_flutter_app/models/mowadhafhi/get_ticket_transactions.dart'; import 'package:mohem_flutter_app/models/mowadhafhi/get_ticket_types.dart'; import 'package:mohem_flutter_app/models/mowadhafhi/get_tickets_list.dart'; +import 'package:mohem_flutter_app/models/my_requests/get_ccp_dff_structure_model.dart'; +import 'package:mohem_flutter_app/models/my_requests/get_ccp_output_model.dart'; +import 'package:mohem_flutter_app/models/my_requests/get_ccp_transactions_model.dart'; +import 'package:mohem_flutter_app/models/my_requests/get_concurrent_programs_model.dart'; import 'package:mohem_flutter_app/models/notification_action_model.dart'; import 'package:mohem_flutter_app/models/notification_get_respond_attributes_list_model.dart'; import 'package:mohem_flutter_app/models/pending_transactions/get_pending_transactions_details.dart'; @@ -128,11 +132,7 @@ class GenericResponseModel { List? getCEICollectionNotificationBodyList; List? getCEIDFFStructureList; List? getCEITransactionList; - List? getCcpDffStructureList; - List? getCcpOutputList; List? getCcpTransactionsList; - List? getCcpTransactionsListNew; - List? getConcurrentProgramsList; List? getContactColsStructureList; List? getContactDetailsList; List? getContactDffStructureList; @@ -170,8 +170,6 @@ class GenericResponseModel { List? getOrganizationsSalariesList; List? getPaymentInformationList; List? getPayslipList; - // List? getPendingReqDetailsList; - // List? getPendingReqFunctionsList; List? getPerformanceAppraisalList; List? getPhonesNotificationBodyList; List? getPoItemHistoryList; @@ -206,6 +204,10 @@ class GenericResponseModel { List? getDepartmentSections; List? getPendingTransactionsFunctions; List? getPendingTransactionsDetails; + List? getConcurrentProgramsModel; + List? getCCPTransactionsModel; + GetCCPOutputModel? getCCPOutputModel; + List? getCCPDFFStructureModel; List? getUserItemTypesList; List? getVacationRulesList; List? getVaccinationOnHandList; @@ -391,11 +393,7 @@ class GenericResponseModel { this.getCEICollectionNotificationBodyList, this.getCEIDFFStructureList, this.getCEITransactionList, - this.getCcpDffStructureList, - this.getCcpOutputList, this.getCcpTransactionsList, - this.getCcpTransactionsListNew, - this.getConcurrentProgramsList, this.getContactColsStructureList, this.getContactDetailsList, this.getContactDffStructureList, @@ -433,8 +431,6 @@ class GenericResponseModel { this.getOrganizationsSalariesList, this.getPaymentInformationList, this.getPayslipList, - // this.getPendingReqDetailsList, - // this.getPendingReqFunctionsList, this.getPerformanceAppraisalList, this.getPhonesNotificationBodyList, this.getPoItemHistoryList, @@ -469,6 +465,10 @@ class GenericResponseModel { this.getDepartmentSections, this.getPendingTransactionsFunctions, this.getPendingTransactionsDetails, + this.getConcurrentProgramsModel, + this.getCCPTransactionsModel, + this.getCCPOutputModel, + this.getCCPDFFStructureModel, this.getUserItemTypesList, this.getVacationRulesList, this.getVaccinationOnHandList, @@ -702,11 +702,7 @@ class GenericResponseModel { getCEICollectionNotificationBodyList = json['GetCEICollectionNotificationBodyList']; getCEIDFFStructureList = json['GetCEIDFFStructureList']; getCEITransactionList = json['GetCEITransactionList']; - getCcpDffStructureList = json['GetCcpDffStructureList']; - getCcpOutputList = json['GetCcpOutputList']; getCcpTransactionsList = json['GetCcpTransactionsList']; - getCcpTransactionsListNew = json['GetCcpTransactionsList_New']; - getConcurrentProgramsList = json['GetConcurrentProgramsList']; getContactColsStructureList = json['GetContactColsStructureList']; getContactDetailsList = json['GetContactDetailsList']; getContactDffStructureList = json['GetContactDffStructureList']; @@ -870,80 +866,105 @@ class GenericResponseModel { if (json['GetTimeCardSummaryList'] != null) { getTimeCardSummaryList = []; json['GetTimeCardSummaryList'].forEach((v) { - getTimeCardSummaryList!.add(new GetTimeCardSummaryList.fromJson(v)); + getTimeCardSummaryList!.add(GetTimeCardSummaryList.fromJson(v)); }); } if (json['Mohemm_ITG_TicketsByEmployeeList'] != null) { getTicketsByEmployeeList = []; json['Mohemm_ITG_TicketsByEmployeeList'].forEach((v) { - getTicketsByEmployeeList!.add(new GetTicketsByEmployeeList.fromJson(v)); + getTicketsByEmployeeList!.add(GetTicketsByEmployeeList.fromJson(v)); }); } if (json['Mohemm_ITG_TicketDetailsList'] != null) { getTicketDetailsByEmployee = []; json['Mohemm_ITG_TicketDetailsList'].forEach((v) { - getTicketDetailsByEmployee!.add(new GetTicketDetailsByEmployee.fromJson(v)); + getTicketDetailsByEmployee!.add(GetTicketDetailsByEmployee.fromJson(v)); }); } if (json['Mohemm_ITG_TicketTransactionsList'] != null) { getTicketTransactions = []; json['Mohemm_ITG_TicketTransactionsList'].forEach((v) { - getTicketTransactions!.add(new GetTicketTransactions.fromJson(v)); + getTicketTransactions!.add(GetTicketTransactions.fromJson(v)); }); } if (json['Mohemm_Itg_TicketTypesList'] != null) { getTicketTypes = []; json['Mohemm_Itg_TicketTypesList'].forEach((v) { - getTicketTypes!.add(new GetTicketTypes.fromJson(v)); + getTicketTypes!.add(GetTicketTypes.fromJson(v)); }); } if (json['Mohemm_Itg_ProjectsList'] != null) { getMowadhafhiProjects = []; json['Mohemm_Itg_ProjectsList'].forEach((v) { - getMowadhafhiProjects!.add(new GetMowadhafhiProjects.fromJson(v)); + getMowadhafhiProjects!.add(GetMowadhafhiProjects.fromJson(v)); }); } if (json['Mohemm_ITG_ProjectDepartmentsList'] != null) { getProjectDepartments = []; json['Mohemm_ITG_ProjectDepartmentsList'].forEach((v) { - getProjectDepartments!.add(new GetProjectDepartments.fromJson(v)); + getProjectDepartments!.add(GetProjectDepartments.fromJson(v)); }); } if (json['Mohemm_ITG_DepartmentSectionsList'] != null) { getDepartmentSections = []; json['Mohemm_ITG_DepartmentSectionsList'].forEach((v) { - getDepartmentSections!.add(new GetDepartmentSections.fromJson(v)); + getDepartmentSections!.add(GetDepartmentSections.fromJson(v)); }); } if (json['Mohemm_ITG_SectionTopicsList'] != null) { getSectionTopics = []; json['Mohemm_ITG_SectionTopicsList'].forEach((v) { - getSectionTopics!.add(new GetSectionTopics.fromJson(v)); + getSectionTopics!.add(GetSectionTopics.fromJson(v)); }); } if (json['GetPendingReqFunctionsList'] != null) { getPendingTransactionsFunctions = []; json['GetPendingReqFunctionsList'].forEach((v) { - getPendingTransactionsFunctions!.add(new GetPendingTransactionsFunctions.fromJson(v)); + getPendingTransactionsFunctions!.add(GetPendingTransactionsFunctions.fromJson(v)); }); } if (json['GetPendingReqDetailsList'] != null) { getPendingTransactionsDetails = []; json['GetPendingReqDetailsList'].forEach((v) { - getPendingTransactionsDetails!.add(new GetPendingTransactionsDetails.fromJson(v)); + getPendingTransactionsDetails!.add(GetPendingTransactionsDetails.fromJson(v)); }); } + if (json['GetConcurrentProgramsList'] != null) { + getConcurrentProgramsModel = []; + json['GetConcurrentProgramsList'].forEach((v) { + getConcurrentProgramsModel!.add(GetConcurrentProgramsModel.fromJson(v)); + }); + } + + if (json['GetCcpTransactionsList_New'] != null) { + getCCPTransactionsModel = []; + json['GetCcpTransactionsList_New'].forEach((v) { + getCCPTransactionsModel!.add(GetCCPTransactionsModel.fromJson(v)); + }); + } + + if (json['GetCcpDffStructureList'] != null) { + getEITDFFStructureList = []; + json['GetCcpDffStructureList'].forEach((v) { + getEITDFFStructureList!.add(GetEITDFFStructureList.fromJson(v)); + }); + } + + if (json['GetCcpOutputList'] != null) { + getCCPOutputModel = GetCCPOutputModel.fromJson(json['GetCcpOutputList']); + } + getUserItemTypesList = json['GetUserItemTypesList']; getVacationRulesList = json['GetVacationRulesList']; getVaccinationOnHandList = json['GetVaccinationOnHandList']; @@ -1213,11 +1234,8 @@ class GenericResponseModel { data['GetCEICollectionNotificationBodyList'] = this.getCEICollectionNotificationBodyList; data['GetCEIDFFStructureList'] = this.getCEIDFFStructureList; data['GetCEITransactionList'] = this.getCEITransactionList; - data['GetCcpDffStructureList'] = this.getCcpDffStructureList; - data['GetCcpOutputList'] = this.getCcpOutputList; data['GetCcpTransactionsList'] = this.getCcpTransactionsList; - data['GetCcpTransactionsList_New'] = this.getCcpTransactionsListNew; - data['GetConcurrentProgramsList'] = this.getConcurrentProgramsList; + // data['GetCcpTransactionsList_New'] = this.getCcpTransactionsListNew; data['GetContactColsStructureList'] = this.getContactColsStructureList; data['GetContactDetailsList'] = this.getContactDetailsList; data['GetContactDffStructureList'] = this.getContactDffStructureList; diff --git a/lib/models/my_requests/get_ccp_dff_structure_model.dart b/lib/models/my_requests/get_ccp_dff_structure_model.dart new file mode 100644 index 0000000..a170466 --- /dev/null +++ b/lib/models/my_requests/get_ccp_dff_structure_model.dart @@ -0,0 +1,220 @@ +class GetCCPDFFStructureModel { + String? aLPHANUMERICALLOWEDFLAG; + String? aPPLICATIONCOLUMNNAME; + String? cHILDSEGMENTSDV; + Null? cHILDSEGMENTSDVSplited; + String? cHILDSEGMENTSVS; + Null? cHILDSEGMENTSVSSplited; + String? dEFAULTTYPE; + String? dEFAULTVALUE; + String? dESCFLEXCONTEXTCODE; + String? dESCFLEXCONTEXTNAME; + String? dESCFLEXNAME; + String? dISPLAYFLAG; + String? eNABLEDFLAG; + ESERVICESDV? eSERVICESDV; + // List? eSERVICESVS; + String? fLEXVALUESETNAME; + String? fORMATTYPE; + String? fORMATTYPEDSP; + String? lONGLISTFLAG; + int? mAXIMUMSIZE; + String? mAXIMUMVALUE; + String? mINIMUMVALUE; + String? mOBILEENABLED; + String? nUMBERPRECISION; + String? nUMERICMODEENABLEDFLAG; + String? pARENTSEGMENTSDV; + List? pARENTSEGMENTSDVSplited; + String? pARENTSEGMENTSVS; + List? pARENTSEGMENTSVSSplitedVS; + String? rEADONLY; + String? rEQUIREDFLAG; + String? sEGMENTNAME; + String? sEGMENTPROMPT; + int? sEGMENTSEQNUM; + String? uPPERCASEONLYFLAG; + String? uSEDFLAG; + String? vALIDATIONTYPE; + String? vALIDATIONTYPEDSP; + + GetCCPDFFStructureModel( + {this.aLPHANUMERICALLOWEDFLAG, + this.aPPLICATIONCOLUMNNAME, + this.cHILDSEGMENTSDV, + this.cHILDSEGMENTSDVSplited, + this.cHILDSEGMENTSVS, + this.cHILDSEGMENTSVSSplited, + this.dEFAULTTYPE, + this.dEFAULTVALUE, + this.dESCFLEXCONTEXTCODE, + this.dESCFLEXCONTEXTNAME, + this.dESCFLEXNAME, + this.dISPLAYFLAG, + this.eNABLEDFLAG, + this.eSERVICESDV, + // this.eSERVICESVS, + this.fLEXVALUESETNAME, + this.fORMATTYPE, + this.fORMATTYPEDSP, + this.lONGLISTFLAG, + this.mAXIMUMSIZE, + this.mAXIMUMVALUE, + this.mINIMUMVALUE, + this.mOBILEENABLED, + this.nUMBERPRECISION, + this.nUMERICMODEENABLEDFLAG, + this.pARENTSEGMENTSDV, + this.pARENTSEGMENTSDVSplited, + this.pARENTSEGMENTSVS, + this.pARENTSEGMENTSVSSplitedVS, + this.rEADONLY, + this.rEQUIREDFLAG, + this.sEGMENTNAME, + this.sEGMENTPROMPT, + this.sEGMENTSEQNUM, + this.uPPERCASEONLYFLAG, + this.uSEDFLAG, + this.vALIDATIONTYPE, + this.vALIDATIONTYPEDSP}); + + GetCCPDFFStructureModel.fromJson(Map json) { + aLPHANUMERICALLOWEDFLAG = json['ALPHANUMERIC_ALLOWED_FLAG']; + aPPLICATIONCOLUMNNAME = json['APPLICATION_COLUMN_NAME']; + cHILDSEGMENTSDV = json['CHILD_SEGMENTS_DV']; + cHILDSEGMENTSDVSplited = json['CHILD_SEGMENTS_DV_Splited']; + cHILDSEGMENTSVS = json['CHILD_SEGMENTS_VS']; + cHILDSEGMENTSVSSplited = json['CHILD_SEGMENTS_VS_Splited']; + dEFAULTTYPE = json['DEFAULT_TYPE']; + dEFAULTVALUE = json['DEFAULT_VALUE']; + dESCFLEXCONTEXTCODE = json['DESC_FLEX_CONTEXT_CODE']; + dESCFLEXCONTEXTNAME = json['DESC_FLEX_CONTEXT_NAME']; + dESCFLEXNAME = json['DESC_FLEX_NAME']; + dISPLAYFLAG = json['DISPLAY_FLAG']; + eNABLEDFLAG = json['ENABLED_FLAG']; + eSERVICESDV = json['E_SERVICES_DV'] != null + ? new ESERVICESDV.fromJson(json['E_SERVICES_DV']) + : null; + // if (json['E_SERVICES_VS'] != null) { + // eSERVICESVS = []; + // json['E_SERVICES_VS'].forEach((v) { + // eSERVICESVS!.add(new Null.fromJson(v)); + // }); + // } + fLEXVALUESETNAME = json['FLEX_VALUE_SET_NAME']; + fORMATTYPE = json['FORMAT_TYPE']; + fORMATTYPEDSP = json['FORMAT_TYPE_DSP']; + lONGLISTFLAG = json['LONGLIST_FLAG']; + mAXIMUMSIZE = json['MAXIMUM_SIZE']; + mAXIMUMVALUE = json['MAXIMUM_VALUE']; + mINIMUMVALUE = json['MINIMUM_VALUE']; + mOBILEENABLED = json['MOBILE_ENABLED']; + nUMBERPRECISION = json['NUMBER_PRECISION']; + nUMERICMODEENABLEDFLAG = json['NUMERIC_MODE_ENABLED_FLAG']; + pARENTSEGMENTSDV = json['PARENT_SEGMENTS_DV']; + // if (json['PARENT_SEGMENTS_DV_Splited'] != null) { + // pARENTSEGMENTSDVSplited = []; + // json['PARENT_SEGMENTS_DV_Splited'].forEach((v) { + // pARENTSEGMENTSDVSplited!.add(new Null.fromJson(v)); + // }); + // } + // pARENTSEGMENTSVS = json['PARENT_SEGMENTS_VS']; + // if (json['PARENT_SEGMENTS_VS_SplitedVS'] != null) { + // pARENTSEGMENTSVSSplitedVS = []; + // json['PARENT_SEGMENTS_VS_SplitedVS'].forEach((v) { + // pARENTSEGMENTSVSSplitedVS!.add(new Null.fromJson(v)); + // }); + // } + rEADONLY = json['READ_ONLY']; + rEQUIREDFLAG = json['REQUIRED_FLAG']; + sEGMENTNAME = json['SEGMENT_NAME']; + sEGMENTPROMPT = json['SEGMENT_PROMPT']; + sEGMENTSEQNUM = json['SEGMENT_SEQ_NUM']; + uPPERCASEONLYFLAG = json['UPPERCASE_ONLY_FLAG']; + uSEDFLAG = json['USED_FLAG']; + vALIDATIONTYPE = json['VALIDATION_TYPE']; + vALIDATIONTYPEDSP = json['VALIDATION_TYPE_DSP']; + } + + Map toJson() { + final Map data = new Map(); + data['ALPHANUMERIC_ALLOWED_FLAG'] = this.aLPHANUMERICALLOWEDFLAG; + data['APPLICATION_COLUMN_NAME'] = this.aPPLICATIONCOLUMNNAME; + data['CHILD_SEGMENTS_DV'] = this.cHILDSEGMENTSDV; + data['CHILD_SEGMENTS_DV_Splited'] = this.cHILDSEGMENTSDVSplited; + data['CHILD_SEGMENTS_VS'] = this.cHILDSEGMENTSVS; + data['CHILD_SEGMENTS_VS_Splited'] = this.cHILDSEGMENTSVSSplited; + data['DEFAULT_TYPE'] = this.dEFAULTTYPE; + data['DEFAULT_VALUE'] = this.dEFAULTVALUE; + data['DESC_FLEX_CONTEXT_CODE'] = this.dESCFLEXCONTEXTCODE; + data['DESC_FLEX_CONTEXT_NAME'] = this.dESCFLEXCONTEXTNAME; + data['DESC_FLEX_NAME'] = this.dESCFLEXNAME; + data['DISPLAY_FLAG'] = this.dISPLAYFLAG; + data['ENABLED_FLAG'] = this.eNABLEDFLAG; + if (this.eSERVICESDV != null) { + data['E_SERVICES_DV'] = this.eSERVICESDV!.toJson(); + } + // if (this.eSERVICESVS != null) { + // data['E_SERVICES_VS'] = this.eSERVICESVS!.map((v) => v.toJson()).toList(); + // } + data['FLEX_VALUE_SET_NAME'] = this.fLEXVALUESETNAME; + data['FORMAT_TYPE'] = this.fORMATTYPE; + data['FORMAT_TYPE_DSP'] = this.fORMATTYPEDSP; + data['LONGLIST_FLAG'] = this.lONGLISTFLAG; + data['MAXIMUM_SIZE'] = this.mAXIMUMSIZE; + data['MAXIMUM_VALUE'] = this.mAXIMUMVALUE; + data['MINIMUM_VALUE'] = this.mINIMUMVALUE; + data['MOBILE_ENABLED'] = this.mOBILEENABLED; + data['NUMBER_PRECISION'] = this.nUMBERPRECISION; + data['NUMERIC_MODE_ENABLED_FLAG'] = this.nUMERICMODEENABLEDFLAG; + data['PARENT_SEGMENTS_DV'] = this.pARENTSEGMENTSDV; + // if (this.pARENTSEGMENTSDVSplited != null) { + // data['PARENT_SEGMENTS_DV_Splited'] = + // this.pARENTSEGMENTSDVSplited!.map((v) => v.toJson()).toList(); + // } + data['PARENT_SEGMENTS_VS'] = this.pARENTSEGMENTSVS; + // if (this.pARENTSEGMENTSVSSplitedVS != null) { + // data['PARENT_SEGMENTS_VS_SplitedVS'] = + // this.pARENTSEGMENTSVSSplitedVS!.map((v) => v.toJson()).toList(); + // } + data['READ_ONLY'] = this.rEADONLY; + data['REQUIRED_FLAG'] = this.rEQUIREDFLAG; + data['SEGMENT_NAME'] = this.sEGMENTNAME; + data['SEGMENT_PROMPT'] = this.sEGMENTPROMPT; + data['SEGMENT_SEQ_NUM'] = this.sEGMENTSEQNUM; + data['UPPERCASE_ONLY_FLAG'] = this.uPPERCASEONLYFLAG; + data['USED_FLAG'] = this.uSEDFLAG; + data['VALIDATION_TYPE'] = this.vALIDATIONTYPE; + data['VALIDATION_TYPE_DSP'] = this.vALIDATIONTYPEDSP; + return data; + } +} + +class ESERVICESDV { + String? pIDCOLUMNNAME; + String? pRETURNMSG; + String? pRETURNSTATUS; + String? pVALUECOLUMNNAME; + + ESERVICESDV( + {this.pIDCOLUMNNAME, + this.pRETURNMSG, + this.pRETURNSTATUS, + this.pVALUECOLUMNNAME}); + + ESERVICESDV.fromJson(Map json) { + pIDCOLUMNNAME = json['P_ID_COLUMN_NAME']; + pRETURNMSG = json['P_RETURN_MSG']; + pRETURNSTATUS = json['P_RETURN_STATUS']; + pVALUECOLUMNNAME = json['P_VALUE_COLUMN_NAME']; + } + + Map toJson() { + final Map data = new Map(); + data['P_ID_COLUMN_NAME'] = this.pIDCOLUMNNAME; + data['P_RETURN_MSG'] = this.pRETURNMSG; + data['P_RETURN_STATUS'] = this.pRETURNSTATUS; + data['P_VALUE_COLUMN_NAME'] = this.pVALUECOLUMNNAME; + return data; + } +} diff --git a/lib/models/my_requests/get_ccp_output_model.dart b/lib/models/my_requests/get_ccp_output_model.dart new file mode 100644 index 0000000..3615a26 --- /dev/null +++ b/lib/models/my_requests/get_ccp_output_model.dart @@ -0,0 +1,21 @@ +class GetCCPOutputModel { + String? pOUTPUTFILE; + String? pRETURNMSG; + String? pRETURNSTATUS; + + GetCCPOutputModel({this.pOUTPUTFILE, this.pRETURNMSG, this.pRETURNSTATUS}); + + GetCCPOutputModel.fromJson(Map json) { + pOUTPUTFILE = json['P_OUTPUT_FILE']; + pRETURNMSG = json['P_RETURN_MSG']; + pRETURNSTATUS = json['P_RETURN_STATUS']; + } + + Map toJson() { + final Map data = new Map(); + data['P_OUTPUT_FILE'] = this.pOUTPUTFILE; + data['P_RETURN_MSG'] = this.pRETURNMSG; + data['P_RETURN_STATUS'] = this.pRETURNSTATUS; + return data; + } +} diff --git a/lib/models/my_requests/get_ccp_transactions_model.dart b/lib/models/my_requests/get_ccp_transactions_model.dart new file mode 100644 index 0000000..9b31244 --- /dev/null +++ b/lib/models/my_requests/get_ccp_transactions_model.dart @@ -0,0 +1,32 @@ +class GetCCPTransactionsModel { + String? cCPPHASE; + String? cCPSTATUS; + String? cONCURRENTPROGRAMNAME; + String? rEQUESTDATE; + int? rEQUESTID; + + GetCCPTransactionsModel( + {this.cCPPHASE, + this.cCPSTATUS, + this.cONCURRENTPROGRAMNAME, + this.rEQUESTDATE, + this.rEQUESTID}); + + GetCCPTransactionsModel.fromJson(Map json) { + cCPPHASE = json['CCP_PHASE']; + cCPSTATUS = json['CCP_STATUS']; + cONCURRENTPROGRAMNAME = json['CONCURRENT_PROGRAM_NAME']; + rEQUESTDATE = json['REQUEST_DATE']; + rEQUESTID = json['REQUEST_ID']; + } + + Map toJson() { + final Map data = new Map(); + data['CCP_PHASE'] = this.cCPPHASE; + data['CCP_STATUS'] = this.cCPSTATUS; + data['CONCURRENT_PROGRAM_NAME'] = this.cONCURRENTPROGRAMNAME; + data['REQUEST_DATE'] = this.rEQUESTDATE; + data['REQUEST_ID'] = this.rEQUESTID; + return data; + } +} diff --git a/lib/models/my_requests/get_concurrent_programs_model.dart b/lib/models/my_requests/get_concurrent_programs_model.dart new file mode 100644 index 0000000..65de317 --- /dev/null +++ b/lib/models/my_requests/get_concurrent_programs_model.dart @@ -0,0 +1,24 @@ +class GetConcurrentProgramsModel { + int? cONCURRENTPROGRAMID; + String? cONCURRENTPROGRAMNAME; + String? uSERCONCURRENTPROGRAMNAME; + + GetConcurrentProgramsModel( + {this.cONCURRENTPROGRAMID, + this.cONCURRENTPROGRAMNAME, + this.uSERCONCURRENTPROGRAMNAME}); + + GetConcurrentProgramsModel.fromJson(Map json) { + cONCURRENTPROGRAMID = json['CONCURRENT_PROGRAM_ID']; + cONCURRENTPROGRAMNAME = json['CONCURRENT_PROGRAM_NAME']; + uSERCONCURRENTPROGRAMNAME = json['USER_CONCURRENT_PROGRAM_NAME']; + } + + Map toJson() { + final Map data = new Map(); + data['CONCURRENT_PROGRAM_ID'] = this.cONCURRENTPROGRAMID; + data['CONCURRENT_PROGRAM_NAME'] = this.cONCURRENTPROGRAMNAME; + data['USER_CONCURRENT_PROGRAM_NAME'] = this.uSERCONCURRENTPROGRAMNAME; + return data; + } +} diff --git a/lib/ui/landing/widget/app_drawer.dart b/lib/ui/landing/widget/app_drawer.dart index c19fab7..346f93a 100644 --- a/lib/ui/landing/widget/app_drawer.dart +++ b/lib/ui/landing/widget/app_drawer.dart @@ -49,6 +49,16 @@ class _AppDrawerState extends State { ), onTap: () { drawerNavigator(context, AppRoutes.pendingTransactions); + }), + const Divider(), + InkWell( + child: const DrawerItem( + 'My Requests', + icon: Icons.person, + color: Colors.grey, + ), + onTap: () { + drawerNavigator(context, AppRoutes.myRequests); }) ])) ]))); diff --git a/lib/ui/screens/my_requests/my_requests.dart b/lib/ui/screens/my_requests/my_requests.dart new file mode 100644 index 0000000..82bc38b --- /dev/null +++ b/lib/ui/screens/my_requests/my_requests.dart @@ -0,0 +1,218 @@ +import 'dart:io'; + +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:mohem_flutter_app/api/my_requests_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/file_process.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/get_eit_dff_structure_list_model.dart'; +import 'package:mohem_flutter_app/models/my_requests/get_ccp_output_model.dart'; +import 'package:mohem_flutter_app/models/my_requests/get_ccp_transactions_model.dart'; +import 'package:mohem_flutter_app/models/my_requests/get_concurrent_programs_model.dart'; +import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; +import 'package:mohem_flutter_app/widgets/button/default_button.dart'; +import 'package:mohem_flutter_app/widgets/dynamic_forms/dynamic_textfield_widget.dart'; + +class MyRequests extends StatefulWidget { + const MyRequests({Key? key}) : super(key: key); + + @override + _MyRequestsState createState() => _MyRequestsState(); +} + +class _MyRequestsState extends State { + List getConcurrentProgramsList = []; + GetConcurrentProgramsModel? selectedConcurrentProgramList; + + List getCCPTransactionsList = []; + + bool isNewRequest = false; + + @override + void initState() { + getConcurrentPrograms(); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBarWidget( + context, + title: "Concurrent Reports", + ), + body: 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), + ), + ], + ), + child: Column( + children: [ + 12.height, + Container( + padding: const EdgeInsets.only(left: 12, right: 12, top: 10, bottom: 0), + margin: const EdgeInsets.only(left: 12, right: 12, top: 0, bottom: 0), + child: PopupMenuButton( + child: DynamicTextFieldWidget( + "Template Name", + selectedConcurrentProgramList?.uSERCONCURRENTPROGRAMNAME ?? "", + isEnable: false, + isPopup: true, + isInputTypeNum: true, + isReadOnly: false, + ).paddingOnly(bottom: 12), + itemBuilder: (_) => >[ + for (int i = 0; i < getConcurrentProgramsList!.length; i++) PopupMenuItem(child: Text(getConcurrentProgramsList![i].uSERCONCURRENTPROGRAMNAME!), value: i), + ], + onSelected: (int popupIndex) { + selectedConcurrentProgramList = getConcurrentProgramsList![popupIndex]; + getCCPTransactions(selectedConcurrentProgramList?.cONCURRENTPROGRAMNAME); + setState(() {}); + }), + ), + 12.height, + Expanded( + child: ListView.separated( + physics: const BouncingScrollPhysics(), + shrinkWrap: true, + itemBuilder: (BuildContext context, int index) { + return Container( + width: double.infinity, + padding: const EdgeInsets.only(left: 12, right: 12, top: 10, bottom: 12), + margin: const EdgeInsets.only(left: 12, right: 12, top: 10, bottom: 0), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: const Color(0xff000000).withOpacity(.05), + blurRadius: 26, + offset: const Offset(0, -3), + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + ("Request ID: " + getCCPTransactionsList[index].rEQUESTID.toString()).toText12(color: MyColors.grey57Color), + DateUtil.formatDateToDate(DateUtil.convertStringToDate(getCCPTransactionsList[index].rEQUESTDATE!), false).toText12(color: MyColors.grey70Color), + ], + ), + Container( + padding: const EdgeInsets.only(top: 10.0), + child: ("Phase: " + getCCPTransactionsList[index].cCPPHASE!).toText12(color: MyColors.grey57Color, isBold: true), + ), + Container( + padding: const EdgeInsets.only(top: 10.0), + child: "Program Name: ".toText12(color: MyColors.grey57Color, isBold: true), + ), + getCCPTransactionsList[index].cONCURRENTPROGRAMNAME!.toText12(color: MyColors.gradiantEndColor), + Container( + padding: const EdgeInsets.only(top: 10.0), + child: InkWell( + onTap: () { + getCCPOutput(getCCPTransactionsList[index].rEQUESTID.toString()); + }, + child: Row( + children: [ + "Output: ".toText12(color: MyColors.grey57Color), + 8.width, + "Open PDF".toText12(color: MyColors.grey57Color), + 6.width, + const Icon(Icons.launch, size: 16.0), + ], + ), + ), + ), + ], + ), + ); + }, + separatorBuilder: (BuildContext context, int index) => 12.height, + itemCount: getCCPTransactionsList.length ?? 0)), + 80.height + ], + ), + ), + bottomSheet: Container( + decoration: const BoxDecoration( + color: MyColors.white, + boxShadow: [ + BoxShadow(color: MyColors.lightGreyEFColor, spreadRadius: 3), + ], + ), + child: DefaultButton(LocaleKeys.createRequest.tr(), () async { + openNewRequest(); + }).insideContainer, + )); + } + + void openNewRequest() async { + await Navigator.pushNamed(context, AppRoutes.newRequest).then((value) { + // getOpenTickets(); + }); + } + + void getConcurrentPrograms() async { + try { + Utils.showLoading(context); + getConcurrentProgramsList = await MyRequestsApiClient().getConcurrentPrograms(); + Utils.hideLoading(context); + setState(() {}); + } catch (ex) { + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + } + } + + void getCCPTransactions(String? templateName) async { + try { + Utils.showLoading(context); + getCCPTransactionsList = await MyRequestsApiClient().getCCPTransactions(templateName); + Utils.hideLoading(context); + setState(() {}); + } catch (ex) { + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + } + } + + void getCCPOutput(String requestID) async { + GetCCPOutputModel getCCPOutputModel; + try { + Utils.showLoading(context); + getCCPOutputModel = await MyRequestsApiClient().getCCPOutput(requestID); + Utils.hideLoading(context); + await FileProcess.downloadFile(getCCPOutputModel.pOUTPUTFILE!, requestID).then((value) { + File file = value; + debugPrint(file.toString()); + FileProcess.openFile(requestID); + }); + setState(() {}); + } catch (ex) { + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + } + } +} diff --git a/lib/ui/screens/my_requests/new_request.dart b/lib/ui/screens/my_requests/new_request.dart new file mode 100644 index 0000000..7e19646 --- /dev/null +++ b/lib/ui/screens/my_requests/new_request.dart @@ -0,0 +1,423 @@ +import 'dart:io'; + +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:mohem_flutter_app/api/my_requests_api_client.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/get_eit_dff_structure_list_model.dart'; +import 'package:mohem_flutter_app/models/my_requests/get_concurrent_programs_model.dart'; +import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; +import 'package:mohem_flutter_app/widgets/button/default_button.dart'; +import 'package:mohem_flutter_app/widgets/dynamic_forms/dynamic_textfield_widget.dart'; + +class NewRequest extends StatefulWidget { + const NewRequest({Key? key}) : super(key: key); + + @override + _NewRequestState createState() => _NewRequestState(); +} + +class _NewRequestState extends State { + List getConcurrentProgramsList = []; + GetConcurrentProgramsModel? selectedConcurrentProgramList; + + List getCCPDFFStructureModelList = []; + + DateTime selectedDate = DateTime.now(); + + @override + void initState() { + getConcurrentPrograms(); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBarWidget( + context, + title: "Concurrent Reports", + ), + body: Container( + child: Column( + children: [ + 12.height, + Container( + padding: const EdgeInsets.only(left: 12, right: 12, top: 10, bottom: 0), + margin: const EdgeInsets.only(left: 12, right: 12, top: 0, bottom: 0), + child: PopupMenuButton( + child: DynamicTextFieldWidget( + "Template Name", + selectedConcurrentProgramList?.uSERCONCURRENTPROGRAMNAME ?? "", + isEnable: false, + isPopup: true, + isInputTypeNum: true, + isReadOnly: false, + ).paddingOnly(bottom: 12), + itemBuilder: (_) => >[ + for (int i = 0; i < getConcurrentProgramsList!.length; i++) PopupMenuItem(child: Text(getConcurrentProgramsList![i].uSERCONCURRENTPROGRAMNAME!), value: i), + ], + onSelected: (int popupIndex) { + selectedConcurrentProgramList = getConcurrentProgramsList![popupIndex]; + getCCPDFFStructure(selectedConcurrentProgramList?.cONCURRENTPROGRAMNAME); + setState(() {}); + }), + ), + (getCCPDFFStructureModelList.isEmpty + ? LocaleKeys.noDataAvailable.tr().toText16().center + : ListView.separated( + physics: const BouncingScrollPhysics(), + padding: const EdgeInsets.all(21), + itemBuilder: (cxt, int parentIndex) => parseDynamicFormatType(getCCPDFFStructureModelList[parentIndex], parentIndex), + separatorBuilder: (cxt, index) => 0.height, + itemCount: getCCPDFFStructureModelList.length)) + .expanded + ], + ), + ), + bottomSheet: Container( + decoration: const BoxDecoration( + color: MyColors.white, + boxShadow: [ + BoxShadow(color: MyColors.lightGreyEFColor, spreadRadius: 3), + ], + ), + child: DefaultButton(LocaleKeys.submit.tr(), () async { + // openNewRequest(); + }).insideContainer, + ) + ); + } + + void getConcurrentPrograms() async { + try { + Utils.showLoading(context); + getConcurrentProgramsList = await MyRequestsApiClient().getConcurrentPrograms(); + Utils.hideLoading(context); + setState(() {}); + } catch (ex) { + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + } + } + + void getCCPDFFStructure(String? templateName) async { + try { + Utils.showLoading(context); + getCCPDFFStructureModelList = await MyRequestsApiClient().getCCPDFFStructure(templateName); + Utils.hideLoading(context); + setState(() {}); + } catch (ex) { + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + } + } + + Widget parseDynamicFormatType(GetEITDFFStructureList model, int index) { + if (model.dISPLAYFLAG != "N") { + if (model.vALIDATIONTYPE == "N") { + if (model.fORMATTYPE == "C") { + return DynamicTextFieldWidget( + (model.sEGMENTPROMPT ?? "") + (model.rEQUIREDFLAG == "Y" ? "*" : ""), + model.eSERVICESDV?.pIDCOLUMNNAME ?? "", + isReadOnly: model.rEADONLY == "Y", + onChange: (text) { + model.fieldAnswer = text; + if (model.eSERVICESDV == null) { + model.eSERVICESDV = ESERVICESDV(); + } + model.eSERVICESDV!.pIDCOLUMNNAME = text; + }, + ).paddingOnly(bottom: 12); + } else if (model.fORMATTYPE == "N") { + return DynamicTextFieldWidget( + (model.sEGMENTPROMPT ?? "") + (model.rEQUIREDFLAG == "Y" ? "*" : ""), + model.eSERVICESDV?.pIDCOLUMNNAME ?? "", + isReadOnly: model.rEADONLY == "Y", + isInputTypeNum: true, + onChange: (text) { + model.fieldAnswer = text; + if (model.eSERVICESDV == null) { + model.eSERVICESDV = ESERVICESDV(); + } + model.eSERVICESDV!.pIDCOLUMNNAME = text; + }, + ).paddingOnly(bottom: 12); + } else if (model.fORMATTYPE == "X") { + String displayText = model.eSERVICESDV?.pIDCOLUMNNAME ?? (getCCPDFFStructureModelList![index].fieldAnswer ?? ""); + if (getCCPDFFStructureModelList![index].isDefaultTypeIsCDPS) { + if (displayText.contains(" 00:00:00")) { + displayText = displayText.replaceAll(" 00:00:00", ""); + } + if (!displayText.contains("-")) { + displayText = DateFormat('yyyy-MM-dd').format(DateFormat("yyyy/MM/dd").parse(displayText)); + } + } + return DynamicTextFieldWidget( + (model.sEGMENTPROMPT ?? "") + (model.rEQUIREDFLAG == "Y" ? "*" : ""), + displayText, + suffixIconData: Icons.calendar_today, + isEnable: false, + onTap: () async { + if ((getCCPDFFStructureModelList![index].eSERVICESDV?.pVALUECOLUMNNAME != null)) { + if (getCCPDFFStructureModelList![index].isDefaultTypeIsCDPS) { + selectedDate = DateFormat("yyyy/MM/dd").parse(getCCPDFFStructureModelList![index].eSERVICESDV!.pVALUECOLUMNNAME!.replaceAll('/"', '').replaceAll(" 00:00:00", "")); + } else { + selectedDate = DateTime.parse(getCCPDFFStructureModelList![index].eSERVICESDV!.pVALUECOLUMNNAME!); + } + } + DateTime date = await _selectDate(context); + DateTime date1 = DateTime(date.year, date.month, date.day); + // getEitDffStructureList![index].fieldAnswer = date.toString(); + ESERVICESDV eservicesdv; + if (getCCPDFFStructureModelList![index].isDefaultTypeIsCDPS) { + eservicesdv = ESERVICESDV( + pIDCOLUMNNAME: DateFormat('yyyy/MM/dd HH:MM:SS').format(date1), + pRETURNMSG: "null", + pRETURNSTATUS: getCCPDFFStructureModelList![index].dEFAULTVALUE, + pVALUECOLUMNNAME: getCCPDFFStructureModelList![index].isDefaultTypeIsCDPS ? DateFormat('yyyy/MM/dd HH:MM:SS').format(date) : DateFormat('yyyy-MM-ddThh:mm:ss.s').format(date)); + } else { + eservicesdv = ESERVICESDV( + pIDCOLUMNNAME: DateFormat('yyyy-MM-dd').format(date1), + pRETURNMSG: "null", + pRETURNSTATUS: getCCPDFFStructureModelList![index].dEFAULTVALUE, + pVALUECOLUMNNAME: getCCPDFFStructureModelList![index].isDefaultTypeIsCDPS ? DateFormat('yyyy-MM-dd hh:mm:ss').format(date) : DateFormat('yyyy-MM-ddThh:mm:ss.s').format(date)); + } + getCCPDFFStructureModelList![index].eSERVICESDV = eservicesdv; + setState(() {}); + if (model.cHILDSEGMENTSDVSplited?.isNotEmpty ?? false) { + // calGetValueSetValues(model); + } + }, + ).paddingOnly(bottom: 12); + } else if (model.fORMATTYPE == "Y") { + String displayText = model.eSERVICESDV?.pIDCOLUMNNAME ?? (getCCPDFFStructureModelList![index].fieldAnswer ?? ""); + if (getCCPDFFStructureModelList![index].isDefaultTypeIsCDPS) { + if (displayText.contains(" 00:00:00")) { + displayText = displayText.replaceAll(" 00:00:00", ""); + } + if (!displayText.contains("-")) { + displayText = DateFormat('yyyy-MM-dd').format(DateFormat("yyyy/MM/dd").parse(displayText)); + } + } + return DynamicTextFieldWidget( + (model.sEGMENTPROMPT ?? "") + (model.rEQUIREDFLAG == "Y" ? "*" : ""), + displayText, + suffixIconData: Icons.calendar_today, + isEnable: false, + onTap: () async { + if ((getCCPDFFStructureModelList![index].eSERVICESDV?.pVALUECOLUMNNAME != null)) { + if (getCCPDFFStructureModelList![index].isDefaultTypeIsCDPS) { + String tempDate = getCCPDFFStructureModelList![index].eSERVICESDV!.pVALUECOLUMNNAME!; + if (tempDate.contains("00:00:00")) { + tempDate = tempDate.replaceAll("00:00:00", '').trim(); + } + selectedDate = DateFormat("yyyy/MM/dd").parse(tempDate); + } else { + selectedDate = DateTime.parse(getCCPDFFStructureModelList![index].eSERVICESDV!.pVALUECOLUMNNAME!); + } + } + DateTime date = await _selectDate(context); + DateTime date1 = DateTime(date.year, date.month, date.day); + // getEitDffStructureList![index].fieldAnswer = date.toString(); + ESERVICESDV eservicesdv; + if (getCCPDFFStructureModelList![index].isDefaultTypeIsCDPS) { + eservicesdv = ESERVICESDV( + pIDCOLUMNNAME: DateFormat('yyyy/MM/dd HH:MM:SS').format(date1), + pRETURNMSG: "null", + pRETURNSTATUS: getCCPDFFStructureModelList![index].dEFAULTVALUE, + pVALUECOLUMNNAME: getCCPDFFStructureModelList![index].isDefaultTypeIsCDPS ? DateFormat('yyyy-MM-dd HH:MM:SS').format(date) : DateFormat('yyyy-MM-ddThh:mm:ss.s').format(date)); + } else { + eservicesdv = ESERVICESDV( + pIDCOLUMNNAME: DateFormat('yyyy-MM-dd').format(date1), + pRETURNMSG: "null", + pRETURNSTATUS: getCCPDFFStructureModelList![index].dEFAULTVALUE, + pVALUECOLUMNNAME: getCCPDFFStructureModelList![index].isDefaultTypeIsCDPS ? DateFormat('yyyy-MM-dd hh:mm:ss').format(date) : DateFormat('yyyy-MM-ddThh:mm:ss.s').format(date)); + } + + getCCPDFFStructureModelList![index].eSERVICESDV = eservicesdv; + setState(() {}); + if (model.cHILDSEGMENTSDVSplited?.isNotEmpty ?? false) { + if (getCCPDFFStructureModelList![index].isDefaultTypeIsCDPS) { + // calGetValueSetValues(model); + } else {} + } + }, + ).paddingOnly(bottom: 12); + } + } else { + return PopupMenuButton( + child: DynamicTextFieldWidget( + (model.sEGMENTPROMPT ?? "") + (model.rEQUIREDFLAG == "Y" ? "*" : ""), + model.eSERVICESDV?.pVALUECOLUMNNAME ?? "", + isEnable: false, + isPopup: true, + isInputTypeNum: true, + isReadOnly: model.rEADONLY == "Y", + ).paddingOnly(bottom: 12), + itemBuilder: (_) => >[ + for (int i = 0; i < model.eSERVICESVS!.length; i++) PopupMenuItem(child: Text(model.eSERVICESVS![i].vALUECOLUMNNAME!), value: i), + ], + onSelected: (int popipIndex) { + ESERVICESDV eservicesdv = ESERVICESDV( + pIDCOLUMNNAME: model.eSERVICESVS![popipIndex].iDCOLUMNNAME, + pRETURNMSG: "null", + pRETURNSTATUS: getCCPDFFStructureModelList![popipIndex].dEFAULTVALUE, + pVALUECOLUMNNAME: model.eSERVICESVS![popipIndex].vALUECOLUMNNAME); + getCCPDFFStructureModelList![index].eSERVICESDV = eservicesdv; + setState(() {}); + if (model.cHILDSEGMENTSDVSplited?.isNotEmpty ?? false) { + // getDefaultValues(model); + } + }); + } + } else { + return const SizedBox(); + } + if (model.fORMATTYPE == "N") { + if (model.eSERVICESVS?.isNotEmpty ?? false) { + return PopupMenuButton( + child: DynamicTextFieldWidget( + (model.sEGMENTPROMPT ?? "") + (model.rEQUIREDFLAG == "Y" ? "*" : ""), + model.eSERVICESDV?.pVALUECOLUMNNAME ?? "", + isEnable: false, + isPopup: true, + isInputTypeNum: true, + isReadOnly: model.rEADONLY == "Y", + ).paddingOnly(bottom: 12), + itemBuilder: (_) => >[ + for (int i = 0; i < model.eSERVICESVS!.length; i++) PopupMenuItem(child: Text(model.eSERVICESVS![i].vALUECOLUMNNAME!), value: i), + ], + onSelected: (int popipIndex) { + ESERVICESDV eservicesdv = ESERVICESDV( + pIDCOLUMNNAME: model.eSERVICESVS![popipIndex].iDCOLUMNNAME, + pRETURNMSG: "null", + pRETURNSTATUS: getCCPDFFStructureModelList![popipIndex].dEFAULTVALUE, + pVALUECOLUMNNAME: model.eSERVICESVS![popipIndex].vALUECOLUMNNAME); + getCCPDFFStructureModelList![index].eSERVICESDV = eservicesdv; + setState(() {}); + if (model.cHILDSEGMENTSDVSplited?.isNotEmpty ?? false) { + // getDefaultValues(model); + } + }); + } + + return DynamicTextFieldWidget( + (model.sEGMENTPROMPT ?? "") + (model.rEQUIREDFLAG == "Y" ? "*" : ""), + model.eSERVICESDV?.pIDCOLUMNNAME ?? "", + isReadOnly: model.rEADONLY == "Y", + onChange: (text) { + model.fieldAnswer = text; + }, + ).paddingOnly(bottom: 12); + } else if (model.fORMATTYPE == "X" || model.fORMATTYPE == "Y") { + String displayText = model.eSERVICESDV?.pIDCOLUMNNAME ?? (getCCPDFFStructureModelList![index].fieldAnswer ?? ""); + if (getCCPDFFStructureModelList![index].isDefaultTypeIsCDPS) { + if (displayText.contains(" 00:00:00")) { + displayText = displayText.replaceAll(" 00:00:00", ""); + } + if (!displayText.contains("-")) { + displayText = DateFormat('yyyy-MM-dd').format(DateFormat("yyyy/MM/dd").parse(displayText)); + } + } + return DynamicTextFieldWidget( + (model.sEGMENTPROMPT ?? "") + (model.rEQUIREDFLAG == "Y" ? "*" : ""), + displayText, + suffixIconData: Icons.calendar_today, + isEnable: false, + onTap: () async { + if ((getCCPDFFStructureModelList![index].eSERVICESDV?.pVALUECOLUMNNAME != null)) { + if (getCCPDFFStructureModelList![index].isDefaultTypeIsCDPS) { + selectedDate = DateFormat("yyyy/MM/dd").parse(getCCPDFFStructureModelList![index].eSERVICESDV!.pVALUECOLUMNNAME!.replaceAll('/"', '').replaceAll(" 00:00:00", "")); + } else { + selectedDate = DateTime.parse(getCCPDFFStructureModelList![index].eSERVICESDV!.pVALUECOLUMNNAME!); + } + } + DateTime date = await _selectDate(context); + DateTime date1 = DateTime(date.year, date.month, date.day); + getCCPDFFStructureModelList![index].fieldAnswer = date.toString(); + ESERVICESDV eservicesdv = ESERVICESDV( + pIDCOLUMNNAME: DateFormat('yyyy-MM-dd').format(date1), + pRETURNMSG: "null", + pRETURNSTATUS: getCCPDFFStructureModelList![index].dEFAULTVALUE, + pVALUECOLUMNNAME: getCCPDFFStructureModelList![index].isDefaultTypeIsCDPS ? DateFormat('yyyy-MM-dd hh:mm:ss').format(date) : DateFormat('yyyy-MM-ddThh:mm:ss.s').format(date)); + getCCPDFFStructureModelList![index].eSERVICESDV = eservicesdv; + setState(() {}); + if (model.cHILDSEGMENTSDVSplited?.isNotEmpty ?? false) { + // calGetValueSetValues(model); + } + }, + ).paddingOnly(bottom: 12); + } else if (model.fORMATTYPE == "I") { + return DynamicTextFieldWidget( + (model.sEGMENTPROMPT ?? "") + (model.rEQUIREDFLAG == "Y" ? "*" : ""), + model.eSERVICESDV?.pIDCOLUMNNAME ?? (getCCPDFFStructureModelList![index].fieldAnswer ?? ""), + suffixIconData: Icons.access_time_filled_rounded, + isEnable: false, + onTap: () async { + if ((getCCPDFFStructureModelList![index].eSERVICESDV?.pVALUECOLUMNNAME != null)) { + var timeString = getCCPDFFStructureModelList![index].eSERVICESDV!.pVALUECOLUMNNAME!.split(":"); + selectedDate = DateTime(0, 0, 0, int.parse(timeString[0]), int.parse(timeString[1])); + + //DateTime.parse(getEitDffStructureList![index].eSERVICESDV!.pVALUECOLUMNNAME!); + } + // TimeOfDay _time = await _selectTime(context); + // DateTime tempTime = DateTime(0, 1, 1, _time.hour, _time.minute); + // String time = DateFormat('HH:mm').format(tempTime).trim(); + + // DateTime date1 = DateTime(date.year, date.month, date.day); + // getEitDffStructureList![index].fieldAnswer = date.toString(); + // ESERVICESDV eservicesdv = ESERVICESDV(pIDCOLUMNNAME: time, pRETURNMSG: "null", pRETURNSTATUS: getEitDffStructureList![index].dEFAULTVALUE, pVALUECOLUMNNAME: time); + // getCCPDFFStructureModelList![index].eSERVICESDV = eservicesdv; + setState(() {}); + if (model.cHILDSEGMENTSDVSplited?.isNotEmpty ?? false) { + // getCCPDFFStructureModelList(model); + } + }, + ).paddingOnly(bottom: 12); + } + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [], + ).objectContainerView(); + } + + Future _selectDate(BuildContext context) async { + DateTime time = selectedDate; + if (Platform.isIOS) { + await showCupertinoModalPopup( + context: context, + builder: (cxt) => Container( + height: 250, + color: Colors.white, + child: CupertinoDatePicker( + backgroundColor: Colors.white, + mode: CupertinoDatePickerMode.date, + onDateTimeChanged: (value) { + if (value != null && value != selectedDate) { + time = value; + } + }, + initialDateTime: selectedDate, + ), + ), + ); + } else { + final DateTime? picked = + await showDatePicker(context: context, initialDate: selectedDate, initialEntryMode: DatePickerEntryMode.calendarOnly, firstDate: DateTime(2015, 8), lastDate: DateTime(2101)); + if (picked != null && picked != selectedDate) { + time = picked; + } + } + return time; + } +} From 5c15d07dc87f22b6570e5e448879b6a6efba060f Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Sun, 21 Aug 2022 15:13:06 +0300 Subject: [PATCH 3/8] updates --- lib/models/generic_response_model.dart | 5 -- .../screens/mowadhafhi/mowadhafhi_home.dart | 65 ++++++++++++------- 2 files changed, 42 insertions(+), 28 deletions(-) diff --git a/lib/models/generic_response_model.dart b/lib/models/generic_response_model.dart index e548a92..300ded9 100644 --- a/lib/models/generic_response_model.dart +++ b/lib/models/generic_response_model.dart @@ -745,8 +745,6 @@ class GenericResponseModel { getCEIDFFStructureList = json['GetCEIDFFStructureList']; getCEITransactionList = json['GetCEITransactionList']; getCcpTransactionsList = json['GetCcpTransactionsList']; - getCcpTransactionsListNew = json['GetCcpTransactionsList_New']; - getConcurrentProgramsList = json['GetConcurrentProgramsList']; if (json['GetContactDetailsList'] != null) { getContactDetailsList = []; json['GetContactDetailsList'].forEach((v) { @@ -1367,8 +1365,6 @@ class GenericResponseModel { data['GetCEIDFFStructureList'] = this.getCEIDFFStructureList; data['GetCEITransactionList'] = this.getCEITransactionList; data['GetCcpTransactionsList'] = this.getCcpTransactionsList; - data['GetCcpTransactionsList_New'] = this.getCcpTransactionsListNew; - data['GetConcurrentProgramsList'] = this.getConcurrentProgramsList; if (this.getContactDetailsList != null) { data['GetContactDetailsList'] = this.getContactDetailsList!.map((v) => v.toJson()).toList(); } @@ -1378,7 +1374,6 @@ class GenericResponseModel { if (this.getContactDffStructureList != null) { data['GetContactDffStructureList'] = this.getContactDffStructureList!.map((v) => v.toJson()).toList(); } - // data['GetCcpTransactionsList_New'] = this.getCcpTransactionsListNew; data['GetContactColsStructureList'] = this.getContactColsStructureList; data['GetContactDetailsList'] = this.getContactDetailsList; data['GetContactDffStructureList'] = this.getContactDffStructureList; diff --git a/lib/ui/screens/mowadhafhi/mowadhafhi_home.dart b/lib/ui/screens/mowadhafhi/mowadhafhi_home.dart index edf6b03..e9f17b2 100644 --- a/lib/ui/screens/mowadhafhi/mowadhafhi_home.dart +++ b/lib/ui/screens/mowadhafhi/mowadhafhi_home.dart @@ -53,8 +53,6 @@ class _MowadhafhiHomeState extends State { }, child: Container( width: double.infinity, - // height: 100.0, - padding: const EdgeInsets.only(left: 12, right: 12, top: 10, bottom: 10), margin: const EdgeInsets.only(left: 12, right: 12, top: 10, bottom: 10), decoration: BoxDecoration( color: Colors.white, @@ -67,31 +65,52 @@ class _MowadhafhiHomeState extends State { ), ], ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + clipBehavior: Clip.antiAlias, + child: Stack( + clipBehavior: Clip.antiAlias, children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - getTicketsByEmployeeList[index].ticketTypeName!.toText14(color: MyColors.grey57Color), - getTicketsByEmployeeList[index].created!.split(" ")[0].toText12(color: MyColors.grey70Color), - ], - ), - Container( - padding: const EdgeInsets.only(top: 10.0), - child: getTicketsByEmployeeList[index].description!.toText12(color: MyColors.grey57Color), + Positioned( + left: -20, + top: -10, + child: Transform.rotate( + angle: 15, + child: Container( + width: 50, + height: 30, + color: Colors.amber, + ), + ), ), Container( - padding: const EdgeInsets.only(top: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + padding: const EdgeInsets.only(left: 15, right: 15, top: 20, bottom: 10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - getTicketsByEmployeeList[index].ticketStatusInternalName!.toText14(color: MyColors.gradiantEndColor), - SvgPicture.asset( - "assets/images/arrow_next.svg", - color: MyColors.darkIconColor, - ) + Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + getTicketsByEmployeeList[index].ticketTypeName!.toText14(color: MyColors.grey57Color), + getTicketsByEmployeeList[index].created!.split(" ")[0].toText12(color: MyColors.grey70Color), + ], + ), + Container( + padding: const EdgeInsets.only(top: 10.0), + child: getTicketsByEmployeeList[index].description!.toText12(color: MyColors.grey57Color), + ), + Container( + padding: const EdgeInsets.only(top: 10.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + getTicketsByEmployeeList[index].ticketStatusInternalName!.toText14(color: MyColors.gradiantEndColor), + SvgPicture.asset( + "assets/images/arrow_next.svg", + color: MyColors.darkIconColor, + ) + ], + ), + ), ], ), ), From a855e535cd2f1a3016d22796ae448def8f5624ac Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Thu, 25 Aug 2022 11:37:36 +0300 Subject: [PATCH 4/8] Item for sale implemented --- ios/Runner/Info.plist | 14 +- lib/api/api_client.dart | 15 +- .../items_for_sale_api_client.dart | 123 ++++++++ lib/classes/colors.dart | 1 + lib/classes/consts.dart | 1 + lib/classes/utils.dart | 25 ++ lib/config/routes.dart | 16 +- .../add_item_for_sale_image_model.dart | 25 ++ .../items_for_sale/get_employee_ads_list.dart | 181 +++++++++++ .../get_items_for_sale_list.dart | 181 +++++++++++ .../items_for_sale/get_regions_list.dart | 48 +++ .../get_sale_categories_list.dart | 36 +++ .../items_for_sale/item_review_model.dart | 35 +++ lib/ui/landing/dashboard_screen.dart | 5 +- .../items_for_sale/add_new_item_for_sale.dart | 216 +++++++++++++ .../fragments/add_details_fragment.dart | 293 ++++++++++++++++++ .../fragments/item_review_fragment.dart | 154 +++++++++ .../fragments/items_for_sale.dart | 239 ++++++++++++++ .../fragments/my_posted_ads_fragment.dart | 213 +++++++++++++ .../fragments/select_category_fragment.dart | 78 +++++ .../items_for_sale/item_for_sale_detail.dart | 136 ++++++++ .../items_for_sale/items_for_sale_home.dart | 111 +++++++ .../dynamic_textfield_widget.dart | 3 +- lib/widgets/image_picker.dart | 154 +++++++++ 24 files changed, 2293 insertions(+), 10 deletions(-) create mode 100644 lib/api/items_for_sale/items_for_sale_api_client.dart create mode 100644 lib/models/items_for_sale/add_item_for_sale_image_model.dart create mode 100644 lib/models/items_for_sale/get_employee_ads_list.dart create mode 100644 lib/models/items_for_sale/get_items_for_sale_list.dart create mode 100644 lib/models/items_for_sale/get_regions_list.dart create mode 100644 lib/models/items_for_sale/get_sale_categories_list.dart create mode 100644 lib/models/items_for_sale/item_review_model.dart create mode 100644 lib/ui/screens/items_for_sale/add_new_item_for_sale.dart create mode 100644 lib/ui/screens/items_for_sale/fragments/add_details_fragment.dart create mode 100644 lib/ui/screens/items_for_sale/fragments/item_review_fragment.dart create mode 100644 lib/ui/screens/items_for_sale/fragments/items_for_sale.dart create mode 100644 lib/ui/screens/items_for_sale/fragments/my_posted_ads_fragment.dart create mode 100644 lib/ui/screens/items_for_sale/fragments/select_category_fragment.dart create mode 100644 lib/ui/screens/items_for_sale/item_for_sale_detail.dart create mode 100644 lib/ui/screens/items_for_sale/items_for_sale_home.dart create mode 100644 lib/widgets/image_picker.dart diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index dadaab0..eaa735c 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -2,6 +2,8 @@ + CADisableMinimumFrameDurationOnPhone + CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable @@ -26,6 +28,10 @@ LaunchScreen UIMainStoryboardFile Main + NSCameraUsageDescription + This app requires camera access to capture & upload pictures. + NSPhotoLibraryUsageDescription + This app requires photo library access to select image as document & upload it. UISupportedInterfaceOrientations UIInterfaceOrientationPortrait @@ -39,9 +45,13 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + LSApplicationQueriesSchemes + + sms + tel + mailto + UIViewControllerBasedStatusBarAppearance - CADisableMinimumFrameDurationOnPhone - diff --git a/lib/api/api_client.dart b/lib/api/api_client.dart index 2f53f78..3385815 100644 --- a/lib/api/api_client.dart +++ b/lib/api/api_client.dart @@ -67,7 +67,7 @@ class ApiClient { factory ApiClient() => _instance; Future postJsonForObject(FactoryConstructor factoryConstructor, String url, T jsonObject, - {String? token, Map? queryParameters, Map? headers, int retryTimes = 0}) async { + {String? token, Map? queryParameters, Map? headers, int retryTimes = 0, bool isFormData = false}) async { var _headers = {'Accept': 'application/json'}; if (headers != null && headers.isNotEmpty) { _headers.addAll(headers); @@ -76,7 +76,7 @@ class ApiClient { print("Url:$url"); print("body:$jsonObject"); } - var response = await postJsonForResponse(url, jsonObject, token: token, queryParameters: queryParameters, headers: _headers, retryTimes: retryTimes); + var response = await postJsonForResponse(url, jsonObject, token: token, queryParameters: queryParameters, headers: _headers, retryTimes: retryTimes, isFormData: isFormData); // try { if (!kReleaseMode) { logger.i("res: " + response.body); @@ -101,8 +101,10 @@ class ApiClient { // } } - Future postJsonForResponse(String url, T jsonObject, {String? token, Map? queryParameters, Map? headers, int retryTimes = 0}) async { + Future postJsonForResponse(String url, T jsonObject, + {String? token, Map? queryParameters, Map? headers, int retryTimes = 0, bool isFormData = false}) async { String? requestBody; + late Map stringObj; if (jsonObject != null) { requestBody = jsonEncode(jsonObject); if (headers == null) { @@ -112,7 +114,12 @@ class ApiClient { } } - return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes); + if (isFormData) { + headers = {'Content-Type': 'application/x-www-form-urlencoded'}; + stringObj = ((jsonObject ?? {}) as Map).map((key, value) => MapEntry(key, value?.toString() ?? "")); + } + + return await _postForResponse(url, isFormData ? stringObj : requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes); } Future _postForResponse(String url, requestBody, {String? token, Map? queryParameters, Map? headers, int retryTimes = 0}) async { diff --git a/lib/api/items_for_sale/items_for_sale_api_client.dart b/lib/api/items_for_sale/items_for_sale_api_client.dart new file mode 100644 index 0000000..31acbc2 --- /dev/null +++ b/lib/api/items_for_sale/items_for_sale_api_client.dart @@ -0,0 +1,123 @@ +import 'dart:convert'; + +import 'package:mohem_flutter_app/api/api_client.dart'; +import 'package:mohem_flutter_app/app_state/app_state.dart'; +import 'package:mohem_flutter_app/classes/consts.dart'; +import 'package:mohem_flutter_app/models/items_for_sale/get_employee_ads_list.dart'; +import 'package:mohem_flutter_app/models/items_for_sale/get_items_for_sale_list.dart'; +import 'package:mohem_flutter_app/models/items_for_sale/get_regions_list.dart'; +import 'package:mohem_flutter_app/models/items_for_sale/get_sale_categories_list.dart'; +import 'package:mohem_flutter_app/models/items_for_sale/item_review_model.dart'; + +class ItemsForSaleApiClient { + static final ItemsForSaleApiClient _instance = ItemsForSaleApiClient._internal(); + + ItemsForSaleApiClient._internal(); + + factory ItemsForSaleApiClient() => _instance; + + Future> getSaleCategories() async { + List getSaleCategoriesList = []; + + String url = "${ApiConsts.cocRest}Mohemm_ITG_GetItemSaleCategory"; + Map postParams = {"EmployeeNumber": AppState().memberInformationList?.eMPLOYEENUMBER, "ItgPageSize": 10, "ItgPageNo": 1}; + + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject((response) { + final body = json.decode(response['Mohemm_ITG_ResponseItem']); + + GetSaleCategoriesList getSaleCategoriesListObj = new GetSaleCategoriesList(); + getSaleCategoriesListObj.categoryID = 0; + getSaleCategoriesListObj.title = "All"; + getSaleCategoriesListObj.titleAr = "الجميع"; + getSaleCategoriesListObj.isActive = true; + getSaleCategoriesListObj.content = + ''; + + getSaleCategoriesList.add(getSaleCategoriesListObj); + + body['result']['data'].forEach((v) { + getSaleCategoriesList.add(new GetSaleCategoriesList.fromJson(v)); + }); + return getSaleCategoriesList; + }, url, postParams); + } + + Future> getItemsForSale(int itgPageNo, int itgCategoryID) async { + List getItemsForSaleList = []; + + String url = "${ApiConsts.cocRest}Mohemm_ITG_GetItemForSale"; + Map postParams = { + "EmployeeNumber": AppState().memberInformationList?.eMPLOYEENUMBER, + "ItgPageSize": 10, + "ItgPageNo": itgPageNo, + "ItgStatus": "Approved", + "ItgCategoryID": itgCategoryID + }; + + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject((response) { + final body = json.decode(response['Mohemm_ITG_ResponseItem']); + + body['result']['data'].forEach((v) { + getItemsForSaleList.add(new GetItemsForSaleList.fromJson(v)); + }); + return getItemsForSaleList; + }, url, postParams); + } + + Future> getEmployeePostedAds() async { + List employeePostedAdsList = []; + + String url = "${ApiConsts.cocRest}Mohemm_ITG_GetItemForSaleByEmployee"; + Map postParams = {"EmployeeNumber": AppState().memberInformationList?.eMPLOYEENUMBER, "ItgEmployeeNumber": AppState().memberInformationList?.eMPLOYEENUMBER}; + + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject((response) { + final body = json.decode(response['Mohemm_ITG_ResponseItem']); + + body['result']['data'].forEach((v) { + employeePostedAdsList.add(new EmployeePostedAds.fromJson(v)); + }); + return employeePostedAdsList; + }, url, postParams); + } + + Future> getRegions() async { + String url = "${ApiConsts.cocRest}Mohemm_ITG_GetRegion"; + List getRegionsList = []; + Map postParams = {"EmployeeNumber": AppState().memberInformationList?.eMPLOYEENUMBER, "ItgEmployeeNumber": AppState().memberInformationList?.eMPLOYEENUMBER}; + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject((response) { + final body = json.decode(response['Mohemm_ITG_ResponseItem']); + + body['result']['data'].forEach((v) { + getRegionsList.add(new GetRegionsList.fromJson(v)); + }); + return getRegionsList; + }, url, postParams); + } + + Future addItemForSale(ItemReviewModel itemReviewModel, List> imagesList) async { + String url = "${ApiConsts.cocRest}Mohemm_ITG_AddItemForSaleMobile"; + Map postParams = { + "ItgImageCollList": imagesList, + "ItgTitle": itemReviewModel.itemTitle, + "ItgTitleAr": itemReviewModel.itemTitle, + "ItgCategoryID": itemReviewModel.selectedSaleCategory!.categoryID, + "ItgDescription": itemReviewModel.itemDescription, + "ItgDescriptionAr": itemReviewModel.itemDescription, + "ItgQuotePrice": itemReviewModel.itemPrice, + "RegionID": itemReviewModel.selectedRegion!.regionID, + "ItgIsActive": true, + "EmployeeNumber": AppState().memberInformationList?.eMPLOYEENUMBER, + "employeeNumber": AppState().memberInformationList?.eMPLOYEENUMBER, + "ItgStatus": itemReviewModel.itemCondition + }; + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject((response) { + final body = json.decode(response['Mohemm_ITG_ResponseItem']); + return body["message"]; + }, url, postParams); + } +} diff --git a/lib/classes/colors.dart b/lib/classes/colors.dart index 4b34186..794b37e 100644 --- a/lib/classes/colors.dart +++ b/lib/classes/colors.dart @@ -22,6 +22,7 @@ class MyColors { static const Color darkWhiteColor = Color(0xffE0E0E0); static const Color redColor = Color(0xffD02127); static const Color yellowColor = Color(0xffF4E31C); + static const Color orange = Color(0xFFCC9B14); static const Color backgroundBlackColor = Color(0xff202529); static const Color black = Color(0xff000000); static const Color white = Color(0xffffffff); diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index e806301..12f818e 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -22,4 +22,5 @@ class SharedPrefsConsts { static String doNotShowWelcomeVideo = "doNotShowWelcomeVideo"; static String mohemmWifiSSID = "mohemmWifiSSID"; static String mohemmWifiPassword = "mohemmWifiPassword"; + static String editItemForSale = "editItemForSale"; } diff --git a/lib/classes/utils.dart b/lib/classes/utils.dart index 292bc4c..e2ae38e 100644 --- a/lib/classes/utils.dart +++ b/lib/classes/utils.dart @@ -178,6 +178,31 @@ class Utils { ); } + static Decoration containerRadius(Color background, double radius) { + return BoxDecoration( + color: background, + border: Border.all( + width: 1, // + color: background // <--- border width here + ), + borderRadius: BorderRadius.circular(radius), + ); + } + + static Widget mHeight(double h) { + return Container( + height: h, + ); + } + + static Widget mDivider(Color color) { + return Divider( + // width: double.infinity, + height: 1, + color: color, + ); + } + static Widget tableColumnValue(String text, {bool isCapitable = true, bool alignCenter = false}) { return Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/config/routes.dart b/lib/config/routes.dart index 72dc5ed..6928f09 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -28,6 +28,9 @@ import 'package:mohem_flutter_app/ui/screens/announcements/announcements.dart'; // import 'package:mohem_flutter_app/ui/my_attendance/work_from_home_screen.dart'; import 'package:mohem_flutter_app/ui/screens/eit/add_eit.dart'; +import 'package:mohem_flutter_app/ui/screens/items_for_sale/add_new_item_for_sale.dart'; +import 'package:mohem_flutter_app/ui/screens/items_for_sale/item_for_sale_detail.dart'; +import 'package:mohem_flutter_app/ui/screens/items_for_sale/items_for_sale_home.dart'; import 'package:mohem_flutter_app/ui/screens/mowadhafhi/mowadhafhi_home.dart'; import 'package:mohem_flutter_app/ui/screens/mowadhafhi/mowadhafhi_hr_request.dart'; import 'package:mohem_flutter_app/ui/screens/mowadhafhi/request_details.dart'; @@ -109,6 +112,11 @@ class AppRoutes { static const String myRequests = "/myRequests"; static const String newRequest = "/newRequests"; + // Items For Sale + static const String itemsForSale = "/itemsForSale"; + static const String itemsForSaleDetail = "/itemsForSaleDetail"; + static const String addNewItemForSale = "/addNewItemForSale"; + //Pay slip static const String monthlyPaySlip = "/monthlyPaySlip"; @@ -175,7 +183,13 @@ class AppRoutes { myRequests: (context) => MyRequests(), newRequest: (context) => NewRequest(), + // Items for sale + itemsForSale: (context) => ItemsForSale(), + itemsForSaleDetail: (context) => ItemForSaleDetailPage(), + addNewItemForSale: (context) => AddNewItemForSale(), + + //pay slip monthlyPaySlip: (context) => MonthlyPaySlipScreen(), }; -} +} \ No newline at end of file diff --git a/lib/models/items_for_sale/add_item_for_sale_image_model.dart b/lib/models/items_for_sale/add_item_for_sale_image_model.dart new file mode 100644 index 0000000..b26929e --- /dev/null +++ b/lib/models/items_for_sale/add_item_for_sale_image_model.dart @@ -0,0 +1,25 @@ +class AddItemForSaleImageModel { + int? attachmentID; + String? base64Data; + String? fileName; + String? contentType; + + AddItemForSaleImageModel( + {this.attachmentID, this.base64Data, this.fileName, this.contentType}); + + AddItemForSaleImageModel.fromJson(Map json) { + attachmentID = json['AttachmentID']; + base64Data = json['Base64Data']; + fileName = json['FileName']; + contentType = json['ContentType']; + } + + Map toJson() { + final Map data = new Map(); + data['AttachmentID'] = this.attachmentID; + data['Base64Data'] = this.base64Data; + data['FileName'] = this.fileName; + data['ContentType'] = this.contentType; + return data; + } +} diff --git a/lib/models/items_for_sale/get_employee_ads_list.dart b/lib/models/items_for_sale/get_employee_ads_list.dart new file mode 100644 index 0000000..97e06b8 --- /dev/null +++ b/lib/models/items_for_sale/get_employee_ads_list.dart @@ -0,0 +1,181 @@ +class EmployeePostedAds { + int? itemSaleID; + String? title; + String? titleAr; + String? description; + String? descriptionAr; + int? categoryID; + String? categoryTitle; + int? regionID; + String? regionName; + String? countryName; + String? currencyCode; + String? startDate; + String? endDate; + int? quotePrice; + int? employeeNumber; + String? profilePicture; + String? fullName; + String? emailAddress; + String? mobileNumber; + bool? isApproved; + String? status; + List? itemAttachments; + String? created; + dynamic? comments; + dynamic? isActive; + int? pageSize; + int? pageNo; + dynamic? languageId; + + EmployeePostedAds( + {this.itemSaleID, + this.title, + this.titleAr, + this.description, + this.descriptionAr, + this.categoryID, + this.categoryTitle, + this.regionID, + this.regionName, + this.countryName, + this.currencyCode, + this.startDate, + this.endDate, + this.quotePrice, + this.employeeNumber, + this.profilePicture, + this.fullName, + this.emailAddress, + this.mobileNumber, + this.isApproved, + this.status, + this.itemAttachments, + this.created, + this.comments, + this.isActive, + this.pageSize, + this.pageNo, + this.languageId}); + + EmployeePostedAds.fromJson(Map json) { + itemSaleID = json['itemSaleID']; + title = json['title']; + titleAr = json['title_Ar']; + description = json['description']; + descriptionAr = json['description_Ar']; + categoryID = json['categoryID']; + categoryTitle = json['categoryTitle']; + regionID = json['regionID']; + regionName = json['regionName']; + countryName = json['countryName']; + currencyCode = json['currencyCode']; + startDate = json['startDate']; + endDate = json['endDate']; + quotePrice = json['quotePrice']; + employeeNumber = json['employeeNumber']; + profilePicture = json['profilePicture']; + fullName = json['fullName']; + emailAddress = json['emailAddress']; + mobileNumber = json['mobileNumber']; + isApproved = json['isApproved']; + status = json['status']; + if (json['itemAttachments'] != null) { + itemAttachments = []; + json['itemAttachments'].forEach((v) { + itemAttachments!.add(new ItemAttachments.fromJson(v)); + }); + } + created = json['created']; + comments = json['comments']; + isActive = json['isActive']; + pageSize = json['pageSize']; + pageNo = json['pageNo']; + languageId = json['languageId']; + } + + Map toJson() { + final Map data = new Map(); + data['itemSaleID'] = this.itemSaleID; + data['title'] = this.title; + data['title_Ar'] = this.titleAr; + data['description'] = this.description; + data['description_Ar'] = this.descriptionAr; + data['categoryID'] = this.categoryID; + data['categoryTitle'] = this.categoryTitle; + data['regionID'] = this.regionID; + data['regionName'] = this.regionName; + data['countryName'] = this.countryName; + data['currencyCode'] = this.currencyCode; + data['startDate'] = this.startDate; + data['endDate'] = this.endDate; + data['quotePrice'] = this.quotePrice; + data['employeeNumber'] = this.employeeNumber; + data['profilePicture'] = this.profilePicture; + data['fullName'] = this.fullName; + data['emailAddress'] = this.emailAddress; + data['mobileNumber'] = this.mobileNumber; + data['isApproved'] = this.isApproved; + data['status'] = this.status; + if (this.itemAttachments != null) { + data['itemAttachments'] = + this.itemAttachments!.map((v) => v.toJson()).toList(); + } + data['created'] = this.created; + data['comments'] = this.comments; + data['isActive'] = this.isActive; + data['pageSize'] = this.pageSize; + data['pageNo'] = this.pageNo; + data['languageId'] = this.languageId; + return data; + } +} + +class ItemAttachments { + int? attachmentId; + String? fileName; + String? contentType; + String? attachFileStream; + String? base64String; + dynamic? isActive; + int? referenceItemId; + String? content; + String? filePath; + + ItemAttachments( + {this.attachmentId, + this.fileName, + this.contentType, + this.attachFileStream, + this.base64String, + this.isActive, + this.referenceItemId, + this.content, + this.filePath}); + + ItemAttachments.fromJson(Map json) { + attachmentId = json['attachmentId']; + fileName = json['fileName']; + contentType = json['contentType']; + attachFileStream = json['attachFileStream']; + base64String = json['base64String']; + isActive = json['isActive']; + referenceItemId = json['referenceItemId']; + content = json['content']; + filePath = json['filePath']; + } + + Map toJson() { + final Map data = new Map(); + data['attachmentId'] = this.attachmentId; + data['fileName'] = this.fileName; + data['contentType'] = this.contentType; + data['attachFileStream'] = this.attachFileStream; + data['base64String'] = this.base64String; + data['isActive'] = this.isActive; + data['referenceItemId'] = this.referenceItemId; + data['content'] = this.content; + data['filePath'] = this.filePath; + return data; + } +} diff --git a/lib/models/items_for_sale/get_items_for_sale_list.dart b/lib/models/items_for_sale/get_items_for_sale_list.dart new file mode 100644 index 0000000..091b023 --- /dev/null +++ b/lib/models/items_for_sale/get_items_for_sale_list.dart @@ -0,0 +1,181 @@ +class GetItemsForSaleList { + int? itemSaleID; + String? title; + String? titleAr; + String? description; + String? descriptionAr; + int? categoryID; + String? categoryTitle; + int? regionID; + String? regionName; + String? countryName; + String? currencyCode; + String? startDate; + String? endDate; + int? quotePrice; + int? employeeNumber; + String? profilePicture; + String? fullName; + String? emailAddress; + String? mobileNumber; + bool? isApproved; + String? status; + List? itemAttachments; + String? created; + dynamic? comments; + dynamic? isActive; + dynamic? pageSize; + dynamic? pageNo; + dynamic? languageId; + + GetItemsForSaleList( + {this.itemSaleID, + this.title, + this.titleAr, + this.description, + this.descriptionAr, + this.categoryID, + this.categoryTitle, + this.regionID, + this.regionName, + this.countryName, + this.currencyCode, + this.startDate, + this.endDate, + this.quotePrice, + this.employeeNumber, + this.profilePicture, + this.fullName, + this.emailAddress, + this.mobileNumber, + this.isApproved, + this.status, + this.itemAttachments, + this.created, + this.comments, + this.isActive, + this.pageSize, + this.pageNo, + this.languageId}); + + GetItemsForSaleList.fromJson(Map json) { + itemSaleID = json['itemSaleID']; + title = json['title']; + titleAr = json['title_Ar']; + description = json['description']; + descriptionAr = json['description_Ar']; + categoryID = json['categoryID']; + categoryTitle = json['categoryTitle']; + regionID = json['regionID']; + regionName = json['regionName']; + countryName = json['countryName']; + currencyCode = json['currencyCode']; + startDate = json['startDate']; + endDate = json['endDate']; + quotePrice = json['quotePrice']; + employeeNumber = json['employeeNumber']; + profilePicture = json['profilePicture']; + fullName = json['fullName']; + emailAddress = json['emailAddress']; + mobileNumber = json['mobileNumber']; + isApproved = json['isApproved']; + status = json['status']; + if (json['itemAttachments'] != null) { + itemAttachments = []; + json['itemAttachments'].forEach((v) { + itemAttachments!.add(new ItemAttachments.fromJson(v)); + }); + } + created = json['created']; + comments = json['comments']; + isActive = json['isActive']; + pageSize = json['pageSize']; + pageNo = json['pageNo']; + languageId = json['languageId']; + } + + Map toJson() { + final Map data = new Map(); + data['itemSaleID'] = this.itemSaleID; + data['title'] = this.title; + data['title_Ar'] = this.titleAr; + data['description'] = this.description; + data['description_Ar'] = this.descriptionAr; + data['categoryID'] = this.categoryID; + data['categoryTitle'] = this.categoryTitle; + data['regionID'] = this.regionID; + data['regionName'] = this.regionName; + data['countryName'] = this.countryName; + data['currencyCode'] = this.currencyCode; + data['startDate'] = this.startDate; + data['endDate'] = this.endDate; + data['quotePrice'] = this.quotePrice; + data['employeeNumber'] = this.employeeNumber; + data['profilePicture'] = this.profilePicture; + data['fullName'] = this.fullName; + data['emailAddress'] = this.emailAddress; + data['mobileNumber'] = this.mobileNumber; + data['isApproved'] = this.isApproved; + data['status'] = this.status; + if (this.itemAttachments != null) { + data['itemAttachments'] = + this.itemAttachments!.map((v) => v.toJson()).toList(); + } + data['created'] = this.created; + data['comments'] = this.comments; + data['isActive'] = this.isActive; + data['pageSize'] = this.pageSize; + data['pageNo'] = this.pageNo; + data['languageId'] = this.languageId; + return data; + } +} + +class ItemAttachments { + int? attachmentId; + String? fileName; + String? contentType; + dynamic? attachFileStream; + dynamic? base64String; + dynamic? isActive; + int? referenceItemId; + String? content; + String? filePath; + + ItemAttachments( + {this.attachmentId, + this.fileName, + this.contentType, + this.attachFileStream, + this.base64String, + this.isActive, + this.referenceItemId, + this.content, + this.filePath}); + + ItemAttachments.fromJson(Map json) { + attachmentId = json['attachmentId']; + fileName = json['fileName']; + contentType = json['contentType']; + attachFileStream = json['attachFileStream']; + base64String = json['base64String']; + isActive = json['isActive']; + referenceItemId = json['referenceItemId']; + content = json['content']; + filePath = json['filePath']; + } + + Map toJson() { + final Map data = new Map(); + data['attachmentId'] = this.attachmentId; + data['fileName'] = this.fileName; + data['contentType'] = this.contentType; + data['attachFileStream'] = this.attachFileStream; + data['base64String'] = this.base64String; + data['isActive'] = this.isActive; + data['referenceItemId'] = this.referenceItemId; + data['content'] = this.content; + data['filePath'] = this.filePath; + return data; + } +} diff --git a/lib/models/items_for_sale/get_regions_list.dart b/lib/models/items_for_sale/get_regions_list.dart new file mode 100644 index 0000000..4b36f03 --- /dev/null +++ b/lib/models/items_for_sale/get_regions_list.dart @@ -0,0 +1,48 @@ +class GetRegionsList { + int? regionID; + String? regionName; + String? regionNameAr; + int? countryID; + String? countryName; + dynamic? isActive; + int? pageSize; + int? pageNo; + dynamic? languageId; + + GetRegionsList( + {this.regionID, + this.regionName, + this.regionNameAr, + this.countryID, + this.countryName, + this.isActive, + this.pageSize, + this.pageNo, + this.languageId}); + + GetRegionsList.fromJson(Map json) { + regionID = json['regionID']; + regionName = json['regionName']; + regionNameAr = json['regionName_Ar']; + countryID = json['countryID']; + countryName = json['countryName']; + isActive = json['isActive']; + pageSize = json['pageSize']; + pageNo = json['pageNo']; + languageId = json['languageId']; + } + + Map toJson() { + final Map data = new Map(); + data['regionID'] = this.regionID; + data['regionName'] = this.regionName; + data['regionName_Ar'] = this.regionNameAr; + data['countryID'] = this.countryID; + data['countryName'] = this.countryName; + data['isActive'] = this.isActive; + data['pageSize'] = this.pageSize; + data['pageNo'] = this.pageNo; + data['languageId'] = this.languageId; + return data; + } +} diff --git a/lib/models/items_for_sale/get_sale_categories_list.dart b/lib/models/items_for_sale/get_sale_categories_list.dart new file mode 100644 index 0000000..03f28e3 --- /dev/null +++ b/lib/models/items_for_sale/get_sale_categories_list.dart @@ -0,0 +1,36 @@ +class GetSaleCategoriesList { + int? categoryID; + String? title; + String? titleAr; + String? content; + bool? isActive; + dynamic? pageSize; + dynamic? pageNo; + dynamic? languageId; + + GetSaleCategoriesList({this.categoryID, this.title, this.titleAr, this.content, this.isActive, this.pageSize, this.pageNo, this.languageId}); + + GetSaleCategoriesList.fromJson(Map json) { + categoryID = json['categoryID']; + title = json['title']; + titleAr = json['title_Ar']; + content = json['content']; + isActive = json['isActive']; + pageSize = json['pageSize']; + pageNo = json['pageNo']; + languageId = json['languageId']; + } + + Map toJson() { + final Map data = new Map(); + data['categoryID'] = this.categoryID; + data['title'] = this.title; + data['title_Ar'] = this.titleAr; + data['content'] = this.content; + data['isActive'] = this.isActive; + data['pageSize'] = this.pageSize; + data['pageNo'] = this.pageNo; + data['languageId'] = this.languageId; + return data; + } +} diff --git a/lib/models/items_for_sale/item_review_model.dart b/lib/models/items_for_sale/item_review_model.dart new file mode 100644 index 0000000..4033746 --- /dev/null +++ b/lib/models/items_for_sale/item_review_model.dart @@ -0,0 +1,35 @@ +import 'package:mohem_flutter_app/models/items_for_sale/get_regions_list.dart'; +import 'package:mohem_flutter_app/models/items_for_sale/get_sale_categories_list.dart'; + +class ItemReviewModel { + String? itemTitle; + String? itemDescription; + String? itemCondition; + GetRegionsList? selectedRegion; + num? itemPrice; + List? itemPhotos; + GetSaleCategoriesList? selectedSaleCategory; + + ItemReviewModel( + this.itemTitle, + this.itemDescription, + this.itemCondition, + this.selectedRegion, + this.itemPrice, + this.itemPhotos, + this.selectedSaleCategory, + ); + + Map toJson() { + final Map data = new Map(); + data['itemTitle'] = this.itemTitle; + data['itemDescription'] = this.itemDescription; + data['itemCondition'] = this.itemCondition; + data['selectedRegion'] = this.selectedRegion; + data['itemPrice'] = this.itemPrice; + data['itemPhotos'] = this.itemPhotos; + data['selectedSaleCategory'] = this.selectedSaleCategory; + return data; + } + +} diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index 4406a4d..d5acce6 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -389,8 +389,9 @@ class _DashboardScreenState extends State { selectedIconTheme: const IconThemeData(color: MyColors.grey3AColor, size: 28), unselectedIconTheme: const IconThemeData(color: MyColors.grey98Color, size: 28), onTap: (int index) { - currentIndex = index; - setState(() {}); + // currentIndex = index; + // setState(() {}); + Navigator.pushNamed(context, AppRoutes.itemsForSale); }, ), ), diff --git a/lib/ui/screens/items_for_sale/add_new_item_for_sale.dart b/lib/ui/screens/items_for_sale/add_new_item_for_sale.dart new file mode 100644 index 0000000..307a834 --- /dev/null +++ b/lib/ui/screens/items_for_sale/add_new_item_for_sale.dart @@ -0,0 +1,216 @@ +import 'package:flutter/material.dart'; +import 'package:mohem_flutter_app/api/items_for_sale/items_for_sale_api_client.dart'; +import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/classes/utils.dart'; +import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; +import 'package:mohem_flutter_app/models/items_for_sale/get_sale_categories_list.dart'; +import 'package:mohem_flutter_app/models/items_for_sale/item_review_model.dart'; +import 'package:mohem_flutter_app/ui/screens/items_for_sale/fragments/add_details_fragment.dart'; +import 'package:mohem_flutter_app/ui/screens/items_for_sale/fragments/item_review_fragment.dart'; +import 'package:mohem_flutter_app/ui/screens/items_for_sale/fragments/select_category_fragment.dart'; +import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; + +class AddNewItemForSale extends StatefulWidget { + int? pageIndex = 0; + ItemReviewModel? itemReviewModel; + + AddNewItemForSale({Key? key, this.pageIndex, this.itemReviewModel}) : super(key: key); + + @override + State createState() => _AddNewItemForSaleState(); +} + +class _AddNewItemForSaleState extends State { + int _currentIndex = 0; + List getSaleCategoriesList = []; + late PageController _controller; + ItemReviewModel? itemReviewModel; + int pageIndex = 0; + + @override + void initState() { + _controller = PageController(); + getItemForSaleCategory(); + super.initState(); + } + + void changePageViewIndex(pageIndex) { + _controller.jumpToPage(pageIndex); + } + + @override + Widget build(BuildContext context) { + getRequestID(); + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBarWidget( + context, + // title: LocaleKeys.mowadhafhiRequest.tr(), + title: "Items for sale", + showHomeButton: true, + ), + body: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AspectRatio( + aspectRatio: 335 / 118, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(20), + boxShadow: [ + BoxShadow( + color: const Color(0xff000000).withOpacity(.05), + blurRadius: 26, + offset: const Offset(0, -3), + ), + ], + ), + child: Row( + children: [ + Expanded( + child: showProgress( + title: "Select Category", + status: _currentIndex == 0 + ? "InProgress" + : _currentIndex > 0 + ? "Completed" + : "Locked", + color: _currentIndex == 0 ? MyColors.orange : MyColors.greenColor, + pageIndex: 0, + ), + ), + Expanded( + child: showProgress( + title: "Add Details", + status: _currentIndex == 1 + ? "InProgress" + : _currentIndex > 1 + ? "Completed" + : "Locked", + color: _currentIndex == 1 + ? MyColors.orange + : _currentIndex > 1 + ? MyColors.greenColor + : MyColors.lightGrayColor, + pageIndex: 1, + ), + ), + showProgress( + title: "Review & Sell", + status: _currentIndex == 2 ? "InProgress" : "Locked", + color: _currentIndex == 2 + ? MyColors.orange + : _currentIndex > 3 + ? MyColors.greenColor + : MyColors.lightGrayColor, + isNeedBorder: false, + pageIndex: 2, + ), + ], + ).paddingAll(21), + ).paddingOnly(left: 21, right: 21, top: 21), + ), + Expanded( + child: PageView( + physics: NeverScrollableScrollPhysics(), + controller: _controller, + onPageChanged: (index) { + setState(() { + _currentIndex = index; + }); + }, + scrollDirection: Axis.horizontal, + children: [ + getSaleCategoriesList.isNotEmpty ? SelectCategoryFragment(changePageViewIndex: changePageViewIndex, getSaleCategoriesList: getSaleCategoriesList) : Container(), + getSaleCategoriesList.isNotEmpty ? AddItemDetailsFragment(changePageViewIndex: changePageViewIndex, selectedSaleCategory: getSaleCategoriesList[0]) : Container(), + ItemReviewFragment(changePageViewIndex: changePageViewIndex), + ], + ), + ), + ], + ), + ); + } + + Widget showProgress({String? title, String? status, Color? color, bool isNeedBorder = true, int? pageIndex}) { + return InkWell( + onTap: () { + if (_currentIndex > pageIndex!) changePageViewIndex(pageIndex); + }, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Container( + width: 26, + height: 26, + decoration: Utils.containerRadius(color!, 200), + child: const Icon( + Icons.done, + color: Colors.white, + size: 16, + ), + ), + if (isNeedBorder) + Expanded( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Utils.mDivider(Colors.grey), + )), + ], + ), + Utils.mHeight(8), + Text( + title!, + style: const TextStyle( + fontSize: 11, + fontWeight: FontWeight.w600, + letterSpacing: -0.44, + ), + ), + Utils.mHeight(2), + Container( + padding: EdgeInsets.all(5), + decoration: Utils.containerRadius(color.withOpacity(0.2), 4), + child: Text( + status!, + style: TextStyle( + fontSize: 8, + fontWeight: FontWeight.w600, + letterSpacing: -0.32, + color: color, + ), + ), + ), + ], + ) + ], + ), + ); + } + + void getRequestID() async { + int args = (ModalRoute.of(context)?.settings.arguments ?? {}) as int; + pageIndex = args; + } + + void getItemForSaleCategory() async { + try { + Utils.showLoading(context); + getSaleCategoriesList = await ItemsForSaleApiClient().getSaleCategories(); + Utils.hideLoading(context); + setState(() {}); + if (pageIndex == 1) { + changePageViewIndex(1); + } + } catch (ex) { + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + } + } +} 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 new file mode 100644 index 0000000..9d253f0 --- /dev/null +++ b/lib/ui/screens/items_for_sale/fragments/add_details_fragment.dart @@ -0,0 +1,293 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:mohem_flutter_app/api/items_for_sale/items_for_sale_api_client.dart'; +import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/classes/consts.dart'; +import 'package:mohem_flutter_app/classes/utils.dart'; +import 'package:mohem_flutter_app/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/items_for_sale/get_regions_list.dart'; +import 'package:mohem_flutter_app/models/items_for_sale/get_sale_categories_list.dart'; +import 'package:mohem_flutter_app/models/items_for_sale/item_review_model.dart'; +import 'package:mohem_flutter_app/ui/screens/items_for_sale/fragments/select_category_fragment.dart'; +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/radio/show_radio.dart'; + +class AddItemDetailsFragment extends StatefulWidget { + final Function changePageViewIndex; + final GetSaleCategoriesList selectedSaleCategory; + static late ItemReviewModel itemReviewModel; + + const AddItemDetailsFragment({Key? key, required this.changePageViewIndex, required this.selectedSaleCategory}) : super(key: key); + + @override + State createState() => _AddItemDetailsFragmentState(); +} + +class _AddItemDetailsFragmentState extends State { + String itemTitle = ""; + String itemDescription = ""; + num itemPrice = 0; + String selectedItemCondition = "new"; + + List getRegionsList = []; + GetRegionsList selectedRegion = GetRegionsList(); + + List images = []; + + @override + void initState() { + getRegions(); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Add details".toText20(isBold: true).paddingOnly(top: 24, left: 21, right: 21), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + DynamicTextFieldWidget( + "Title", + itemTitle.isEmpty ? "Item title" : itemTitle, + isEnable: true, + suffixIconData: Icons.search, + isPopup: false, + lines: 1, + isInputTypeNum: false, + isReadOnly: false, + onChange: (String value) { + itemTitle = value; + }, + ).paddingOnly(), + DynamicTextFieldWidget( + "Description", + itemDescription.isEmpty ? "Item description" : itemDescription, + isEnable: true, + suffixIconData: Icons.search, + isPopup: false, + lines: 4, + isInputTypeNum: false, + isReadOnly: false, + onChange: (String value) { + itemDescription = value; + }, + ).paddingOnly(top: 12), + "Item Condition".toText14(isBold: true).paddingOnly(top: 21), + Row( + children: [ + ShowRadio(title: "New", value: "new", groupValue: selectedItemCondition, selectedColor: MyColors.gradiantStartColor).onPress(() { + selectedItemCondition = "new"; + setState(() {}); + }), + 12.width, + ShowRadio(title: "Used", value: "used", groupValue: selectedItemCondition, selectedColor: MyColors.gradiantStartColor).onPress(() { + selectedItemCondition = "used"; + setState(() {}); + }), + ], + ).paddingOnly(top: 12), + PopupMenuButton( + child: DynamicTextFieldWidget( + "Region", + selectedRegion.regionName ?? "Select Region", + isEnable: false, + isPopup: true, + isInputTypeNum: true, + isReadOnly: false, + ), + itemBuilder: (_) => >[ + for (int i = 0; i < getRegionsList!.length; i++) PopupMenuItem(child: Text(getRegionsList[i].regionName!), value: i), + ], + onSelected: (int popupIndex) { + selectedRegion = getRegionsList![popupIndex]; + setState(() {}); + }, + ).paddingOnly(top: 21), + DynamicTextFieldWidget( + "Item Price", + itemPrice == 0 ? "Price" : itemPrice.toString(), + isEnable: true, + suffixIconData: Icons.search, + isPopup: false, + lines: 1, + isInputTypeNum: true, + isReadOnly: false, + onChange: (String value) { + itemPrice = num.parse(value); + }, + ).paddingOnly(top: 12), + "Item Photos".toText14(isBold: true).paddingOnly(top: 16), + attachmentView("Attachments").paddingOnly(top: 12), + Row( + children: [ + DefaultButton( + LocaleKeys.cancel.tr(), + () async { + Navigator.of(context).pop(); + }, + colors: const [Color(0xffD02127), Color(0xffD02127)], + ).expanded, + 12.width, + DefaultButton( + LocaleKeys.next.tr(), + isButtonDisabled() + ? null + : () async { + AddItemDetailsFragment.itemReviewModel = getItemReviewObject(); + widget.changePageViewIndex(2); + }, + disabledColor: MyColors.lightGrayColor, + ).expanded + ], + ).paddingOnly(top: 21), + ], + ).objectContainerView(title: "Item Info").paddingAll(21), + ], + ), + ); + } + + ItemReviewModel getItemReviewObject() { + ItemReviewModel itemReviewModel = ItemReviewModel(itemTitle, itemDescription, selectedItemCondition, selectedRegion, itemPrice, images, widget.selectedSaleCategory); + return itemReviewModel; + } + + bool isButtonDisabled() { + if (itemTitle.isNotEmpty && itemDescription.isNotEmpty && selectedRegion != null && itemPrice != 0 && images.isNotEmpty) { + return false; + } else { + return true; + } + } + + Widget attachmentView(String title) { + return Container( + padding: const EdgeInsets.only(top: 15, bottom: 15, left: 14, right: 14), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(15), + boxShadow: [ + BoxShadow( + color: const Color(0xff000000).withOpacity(.05), + blurRadius: 26, + offset: const Offset(0, -3), + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + title.toText16().expanded, + 6.width, + SimpleButton(LocaleKeys.add.tr(), () async { + ImageOptions.showImageOptions(context, (String image, File file) { + setState(() { + images.add(image); + }); + }); + }, fontSize: 14), + ], + ), + if (images.isNotEmpty) 12.height, + if (images.isNotEmpty) + ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (cxt, index) { + return Container( + margin: const EdgeInsets.all(10), + padding: const EdgeInsets.all(8.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Icon(Icons.attach_file_sharp), + const SizedBox( + width: 8, + ), + 'image ${index + 1}.png'.toText16(), + ], + ), + InkWell( + onTap: () { + setState(() { + images.remove(images[index]); + }); + }, + child: Icon( + Icons.delete_sharp, + color: Colors.red[300], + )) + ], + ), + ); + }, + separatorBuilder: (cxt, index) => 6.height, + itemCount: images.length), + ], + ), + ); + } + + void getAdDetails() async { + String details = await Utils.getStringFromPrefs(SharedPrefsConsts.editItemForSale); + final body = json.decode(details); + + GetRegionsList selectedRegionAd = GetRegionsList(); + + GetSaleCategoriesList selectedSaleCategoryAd = GetSaleCategoriesList(); + + itemTitle = body["itemTitle"]; + itemDescription = body["itemDescription"]; + selectedItemCondition = body["itemCondition"].toString().toLowerCase(); + selectedRegionAd.regionID = body["selectedRegion"]["regionID"]; + selectedRegionAd.regionName = body["selectedRegion"]["regionName"]; + selectedRegion = selectedRegionAd; + itemPrice = body["itemPrice"]; + selectedSaleCategoryAd.categoryID = body["selectedSaleCategory"]["categoryID"]; + selectedSaleCategoryAd.title = body["selectedSaleCategory"]["title"]; + if (body["itemPhotos"].length != 0) { + images.add(body["itemPhotos"][0]); + } + ItemReviewModel itemReviewModel = + ItemReviewModel(body["itemTitle"], body["itemDescription"], body["itemCondition"].toString().toLowerCase(), selectedRegionAd, body["itemPrice"], images, selectedSaleCategoryAd); + + AddItemDetailsFragment.itemReviewModel = itemReviewModel; + SelectCategoryFragment.selectedSaleCategory = selectedSaleCategoryAd; + + setState(() {}); + } + + void getRegions() async { + try { + Utils.showLoading(context); + getRegionsList = await ItemsForSaleApiClient().getRegions(); + Utils.hideLoading(context); + setState(() {}); + getAdDetails(); + } catch (ex) { + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + } + } +} diff --git a/lib/ui/screens/items_for_sale/fragments/item_review_fragment.dart b/lib/ui/screens/items_for_sale/fragments/item_review_fragment.dart new file mode 100644 index 0000000..0b02658 --- /dev/null +++ b/lib/ui/screens/items_for_sale/fragments/item_review_fragment.dart @@ -0,0 +1,154 @@ +import 'dart:convert'; + +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:mohem_flutter_app/api/items_for_sale/items_for_sale_api_client.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/items_for_sale/add_item_for_sale_image_model.dart'; +import 'package:mohem_flutter_app/models/items_for_sale/item_review_model.dart'; +import 'package:mohem_flutter_app/ui/screens/items_for_sale/fragments/add_details_fragment.dart'; +import 'package:mohem_flutter_app/ui/screens/items_for_sale/fragments/select_category_fragment.dart'; +import 'package:mohem_flutter_app/widgets/button/default_button.dart'; + +class ItemReviewFragment extends StatefulWidget { + final Function changePageViewIndex; + + ItemReviewFragment({Key? key, required this.changePageViewIndex}) : super(key: key); + + @override + State createState() => _ItemReviewFragmentState(); +} + +class _ItemReviewFragmentState extends State { + ItemReviewModel? itemReviewModel; + + @override + void initState() { + itemReviewModel = AddItemDetailsFragment.itemReviewModel; + itemReviewModel!.selectedSaleCategory = SelectCategoryFragment.selectedSaleCategory; + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(20), + boxShadow: [ + BoxShadow( + color: const Color(0xff000000).withOpacity(.05), + blurRadius: 26, + offset: const Offset(0, -3), + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + itemReviewModel!.itemTitle.toString().toText17(isBold: true).paddingOnly(top: 12), + itemReviewModel!.itemDescription.toString().toText14().paddingOnly(top: 8), + itemReviewModel!.itemCondition.toString().toText14(color: MyColors.yellowColor).paddingOnly(top: 12), + SizedBox( + height: 105.0, + child: ListView.separated( + shrinkWrap: true, + physics: const BouncingScrollPhysics(), + scrollDirection: Axis.horizontal, + itemBuilder: (cxt, index) { + return Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: const Color(0xff000000).withOpacity(.05), + blurRadius: 26, + offset: const Offset(0, -3), + ), + ], + ), + width: 100, + height: 100, + child: ClipRRect( + borderRadius: BorderRadius.circular(6), + child: Image.memory( + base64Decode(itemReviewModel!.itemPhotos![index]), + fit: BoxFit.contain, + ), + ), + ).paddingOnly(top: 12.0, bottom: 12.0); + }, + separatorBuilder: (cxt, index) => 8.width, + itemCount: itemReviewModel!.itemPhotos!.length), + ), + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + "Selling for ".toText14(), + "${itemReviewModel!.itemPrice.toString()} SAR".toText20(isBold: true), + ], + ), + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + const Icon( + Icons.warning_sharp, + size: 20, + color: MyColors.redColor, + ).paddingOnly(top: 21), + "This ad will be valid for 2 weeks after approval.".toText11(color: MyColors.redColor).paddingOnly(left: 10, right: 10), + ], + ), + const Spacer(), + Row( + children: [ + DefaultButton( + LocaleKeys.cancel.tr(), + () async { + Navigator.of(context).pop(); + }, + colors: const [Color(0xffD02127), Color(0xffD02127)], + ).expanded, + 12.width, + DefaultButton( + LocaleKeys.submit.tr(), + () async { + submitItemForSale(); + }, + disabledColor: MyColors.lightGrayColor, + ).expanded + ], + ).paddingOnly(top: 21), + ], + ), + ).paddingAll(21); + } + + void submitItemForSale() async { + List> imagesList = []; + int attachmentID = 1; + for (var element in itemReviewModel!.itemPhotos!) { + imagesList.add(AddItemForSaleImageModel(attachmentID: attachmentID, base64Data: element, fileName: "Image_$attachmentID", contentType: "image/png").toJson()); + attachmentID++; + } + + try { + Utils.showLoading(context); + String message = await ItemsForSaleApiClient().addItemForSale(itemReviewModel!, imagesList); + Utils.hideLoading(context); + Utils.showToast(message); + Navigator.of(context).pop(); + setState(() {}); + } catch (ex) { + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + } + } +} 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 new file mode 100644 index 0000000..ffb45e0 --- /dev/null +++ b/lib/ui/screens/items_for_sale/fragments/items_for_sale.dart @@ -0,0 +1,239 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:mohem_flutter_app/api/items_for_sale/items_for_sale_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/models/items_for_sale/get_items_for_sale_list.dart'; +import 'package:mohem_flutter_app/models/items_for_sale/get_sale_categories_list.dart'; +import 'package:mohem_flutter_app/ui/screens/items_for_sale/items_for_sale_home.dart'; +import 'package:mohem_flutter_app/widgets/dynamic_forms/dynamic_textfield_widget.dart'; + +class ItemsForSaleFragment extends StatefulWidget { + @override + State createState() => _ItemsForSaleFragmentState(); +} + +class _ItemsForSaleFragmentState extends State { + TextEditingController searchController = TextEditingController(); + + List getSaleCategoriesList = []; + List getItemsForSaleList = []; + + ScrollController gridScrollController = ScrollController(); + int currentPageNo = 1; + int currentCategoryID = 0; + + @override + void initState() { + getItemForSaleCategory(); + gridScrollController.addListener(() { + if (gridScrollController.position.atEdge) { + bool isTop = gridScrollController.position.pixels == 0; + if (!isTop) { + print('At the bottom'); + currentPageNo++; + getItemsForSale(currentPageNo, currentCategoryID); + } + } + }); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + controller: gridScrollController, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + DynamicTextFieldWidget( + "Search", + "Search Items", + isEnable: true, + suffixIconData: Icons.search, + isPopup: false, + lines: 1, + isInputTypeNum: false, + isReadOnly: false, + onChange: (String value) { + // _runFilter(value); + }, + ).paddingOnly(left: 21, right: 21, top: 21, bottom: 18), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + "Browse Categories".toText17(), + IconButton( + icon: const Icon(Icons.filter_alt_sharp, color: MyColors.darkIconColor, size: 28.0), + onPressed: () => Navigator.pop(context), + ), + ], + ).paddingOnly(left: 21, right: 21), + SizedBox( + height: 105.0, + child: getSaleCategoriesList.isNotEmpty + ? ListView.separated( + shrinkWrap: true, + physics: const BouncingScrollPhysics(), + padding: const EdgeInsets.only(left: 21, right: 21, top: 13, bottom: 13), + scrollDirection: Axis.horizontal, + itemBuilder: (cxt, index) { + return AspectRatio( + aspectRatio: 1 / 1, + child: InkWell( + onTap: () { + setState(() { + currentCategoryID = getSaleCategoriesList[index].categoryID!; + getItemsForSaleList.clear(); + currentPageNo = 1; + getItemsForSale(currentPageNo, currentCategoryID); + }); + }, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(15), + boxShadow: [ + BoxShadow( + color: const Color(0xff000000).withOpacity(.05), + blurRadius: 26, + offset: const Offset(0, -3), + ), + ], + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SvgPicture.string(getSaleCategoriesList[index].content!, fit: BoxFit.contain), + currentCategoryID == getSaleCategoriesList[index].categoryID ? const Icon(Icons.check_circle_rounded, color: MyColors.greenColor, size: 16.0) : Container(), + ], + ).expanded, + getSaleCategoriesList[index].title!.toText10() + ], + ).paddingOnly(left: 10, right: 10, bottom: 10, top: 12), + ), + ), + ); + }, + separatorBuilder: (cxt, index) => 12.width, + itemCount: getSaleCategoriesList.length) + : Container(), + ), + getItemsForSaleList.isNotEmpty + ? GridView( + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2, childAspectRatio: 162 / 266, crossAxisSpacing: 12, mainAxisSpacing: 12), + padding: const EdgeInsets.only(left: 21, right: 21, bottom: 21, top: 21), + shrinkWrap: true, + primary: false, + physics: const ScrollPhysics(), + children: getItemsForSaleWidgets(), + ) + : Utils.getNoDataWidget(context).paddingOnly(top: 50), + // 32.height, + ], + ), + ); + } + + List getItemsForSaleWidgets() { + List itemsList = []; + + getItemsForSaleList.forEach((element) { + itemsList.add(getItemCard(element)); + }); + + return itemsList; + } + + Widget getItemCard(GetItemsForSaleList getItemsForSaleList) { + return InkWell( + onTap: () { + Navigator.pushNamed(context, AppRoutes.itemsForSaleDetail, arguments: getItemsForSaleList); + }, + child: Container( + padding: const EdgeInsets.all(10.0), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: const Color(0xff000000).withOpacity(.05), + blurRadius: 26, + offset: const Offset(0, -3), + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Hero( + tag: "ItemImage" + getItemsForSaleList.itemSaleID.toString(), + transitionOnUserGestures: true, + child: AspectRatio( + aspectRatio: 148 / 127, + child: ClipRRect( + borderRadius: BorderRadius.circular(6), + child: Image.memory( + base64Decode(getItemsForSaleList.itemAttachments![0].content!), + fit: BoxFit.cover, + ), + ), + ), + ), + 10.height, + getItemsForSaleList.title!.toText16(isBold: true, color: const Color(0xff2B353E), maxlines: 1), + 10.height, + getItemsForSaleList.description!.toText12(maxLine: 2, color: const Color(0xff535353)), + 16.height, + getItemsForSaleList.status!.toText14(isBold: true, color: getItemsForSaleList.status == 'Approved' ? MyColors.greenColor : MyColors.yellowColor), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: ["${getItemsForSaleList.quotePrice} ${getItemsForSaleList.currencyCode!}".toText14(isBold: true), SvgPicture.asset("assets/images/arrow_next.svg").paddingOnly(bottom: 4)], + ), + ], + ), + ), + ); + } + + void getItemForSaleCategory() async { + try { + Utils.showLoading(context); + getSaleCategoriesList = await ItemsForSaleApiClient().getSaleCategories(); + Utils.hideLoading(context); + setState(() {}); + getItemsForSale(currentPageNo, currentCategoryID); + } catch (ex) { + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + } + } + + void getItemsForSale(int itgPageNo, int itgCategoryID) async { + List getItemsForSaleListLocal = []; + try { + Utils.showLoading(context); + getItemsForSaleListLocal.clear(); + getItemsForSaleListLocal = await ItemsForSaleApiClient().getItemsForSale(itgPageNo, itgCategoryID); + getItemsForSaleList.addAll(getItemsForSaleListLocal); + Utils.hideLoading(context); + setState(() {}); + } catch (ex) { + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + } + } +} diff --git a/lib/ui/screens/items_for_sale/fragments/my_posted_ads_fragment.dart b/lib/ui/screens/items_for_sale/fragments/my_posted_ads_fragment.dart new file mode 100644 index 0000000..f477672 --- /dev/null +++ b/lib/ui/screens/items_for_sale/fragments/my_posted_ads_fragment.dart @@ -0,0 +1,213 @@ +import 'dart:convert'; + +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'package:mohem_flutter_app/api/items_for_sale/items_for_sale_api_client.dart'; +import 'package:mohem_flutter_app/app_state/app_state.dart'; +import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/classes/consts.dart'; +import 'package:mohem_flutter_app/classes/date_uitl.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/items_for_sale/get_employee_ads_list.dart'; +import 'package:mohem_flutter_app/models/items_for_sale/get_regions_list.dart'; +import 'package:mohem_flutter_app/models/items_for_sale/get_sale_categories_list.dart'; +import 'package:mohem_flutter_app/models/items_for_sale/item_review_model.dart'; + +class MyPostedAdsFragment extends StatefulWidget { + const MyPostedAdsFragment({Key? key}) : super(key: key); + + @override + State createState() => _MyPostedAdsFragmentState(); +} + +class _MyPostedAdsFragmentState extends State { + List employeePostedAdsList = []; + + @override + void initState() { + getAdsByEmployee(); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + child: Container( + margin: const EdgeInsets.all(21), + child: employeePostedAdsList.isNotEmpty + ? ListView.separated( + shrinkWrap: true, + physics: const BouncingScrollPhysics(), + itemBuilder: (cxt, index) { + return Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(15), + boxShadow: [ + BoxShadow( + color: const Color(0xff000000).withOpacity(.05), + blurRadius: 26, + offset: const Offset(0, -3), + ), + ], + ), + child: Column( + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Container( + width: 50, + height: 50, + decoration: BoxDecoration( + color: Colors.white, + boxShadow: [ + BoxShadow( + color: const Color(0xff000000).withOpacity(.05), + blurRadius: 26, + offset: const Offset(0, -3), + ), + ], + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(6), + child: employeePostedAdsList[index].itemAttachments!.isNotEmpty + ? Image.memory( + base64Decode(employeePostedAdsList[index].itemAttachments![0].content!), + fit: BoxFit.contain, + ) + : Container(), + ), + ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + employeePostedAdsList[index].title!.toText16(isBold: true, color: const Color(0xff2B353E)).paddingOnly(left: 12, right: 12), + "Posted on ${DateUtil.formatDateToDate(DateTime.parse(employeePostedAdsList[index].created!), false)}" + .toText12(color: Color(0xff969696)) + .paddingOnly(left: 7, right: 7), + ], + ), + employeePostedAdsList[index].description!.toText12(color: const Color(0xff2B353E), maxLine: 1).paddingOnly(left: 12, right: 12, bottom: 12), + employeePostedAdsList[index] + .status! + .toText12(isBold: true, color: employeePostedAdsList[index].status == 'Approved' ? MyColors.greenColor : MyColors.yellowColor) + .paddingOnly(left: 12, right: 12), + // Row( + // children: [ + // IconButton( + // padding: EdgeInsets.zero, + // icon: const Icon( + // Icons.delete_rounded, + // size: 25, + // color: MyColors.redColor, + // ), + // constraints: const BoxConstraints(), + // onPressed: () { + // updateItemForSale(employeePostedAdsList[index].itemSaleID!); + // }), + // 37.width, + // IconButton( + // padding: EdgeInsets.zero, + // icon: const Icon( + // Icons.edit_note_sharp, + // size: 25, + // color: Color(0xff2E303A), + // ), + // constraints: const BoxConstraints(), + // onPressed: () {}), + // ], + // ), + ], + ), + ), + ], + ).paddingOnly(left: 7, right: 7, bottom: 0, top: 12), + const Divider( + color: MyColors.lightGreyEFColor, + thickness: 1.0, + ), + Row( + children: [ + LocaleKeys.remove.tr().toText12(color: MyColors.redColor).center.onPress(() { + updateItemForSale(employeePostedAdsList[index].itemSaleID!); + }).expanded, + Container(width: 1, height: 30, color: MyColors.lightGreyEFColor), + LocaleKeys.edit.tr().toText12(color: MyColors.gradiantEndColor).center.onPress(() { + GetRegionsList selectedRegion = GetRegionsList(); + selectedRegion.regionID = employeePostedAdsList[index].regionID; + selectedRegion.regionName = employeePostedAdsList[index].regionName; + GetSaleCategoriesList selectedSaleCategory = GetSaleCategoriesList(); + selectedSaleCategory.categoryID = employeePostedAdsList[index].categoryID; + selectedSaleCategory.title = employeePostedAdsList[index].categoryTitle; + List itemPhotos = []; + itemPhotos.add(employeePostedAdsList[index].itemAttachments![0].content!.toString()); + ItemReviewModel itemReviewModel = ItemReviewModel(employeePostedAdsList[index].title, employeePostedAdsList[index].description, employeePostedAdsList[index].status, + selectedRegion, employeePostedAdsList[index].quotePrice, itemPhotos, selectedSaleCategory); + Utils.saveStringFromPrefs(SharedPrefsConsts.editItemForSale, jsonEncode(itemReviewModel.toJson())); + Navigator.pushNamed(context, AppRoutes.addNewItemForSale, arguments: 1); + }).expanded, + ], + ), + 8.height + ], + ), + ); + }, + separatorBuilder: (cxt, index) => 12.height, + itemCount: employeePostedAdsList.length) + : Utils.getNoDataWidget(context).paddingOnly(top: 200.0), + ), + ); + } + + void updateItemForSale(int itemSaleID) async { + Utils.showLoading(context); + + String? empNum = AppState().memberInformationList?.eMPLOYEENUMBER; + String? empMobNum = AppState().memberInformationList?.eMPLOYEEMOBILENUMBER; + String? loginTokenID = AppState().postParamsObject?.logInTokenID; + String? tokenID = AppState().postParamsObject?.tokenID; + + var request = http.MultipartRequest('POST', Uri.parse("${ApiConsts.cocRest}Mohemm_ITG_UpdateItemForSale")); + request.fields['itemSaleID'] = itemSaleID.toString(); + request.fields['Channel'] = "31"; + request.fields['isActive'] = "false"; + request.fields['LogInToken'] = loginTokenID!; + request.fields['Token'] = tokenID!; + request.fields['MobileNo'] = empMobNum!; + request.fields['EmployeeNumber'] = empNum!; + request.fields['employeeNumber'] = empNum; + var response = await request.send().catchError((e) { + Utils.hideLoading(context); + Utils.handleException(e, context, null); + }); + print(response.statusCode); + Utils.hideLoading(context); + getAdsByEmployee(); + } + + void getAdsByEmployee() async { + try { + employeePostedAdsList.clear(); + Utils.showLoading(context); + employeePostedAdsList = await ItemsForSaleApiClient().getEmployeePostedAds(); + Utils.hideLoading(context); + setState(() {}); + } catch (ex) { + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + } + } +} diff --git a/lib/ui/screens/items_for_sale/fragments/select_category_fragment.dart b/lib/ui/screens/items_for_sale/fragments/select_category_fragment.dart new file mode 100644 index 0000000..6255302 --- /dev/null +++ b/lib/ui/screens/items_for_sale/fragments/select_category_fragment.dart @@ -0,0 +1,78 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:mohem_flutter_app/extensions/string_extensions.dart'; +import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; +import 'package:mohem_flutter_app/models/items_for_sale/get_sale_categories_list.dart'; + +class SelectCategoryFragment extends StatelessWidget { + final Function changePageViewIndex; + final List getSaleCategoriesList; + static late GetSaleCategoriesList selectedSaleCategory; + + SelectCategoryFragment({Key? key, required this.changePageViewIndex, required this.getSaleCategoriesList}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + "What are you offering".toText20(isBold: true).paddingOnly(top: 24, left: 21, right: 21), + getSaleCategoriesList.isNotEmpty + ? GridView( + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, childAspectRatio: 105 / 105, crossAxisSpacing: 12, mainAxisSpacing: 12), + padding: const EdgeInsets.only(top: 15, bottom: 15, left: 21, right: 21), + shrinkWrap: true, + primary: false, + physics: const ScrollPhysics(), + children: getItemsForSaleWidgets(), + ) + : Container(), + ], + ), + ); + } + + List getItemsForSaleWidgets() { + List itemsList = []; + + getSaleCategoriesList.forEach((element) { + itemsList.add(InkWell( + onTap: () { + selectedSaleCategory = element; + changePageViewIndex(1); + }, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(15), + boxShadow: [ + BoxShadow( + color: const Color(0xff000000).withOpacity(.05), + blurRadius: 26, + offset: const Offset(0, -3), + ), + ], + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SvgPicture.string(element.content!, fit: BoxFit.contain, width: 32, height: 32), + ], + ).expanded, + element.title!.toText12() + ], + ).paddingOnly(left: 10, right: 10, bottom: 10, top: 12), + ), + )); + }); + + return itemsList; + } +} 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 new file mode 100644 index 0000000..8d3b09c --- /dev/null +++ b/lib/ui/screens/items_for_sale/item_for_sale_detail.dart @@ -0,0 +1,136 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/classes/date_uitl.dart'; +import 'package:mohem_flutter_app/extensions/string_extensions.dart'; +import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; +import 'package:mohem_flutter_app/models/items_for_sale/get_items_for_sale_list.dart'; +import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; +import 'package:mohem_flutter_app/widgets/button/default_button.dart'; +import 'package:mohem_flutter_app/widgets/circular_avatar.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class ItemForSaleDetailPage extends StatefulWidget { + const ItemForSaleDetailPage({Key? key}) : super(key: key); + + @override + State createState() => _ItemForSaleDetailPageState(); +} + +class _ItemForSaleDetailPageState extends State { + late GetItemsForSaleList getItemsForSaleList; + + @override + Widget build(BuildContext context) { + getItemsForSaleList = ModalRoute.of(context)?.settings.arguments as GetItemsForSaleList; + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBarWidget(context, + // title: LocaleKeys.mowadhafhiRequest.tr(), + title: "Items for sale", + showHomeButton: true), + body: SingleChildScrollView( + child: AspectRatio( + aspectRatio: 336 / 554, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: const Color(0xff000000).withOpacity(.05), + blurRadius: 26, + offset: const Offset(0, -3), + ), + ], + ), + // color: Colors.red, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Container( + decoration: BoxDecoration( + boxShadow: [ + BoxShadow( + color: const Color(0xffEBEBEB).withOpacity(1.0), + blurRadius: 26, + offset: const Offset(0, -3), + ), + ], + ), + child: Hero( + tag: "ItemImage" + getItemsForSaleList.itemSaleID.toString(), + transitionOnUserGestures: true, + child: AspectRatio( + aspectRatio: 148 / 127, + child: ClipRRect( + borderRadius: BorderRadius.circular(6), + child: Image.memory( + base64Decode(getItemsForSaleList.itemAttachments![0].content!), + fit: BoxFit.cover, + ), + ), + ).paddingAll(8), + ), + ), + getItemsForSaleList.title!.toText20(isBold: true, color: const Color(0xff2B353E)).paddingOnly(left: 21, right: 21), + getItemsForSaleList.description!.toText12(maxLine: 5, color: const Color(0xff535353)).paddingOnly(left: 21, right: 21, bottom: 21), + getItemsForSaleList.status!.toText16(isBold: true, color: getItemsForSaleList.status == 'Approved' ? MyColors.greenColor : MyColors.yellowColor).paddingOnly(left: 21, right: 21), + "${getItemsForSaleList.quotePrice} ${getItemsForSaleList.currencyCode!}".toText20(isBold: true).paddingOnly(left: 21, right: 21, bottom: 15), + const Divider().paddingOnly(left: 21, right: 21), + Row( + children: [ + CircularAvatar( + height: 40, + width: 40, + ).paddingOnly(left: 21, top: 21), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + getItemsForSaleList.fullName!.toText14(isBold: true).paddingOnly(left: 7, right: 7), + "Posted on: ${DateUtil.formatDateToDate(DateTime.parse(getItemsForSaleList.created!), false)}".toText12().paddingOnly(left: 7, right: 7), + ], + ).paddingOnly(top: 18), + ], + ), + ], + ), + ).paddingAll(21), + ), + ), + bottomSheet: Container( + decoration: const BoxDecoration( + color: MyColors.white, + boxShadow: [ + BoxShadow(color: MyColors.lightGreyEFColor, spreadRadius: 1), + ], + ), + child: Row( + children: [ + DefaultButton("Email", () async { + final Uri emailLaunchUri = Uri( + scheme: 'mailto', + path: getItemsForSaleList.emailAddress, + ); + launchUrl(emailLaunchUri); + }, iconData: Icons.email_sharp, isTextExpanded: false) + .insideContainer + .expanded, + DefaultButton("Call", () async { + final Uri callLaunchUri = Uri( + scheme: 'tel', + path: getItemsForSaleList.mobileNumber, + ); + launchUrl(callLaunchUri); + }, iconData: Icons.call_sharp, isTextExpanded: false) + .insideContainer + .expanded, + ], + ), + ), + ); + } +} diff --git a/lib/ui/screens/items_for_sale/items_for_sale_home.dart b/lib/ui/screens/items_for_sale/items_for_sale_home.dart new file mode 100644 index 0000000..360c0ae --- /dev/null +++ b/lib/ui/screens/items_for_sale/items_for_sale_home.dart @@ -0,0 +1,111 @@ +import 'package:flutter/material.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/models/items_for_sale/get_sale_categories_list.dart'; +import 'package:mohem_flutter_app/ui/screens/items_for_sale/fragments/items_for_sale.dart'; +import 'package:mohem_flutter_app/ui/screens/items_for_sale/fragments/my_posted_ads_fragment.dart'; +import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; + +class ItemsForSale extends StatefulWidget { + const ItemsForSale({Key? key}) : super(key: key); + + @override + State createState() => _ItemsForSaleState(); +} + +class _ItemsForSaleState extends State { + int tabIndex = 0; + PageController controller = PageController(); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBarWidget(context, + // title: LocaleKeys.mowadhafhiRequest.tr(), + title: "Items for sale", + showHomeButton: true), + body: 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("Items for sale", 0), myTab("My posted ads", 1)], + ), + ), + PageView( + controller: controller, + physics: const NeverScrollableScrollPhysics(), + onPageChanged: (int pageIndex) { + setState(() { + tabIndex = pageIndex; + }); + }, + children: [ + ItemsForSaleFragment(), + MyPostedAdsFragment() + ], + ).expanded, + ], + ), + floatingActionButton: Container( + height: 50, + width: 50, + decoration: const BoxDecoration( + shape: BoxShape.circle, + gradient: LinearGradient(transform: GradientRotation(.83), begin: Alignment.topRight, end: Alignment.bottomLeft, colors: [ + MyColors.gradiantEndColor, + MyColors.gradiantStartColor, + ]), + ), + child: const Icon(Icons.add, color: Colors.white, size: 30), + ).onPress(() { + Navigator.pushNamed(context, AppRoutes.addNewItemForSale); + }) + ); + } + + Widget myTab(String title, int index) { + bool isSelected = (index == tabIndex); + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + title.toText12(color: isSelected ? Colors.white : Colors.white.withOpacity(.74), isCenter: true), + 4.height, + Container( + height: 8, + width: 8, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: isSelected ? Colors.white : Colors.transparent, + ), + ).onPress(() { + setState(() { + // showFabOptions = true; + }); + }) + ], + ).onPress(() { + controller.jumpToPage(index); + }).expanded; + } +} diff --git a/lib/widgets/dynamic_forms/dynamic_textfield_widget.dart b/lib/widgets/dynamic_forms/dynamic_textfield_widget.dart index c44be0d..5bf8875 100644 --- a/lib/widgets/dynamic_forms/dynamic_textfield_widget.dart +++ b/lib/widgets/dynamic_forms/dynamic_textfield_widget.dart @@ -62,7 +62,8 @@ class DynamicTextFieldWidget extends StatelessWidget { TextField( enabled: isEnable, scrollPadding: EdgeInsets.zero, readOnly: isReadOnly, - keyboardType: isInputTypeNum ? TextInputType.number : TextInputType.text, + keyboardType: isInputTypeNum ? const TextInputType.numberWithOptions(signed: true) : TextInputType.text, + textInputAction: TextInputAction.done, //controller: controller, maxLines: lines, obscuringCharacter: "*", diff --git a/lib/widgets/image_picker.dart b/lib/widgets/image_picker.dart new file mode 100644 index 0000000..6c1a06f --- /dev/null +++ b/lib/widgets/image_picker.dart @@ -0,0 +1,154 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/extensions/string_extensions.dart'; + +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: 20))?.path ?? ""); + String fileName = _image.path; + final 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: 20))?.path ?? ""); + String fileName = _image.path; + final 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; + final bytes = File(fileName).readAsBytesSync(); + String base64Encode = base64.encode(bytes); + if (base64Encode != null) { + image(base64Encode, _image); + } +} + +void cameraImageAndroid(Function(String, File) image) async { + File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.camera, imageQuality: 20))?.path ?? ""); + String fileName = _image.path; + final bytes = File(fileName).readAsBytesSync(); + String base64Encode = base64.encode(bytes); + if (base64Encode != null) { + image(base64Encode, _image); + } +} + +class _BottomSheet extends StatelessWidget { + final List children; + + const _BottomSheet({Key? key, required this.children}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.symmetric(vertical: 12.0), + decoration: BoxDecoration(color: Theme.of(context).backgroundColor, borderRadius: const BorderRadius.only(topLeft: Radius.circular(16.0), topRight: Radius.circular(16.0))), + child: SafeArea( + top: false, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + decoration: BoxDecoration(color: Theme.of(context).dividerColor, borderRadius: BorderRadius.circular(3.0)), + width: 40.0, + height: 6.0, + ), + ...children + ], + ), + ), + ); + } +} + +class _BottomSheetItem extends StatelessWidget { + final Function onTap; + final IconData icon; + final String title; + final Color color; + + _BottomSheetItem({Key? key, required this.onTap, required this.title, required this.icon, this.color = MyColors.gradiantStartColor}) : super(key: key); + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: () { + if (onTap != null) { + Navigator.pop(context); + onTap(); + } + }, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 18.0, vertical: 18.0), + child: Row( + children: [ + if (icon != null) + Icon( + icon, + color: color, + size: 18.0, + ), + if (icon != null) const SizedBox(width: 24.0), + title.toText17(), + ], + ), + ), + ); + } +} From 028caf1379247bf1c7b166fa6f954648e26b2ea2 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Sun, 28 Aug 2022 22:11:35 +0300 Subject: [PATCH 5/8] Offers & Discounts implemented --- lib/api/offers_and_discounts_api_client.dart | 69 +++++ lib/config/routes.dart | 9 + lib/extensions/string_extensions.dart | 15 +- .../get_categories_list.dart | 49 ++++ .../offers_and_discounts/get_offers_list.dart | 96 +++++++ lib/provider/dashboard_provider_model.dart | 17 ++ lib/ui/landing/dashboard_screen.dart | 99 +++++-- .../fragments/items_for_sale.dart | 1 - .../offers_and_discounts_details.dart | 239 +++++++++++++++ .../offers_and_discounts_home.dart | 271 ++++++++++++++++++ .../shimmer/offers_shimmer_widget.dart | 46 +++ pubspec.yaml | 6 +- 12 files changed, 877 insertions(+), 40 deletions(-) create mode 100644 lib/api/offers_and_discounts_api_client.dart create mode 100644 lib/models/offers_and_discounts/get_categories_list.dart create mode 100644 lib/models/offers_and_discounts/get_offers_list.dart create mode 100644 lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart create mode 100644 lib/ui/screens/offers_and_discounts/offers_and_discounts_home.dart create mode 100644 lib/widgets/shimmer/offers_shimmer_widget.dart diff --git a/lib/api/offers_and_discounts_api_client.dart b/lib/api/offers_and_discounts_api_client.dart new file mode 100644 index 0000000..2f5714b --- /dev/null +++ b/lib/api/offers_and_discounts_api_client.dart @@ -0,0 +1,69 @@ +import 'dart:convert'; + +import 'package:mohem_flutter_app/api/api_client.dart'; +import 'package:mohem_flutter_app/app_state/app_state.dart'; +import 'package:mohem_flutter_app/classes/consts.dart'; +import 'package:mohem_flutter_app/models/offers_and_discounts/get_categories_list.dart'; +import 'package:mohem_flutter_app/models/offers_and_discounts/get_offers_list.dart'; + +class OffersAndDiscountsApiClient { + static final OffersAndDiscountsApiClient _instance = OffersAndDiscountsApiClient._internal(); + + OffersAndDiscountsApiClient._internal(); + + factory OffersAndDiscountsApiClient() => _instance; + + Future> getSaleCategories() async { + List getSaleCategoriesList = []; + + String url = "${ApiConsts.cocRest}Mohemm_ITG_GetCategories"; + Map postParams = {"EmployeeNumber": AppState().memberInformationList?.eMPLOYEENUMBER, "ItgPageSize": 100, "ItgPageNo": 1}; + + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject( + (response) { + final body = json.decode(response['Mohemm_ITG_ResponseItem']); + + GetCategoriesList getSaleCategoriesListObj = GetCategoriesList(); + getSaleCategoriesListObj.id = 0; + getSaleCategoriesListObj.categoryNameEn = "All"; + getSaleCategoriesListObj.categoryNameAr = "الجميع"; + getSaleCategoriesListObj.isActive = true; + getSaleCategoriesListObj.content = + ''; + + getSaleCategoriesList.add(getSaleCategoriesListObj); + + body['result']['data'].forEach((v) { + getSaleCategoriesList.add(GetCategoriesList.fromJson(v)); + }); + return getSaleCategoriesList; + }, + url, + postParams, + ); + } + + Future> getOffersList(int categoryID, int pageSize) async { + List getSaleCategoriesList = []; + + String url = "${ApiConsts.cocRest}GetOfferDiscountsConfigData"; + Map postParams = {"EmployeeNumber": AppState().memberInformationList?.eMPLOYEENUMBER, "ItgPageSize": pageSize, "ItgPageNo": 1, "ItgCategoryID": categoryID}; + + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject( + (response) { + final body = json.decode(response['Mohemm_ITG_ResponseItem']); + + final bodyData = json.decode(body['result']['data']); + + bodyData.forEach((v) { + getSaleCategoriesList.add(OffersListModel.fromJson(v)); + }); + return getSaleCategoriesList; + }, + url, + postParams, + ); + } +} diff --git a/lib/config/routes.dart b/lib/config/routes.dart index 6928f09..270cb48 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -36,6 +36,8 @@ import 'package:mohem_flutter_app/ui/screens/mowadhafhi/mowadhafhi_hr_request.da import 'package:mohem_flutter_app/ui/screens/mowadhafhi/request_details.dart'; import 'package:mohem_flutter_app/ui/screens/my_requests/my_requests.dart'; import 'package:mohem_flutter_app/ui/screens/my_requests/new_request.dart'; +import 'package:mohem_flutter_app/ui/screens/offers_and_discounts/offers_and_discounts_details.dart'; +import 'package:mohem_flutter_app/ui/screens/offers_and_discounts/offers_and_discounts_home.dart'; import 'package:mohem_flutter_app/ui/screens/pending_transactions/pending_transactions.dart'; import 'package:mohem_flutter_app/ui/screens/pending_transactions/pending_transactions_details.dart'; import 'package:mohem_flutter_app/ui/screens/profile/profile_screen.dart'; @@ -117,6 +119,10 @@ class AppRoutes { static const String itemsForSaleDetail = "/itemsForSaleDetail"; static const String addNewItemForSale = "/addNewItemForSale"; + // Offers & Discounts + static const String offersAndDiscounts = "/offersAndDiscounts"; + static const String offersAndDiscountsDetails = "/offersAndDiscountsDetails"; + //Pay slip static const String monthlyPaySlip = "/monthlyPaySlip"; @@ -188,6 +194,9 @@ class AppRoutes { itemsForSaleDetail: (context) => ItemForSaleDetailPage(), addNewItemForSale: (context) => AddNewItemForSale(), + // Offers & Discounts + offersAndDiscounts: (context) => OffersAndDiscountsHome(), + offersAndDiscountsDetails: (context) => OffersAndDiscountsDetails(), //pay slip monthlyPaySlip: (context) => MonthlyPaySlipScreen(), diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index 869b61c..8f280b1 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -15,8 +15,9 @@ extension CapExtension on String { extension EmailValidator on String { Widget get toWidget => Text(this); - Widget toText10({Color? color, bool isBold = false}) => Text( + Widget toText10({Color? color, bool isBold = false, int maxLine = 0}) => Text( this, + maxLines: (maxLine > 0) ? maxLine : null, style: TextStyle(fontSize: 10, fontWeight: isBold ? FontWeight.bold : FontWeight.w600, color: color ?? MyColors.darkTextColor, letterSpacing: -0.4), ); @@ -49,15 +50,21 @@ extension EmailValidator on String { style: TextStyle(fontSize: 13, fontWeight: FontWeight.w600, color: color ?? MyColors.darkTextColor, letterSpacing: -0.52, decoration: isUnderLine ? TextDecoration.underline : null), ); - Widget toText14({Color? color, bool isBold = false}) => Text( + Widget toText14({Color? color, bool isBold = false, int? maxlines}) => Text( this, + maxLines: maxlines, style: TextStyle(color: color ?? MyColors.darkTextColor, fontSize: 14, letterSpacing: -0.48, fontWeight: isBold ? FontWeight.bold : FontWeight.w600), ); - Widget toText16({Color? color, bool isBold = false, int? maxlines}) => Text( + Widget toText16({Color? color, bool isBold = false, int? maxlines, bool isUnderLine = false}) => Text( this, maxLines: maxlines, - style: TextStyle(color: color ?? MyColors.darkTextColor, fontSize: 16, letterSpacing: -0.64, fontWeight: isBold ? FontWeight.bold : FontWeight.w600), + style: TextStyle( + color: color ?? MyColors.darkTextColor, + fontSize: 16, + letterSpacing: -0.64, + fontWeight: isBold ? FontWeight.bold : FontWeight.w600, + decoration: isUnderLine ? TextDecoration.underline : TextDecoration.none), ); Widget toText17({Color? color, bool isBold = false}) => Text( diff --git a/lib/models/offers_and_discounts/get_categories_list.dart b/lib/models/offers_and_discounts/get_categories_list.dart new file mode 100644 index 0000000..502a850 --- /dev/null +++ b/lib/models/offers_and_discounts/get_categories_list.dart @@ -0,0 +1,49 @@ +class GetCategoriesList { + int? id; + String? categoryNameEn; + String? content; + String? categoryNameAr; + int? channelId; + bool? isActive; + int? pageSize; + int? pageNo; + int? languageId; + + GetCategoriesList({ + this.id, + this.categoryNameEn, + this.content, + this.categoryNameAr, + this.channelId, + this.isActive, + this.pageSize, + this.pageNo, + this.languageId, + }); + + GetCategoriesList.fromJson(Map json) { + id = json['id']; + categoryNameEn = json['categoryName_en']; + content = json['content']; + categoryNameAr = json['categoryName_ar']; + channelId = json['channelId']; + isActive = json['isActive']; + pageSize = json['pageSize']; + pageNo = json['pageNo']; + languageId = json['languageId']; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['categoryName_en'] = categoryNameEn; + data['content'] = content; + data['categoryName_ar'] = categoryNameAr; + data['channelId'] = channelId; + data['isActive'] = isActive; + data['pageSize'] = pageSize; + data['pageNo'] = pageNo; + data['languageId'] = languageId; + return data; + } +} diff --git a/lib/models/offers_and_discounts/get_offers_list.dart b/lib/models/offers_and_discounts/get_offers_list.dart new file mode 100644 index 0000000..2b08ba6 --- /dev/null +++ b/lib/models/offers_and_discounts/get_offers_list.dart @@ -0,0 +1,96 @@ +class OffersListModel { + String? title; + String? titleAR; + String? description; + String? descriptionAR; + String? startDate; + String? endDate; + String? logo; + String? bannerImage; + String? discount; + String? rowID; + String? categoryNameEn; + String? categoryNameAr; + String? categoryID; + String? isHasLocation; + String? created; + String? publishedDesc; + String? published; + String? expireAfter; + String? status; + String? isActive; + String? totalItems; + + OffersListModel( + {this.title, + this.titleAR, + this.description, + this.descriptionAR, + this.startDate, + this.endDate, + this.logo, + this.bannerImage, + this.discount, + this.rowID, + this.categoryNameEn, + this.categoryNameAr, + this.categoryID, + this.isHasLocation, + this.created, + this.publishedDesc, + this.published, + this.expireAfter, + this.status, + this.isActive, + this.totalItems}); + + OffersListModel.fromJson(Map json) { + title = json['Title']; + titleAR = json['Title_AR']; + description = json['Description']; + descriptionAR = json['Description_AR']; + startDate = json['Start Date']; + endDate = json['End Date']; + logo = json['Logo']; + bannerImage = json['Banner_Image']; + discount = json['Discount']; + rowID = json['rowID']; + categoryNameEn = json['categoryName_en']; + categoryNameAr = json['categoryName_ar']; + categoryID = json['categoryID']; + isHasLocation = json['IsHasLocation']; + created = json['created']; + publishedDesc = json['PublishedDesc']; + published = json['Published']; + expireAfter = json['ExpireAfter']; + status = json['Status']; + isActive = json['IsActive']; + totalItems = json['TotalItems']; + } + + Map toJson() { + final Map data = new Map(); + data['Title'] = this.title; + data['Title_AR'] = this.titleAR; + data['Description'] = this.description; + data['Description_AR'] = this.descriptionAR; + data['Start Date'] = this.startDate; + data['End Date'] = this.endDate; + data['Logo'] = this.logo; + data['Banner_Image'] = this.bannerImage; + data['Discount'] = this.discount; + data['rowID'] = this.rowID; + data['categoryName_en'] = this.categoryNameEn; + data['categoryName_ar'] = this.categoryNameAr; + data['categoryID'] = this.categoryID; + data['IsHasLocation'] = this.isHasLocation; + data['created'] = this.created; + data['PublishedDesc'] = this.publishedDesc; + data['Published'] = this.published; + data['ExpireAfter'] = this.expireAfter; + data['Status'] = this.status; + data['IsActive'] = this.isActive; + data['TotalItems'] = this.totalItems; + return data; + } +} diff --git a/lib/provider/dashboard_provider_model.dart b/lib/provider/dashboard_provider_model.dart index 511fc03..ddb245d 100644 --- a/lib/provider/dashboard_provider_model.dart +++ b/lib/provider/dashboard_provider_model.dart @@ -4,6 +4,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:mohem_flutter_app/api/dashboard_api_client.dart'; +import 'package:mohem_flutter_app/api/offers_and_discounts_api_client.dart'; import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; import 'package:mohem_flutter_app/main.dart'; @@ -13,6 +14,7 @@ import 'package:mohem_flutter_app/models/dashboard/itg_forms_model.dart'; import 'package:mohem_flutter_app/models/dashboard/menu_entries.dart'; import 'package:mohem_flutter_app/models/dashboard/menus.dart'; import 'package:mohem_flutter_app/models/generic_response_model.dart'; +import 'package:mohem_flutter_app/models/offers_and_discounts/get_offers_list.dart'; /// Mix-in [DiagnosticableTreeMixin] to have access to [debugFillProperties] for the devtool // ignore: prefer_mixin @@ -41,6 +43,9 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { List? homeMenus; List? getMenuEntriesList; + //Offers And Discounts + List getOffersList = []; + //Attendance Tracking API's & Methods Future fetchAttendanceTracking(context) async { try { @@ -175,6 +180,18 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } } + void getCategoryOffersListAPI(BuildContext context) async { + try { + // Utils.showLoading(context); + getOffersList = await OffersAndDiscountsApiClient().getOffersList(0, 6); + notifyListeners(); + } catch (ex) { + // Utils.hideLoading(context); + notifyListeners(); + Utils.handleException(ex, context, null); + } + } + List parseMenus(List getMenuEntriesList) { List menus = []; for (int i = 0; i < getMenuEntriesList.length; i++) { diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index d5acce6..4d2cc38 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -13,11 +13,13 @@ 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/offers_and_discounts/get_offers_list.dart'; import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart'; import 'package:mohem_flutter_app/ui/landing/widget/app_drawer.dart'; import 'package:mohem_flutter_app/ui/landing/widget/menus_widget.dart'; import 'package:mohem_flutter_app/ui/landing/widget/services_widget.dart'; import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart'; +import 'package:mohem_flutter_app/widgets/shimmer/offers_shimmer_widget.dart'; import 'package:provider/provider.dart'; class DashboardScreen extends StatefulWidget { @@ -44,6 +46,7 @@ class _DashboardScreenState extends State { data.fetchMissingSwipe(context); data.fetchLeaveTicketBalance(context); data.fetchMenuEntries(); + data.getCategoryOffersListAPI(context); } @override @@ -267,7 +270,11 @@ class _DashboardScreenState extends State { ], ), ), - LocaleKeys.viewAllOffers.tr().toText12(isUnderLine: true), + InkWell( + onTap: () { + Navigator.pushNamed(context, AppRoutes.offersAndDiscounts); + }, + child: LocaleKeys.viewAllOffers.tr().toText12(isUnderLine: true)), ], ).paddingOnly(left: 21, right: 21), SizedBox( @@ -278,37 +285,50 @@ class _DashboardScreenState extends State { padding: const EdgeInsets.only(left: 21, right: 21, top: 13), scrollDirection: Axis.horizontal, itemBuilder: (cxt, index) { - return SizedBox( - width: 73, - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Container( - width: 73, - height: 73, - decoration: BoxDecoration( - borderRadius: const BorderRadius.all( - Radius.circular(100), - ), - border: Border.all(color: MyColors.lightGreyEDColor, width: 1), - ), - child: ClipRRect( - borderRadius: const BorderRadius.all( - Radius.circular(50), - ), - child: Image.network( - "https://play-lh.googleusercontent.com/NPo88ojmhah4HDiposucJmfQIop4z4xc8kqJK9ITO9o-yCab2zxIp7PPB_XPj2iUojo", - fit: BoxFit.cover, + return data.getOffersList.isNotEmpty + ? InkWell( + onTap: () { + navigateToDetails(data.getOffersList[index]); + }, + child: SizedBox( + width: 73, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + width: 73, + height: 73, + decoration: BoxDecoration( + borderRadius: const BorderRadius.all( + Radius.circular(100), + ), + border: Border.all(color: MyColors.lightGreyEDColor, width: 1), + ), + child: ClipRRect( + borderRadius: const BorderRadius.all( + Radius.circular(50), + ), + child: Hero( + tag: "ItemImage" + data.getOffersList[index].rowID!, + transitionOnUserGestures: true, + child: Image.network( + data.getOffersList[index].bannerImage!, + fit: BoxFit.contain, + ), + ), + ), + ), + 4.height, + Expanded( + child: AppState().isArabic(context) + ? data.getOffersList[index].titleAR!.toText12(isCenter: true, maxLine: 1) + : data.getOffersList[index].title!.toText12(isCenter: true, maxLine: 1), + ), + ], ), ), - ), - 4.height, - Expanded( - child: namesD[6 % (index + 1)].toText12(isCenter: true, maxLine: 2), - ), - ], - ), - ); + ) + : const OffersShimmerWidget(); }, separatorBuilder: (cxt, index) => 8.width, itemCount: 6), @@ -397,4 +417,23 @@ class _DashboardScreenState extends State { ), ); } + + void navigateToDetails(OffersListModel offersListModelObj) { + List getOffersDetailList = []; + getOffersDetailList.clear(); + int counter = 1; + + getOffersDetailList.add(offersListModelObj); + + data.getOffersList.forEach((element) { + if (counter <= 4) { + if (element.rowID != offersListModelObj.rowID) { + getOffersDetailList.add(element); + counter++; + } + } + }); + + Navigator.pushNamed(context, AppRoutes.offersAndDiscountsDetails, arguments: getOffersDetailList); + } } 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 ffb45e0..93ea8e9 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 @@ -195,7 +195,6 @@ class _ItemsForSaleFragmentState extends State { ), 10.height, getItemsForSaleList.title!.toText16(isBold: true, color: const Color(0xff2B353E), maxlines: 1), - 10.height, getItemsForSaleList.description!.toText12(maxLine: 2, color: const Color(0xff535353)), 16.height, getItemsForSaleList.status!.toText14(isBold: true, color: getItemsForSaleList.status == 'Approved' ? MyColors.greenColor : MyColors.yellowColor), diff --git a/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart b/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart new file mode 100644 index 0000000..e5b7f11 --- /dev/null +++ b/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart @@ -0,0 +1,239 @@ +import 'dart:io'; +import 'dart:typed_data'; +import 'dart:ui' as ui; + +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_html/flutter_html.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:mohem_flutter_app/app_state/app_state.dart'; +import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/extensions/int_extensions.dart'; +import 'package:mohem_flutter_app/extensions/string_extensions.dart'; +import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; +import 'package:mohem_flutter_app/models/offers_and_discounts/get_offers_list.dart'; +import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:share/share.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class OffersAndDiscountsDetails extends StatefulWidget { + const OffersAndDiscountsDetails({Key? key}) : super(key: key); + + @override + State createState() => _OffersAndDiscountsDetailsState(); +} + +class _OffersAndDiscountsDetailsState extends State { + // late OffersListModel getOffersList; + late List getOffersList; + late ScrollController _scrollController; + + GlobalKey _globalKey = GlobalKey(); + + @override + void initState() { + _scrollController = ScrollController(); + super.initState(); + } + + @override + Widget build(BuildContext context) { + getOffersList = ModalRoute.of(context)?.settings.arguments as List; + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBarWidget( + context, + // title: LocaleKeys.mowadhafhiRequest.tr(), + title: "Offers & Discounts", + showHomeButton: true, + ), + body: SingleChildScrollView( + controller: _scrollController, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: const Color(0xff000000).withOpacity(.05), + blurRadius: 26, + offset: const Offset(0, -3), + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Hero( + tag: "ItemImage" + getOffersList[0].rowID!, + // transitionOnUserGestures: true, + child: RepaintBoundary( + key: _globalKey, + child: ClipRRect( + borderRadius: BorderRadius.circular(6), + child: Image.network( + getOffersList[0].bannerImage!, + fit: BoxFit.contain, + ), + ).paddingAll(12), + ), + ), + 8.height, + AppState().isArabic(context) + ? getOffersList[0].titleAR!.toText22(isBold: true, color: const Color(0xff2B353E)).center + : getOffersList[0].title!.toText22(isBold: true, color: const Color(0xff2B353E)).center, + Html( + data: AppState().isArabic(context) ? getOffersList[0].descriptionAR! : getOffersList[0].description ?? "", + onLinkTap: (String? url, RenderContext context, Map attributes, _) { + launchUrl(Uri.parse(url!)); + }, + ), + checkDate(getOffersList[0].endDate!).paddingOnly(left: 8), + 10.height, + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + getOffersList[0].discount!.toText16(isBold: true), + InkWell( + onTap: () { + _shareOfferAsImage(); + }, + child: const Icon(Icons.share, color: MyColors.darkIconColor).paddingOnly(bottom: 4)) + ], + ).paddingOnly(left: 8, right: 8), + getOffersList[0].isHasLocation == "true" + ? InkWell( + onTap: () {}, + child: Row( + children: [const Icon(Icons.map_sharp, color: MyColors.darkIconColor).paddingOnly(bottom: 4), "Offer Location".toText16(isUnderLine: true).paddingOnly(left: 8)], + ).paddingOnly(left: 8, right: 8, top: 8), + ) + : 12.height, + ], + ), + ).paddingOnly(left: 21, right: 21, top: 21), + "Related Offers".toText22(isBold: true, color: const Color(0xff2B353E)).paddingAll(21.0), + GridView( + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2, childAspectRatio: 162 / 266, crossAxisSpacing: 12, mainAxisSpacing: 12), + padding: const EdgeInsets.only(left: 21, right: 21, bottom: 21, top: 21), + shrinkWrap: true, + primary: false, + physics: const ScrollPhysics(), + children: getItemsForSaleWidgets(), + ), + 50.height, + ], + ), + ), + ); + } + + void _shareOfferAsImage() async { + try { + RenderRepaintBoundary? boundary = _globalKey.currentContext?.findRenderObject() as RenderRepaintBoundary; + ui.Image? image = await boundary.toImage(pixelRatio: 3.0); + ByteData? byteData = await image.toByteData(format: ui.ImageByteFormat.png); + Uint8List pngBytes = byteData!.buffer.asUint8List(); + + Directory tempDir = await getTemporaryDirectory(); + File file = await File('${tempDir.path}/${DateTime.now().toString()}.png').create(); + await file.writeAsBytes(pngBytes); + await Share.shareFiles([(file.path)], text: AppState().isArabic(context) ? getOffersList[0].titleAR : getOffersList[0].title); + } catch (ex) { + debugPrint(ex.toString()); + } + } + + void _scrollToTop() { + _scrollController.animateTo( + 0, + duration: const Duration(milliseconds: 500), + curve: Curves.linear, + ); + } + + List getItemsForSaleWidgets() { + List itemsList = []; + for (int i = 1; i < 5; i++) { + itemsList.add(getItemCard(getOffersList[i])); + } + return itemsList; + } + + Widget getItemCard(OffersListModel getOffersList) { + return InkWell( + onTap: () { + this.getOffersList[0] = getOffersList; + _scrollToTop(); + setState(() {}); + }, + child: Container( + padding: const EdgeInsets.all(10.0), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: const Color(0xff000000).withOpacity(.05), + blurRadius: 26, + offset: const Offset(0, -3), + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Hero( + tag: "ItemImage" + getOffersList.rowID!, + transitionOnUserGestures: true, + child: AspectRatio( + aspectRatio: 148 / 127, + child: ClipRRect( + borderRadius: BorderRadius.circular(6), + child: Image.network( + getOffersList.bannerImage!, + fit: BoxFit.contain, + ), + ), + ), + ), + 5.height, + getOffersList.title!.toText16(isBold: true, color: const Color(0xff2B353E), maxlines: 1), + // Html( + // data: AppState().isArabic(context) ? getOffersList.descriptionAR! : getOffersList.description ?? "", + // // onLinkTap: (String? url, RenderContext context, Map attributes, _) { + // // launchUrl(Uri.parse(url!)); + // // } + // ), + getOffersList.description!.toText12(maxLine: 2, color: const Color(0xff535353)), + 16.height, + getOffersList.discount!.toText14(isBold: true, maxlines: 1), + 10.height, + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [checkDate(getOffersList.endDate!), SvgPicture.asset("assets/images/arrow_next.svg").paddingOnly(bottom: 4)], + ), + ], + ), + ), + ); + } + + void getOfferLocation() {} + + Widget checkDate(String endDate) { + DateTime endDateObj = DateFormat("yyyy-MM-dd").parse(endDate); + if (endDateObj.isAfter(DateTime.now())) { + return "Offer Valid".toText16(isBold: true, color: MyColors.greenColor); + } else { + return "Offer Expired".toText16(isBold: true, color: MyColors.redColor); + } + } +} diff --git a/lib/ui/screens/offers_and_discounts/offers_and_discounts_home.dart b/lib/ui/screens/offers_and_discounts/offers_and_discounts_home.dart new file mode 100644 index 0000000..bdf6ed5 --- /dev/null +++ b/lib/ui/screens/offers_and_discounts/offers_and_discounts_home.dart @@ -0,0 +1,271 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:mohem_flutter_app/api/offers_and_discounts_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/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/models/offers_and_discounts/get_categories_list.dart'; +import 'package:mohem_flutter_app/models/offers_and_discounts/get_offers_list.dart'; +import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; +import 'package:mohem_flutter_app/widgets/dynamic_forms/dynamic_textfield_widget.dart'; + +class OffersAndDiscountsHome extends StatefulWidget { + const OffersAndDiscountsHome({Key? key}) : super(key: key); + + @override + State createState() => _OffersAndDiscountsHomeState(); +} + +class _OffersAndDiscountsHomeState extends State { + List getCategoriesList = []; + List getOffersList = []; + + int currentCategoryID = 0; + + @override + void initState() { + getCategoriesListAPI(); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBarWidget( + context, + // title: LocaleKeys.mowadhafhiRequest.tr(), + title: "Offers & Discounts", + showHomeButton: true, + ), + body: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + DynamicTextFieldWidget( + "Search", + "Search Items", + isEnable: true, + suffixIconData: Icons.search, + isPopup: false, + lines: 1, + isInputTypeNum: false, + isReadOnly: false, + onChange: (String value) { + // _runFilter(value); + }, + ).paddingOnly(left: 21, right: 21, top: 21, bottom: 18), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + "Browse Categories".toText17(), + IconButton( + icon: const Icon(Icons.filter_alt_sharp, color: MyColors.darkIconColor, size: 28.0), + onPressed: () => Navigator.pop(context), + ), + ], + ).paddingOnly(left: 21, right: 21), + SizedBox( + height: 110.0, + child: getCategoriesList.isNotEmpty + ? ListView.separated( + shrinkWrap: true, + physics: const BouncingScrollPhysics(), + padding: const EdgeInsets.only(left: 21, right: 21, top: 13, bottom: 13), + scrollDirection: Axis.horizontal, + itemBuilder: (cxt, index) { + return AspectRatio( + aspectRatio: 1 / 1, + child: InkWell( + onTap: () { + setState(() { + currentCategoryID = getCategoriesList[index].id!; + // getItemsForSaleList.clear(); + // currentPageNo = 1; + // getItemsForSale(currentPageNo, currentCategoryID); + }); + }, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(15), + boxShadow: [ + BoxShadow( + color: const Color(0xff000000).withOpacity(.05), + blurRadius: 26, + offset: const Offset(0, -3), + ), + ], + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SvgPicture.string( + getCategoriesList[index].content!, + fit: BoxFit.contain, + width: 25, + height: 25, + ), + currentCategoryID == getCategoriesList[index].id ? const Icon(Icons.check_circle_rounded, color: MyColors.greenColor, size: 16.0) : Container(), + ], + ).expanded, + AppState().isArabic(context) ? getCategoriesList[index].categoryNameAr!.toText10(maxLine: 1) : getCategoriesList[index].categoryNameEn!.toText10(maxLine: 1) + ], + ).paddingOnly(left: 10, right: 10, bottom: 10, top: 12), + ), + ), + ); + }, + separatorBuilder: (cxt, index) => 12.width, + itemCount: getCategoriesList.length, + ) + : Container(), + ), + getOffersList.isNotEmpty + ? GridView( + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2, childAspectRatio: 162 / 266, crossAxisSpacing: 12, mainAxisSpacing: 12), + padding: const EdgeInsets.only(left: 21, right: 21, bottom: 21, top: 21), + shrinkWrap: true, + primary: false, + physics: const ScrollPhysics(), + children: getItemsForSaleWidgets(), + ) + : Utils.getNoDataWidget(context).paddingOnly(top: 50), + ], + ), + ), + ); + } + + List getItemsForSaleWidgets() { + List itemsList = []; + + for (var element in getOffersList) { + itemsList.add(getItemCard(element)); + } + + return itemsList; + } + + Widget getItemCard(OffersListModel getOffersList) { + return InkWell( + onTap: () { + navigateToDetails(getOffersList); + }, + child: Container( + padding: const EdgeInsets.all(10.0), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: const Color(0xff000000).withOpacity(.05), + blurRadius: 26, + offset: const Offset(0, -3), + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Hero( + tag: "ItemImage" + getOffersList.rowID!, + transitionOnUserGestures: true, + child: AspectRatio( + aspectRatio: 148 / 127, + child: ClipRRect( + borderRadius: BorderRadius.circular(6), + child: Image.network( + getOffersList.bannerImage!, + fit: BoxFit.contain, + ), + ), + ), + ), + 10.height, + AppState().isArabic(context) ? getOffersList.titleAR!.toText16(isBold: true, color: const Color(0xff2B353E), maxlines: 1) : getOffersList.title!.toText16(isBold: true, color: const Color(0xff2B353E), maxlines: 1), + // Html( + // data: AppState().isArabic(context) ? getOffersList.descriptionAR! : getOffersList.description ?? "", + // // onLinkTap: (String? url, RenderContext context, Map attributes, _) { + // // launchUrl(Uri.parse(url!)); + // // } + // ), + getOffersList.description!.toText12(maxLine: 2, color: const Color(0xff535353)), + 16.height, + getOffersList.discount!.toText14(isBold: true, maxlines: 1), + 10.height, + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [checkDate(getOffersList.endDate!), SvgPicture.asset("assets/images/arrow_next.svg").paddingOnly(bottom: 4)], + ), + ], + ), + ), + ); + } + + void navigateToDetails(OffersListModel offersListModelObj) { + List getOffersDetailList = []; + getOffersDetailList.clear(); + int counter = 1; + + getOffersDetailList.add(offersListModelObj); + + getOffersList.forEach((element) { + if(counter <= 4) { + if(element.rowID != offersListModelObj.rowID) { + getOffersDetailList.add(element); + counter++; + } + } + }); + + Navigator.pushNamed(context, AppRoutes.offersAndDiscountsDetails, arguments: getOffersDetailList); + } + + Widget checkDate(String endDate) { + DateTime endDateObj = DateFormat("yyyy-MM-dd").parse(endDate); + if (endDateObj.isAfter(DateTime.now())) { + return "Offer Valid".toText14(isBold: true, color: MyColors.greenColor); + } else { + return "Offer Expired".toText14(isBold: true, color: MyColors.redColor); + } + } + + void getCategoriesListAPI() async { + try { + Utils.showLoading(context); + getCategoriesList = await OffersAndDiscountsApiClient().getSaleCategories(); + Utils.hideLoading(context); + setState(() {}); + getCategoryOffersListAPI(); + } catch (ex) { + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + } + } + + void getCategoryOffersListAPI() async { + try { + Utils.showLoading(context); + getOffersList = await OffersAndDiscountsApiClient().getOffersList(currentCategoryID, 100); + Utils.hideLoading(context); + setState(() {}); + } catch (ex) { + Utils.hideLoading(context); + Utils.handleException(ex, context, null); + } + } +} diff --git a/lib/widgets/shimmer/offers_shimmer_widget.dart b/lib/widgets/shimmer/offers_shimmer_widget.dart new file mode 100644 index 0000000..8e090d1 --- /dev/null +++ b/lib/widgets/shimmer/offers_shimmer_widget.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; +import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/extensions/int_extensions.dart'; +import 'package:mohem_flutter_app/extensions/string_extensions.dart'; +import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; + +class OffersShimmerWidget extends StatelessWidget { + const OffersShimmerWidget({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + child: SizedBox( + width: 73, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + width: 73, + height: 73, + decoration: BoxDecoration( + borderRadius: const BorderRadius.all( + Radius.circular(100), + ), + border: Border.all(color: MyColors.lightGreyEDColor, width: 1), + ), + child: ClipRRect( + borderRadius: const BorderRadius.all( + Radius.circular(50), + ), + child: Image.network( + "https://play-lh.googleusercontent.com/NPo88ojmhah4HDiposucJmfQIop4z4xc8kqJK9ITO9o-yCab2zxIp7PPB_XPj2iUojo", + fit: BoxFit.cover, + ).toShimmer(), + ), + ), + 8.height, + Container( + child: "Offers And Discounts".toText12(isCenter: true, maxLine: 1).toShimmer(), + ), + ], + ), + ), + ); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 8346c5c..fcd8742 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -71,12 +71,8 @@ dependencies: # flutter_barcode_scanner: ^2.0.0 qr_code_scanner: ^1.0.0 qr_flutter: ^4.0.0 - - - - - url_launcher: ^6.0.15 + share: 2.0.4 dev_dependencies: flutter_test: From 52438ce711821197727ea2c1bfa9cf43ae0f28da Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Mon, 29 Aug 2022 09:59:56 +0300 Subject: [PATCH 6/8] offers & discounts implemented --- lib/provider/dashboard_provider_model.dart | 2 + lib/ui/landing/dashboard_screen.dart | 108 +++++++++++---------- 2 files changed, 58 insertions(+), 52 deletions(-) diff --git a/lib/provider/dashboard_provider_model.dart b/lib/provider/dashboard_provider_model.dart index ddb245d..289ab33 100644 --- a/lib/provider/dashboard_provider_model.dart +++ b/lib/provider/dashboard_provider_model.dart @@ -44,6 +44,7 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { List? getMenuEntriesList; //Offers And Discounts + bool isOffersLoading = true; List getOffersList = []; //Attendance Tracking API's & Methods @@ -184,6 +185,7 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { try { // Utils.showLoading(context); getOffersList = await OffersAndDiscountsApiClient().getOffersList(0, 6); + isOffersLoading = false; notifyListeners(); } catch (ex) { // Utils.hideLoading(context); diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index 4d2cc38..3630660 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -277,61 +277,65 @@ class _DashboardScreenState extends State { child: LocaleKeys.viewAllOffers.tr().toText12(isUnderLine: true)), ], ).paddingOnly(left: 21, right: 21), - SizedBox( - height: 103 + 33, - child: ListView.separated( - shrinkWrap: true, - physics: const BouncingScrollPhysics(), - padding: const EdgeInsets.only(left: 21, right: 21, top: 13), - scrollDirection: Axis.horizontal, - itemBuilder: (cxt, index) { - return data.getOffersList.isNotEmpty - ? InkWell( - onTap: () { - navigateToDetails(data.getOffersList[index]); - }, - child: SizedBox( - width: 73, - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Container( - width: 73, - height: 73, - decoration: BoxDecoration( - borderRadius: const BorderRadius.all( - Radius.circular(100), - ), - border: Border.all(color: MyColors.lightGreyEDColor, width: 1), - ), - child: ClipRRect( - borderRadius: const BorderRadius.all( - Radius.circular(50), - ), - child: Hero( - tag: "ItemImage" + data.getOffersList[index].rowID!, - transitionOnUserGestures: true, - child: Image.network( - data.getOffersList[index].bannerImage!, - fit: BoxFit.contain, + Consumer( + builder: (context, model, child) { + return SizedBox( + height: 103 + 33, + child: ListView.separated( + shrinkWrap: true, + physics: const BouncingScrollPhysics(), + padding: const EdgeInsets.only(left: 21, right: 21, top: 13), + scrollDirection: Axis.horizontal, + itemBuilder: (cxt, index) { + return model.isOffersLoading + ? const OffersShimmerWidget() + : InkWell( + onTap: () { + navigateToDetails(data.getOffersList[index]); + }, + child: SizedBox( + width: 73, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + width: 73, + height: 73, + decoration: BoxDecoration( + borderRadius: const BorderRadius.all( + Radius.circular(100), + ), + border: Border.all(color: MyColors.lightGreyEDColor, width: 1), + ), + child: ClipRRect( + borderRadius: const BorderRadius.all( + Radius.circular(50), + ), + child: Hero( + tag: "ItemImage" + data.getOffersList[index].rowID!, + transitionOnUserGestures: true, + child: Image.network( + data.getOffersList[index].bannerImage!, + fit: BoxFit.contain, + ), + ), ), ), - ), - ), - 4.height, - Expanded( - child: AppState().isArabic(context) - ? data.getOffersList[index].titleAR!.toText12(isCenter: true, maxLine: 1) - : data.getOffersList[index].title!.toText12(isCenter: true, maxLine: 1), + 4.height, + Expanded( + child: AppState().isArabic(context) + ? data.getOffersList[index].titleAR!.toText12(isCenter: true, maxLine: 1) + : data.getOffersList[index].title!.toText12(isCenter: true, maxLine: 1), + ), + ], ), - ], - ), - ), - ) - : const OffersShimmerWidget(); - }, - separatorBuilder: (cxt, index) => 8.width, - itemCount: 6), + ), + ); + }, + separatorBuilder: (cxt, index) => 8.width, + itemCount: 6), + ); + }, ), ], ), From 7c0589ef323c3363b45e2ca3d86f89c614417bcc Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Mon, 29 Aug 2022 10:15:41 +0300 Subject: [PATCH 7/8] Announcement details fixes --- lib/api/pending_transactions_api_client.dart | 15 +++++++++++++++ .../announcements/announcement_details.dart | 6 +----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/lib/api/pending_transactions_api_client.dart b/lib/api/pending_transactions_api_client.dart index b8ddd60..44b2363 100644 --- a/lib/api/pending_transactions_api_client.dart +++ b/lib/api/pending_transactions_api_client.dart @@ -1,7 +1,10 @@ +import 'dart:convert'; + import 'package:mohem_flutter_app/api/api_client.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/consts.dart'; import 'package:mohem_flutter_app/models/generic_response_model.dart'; +import 'package:mohem_flutter_app/models/get_announcement_details.dart'; import 'package:mohem_flutter_app/models/pending_transactions/get_pending_transactions_details.dart'; import 'package:mohem_flutter_app/models/pending_transactions/get_req_functions.dart'; @@ -45,4 +48,16 @@ class PendingTransactionsApiClient { return responseData.mohemmITGResponseItem ?? ""; }, url, postParams); } + + Future getAnnouncementDetails(int itgAwarenessID, int itgPageNo, int itgRowID) async { + String url = "${ApiConsts.cocRest}GetAnnouncementDiscountsConfigData"; + Map postParams = {"EmployeeNumber": AppState().memberInformationList?.eMPLOYEENUMBER.toString(), "ItgAwarenessID": itgAwarenessID, "ItgPageNo": itgPageNo, "ItgPageSize": 5, "ItgRowID": itgRowID}; + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject((json) { + GenericResponseModel? responseData = GenericResponseModel.fromJson(json); + var jsonDecodedData = jsonDecode(jsonDecode(responseData.mohemmITGResponseItem!)['result']['data']); + return GetAnnouncementDetails.fromJson(jsonDecodedData[0]); + }, url, postParams); + } + } diff --git a/lib/ui/screens/announcements/announcement_details.dart b/lib/ui/screens/announcements/announcement_details.dart index 3b11cdf..c9645ec 100644 --- a/lib/ui/screens/announcements/announcement_details.dart +++ b/lib/ui/screens/announcements/announcement_details.dart @@ -106,11 +106,7 @@ class _AnnouncementDetailsState extends State { Future getAnnouncementDetails(int itgAwarenessID, int itgRowID) async { try { Utils.showLoading(context); - jsonResponse = await PendingTransactionsApiClient().getAnnouncements(itgAwarenessID, currentPageNo, itgRowID); - // todo '@haroon' move below post processing code to above method and get exact model which you need, - - var jsonDecodedData = jsonDecode(jsonDecode(jsonResponse)['result']['data']); - getAnnouncementDetailsObj = GetAnnouncementDetails.fromJson(jsonDecodedData[0]); + getAnnouncementDetailsObj = await PendingTransactionsApiClient().getAnnouncementDetails(itgAwarenessID, currentPageNo, itgRowID); Utils.hideLoading(context); setState(() {}); } catch (ex) { From 50f203cd558fe9c5dd93710af71db282522425ea Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Mon, 29 Aug 2022 13:44:04 +0300 Subject: [PATCH 8/8] Updates & fixes --- .../items_for_sale/get_employee_ads_list.dart | 10 +- .../get_ccp_dff_structure_model.dart | 20 -- .../items_for_sale/item_for_sale_detail.dart | 184 +++++++------- lib/ui/screens/my_requests/my_requests.dart | 236 +++++++++--------- lib/ui/screens/my_requests/new_request.dart | 29 +-- .../offers_and_discounts_details.dart | 91 +++---- 6 files changed, 267 insertions(+), 303 deletions(-) diff --git a/lib/models/items_for_sale/get_employee_ads_list.dart b/lib/models/items_for_sale/get_employee_ads_list.dart index 17a2180..68aa805 100644 --- a/lib/models/items_for_sale/get_employee_ads_list.dart +++ b/lib/models/items_for_sale/get_employee_ads_list.dart @@ -22,11 +22,10 @@ class EmployeePostedAds { String? status; List? itemAttachments; String? created; - dynamic? comments; - dynamic? isActive; + bool? isActive; int? pageSize; int? pageNo; - dynamic? languageId; + int? languageId; EmployeePostedAds( {this.itemSaleID, @@ -52,7 +51,6 @@ class EmployeePostedAds { this.status, this.itemAttachments, this.created, - this.comments, this.isActive, this.pageSize, this.pageNo, @@ -87,7 +85,6 @@ class EmployeePostedAds { }); } created = json['created']; - comments = json['comments']; isActive = json['isActive']; pageSize = json['pageSize']; pageNo = json['pageNo']; @@ -122,7 +119,6 @@ class EmployeePostedAds { this.itemAttachments!.map((v) => v.toJson()).toList(); } data['created'] = this.created; - data['comments'] = this.comments; data['isActive'] = this.isActive; data['pageSize'] = this.pageSize; data['pageNo'] = this.pageNo; @@ -137,7 +133,7 @@ class ItemAttachments { String? contentType; String? attachFileStream; String? base64String; - dynamic? isActive; + bool? isActive; int? referenceItemId; String? content; String? filePath; diff --git a/lib/models/my_requests/get_ccp_dff_structure_model.dart b/lib/models/my_requests/get_ccp_dff_structure_model.dart index 878cec4..f5e80cf 100644 --- a/lib/models/my_requests/get_ccp_dff_structure_model.dart +++ b/lib/models/my_requests/get_ccp_dff_structure_model.dart @@ -13,7 +13,6 @@ class GetCCPDFFStructureModel { String? dISPLAYFLAG; String? eNABLEDFLAG; ESERVICESDV? eSERVICESDV; - // List? eSERVICESVS; String? fLEXVALUESETNAME; String? fORMATTYPE; String? fORMATTYPEDSP; @@ -95,12 +94,6 @@ class GetCCPDFFStructureModel { eSERVICESDV = json['E_SERVICES_DV'] != null ? new ESERVICESDV.fromJson(json['E_SERVICES_DV']) : null; - // if (json['E_SERVICES_VS'] != null) { - // eSERVICESVS = []; - // json['E_SERVICES_VS'].forEach((v) { - // eSERVICESVS!.add(new Null.fromJson(v)); - // }); - // } fLEXVALUESETNAME = json['FLEX_VALUE_SET_NAME']; fORMATTYPE = json['FORMAT_TYPE']; fORMATTYPEDSP = json['FORMAT_TYPE_DSP']; @@ -112,19 +105,6 @@ class GetCCPDFFStructureModel { nUMBERPRECISION = json['NUMBER_PRECISION']; nUMERICMODEENABLEDFLAG = json['NUMERIC_MODE_ENABLED_FLAG']; pARENTSEGMENTSDV = json['PARENT_SEGMENTS_DV']; - // if (json['PARENT_SEGMENTS_DV_Splited'] != null) { - // pARENTSEGMENTSDVSplited = []; - // json['PARENT_SEGMENTS_DV_Splited'].forEach((v) { - // pARENTSEGMENTSDVSplited!.add(new Null.fromJson(v)); - // }); - // } - // pARENTSEGMENTSVS = json['PARENT_SEGMENTS_VS']; - // if (json['PARENT_SEGMENTS_VS_SplitedVS'] != null) { - // pARENTSEGMENTSVSSplitedVS = []; - // json['PARENT_SEGMENTS_VS_SplitedVS'].forEach((v) { - // pARENTSEGMENTSVSSplitedVS!.add(new Null.fromJson(v)); - // }); - // } rEADONLY = json['READ_ONLY']; rEQUIREDFLAG = json['REQUIRED_FLAG']; sEGMENTNAME = json['SEGMENT_NAME']; 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 01c60a6..c85f4e0 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 @@ -29,105 +29,109 @@ class _ItemForSaleDetailPageState extends State { appBar: AppBarWidget(context, // title: LocaleKeys.mowadhafhiRequest.tr(), title: "Items for sale", - showHomeButton: true), + showHomeButton: true,), body: SingleChildScrollView( - child: AspectRatio( - aspectRatio: 336 / 554, - child: Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(10), - boxShadow: [ - BoxShadow( - color: const Color(0xff000000).withOpacity(.05), - blurRadius: 26, - offset: const Offset(0, -3), + child: Column( + children: [ + AspectRatio( + aspectRatio: 336 / 554, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: const Color(0xff000000).withOpacity(.05), + blurRadius: 26, + offset: const Offset(0, -3), + ), + ], ), - ], - ), - // color: Colors.red, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Container( - decoration: BoxDecoration( - boxShadow: [ - BoxShadow( - color: const Color(0xffEBEBEB).withOpacity(1.0), - blurRadius: 26, - offset: const Offset(0, -3), + // color: Colors.red, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Container( + decoration: BoxDecoration( + boxShadow: [ + BoxShadow( + color: const Color(0xffEBEBEB).withOpacity(1.0), + blurRadius: 26, + offset: const Offset(0, -3), + ), + ], ), - ], - ), - child: Hero( - tag: "ItemImage" + getItemsForSaleList.itemSaleID.toString(), - transitionOnUserGestures: true, - child: AspectRatio( - aspectRatio: 148 / 127, - child: ClipRRect( - borderRadius: BorderRadius.circular(6), - child: Image.memory( - base64Decode(getItemsForSaleList.itemAttachments![0].content!), - fit: BoxFit.cover, - ), + child: Hero( + tag: "ItemImage" + getItemsForSaleList.itemSaleID.toString(), + transitionOnUserGestures: true, + child: AspectRatio( + aspectRatio: 148 / 127, + child: ClipRRect( + borderRadius: BorderRadius.circular(6), + child: Image.memory( + base64Decode(getItemsForSaleList.itemAttachments![0].content!), + fit: BoxFit.cover, + ), + ), + ).paddingAll(8), ), - ).paddingAll(8), - ), - ), - getItemsForSaleList.title!.toText20(isBold: true, color: const Color(0xff2B353E)).paddingOnly(left: 21, right: 21), - getItemsForSaleList.description!.toText12(maxLine: 5, color: const Color(0xff535353)).paddingOnly(left: 21, right: 21, bottom: 21), - getItemsForSaleList.status!.toText16(isBold: true, color: getItemsForSaleList.status == 'Approved' ? MyColors.greenColor : MyColors.yellowColor).paddingOnly(left: 21, right: 21), - "${getItemsForSaleList.quotePrice} ${getItemsForSaleList.currencyCode!}".toText20(isBold: true).paddingOnly(left: 21, right: 21, bottom: 15), - const Divider().paddingOnly(left: 21, right: 21), - Row( - children: [ - CircularAvatar( - height: 40, - width: 40, - ).paddingOnly(left: 21, top: 21), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, + ), + getItemsForSaleList.title!.toText20(isBold: true, color: const Color(0xff2B353E)).paddingOnly(left: 21, right: 21), + getItemsForSaleList.description!.toText12(maxLine: 5, color: const Color(0xff535353)).paddingOnly(left: 21, right: 21, bottom: 21), + getItemsForSaleList.status!.toText16(isBold: true, color: getItemsForSaleList.status == 'Approved' ? MyColors.greenColor : MyColors.yellowColor).paddingOnly(left: 21, right: 21), + "${getItemsForSaleList.quotePrice} ${getItemsForSaleList.currencyCode!}".toText20(isBold: true).paddingOnly(left: 21, right: 21, bottom: 15), + const Divider().paddingOnly(left: 21, right: 21), + Row( children: [ - getItemsForSaleList.fullName!.toText14(isBold: true).paddingOnly(left: 7, right: 7), - "Posted on: ${DateUtil.formatDateToDate(DateTime.parse(getItemsForSaleList.created!), false)}".toText12().paddingOnly(left: 7, right: 7), + CircularAvatar( + height: 40, + width: 40, + ).paddingOnly(left: 21, top: 21), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + getItemsForSaleList.fullName!.toText14(isBold: true).paddingOnly(left: 7, right: 7), + "Posted on: ${DateUtil.formatDateToDate(DateTime.parse(getItemsForSaleList.created!), false)}".toText12().paddingOnly(left: 7, right: 7), + ], + ).paddingOnly(top: 18), ], - ).paddingOnly(top: 18), + ), ], ), - ], + ).paddingAll(21), + ), + Container( + decoration: const BoxDecoration( + color: MyColors.white, + boxShadow: [ + BoxShadow(color: MyColors.lightGreyEFColor, spreadRadius: 1), + ], + ), + child: Row( + children: [ + DefaultButton("Email", () async { + Uri emailLaunchUri = Uri( + scheme: 'mailto', + path: getItemsForSaleList.emailAddress, + ); + launchUrl(emailLaunchUri); + }, iconData: Icons.email_sharp, isTextExpanded: false) + .insideContainer + .expanded, + DefaultButton("Call", () async { + Uri callLaunchUri = Uri( + scheme: 'tel', + path: getItemsForSaleList.mobileNumber, + ); + launchUrl(callLaunchUri); + }, iconData: Icons.call_sharp, isTextExpanded: false) + .insideContainer + .expanded, + ], + ), ), - ).paddingAll(21), - ), - ), - bottomSheet: Container( - decoration: const BoxDecoration( - color: MyColors.white, - boxShadow: [ - BoxShadow(color: MyColors.lightGreyEFColor, spreadRadius: 1), - ], - ), - child: Row( - children: [ - DefaultButton("Email", () async { - Uri emailLaunchUri = Uri( - scheme: 'mailto', - path: getItemsForSaleList.emailAddress, - ); - launchUrl(emailLaunchUri); - }, iconData: Icons.email_sharp, isTextExpanded: false) - .insideContainer - .expanded, - DefaultButton("Call", () async { - Uri callLaunchUri = Uri( - scheme: 'tel', - path: getItemsForSaleList.mobileNumber, - ); - launchUrl(callLaunchUri); - }, iconData: Icons.call_sharp, isTextExpanded: false) - .insideContainer - .expanded, ], ), ), diff --git a/lib/ui/screens/my_requests/my_requests.dart b/lib/ui/screens/my_requests/my_requests.dart index 82bc38b..ebeff43 100644 --- a/lib/ui/screens/my_requests/my_requests.dart +++ b/lib/ui/screens/my_requests/my_requests.dart @@ -13,7 +13,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/models/get_eit_dff_structure_list_model.dart'; import 'package:mohem_flutter_app/models/my_requests/get_ccp_output_model.dart'; import 'package:mohem_flutter_app/models/my_requests/get_ccp_transactions_model.dart'; import 'package:mohem_flutter_app/models/my_requests/get_concurrent_programs_model.dart'; @@ -45,127 +44,128 @@ class _MyRequestsState extends State { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: Colors.white, - appBar: AppBarWidget( - context, - title: "Concurrent Reports", + backgroundColor: Colors.white, + appBar: AppBarWidget( + context, + title: "Concurrent Reports", + ), + body: 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), + ), + ], ), - body: 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), - ), - ], - ), - child: Column( - children: [ - 12.height, - Container( - padding: const EdgeInsets.only(left: 12, right: 12, top: 10, bottom: 0), - margin: const EdgeInsets.only(left: 12, right: 12, top: 0, bottom: 0), - child: PopupMenuButton( - child: DynamicTextFieldWidget( - "Template Name", - selectedConcurrentProgramList?.uSERCONCURRENTPROGRAMNAME ?? "", - isEnable: false, - isPopup: true, - isInputTypeNum: true, - isReadOnly: false, - ).paddingOnly(bottom: 12), - itemBuilder: (_) => >[ - for (int i = 0; i < getConcurrentProgramsList!.length; i++) PopupMenuItem(child: Text(getConcurrentProgramsList![i].uSERCONCURRENTPROGRAMNAME!), value: i), - ], - onSelected: (int popupIndex) { - selectedConcurrentProgramList = getConcurrentProgramsList![popupIndex]; - getCCPTransactions(selectedConcurrentProgramList?.cONCURRENTPROGRAMNAME); - setState(() {}); - }), - ), - 12.height, - Expanded( - child: ListView.separated( - physics: const BouncingScrollPhysics(), - shrinkWrap: true, - itemBuilder: (BuildContext context, int index) { - return Container( - width: double.infinity, - padding: const EdgeInsets.only(left: 12, right: 12, top: 10, bottom: 12), - margin: const EdgeInsets.only(left: 12, right: 12, top: 10, bottom: 0), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(10), - boxShadow: [ - BoxShadow( - color: const Color(0xff000000).withOpacity(.05), - blurRadius: 26, - offset: const Offset(0, -3), - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - ("Request ID: " + getCCPTransactionsList[index].rEQUESTID.toString()).toText12(color: MyColors.grey57Color), - DateUtil.formatDateToDate(DateUtil.convertStringToDate(getCCPTransactionsList[index].rEQUESTDATE!), false).toText12(color: MyColors.grey70Color), - ], - ), - Container( - padding: const EdgeInsets.only(top: 10.0), - child: ("Phase: " + getCCPTransactionsList[index].cCPPHASE!).toText12(color: MyColors.grey57Color, isBold: true), - ), - Container( - padding: const EdgeInsets.only(top: 10.0), - child: "Program Name: ".toText12(color: MyColors.grey57Color, isBold: true), - ), - getCCPTransactionsList[index].cONCURRENTPROGRAMNAME!.toText12(color: MyColors.gradiantEndColor), - Container( - padding: const EdgeInsets.only(top: 10.0), - child: InkWell( - onTap: () { - getCCPOutput(getCCPTransactionsList[index].rEQUESTID.toString()); - }, - child: Row( - children: [ - "Output: ".toText12(color: MyColors.grey57Color), - 8.width, - "Open PDF".toText12(color: MyColors.grey57Color), - 6.width, - const Icon(Icons.launch, size: 16.0), - ], - ), + child: Column( + children: [ + 12.height, + Container( + padding: const EdgeInsets.only(left: 12, right: 12, top: 10, bottom: 0), + margin: const EdgeInsets.only(left: 12, right: 12, top: 0, bottom: 0), + child: PopupMenuButton( + child: DynamicTextFieldWidget( + "Template Name", + selectedConcurrentProgramList?.uSERCONCURRENTPROGRAMNAME ?? "", + isEnable: false, + isPopup: true, + isInputTypeNum: true, + isReadOnly: false, + ).paddingOnly(bottom: 12), + itemBuilder: (_) => >[ + for (int i = 0; i < getConcurrentProgramsList!.length; i++) PopupMenuItem(child: Text(getConcurrentProgramsList![i].uSERCONCURRENTPROGRAMNAME!), value: i), + ], + onSelected: (int popupIndex) { + selectedConcurrentProgramList = getConcurrentProgramsList![popupIndex]; + getCCPTransactions(selectedConcurrentProgramList?.cONCURRENTPROGRAMNAME); + setState(() {}); + }), + ), + 12.height, + Expanded( + child: ListView.separated( + physics: const BouncingScrollPhysics(), + shrinkWrap: true, + itemBuilder: (BuildContext context, int index) { + return Container( + width: double.infinity, + padding: const EdgeInsets.only(left: 12, right: 12, top: 10, bottom: 12), + margin: const EdgeInsets.only(left: 12, right: 12, top: 10, bottom: 0), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: const Color(0xff000000).withOpacity(.05), + blurRadius: 26, + offset: const Offset(0, -3), + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + ("Request ID: " + getCCPTransactionsList[index].rEQUESTID.toString()).toText12(color: MyColors.grey57Color), + DateUtil.formatDateToDate(DateUtil.convertStringToDate(getCCPTransactionsList[index].rEQUESTDATE!), false).toText12(color: MyColors.grey70Color), + ], + ), + Container( + padding: const EdgeInsets.only(top: 10.0), + child: ("Phase: " + getCCPTransactionsList[index].cCPPHASE!).toText12(color: MyColors.grey57Color, isBold: true), + ), + Container( + padding: const EdgeInsets.only(top: 10.0), + child: "Program Name: ".toText12(color: MyColors.grey57Color, isBold: true), + ), + getCCPTransactionsList[index].cONCURRENTPROGRAMNAME!.toText12(color: MyColors.gradiantEndColor), + Container( + padding: const EdgeInsets.only(top: 10.0), + child: InkWell( + onTap: () { + getCCPOutput(getCCPTransactionsList[index].rEQUESTID.toString()); + }, + child: Row( + children: [ + "Output: ".toText12(color: MyColors.grey57Color), + 8.width, + "Open PDF".toText12(color: MyColors.grey57Color), + 6.width, + const Icon(Icons.launch, size: 16.0), + ], ), ), - ], - ), - ); - }, - separatorBuilder: (BuildContext context, int index) => 12.height, - itemCount: getCCPTransactionsList.length ?? 0)), - 80.height - ], - ), + ), + ], + ), + ); + }, + separatorBuilder: (BuildContext context, int index) => 12.height, + itemCount: getCCPTransactionsList.length ?? 0)), + 80.height, + Container( + decoration: const BoxDecoration( + color: MyColors.white, + boxShadow: [ + BoxShadow(color: MyColors.lightGreyEFColor, spreadRadius: 3), + ], + ), + child: DefaultButton(LocaleKeys.createRequest.tr(), () async { + openNewRequest(); + }).insideContainer, + ) + ], ), - bottomSheet: Container( - decoration: const BoxDecoration( - color: MyColors.white, - boxShadow: [ - BoxShadow(color: MyColors.lightGreyEFColor, spreadRadius: 3), - ], - ), - child: DefaultButton(LocaleKeys.createRequest.tr(), () async { - openNewRequest(); - }).insideContainer, - )); + ), + ); } void openNewRequest() async { diff --git a/lib/ui/screens/my_requests/new_request.dart b/lib/ui/screens/my_requests/new_request.dart index 9577944..4cc2b20 100644 --- a/lib/ui/screens/my_requests/new_request.dart +++ b/lib/ui/screens/my_requests/new_request.dart @@ -78,21 +78,23 @@ class _NewRequestState extends State { itemBuilder: (cxt, int parentIndex) => parseDynamicFormatType(getCCPDFFStructureModelList[parentIndex], parentIndex), separatorBuilder: (cxt, index) => 0.height, itemCount: getCCPDFFStructureModelList.length)) - .expanded + .expanded, + Container( + decoration: const BoxDecoration( + color: MyColors.white, + boxShadow: [ + BoxShadow(color: MyColors.lightGreyEFColor, spreadRadius: 3), + ], + ), + child: DefaultButton(LocaleKeys.submit.tr(), () async { + // openNewRequest(); + }) + .insideContainer, + ) ], ), ), - bottomSheet: Container( - decoration: const BoxDecoration( - color: MyColors.white, - boxShadow: [ - BoxShadow(color: MyColors.lightGreyEFColor, spreadRadius: 3), - ], - ), - child: DefaultButton(LocaleKeys.submit.tr(), () async { - // openNewRequest(); - }).insideContainer, - ) + // bottomSheet: ); } @@ -412,8 +414,7 @@ class _NewRequestState extends State { ), ); } else { - DateTime? picked = - await showDatePicker(context: context, initialDate: selectedDate, initialEntryMode: DatePickerEntryMode.calendarOnly, firstDate: DateTime(2015, 8), lastDate: DateTime(2101)); + DateTime? picked = await showDatePicker(context: context, initialDate: selectedDate, initialEntryMode: DatePickerEntryMode.calendarOnly, firstDate: DateTime(2015, 8), lastDate: DateTime(2101)); if (picked != null && picked != selectedDate) { time = picked; } diff --git a/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart b/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart index e5b7f11..e1e216d 100644 --- a/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart +++ b/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart @@ -167,63 +167,46 @@ class _OffersAndDiscountsDetailsState extends State { } Widget getItemCard(OffersListModel getOffersList) { - return InkWell( - onTap: () { - this.getOffersList[0] = getOffersList; - _scrollToTop(); - setState(() {}); - }, - child: Container( - padding: const EdgeInsets.all(10.0), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(10), - boxShadow: [ - BoxShadow( - color: const Color(0xff000000).withOpacity(.05), - blurRadius: 26, - offset: const Offset(0, -3), - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Hero( - tag: "ItemImage" + getOffersList.rowID!, - transitionOnUserGestures: true, - child: AspectRatio( - aspectRatio: 148 / 127, - child: ClipRRect( - borderRadius: BorderRadius.circular(6), - child: Image.network( - getOffersList.bannerImage!, - fit: BoxFit.contain, - ), - ), + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Hero( + tag: "ItemImage" + getOffersList.rowID!, + transitionOnUserGestures: true, + child: AspectRatio( + aspectRatio: 148 / 127, + child: ClipRRect( + borderRadius: BorderRadius.circular(6), + child: Image.network( + getOffersList.bannerImage!, + fit: BoxFit.contain, ), ), - 5.height, - getOffersList.title!.toText16(isBold: true, color: const Color(0xff2B353E), maxlines: 1), - // Html( - // data: AppState().isArabic(context) ? getOffersList.descriptionAR! : getOffersList.description ?? "", - // // onLinkTap: (String? url, RenderContext context, Map attributes, _) { - // // launchUrl(Uri.parse(url!)); - // // } - // ), - getOffersList.description!.toText12(maxLine: 2, color: const Color(0xff535353)), - 16.height, - getOffersList.discount!.toText14(isBold: true, maxlines: 1), - 10.height, - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [checkDate(getOffersList.endDate!), SvgPicture.asset("assets/images/arrow_next.svg").paddingOnly(bottom: 4)], - ), - ], + ), ), - ), - ); + 5.height, + getOffersList.title!.toText16(isBold: true, color: const Color(0xff2B353E), maxlines: 1), + // Html( + // data: AppState().isArabic(context) ? getOffersList.descriptionAR! : getOffersList.description ?? "", + // // onLinkTap: (String? url, RenderContext context, Map attributes, _) { + // // launchUrl(Uri.parse(url!)); + // // } + // ), + getOffersList.description!.toText12(maxLine: 2, color: const Color(0xff535353)), + 16.height, + getOffersList.discount!.toText14(isBold: true, maxlines: 1), + 8.height, + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [checkDate(getOffersList.endDate!), SvgPicture.asset("assets/images/arrow_next.svg").paddingOnly(bottom: 4)], + ), + ], + ).objectContainerView().onPress(() { + this.getOffersList[0] = getOffersList; + _scrollToTop(); + setState(() {}); + }); } void getOfferLocation() {}