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..436ae6e --- /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) { + var 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) { + var 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) { + var 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) { + var 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) { + var body = json.decode(response['Mohemm_ITG_ResponseItem']); + return body["message"]; + }, url, postParams); + } +} 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/api/offers_and_discounts_api_client.dart b/lib/api/offers_and_discounts_api_client.dart new file mode 100644 index 0000000..b5aa9e6 --- /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) { + var 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) { + var body = json.decode(response['Mohemm_ITG_ResponseItem']); + + var bodyData = json.decode(body['result']['data']); + + bodyData.forEach((v) { + getSaleCategoriesList.add(OffersListModel.fromJson(v)); + }); + return getSaleCategoriesList; + }, + url, + postParams, + ); + } +} 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/classes/colors.dart b/lib/classes/colors.dart index 322bac6..3469681 100644 --- a/lib/classes/colors.dart +++ b/lib/classes/colors.dart @@ -23,6 +23,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 yellowFavColor = Color(0xffEAC321); static const Color backgroundBlackColor = Color(0xff202529); static const Color black = Color(0xff000000); 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/file_process.dart b/lib/classes/file_process.dart new file mode 100644 index 0000000..6974702 --- /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 Future 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/classes/utils.dart b/lib/classes/utils.dart index cf2ef23..7977598 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 4b51ca3..4917314 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -39,9 +39,16 @@ 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'; +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/submenu_screen.dart'; @@ -121,6 +128,19 @@ class AppRoutes { static const String announcements = "/announcements"; static const String announcementsDetails = "/announcementsDetails"; + // My Requests + 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"; + + // Offers & Discounts + static const String offersAndDiscounts = "/offersAndDiscounts"; + static const String offersAndDiscountsDetails = "/offersAndDiscountsDetails"; + //Pay slip static const String monthlyPaySlip = "/monthlyPaySlip"; @@ -199,6 +219,19 @@ class AppRoutes { announcements: (context) => Announcements(), announcementsDetails: (context) => AnnouncementDetails(), + //My Requests + myRequests: (context) => MyRequests(), + newRequest: (context) => NewRequest(), + + // Items for sale + itemsForSale: (context) => ItemsForSale(), + itemsForSaleDetail: (context) => ItemForSaleDetailPage(), + addNewItemForSale: (context) => AddNewItemForSale(), + + // Offers & Discounts + offersAndDiscounts: (context) => OffersAndDiscountsHome(), + offersAndDiscountsDetails: (context) => OffersAndDiscountsDetails(), + //pay slip monthlyPaySlip: (context) => MonthlyPaySlipScreen(), @@ -215,4 +248,4 @@ class AppRoutes { }; -} +} \ No newline at end of file diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index e895ad1..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,21 +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 isUnderLine = false, 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, - decoration: isUnderLine ? TextDecoration.underline : null, - ), + 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/generic_response_model.dart b/lib/models/generic_response_model.dart index 5ee6007..11d7ec2 100644 --- a/lib/models/generic_response_model.dart +++ b/lib/models/generic_response_model.dart @@ -56,6 +56,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/my_team/get_employee_subordinates_list.dart'; import 'package:mohem_flutter_app/models/my_team/get_subordinates_leaves_total_vacations_list_model.dart'; import 'package:mohem_flutter_app/models/notification_action_model.dart'; @@ -144,6 +148,8 @@ class GenericResponseModel { String? disableSessionList; String? employeeQR; String? forgetPasswordTokenID; + List? getCcpTransactionsListNew; + List? getConcurrentProgramsList; List? getAbsenceAttachmentsList; List? getAbsenceAttendanceTypesList; List? getAbsenceCollectionNotificationBodyList; @@ -162,11 +168,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; @@ -204,9 +206,6 @@ class GenericResponseModel { List? getOrganizationsSalariesList; List? getPaymentInformationList; List? getPayslipList; - - // List? getPendingReqDetailsList; - // List? getPendingReqFunctionsList; List? getPerformanceAppraisalList; List? getPhonesNotificationBodyList; List? getPoItemHistoryList; @@ -222,6 +221,10 @@ class GenericResponseModel { List? getShiftTypesList; List? getStampMsNotificationBodyList; List? getStampNsNotificationBodyList; + List? getConcurrentProgramsModel; + List? getCCPTransactionsModel; + GetCCPOutputModel? getCCPOutputModel; + List? getCCPDFFStructureModel; List? getSubordinatesAttdStatusList; List? getSubordinatesLeavesList; List?getSubordinatesLeavesTotalVacationsList; @@ -426,8 +429,6 @@ class GenericResponseModel { this.getCEICollectionNotificationBodyList, this.getCEIDFFStructureList, this.getCEITransactionList, - this.getCcpDffStructureList, - this.getCcpOutputList, this.getCcpTransactionsList, this.getCcpTransactionsListNew, this.getConcurrentProgramsList, @@ -468,8 +469,6 @@ class GenericResponseModel { this.getOrganizationsSalariesList, this.getPaymentInformationList, this.getPayslipList, - // this.getPendingReqDetailsList, - // this.getPendingReqFunctionsList, this.getPerformanceAppraisalList, this.getPhonesNotificationBodyList, this.getPoItemHistoryList, @@ -504,6 +503,10 @@ class GenericResponseModel { this.getDepartmentSections, this.getPendingTransactionsFunctions, this.getPendingTransactionsDetails, + this.getConcurrentProgramsModel, + this.getCCPTransactionsModel, + this.getCCPOutputModel, + this.getCCPDFFStructureModel, this.getUserItemTypesList, this.getVacationRulesList, this.getVaccinationOnHandList, @@ -774,11 +777,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']; if (json['GetContactDetailsList'] != null) { getContactDetailsList = []; json['GetContactDetailsList'].forEach((v) { @@ -791,6 +790,9 @@ class GenericResponseModel { getContactColsStructureList!.add(GetContactColsStructureList.fromJson(v)); }); } + getContactColsStructureList = json['GetContactColsStructureList']; + getContactDetailsList = json['GetContactDetailsList']; + getContactDffStructureList = json['GetContactDffStructureList']; getContactNotificationBodyList = json["GetContactNotificationBodyList"] == null ? null : GetContactNotificationBodyList.fromJson(json["GetContactNotificationBodyList"]); if (json['GetCountriesList'] != null) { @@ -1086,6 +1088,31 @@ class GenericResponseModel { }); } + 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']); + } + if (json['GetUserItemTypesList'] != null) { getUserItemTypesList = []; json['GetUserItemTypesList'].forEach((v) { @@ -1414,11 +1441,7 @@ 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; if (this.getContactDetailsList != null) { data['GetContactDetailsList'] = this.getContactDetailsList!.map((v) => v.toJson()).toList(); } @@ -1428,6 +1451,9 @@ class GenericResponseModel { if (this.getContactDffStructureList != null) { data['GetContactDffStructureList'] = this.getContactDffStructureList!.map((v) => v.toJson()).toList(); } + data['GetContactColsStructureList'] = this.getContactColsStructureList; + data['GetContactDetailsList'] = this.getContactDetailsList; + data['GetContactDffStructureList'] = this.getContactDffStructureList; data['GetContactNotificationBodyList'] = this.getContactNotificationBodyList; data['GetCountriesList'] = this.getCountriesList; if (this.getDayHoursTypeDetailsList != null) { diff --git a/lib/models/get_announcement_details.dart b/lib/models/get_announcement_details.dart index 45e4a1c..32ff65f 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/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..99f2d63 --- /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() { + 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..68aa805 --- /dev/null +++ b/lib/models/items_for_sale/get_employee_ads_list.dart @@ -0,0 +1,177 @@ +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; + bool? isActive; + int? pageSize; + int? pageNo; + int? 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.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']; + isActive = json['isActive']; + pageSize = json['pageSize']; + pageNo = json['pageNo']; + languageId = json['languageId']; + } + + Map toJson() { + 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['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; + bool? 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() { + 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..da0dade --- /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() { + 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() { + 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..4b2c0dc --- /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() { + 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..e140f30 --- /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() { + 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..4aac997 --- /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() { + 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/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..f5e80cf --- /dev/null +++ b/lib/models/my_requests/get_ccp_dff_structure_model.dart @@ -0,0 +1,200 @@ +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; + 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; + 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']; + 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() { + 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() { + 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..fa7c1cb --- /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() { + 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..8d84993 --- /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() { + 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..c4a8a09 --- /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() { + 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/models/offers_and_discounts/get_categories_list.dart b/lib/models/offers_and_discounts/get_categories_list.dart new file mode 100644 index 0000000..0e7ff7b --- /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() { + 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..2ba42ea --- /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() { + 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..289ab33 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,10 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { List? homeMenus; List? getMenuEntriesList; + //Offers And Discounts + bool isOffersLoading = true; + List getOffersList = []; + //Attendance Tracking API's & Methods Future fetchAttendanceTracking(context) async { try { @@ -175,6 +181,19 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } } + void getCategoryOffersListAPI(BuildContext context) async { + try { + // Utils.showLoading(context); + getOffersList = await OffersAndDiscountsApiClient().getOffersList(0, 6); + isOffersLoading = false; + 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 4a6ad82..9a3baa0 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -13,6 +13,7 @@ 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'; @@ -20,6 +21,7 @@ import 'package:mohem_flutter_app/ui/landing/widget/services_widget.dart'; import 'package:mohem_flutter_app/widgets/bottom_sheet.dart'; import 'package:mohem_flutter_app/widgets/mark_attendance_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 { @@ -46,6 +48,7 @@ class _DashboardScreenState extends State { data.fetchMissingSwipe(context); data.fetchLeaveTicketBalance(context); data.fetchMenuEntries(); + data.getCategoryOffersListAPI(context); } @override @@ -271,51 +274,72 @@ 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( - height: 103 + 33, - child: ListView.separated( - shrinkWrap: true, - physics: const BouncingScrollPhysics(), - padding: const EdgeInsets.only(left: 21, right: 21, top: 13), - scrollDirection: Axis.horizontal, - itemBuilder: (cxt, index) { - return SizedBox( - width: 73, - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Container( - width: 73, - height: 73, - decoration: BoxDecoration( - borderRadius: const BorderRadius.all( - Radius.circular(100), - ), - border: Border.all(color: MyColors.lightGreyEDColor, width: 1), - ), - child: ClipRRect( - borderRadius: const BorderRadius.all( - Radius.circular(50), - ), - child: Image.network( - "https://play-lh.googleusercontent.com/NPo88ojmhah4HDiposucJmfQIop4z4xc8kqJK9ITO9o-yCab2zxIp7PPB_XPj2iUojo", - fit: BoxFit.cover, - ), - ), - ), - 4.height, - Expanded( - child: namesD[6 % (index + 1)].toText12(isCenter: true, maxLine: 2), - ), - ], - ), - ); - }, - separatorBuilder: (cxt, index) => 8.width, - itemCount: 6), + 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), + ), + ], + ), + ), + ); + }, + separatorBuilder: (cxt, index) => 8.width, + itemCount: 6), + ); + }, ), ], ), @@ -393,11 +417,31 @@ 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); }, ), ), ); } + + 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/landing/widget/app_drawer.dart b/lib/ui/landing/widget/app_drawer.dart index e9a33b4..70fc38f 100644 --- a/lib/ui/landing/widget/app_drawer.dart +++ b/lib/ui/landing/widget/app_drawer.dart @@ -1,13 +1,12 @@ +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:mohem_flutter_app/config/routes.dart'; +import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; +import 'package:mohem_flutter_app/ui/dialogs/id/business_card_dialog.dart'; import 'package:mohem_flutter_app/ui/dialogs/id/employee_digital_id_dialog.dart'; import 'package:mohem_flutter_app/ui/landing/widget/drawer_item.dart'; - import 'package:mohem_flutter_app/widgets/dialogs/dialogs.dart'; -import 'package:mohem_flutter_app/ui/dialogs/id/business_card_dialog.dart'; -import 'package:easy_localization/easy_localization.dart'; -import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; class AppDrawer extends StatefulWidget { @override @@ -18,100 +17,101 @@ class _AppDrawerState extends State { @override Widget build(BuildContext context) { return Container( - color: Colors.white, - child: Drawer( - child: Column( - children: [ - const SizedBox( - height: 200, + color: Colors.white, + child: Drawer( + child: Column(children: [ + const SizedBox( + height: 200, + ), + Expanded( + child: ListView(padding: const EdgeInsets.all(21), physics: const BouncingScrollPhysics(), children: [ + Divider(), + InkWell( + child: DrawerItem( + //'My Profile', + LocaleKeys.myProfile.tr(), + icon: Icons.person, + color: Colors.grey, + ), + onTap: () { + drawerNavigator(context, AppRoutes.profile); + }), + Divider(), + InkWell( + child: DrawerItem( + // 'Mowadhafhi', + LocaleKeys.mowadhafhi.tr(), + icon: Icons.person, + color: Colors.grey, + ), + onTap: () { + drawerNavigator(context, AppRoutes.mowadhafhi); + }, ), - Expanded( - child: ListView( - padding: const EdgeInsets.all(21), - physics: const BouncingScrollPhysics(), - children: [ - const Divider(), - InkWell( - child: new DrawerItem( - //'My Profile', - LocaleKeys.myProfile.tr(), - icon: Icons.person, - color: Colors.grey, - ), - onTap: () { - drawerNavigator(context, AppRoutes.profile); - }), - const Divider(), - InkWell( - child: DrawerItem( - // 'Mowadhafhi', - LocaleKeys.mowadhafhi.tr(), - icon: Icons.person, - color: Colors.grey, - ), - onTap: () { - drawerNavigator(context, AppRoutes.mowadhafhi); - }, - ), - const Divider(), - InkWell( - child: DrawerItem( - LocaleKeys.pendingTransactions.tr(), - icon: Icons.person, - color: Colors.grey, - ), - onTap: () { - drawerNavigator(context, AppRoutes.pendingTransactions); - }, - ), - const Divider(), - InkWell( - child: DrawerItem( - "My Team", - icon: Icons.person, - color: Colors.grey, - ), - onTap: () { - drawerNavigator(context, AppRoutes.myTeam); - }, - ), - InkWell( - child: DrawerItem( - LocaleKeys.employeeDigitalID.tr(), - icon: Icons.insert_drive_file_outlined, - color: Colors.grey, - ), - onTap: () { - showMDialog(context, child: EmployeeDigitialIdDialog()); - }, - ), - Divider(), - InkWell( - child: DrawerItem( - LocaleKeys.businessCard.tr(), - icon: Icons.insert_drive_file_outlined, - color: Colors.grey, - ), - onTap: () { - showMDialog(context, child: BusinessCardDialog()); - }, - ), - ], + Divider(), + InkWell( + child: DrawerItem( + LocaleKeys.pendingTransactions.tr(), + icon: Icons.person, + color: Colors.grey, ), - ) - ], - ), - ), - ); + onTap: () { + drawerNavigator(context, AppRoutes.pendingTransactions); + }, + ), + const Divider(), + InkWell( + child: DrawerItem( + "My Team", + icon: Icons.person, + color: Colors.grey, + ), + onTap: () { + drawerNavigator(context, AppRoutes.myTeam); + }, + ), + Divider(), + InkWell( + child: const DrawerItem( + 'My Requests', + icon: Icons.person, + color: Colors.grey, + ), + onTap: () { + drawerNavigator(context, AppRoutes.myRequests); + }), + InkWell( + child: DrawerItem( + LocaleKeys.employeeDigitalID.tr(), + icon: Icons.insert_drive_file_outlined, + color: Colors.grey, + ), + onTap: () { + showMDialog(context, child: EmployeeDigitialIdDialog()); + }, + ), + Divider(), + InkWell( + child: DrawerItem( + LocaleKeys.businessCard.tr(), + icon: Icons.insert_drive_file_outlined, + color: Colors.grey, + ), + onTap: () { + showMDialog(context, child: BusinessCardDialog()); + }, + ), + ])) + ]))); } void drawerNavigator(context, routeName) { Navigator.of(context).pushNamed(routeName); } -} -String capitalizeOnlyFirstLater(String text) { - if (text.trim().isEmpty) return ""; + String capitalizeOnlyFirstLater(String text) { + if (text.trim().isEmpty) return ""; - return "${text[0].toUpperCase()}${text.substring(1)}"; + return "${text[0].toUpperCase()}${text.substring(1)}"; + } } diff --git a/lib/ui/screens/announcements/announcement_details.dart b/lib/ui/screens/announcements/announcement_details.dart index 06af534..dbe1eb2 100644 --- a/lib/ui/screens/announcements/announcement_details.dart +++ b/lib/ui/screens/announcements/announcement_details.dart @@ -4,11 +4,14 @@ import 'package:easy_localization/easy_localization.dart'; 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/widget_extensions.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.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); @@ -74,14 +77,10 @@ class _AnnouncementDetailsState extends State { } } - 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); - // 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) { diff --git a/lib/ui/screens/announcements/announcements.dart b/lib/ui/screens/announcements/announcements.dart index 56ca155..d43c12c 100644 --- a/lib/ui/screens/announcements/announcements.dart +++ b/lib/ui/screens/announcements/announcements.dart @@ -129,8 +129,6 @@ class _AnnouncementsState extends State { 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']); for (int i = 0; i < jsonDecodedData.length; i++) { getAnnouncementsObject.add(GetAnnouncementsObject.fromJson(jsonDecodedData[i])); 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..7919c0d --- /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); + var 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..93ea8e9 --- /dev/null +++ b/lib/ui/screens/items_for_sale/fragments/items_for_sale.dart @@ -0,0 +1,238 @@ +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), + 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..c85f4e0 --- /dev/null +++ b/lib/ui/screens/items_for_sale/item_for_sale_detail.dart @@ -0,0 +1,140 @@ +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: 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), + ), + ], + ), + 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), + ), + 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/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/ui/screens/my_requests/my_requests.dart b/lib/ui/screens/my_requests/my_requests.dart new file mode 100644 index 0000000..ebeff43 --- /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/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, + 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..4cc2b20 --- /dev/null +++ b/lib/ui/screens/my_requests/new_request.dart @@ -0,0 +1,424 @@ +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, + Container( + decoration: const BoxDecoration( + color: MyColors.white, + boxShadow: [ + BoxShadow(color: MyColors.lightGreyEFColor, spreadRadius: 3), + ], + ), + child: DefaultButton(LocaleKeys.submit.tr(), () async { + // openNewRequest(); + }) + .insideContainer, + ) + ], + ), + ), + // bottomSheet: + ); + } + + 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 { + 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; + } +} 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..e1e216d --- /dev/null +++ b/lib/ui/screens/offers_and_discounts/offers_and_discounts_details.dart @@ -0,0 +1,222 @@ +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 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), + 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() {} + + 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/dynamic_forms/dynamic_textfield_widget.dart b/lib/widgets/dynamic_forms/dynamic_textfield_widget.dart index 398b746..91e0ce1 100644 --- a/lib/widgets/dynamic_forms/dynamic_textfield_widget.dart +++ b/lib/widgets/dynamic_forms/dynamic_textfield_widget.dart @@ -64,8 +64,8 @@ class DynamicTextFieldWidget extends StatelessWidget { TextField( enabled: isEnable, scrollPadding: EdgeInsets.zero, readOnly: isReadOnly, - textInputAction: inputAction, - 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..ec57085 --- /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; + var bytes = File(fileName).readAsBytesSync(); + String base64Encode = base64.encode(bytes); + if (base64Encode != null) { + image(base64Encode, _image); + } + } + }, + ), + _BottomSheetItem( + title: "Camera", + icon: Icons.camera_alt, + onTap: () async { + if (Platform.isAndroid) { + cameraImageAndroid(image); + } else { + File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.camera, imageQuality: 20))?.path ?? ""); + String fileName = _image.path; + var bytes = File(fileName).readAsBytesSync(); + String base64Encode = base64.encode(bytes); + if (base64Encode != null) { + image(base64Encode, _image); + } + } + }, + ), + _BottomSheetItem( + title: "Cancel", + onTap: () {}, + icon: Icons.cancel, + color: MyColors.redColor, + ) + ], + ); + }); + } +} + +void galleryImageAndroid(Function(String, File) image) async { + File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.gallery, imageQuality: 20))?.path ?? ""); + String fileName = _image.path; + var bytes = File(fileName).readAsBytesSync(); + String base64Encode = base64.encode(bytes); + 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; + var 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(), + ], + ), + ), + ); + } +} 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 dde9d39..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.1.5 - - - - - + url_launcher: ^6.0.15 + share: 2.0.4 dev_dependencies: flutter_test: