From 8d95e458b17740e4234e9f574c1afec3782e1f4a Mon Sep 17 00:00:00 2001 From: FaizHashmiCS22 Date: Wed, 31 May 2023 14:34:35 +0300 Subject: [PATCH] Added few API Calls --- lib/api/api_client.dart | 44 ++- lib/classes/consts.dart | 10 + lib/config/routes.dart | 1 + lib/extensions/string_extensions.dart | 149 +++++++++- .../advertisment_models/ad_details_model.dart | 162 +++++----- .../special_service_model.dart | 38 +-- .../ss_car_check_schedule_model.dart | 117 ++++++++ .../ss_photo_schedule_model.dart | 95 ++++++ .../appointment_list_model.dart | 109 +++++++ ...ric_model.dart => generic_resp_model.dart} | 6 +- lib/models/provider_category_model.dart | 32 ++ lib/models/provider_service_model.dart | 65 ++++ lib/models/widgets_models.dart | 30 +- lib/repositories/common_repo.dart | 166 ++++++++--- lib/theme/colors.dart | 1 + lib/utils/enums.dart | 14 + lib/view_models/ad_view_model.dart | 280 +++++++++++++++--- .../ad_duration_container.dart | 157 ++++++++-- .../ad_review_containers.dart | 130 +++++--- .../damage_parts_container.dart | 31 +- .../vehicle_details_container.dart | 10 +- lib/views/advertisement/ads_detail_view.dart | 1 - lib/views/advertisement/ads_list.dart | 23 +- .../advertisement/bottom_sheet_content.dart | 218 +++++++++----- .../create_ad_progress_steps.dart | 7 +- .../advertisement/custom_add_button.dart | 6 +- .../picked_images_container.dart | 37 ++- lib/views/user/login_with_password_page.dart | 22 +- lib/widgets/common_widgets/app_bar.dart | 1 + .../common_widgets/categories_list.dart | 6 +- .../customer_appointment_slider_widget.dart | 143 --------- .../common_widgets/info_bottom_sheet.dart | 43 +++ .../common_widgets/provider_details_card.dart | 4 +- lib/widgets/common_widgets/time_slots.dart | 29 +- lib/widgets/dropdown/dropdow_field.dart | 5 + lib/widgets/extensions/extensions_widget.dart | 112 +------ lib/widgets/txt_field.dart | 16 +- 37 files changed, 1617 insertions(+), 703 deletions(-) create mode 100644 lib/models/advertisment_models/ss_car_check_schedule_model.dart create mode 100644 lib/models/advertisment_models/ss_photo_schedule_model.dart create mode 100644 lib/models/appointments_models/appointment_list_model.dart rename lib/models/{advertisment_models/ads_generic_model.dart => generic_resp_model.dart} (98%) create mode 100644 lib/models/provider_category_model.dart create mode 100644 lib/models/provider_service_model.dart delete mode 100644 lib/widgets/common_widgets/customer_appointment_slider_widget.dart create mode 100644 lib/widgets/common_widgets/info_bottom_sheet.dart diff --git a/lib/api/api_client.dart b/lib/api/api_client.dart index b59e938..7707f40 100644 --- a/lib/api/api_client.dart +++ b/lib/api/api_client.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:convert'; +import 'dart:developer'; import 'dart:io'; import 'package:flutter/foundation.dart'; @@ -73,20 +74,20 @@ class ApiClientImp implements ApiClient { headers0.addAll(headers); } if (!kReleaseMode) { - debugPrint("Url:$url"); - debugPrint("body:$jsonObject"); + log("Url:$url"); + log("body:$jsonObject"); } var response = await postJsonForResponse(url, jsonObject, token: token, queryParameters: queryParameters, headers: headers0, retryTimes: retryTimes); try { if (!kReleaseMode) { - debugPrint("res121:${response.body}"); - debugPrint("res121:${response.statusCode}"); + log("res121:${response.body}"); + log("res121:${response.statusCode}"); } var jsonData = jsonDecode(response.body); return factoryConstructor(jsonData); } catch (ex) { - debugPrint(ex.toString()); - debugPrint("exception:$ex"); + log(ex.toString()); + log("exception:$ex"); throw APIException(APIException.BAD_RESPONSE_FORMAT, arguments: ex); } } @@ -134,9 +135,9 @@ class ApiClientImp implements ApiClient { response = await _post(Uri.parse(url), body: requestBody, headers: headers0).timeout(const Duration(seconds: 100)); if (!kReleaseMode) { - debugPrint("Url:$url"); - debugPrint("body:$requestBody"); - debugPrint("res: ${response.body}"); + log("Url:$url"); + log("body:$requestBody"); + log("res: ${response.body}"); } if (response.statusCode >= 200 && response.statusCode < 500) { var jsonData = jsonDecode(response.body); @@ -150,7 +151,7 @@ class ApiClientImp implements ApiClient { } } on SocketException catch (e) { if (retryTimes > 0) { - debugPrint('will retry after 3 seconds...'); + log('will retry after 3 seconds...'); await Future.delayed(const Duration(seconds: 3)); return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); } else { @@ -158,7 +159,7 @@ class ApiClientImp implements ApiClient { } } on HttpException catch (e) { if (retryTimes > 0) { - debugPrint('will retry after 3 seconds...'); + log('will retry after 3 seconds...'); await Future.delayed(const Duration(seconds: 3)); return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); } else { @@ -168,14 +169,14 @@ class ApiClientImp implements ApiClient { throw APIException(APIException.TIMEOUT, arguments: e); } on ClientException catch (e) { if (retryTimes > 0) { - debugPrint('will retry after 3 seconds...'); + log('will retry after 3 seconds...'); await Future.delayed(const Duration(seconds: 3)); return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); } else { throw APIException(APIException.OTHER, arguments: e); } } catch (ex) { - debugPrint("exception1:$ex"); + log("exception1:$ex"); throw APIException(APIException.BAD_RESPONSE_FORMAT, arguments: ex); } } @@ -203,13 +204,10 @@ class ApiClientImp implements ApiClient { } var response = await getJsonForResponse(url, token: token, queryParameters: queryParameters, headers: headers0, retryTimes: retryTimes); try { - if (!kReleaseMode) { - debugPrint("res:${response.body}"); - } var jsonData = jsonDecode(response.body); return factoryConstructor(jsonData); } catch (ex) { - debugPrint("exception:${response.body}"); + log("exception:${response.body}"); throw APIException(APIException.BAD_RESPONSE_FORMAT, arguments: ex); } } @@ -242,14 +240,14 @@ class ApiClientImp implements ApiClient { } if (!kReleaseMode) { - debugPrint("Url:$url"); - debugPrint("queryParameters:$queryParameters"); + log("Url:$url"); + log("queryParameters:$queryParameters"); } var response = await _get(Uri.parse(url), headers: headers0).timeout(const Duration(seconds: 60)); if (!kReleaseMode) { - debugPrint("res: ${response.body}"); - debugPrint("resCode: ${response.statusCode}"); + log("res: ${response.body}"); + log("resCode: ${response.statusCode}"); } if (response.statusCode >= 200 && response.statusCode < 500) { var jsonData = jsonDecode(response.body); @@ -264,7 +262,7 @@ class ApiClientImp implements ApiClient { } } on SocketException catch (e) { if (retryTimes > 0) { - debugPrint('will retry after 3 seconds...'); + log('will retry after 3 seconds...'); await Future.delayed(const Duration(seconds: 3)); return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); } else { @@ -272,7 +270,7 @@ class ApiClientImp implements ApiClient { } } on HttpException catch (e) { if (retryTimes > 0) { - debugPrint('will retry after 3 seconds...'); + log('will retry after 3 seconds...'); await Future.delayed(const Duration(seconds: 3)); return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); } else { diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index dc88a76..2297ca5 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -50,6 +50,11 @@ class ApiConsts { static String ServiceProviderService_Get = "${baseUrlServices}api/ServiceProviders/ServiceProviderService_Get"; static String BranchesAndServices = "${baseUrlServices}api/ServiceProviders/ServiceProviderDetail_Get"; + //Appointment APIs + static String serviceProvidersAppointmentGet = "${baseUrlServices}api/ServiceProviders/ServiceProvidersAppointment_Get"; + static String serviceCategoryGet = "${baseUrlServices}api/Master/ServiceCategory_Get"; + static String servicesGet = "${baseUrlServices}api/ServiceProviders/Services_Get"; + //Advertisement APIs static String vehicleTypeGet = "${baseUrlServices}api/ServiceProviders/VehicleType_Get"; static String vehicleModelGet = "${baseUrlServices}api/Master/VehicleModel_Get"; @@ -68,6 +73,8 @@ class ApiConsts { static String vehicleAdsSpecialServicesGet = "${baseUrlServices}api/Common/SpecialService_Get"; static String vehicleAdsSingleStepCreate = "${baseUrlServices}api/Advertisement/AdsSingleStep_Create"; static String vehicleAdsGet = "${baseUrlServices}api/Advertisement/Ads_Get"; + static String adsCarCheckupSPBranchScheduleSlotGet = "${baseUrlServices}api/Advertisement/AdsCarCheckupSPBranchScheduleSlot_Get"; + static String adsPhotoOfficeAppointmentScheduleSlotGet = "${baseUrlServices}api/Advertisement/PhotoOfficeAppointmentScheduleSlot_Get"; } class GlobalConsts { @@ -86,6 +93,9 @@ class GlobalConsts { static String attachImageError = "You must add at least 3 images"; static String attachDamagePartImage = "Please add part image"; static String adDurationDateError = "Ad Duration start date cannot be empty"; + static String adReservablePriceErrorConst = "Ad Reservable price cannot be empty"; + static String reserveAdPriceInfo = + "Some dummy description to explain the following concept. This price will be for 24 hours and if a user cancels the reservations before 24 hours then the amount will be automatically refunded to the buyer."; } class MyAssets { diff --git a/lib/config/routes.dart b/lib/config/routes.dart index b3d6303..81f25bc 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -55,6 +55,7 @@ class AppRoutes { static const String appointmentDetailView = "/appointmentDetailView"; static const String adsDetailView = "/adsDetailView"; static const String createAdView = "/createAdView"; + static const String bookAppointmenServicesView = "/bookAppointmenServicesView"; //Subcriptions diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index f899df1..f26ea7e 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -1,7 +1,8 @@ +import 'package:auto_size_text/auto_size_text.dart'; +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/cupertino.dart'; -import 'package:intl/intl.dart'; import 'package:mc_common_app/theme/colors.dart'; -import 'package:auto_size_text/auto_size_text.dart'; +import 'package:mc_common_app/utils/enums.dart'; extension EmailValidator on String { Widget toText( @@ -18,6 +19,7 @@ extension EmailValidator on String { this, textAlign: textAlign, maxLines: maxLines, + style: TextStyle( height: height, decoration: isUnderLine ? TextDecoration.underline : textDecoration ?? TextDecoration.none, @@ -36,14 +38,73 @@ extension EmailValidator on String { return RegExp(r'^[0-9]+$').hasMatch(this); } - String toFormattedDate() { - String date = split("T")[0]; - String time = split("T")[1]; - var dates = date.split("-"); - return "${dates[2]} ${getMonth(int.parse(dates[1]))} ${dates[0]} ${DateFormat('hh:mm a').format(DateFormat('hh:mm:ss').parse(time))}"; + getMonth(int month) { + switch (month) { + case 1: + return "January"; + case 2: + return "February"; + case 3: + return "March"; + case 4: + return "April"; + case 5: + return "May"; + case 6: + return "June"; + case 7: + return "July"; + case 8: + return "August"; + case 9: + return "September"; + case 10: + return "October"; + case 11: + return "November"; + case 12: + return "December"; + } } +} - getMonth(int month) { +extension FormatDate on String { + /// get month by + /// [month] convert month number in to month name + /// get month by + /// [month] convert month number in to month name in Arabic + static String getMonthArabic(int month) { + switch (month) { + case 1: + return "يناير"; + case 2: + return " فبراير"; + case 3: + return "مارس"; + case 4: + return "أبريل"; + case 5: + return "مايو"; + case 6: + return "يونيو"; + case 7: + return "يوليو"; + case 8: + return "أغسطس"; + case 9: + return "سبتمبر"; + case 10: + return " اكتوبر"; + case 11: + return " نوفمبر"; + case 12: + return "ديسمبر"; + default: + return ""; + } + } + + static String getMonth(int month) { switch (month) { case 1: return "January"; @@ -69,6 +130,78 @@ extension EmailValidator on String { return "November"; case 12: return "December"; + default: + return ""; + } + } + + String toFormattedDate() { + String date = split("T")[0]; + String time = split("T")[1]; + var dates = date.split("-"); + return "${dates[2]} ${getMonth(int.parse(dates[1]))} ${dates[0]} ${DateFormat('hh:mm a', "en_US").format(DateFormat('hh:mm:ss', "en_US").parse(time))}"; + } + + String toFormattedDateWithoutTime() { + String date = split("T")[0]; + var dates = date.split("-"); + return "${dates[2]} ${getMonth(int.parse(dates[1]))}, ${dates[0]}"; + } +} + +extension AdPostEnum on int { + AdPostStatus toAdPostEnum() { + if (this == 1) { + return AdPostStatus.pendingForReview; + } else if (this == 2) { + return AdPostStatus.pendingForPayment; + } else if (this == 3) { + return AdPostStatus.rejected; + } else if (this == 4) { + return AdPostStatus.cancelled; + } else if (this == 5) { + return AdPostStatus.pendingForPost; + } else if (this == 6) { + return AdPostStatus.active; + } else if (this == 7) { + return AdPostStatus.expired; + } else if (this == 8) { + return AdPostStatus.sold; + } else if (this == 9) { + return AdPostStatus.reserved; + } else if (this == 10) { + return AdPostStatus.buyingService; + } else if (this == 11) { + return AdPostStatus.reserveCancel; + } else { + return AdPostStatus.pendingForPost; + } + } +} + +extension DateTimeConversions on DateTime { + String getTimeAgo({bool numericDates = true}) { + final date2 = DateTime.now(); + final difference = date2.difference(this); + + if ((difference.inDays / 7).floor() >= 1) { + return (numericDates) ? '1 week ago' : 'Last week'; + } else if (difference.inDays >= 2) { + return '${difference.inDays} days ago'; + } else if (difference.inDays >= 1) { + return (numericDates) ? '1 day ago' : 'Yesterday'; + } else if (difference.inHours >= 2) { + return '${difference.inHours} hours ago'; + } else if (difference.inHours >= 1) { + return (numericDates) ? '1 hour ago' : 'An hour ago'; + } else if (difference.inMinutes >= 2) { + return '${difference.inMinutes} minutes ago'; + } else if (difference.inMinutes >= 1) { + return (numericDates) ? '1 minute ago' : 'A minute ago'; + } else if (difference.inSeconds >= 3) { + return '${difference.inSeconds} seconds ago'; + } else { + return 'Just now'; } } } diff --git a/lib/models/advertisment_models/ad_details_model.dart b/lib/models/advertisment_models/ad_details_model.dart index 4842115..d27b578 100644 --- a/lib/models/advertisment_models/ad_details_model.dart +++ b/lib/models/advertisment_models/ad_details_model.dart @@ -1,4 +1,6 @@ +import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/models/advertisment_models/special_service_model.dart'; +import 'package:mc_common_app/utils/enums.dart'; class AdDetailsModel { int? id; @@ -6,6 +8,7 @@ class AdDetailsModel { String? enddate; Vehicle? vehicle; List? specialservice; + // List? reserved; int? statusID; String? statuslabel; @@ -32,46 +35,47 @@ class AdDetailsModel { double? reservePrice; bool? isMCHandled; String? modifiedOn; + AdPostStatus? adPostStatus; AdDetailsModel( {this.id, - this.startdate, - this.enddate, - this.vehicle, - this.specialservice, - // this.reserved, - this.statusID, - this.statuslabel, - this.adsDurationPrice, - this.adsDurationDiscount, - this.adsDurationDiscountPrice, - this.comment, - this.active, - this.isPaid, - this.isSubscription, - this.isVerified, - this.netPrice, - this.specialServiceTotalPrice, - this.taxPrice, - this.totalPrice, - this.userID, - this.vehiclePostingID, - this.qrCodePath, - this.isCustomerAcknowledged, - this.createdByRole, - this.totalViews, - this.createdOn, - this.priceExcludingDiscount, - this.reservePrice, - this.isMCHandled, - this.modifiedOn}); + this.startdate, + this.enddate, + this.vehicle, + this.specialservice, + // this.reserved, + this.statusID, + this.statuslabel, + this.adsDurationPrice, + this.adsDurationDiscount, + this.adsDurationDiscountPrice, + this.comment, + this.active, + this.isPaid, + this.isSubscription, + this.isVerified, + this.netPrice, + this.specialServiceTotalPrice, + this.taxPrice, + this.totalPrice, + this.userID, + this.vehiclePostingID, + this.qrCodePath, + this.isCustomerAcknowledged, + this.createdByRole, + this.totalViews, + this.createdOn, + this.priceExcludingDiscount, + this.reservePrice, + this.isMCHandled, + this.adPostStatus, + this.modifiedOn}); AdDetailsModel.fromJson(Map json) { id = json['id']; startdate = json['startdate']; enddate = json['enddate']; - vehicle = - json['vehicle'] != null ? Vehicle.fromJson(json['vehicle']) : null; + vehicle = json['vehicle'] != null ? Vehicle.fromJson(json['vehicle']) : null; if (json['specialservice'] != null) { specialservice = []; json['specialservice'].forEach((v) { @@ -109,6 +113,7 @@ class AdDetailsModel { reservePrice = json['reservePrice']; isMCHandled = json['isMCHandled']; modifiedOn = json['modifiedOn']; + adPostStatus = (json['statusID'] as int).toAdPostEnum(); } Map toJson() { @@ -120,8 +125,7 @@ class AdDetailsModel { data['vehicle'] = vehicle!.toJson(); } if (specialservice != null) { - data['specialservice'] = - specialservice!.map((v) => v.toJson()).toList(); + data['specialservice'] = specialservice!.map((v) => v.toJson()).toList(); } // if (reserved != null) { // data['reserved'] = reserved!.map((v) => v.toJson()).toList(); @@ -184,30 +188,30 @@ class Vehicle { Vehicle( {this.id, - this.cityID, - this.cityName, - this.demandAmount, - this.isActive, - this.isFinanceAvailable, - this.status, - this.statustext, - this.category, - this.color, - this.condition, - this.mileage, - this.model, - this.modelyear, - this.sellertype, - this.transmission, - this.duration, - this.image, - this.damagereport, - this.vehicleDescription, - this.vehicleTitle, - this.vehicleType, - this.vehicleVIN, - this.countryID, - this.currency}); + this.cityID, + this.cityName, + this.demandAmount, + this.isActive, + this.isFinanceAvailable, + this.status, + this.statustext, + this.category, + this.color, + this.condition, + this.mileage, + this.model, + this.modelyear, + this.sellertype, + this.transmission, + this.duration, + this.image, + this.damagereport, + this.vehicleDescription, + this.vehicleTitle, + this.vehicleType, + this.vehicleVIN, + this.countryID, + this.currency}); Vehicle.fromJson(Map json) { id = json['id']; @@ -218,29 +222,15 @@ class Vehicle { isFinanceAvailable = json['isFinanceAvailable']; status = json['status']; statustext = json['statustext']; - category = json['category'] != null - ? Category.fromJson(json['category']) - : null; + category = json['category'] != null ? Category.fromJson(json['category']) : null; color = json['color'] != null ? Category.fromJson(json['color']) : null; - condition = json['condition'] != null - ? Condition.fromJson(json['condition']) - : null; - mileage = - json['mileage'] != null ? Mileage.fromJson(json['mileage']) : null; - model = - json['model'] != null ? Condition.fromJson(json['model']) : null; - modelyear = json['modelyear'] != null - ? ModelYear.fromJson(json['modelyear']) - : null; - sellertype = json['sellertype'] != null - ? Condition.fromJson(json['sellertype']) - : null; - transmission = json['transmission'] != null - ? Condition.fromJson(json['transmission']) - : null; - duration = json['duration'] != null - ? Duration.fromJson(json['duration']) - : null; + condition = json['condition'] != null ? Condition.fromJson(json['condition']) : null; + mileage = json['mileage'] != null ? Mileage.fromJson(json['mileage']) : null; + model = json['model'] != null ? Condition.fromJson(json['model']) : null; + modelyear = json['modelyear'] != null ? ModelYear.fromJson(json['modelyear']) : null; + sellertype = json['sellertype'] != null ? Condition.fromJson(json['sellertype']) : null; + transmission = json['transmission'] != null ? Condition.fromJson(json['transmission']) : null; + duration = json['duration'] != null ? Duration.fromJson(json['duration']) : null; if (json['image'] != null) { image = []; json['image'].forEach((v) { @@ -419,9 +409,7 @@ class Duration { label = json['label']; days = json['days']; price = json['price']; - country = json['country'] != null - ? ModelYear.fromJson(json['country']) - : null; + country = json['country'] != null ? ModelYear.fromJson(json['country']) : null; } Map toJson() { @@ -470,13 +458,7 @@ class DamageReport { int? vehicleDamagePartID; String? partName; - DamageReport( - {this.id, - this.comment, - this.imageUrl, - this.isActive, - this.vehicleDamagePartID, - this.partName}); + DamageReport({this.id, this.comment, this.imageUrl, this.isActive, this.vehicleDamagePartID, this.partName}); DamageReport.fromJson(Map json) { id = json['id']; diff --git a/lib/models/advertisment_models/special_service_model.dart b/lib/models/advertisment_models/special_service_model.dart index 3f5ff63..59affc4 100644 --- a/lib/models/advertisment_models/special_service_model.dart +++ b/lib/models/advertisment_models/special_service_model.dart @@ -12,23 +12,21 @@ class SpecialServiceModel { List? office; bool? isDelivery; bool? isSelected; - bool? isChecked; SpecialServiceModel( {this.id, - this.name, - this.description, - this.price, - this.specialServiceType, - this.specialServiceTypeName, - this.isActive, - this.startDate, - this.endDate, - this.details, - this.office, - this.isSelected = false, - this.isChecked = false, - this.isDelivery}); + this.name, + this.description, + this.price, + this.specialServiceType, + this.specialServiceTypeName, + this.isActive, + this.startDate, + this.endDate, + this.details, + this.office, + this.isSelected, + this.isDelivery}); SpecialServiceModel.fromJson(Map json) { id = json['id']; @@ -54,7 +52,6 @@ class SpecialServiceModel { } isDelivery = json['isDelivery']; isSelected = false; - isChecked = false; } Map toJson() { @@ -86,7 +83,8 @@ class Details { int? tocity; int? price; - Details({this.id, this.specialServiceID, this.fromcity, this.tocity, this.price}); + Details( + {this.id, this.specialServiceID, this.fromcity, this.tocity, this.price}); Details.fromJson(Map json) { id = json['id']; @@ -115,7 +113,13 @@ class Office { String? city; int? specialServiceID; - Office({this.id, this.officeAreaName, this.officeAreaNameN, this.cityID, this.city, this.specialServiceID}); + Office( + {this.id, + this.officeAreaName, + this.officeAreaNameN, + this.cityID, + this.city, + this.specialServiceID}); Office.fromJson(Map json) { id = json['id']; diff --git a/lib/models/advertisment_models/ss_car_check_schedule_model.dart b/lib/models/advertisment_models/ss_car_check_schedule_model.dart new file mode 100644 index 0000000..8c538bc --- /dev/null +++ b/lib/models/advertisment_models/ss_car_check_schedule_model.dart @@ -0,0 +1,117 @@ +class SSCarCheckScheduleModel { + int? serviceProviderID; + int? serviceProviderBranchID; + int? branchAppointmentScheduleID; + String? branchName; + String? address; + String? latitude; + String? longitude; + List? scheduleServices; + List? branchScheduleSlots; + int? totalItemsCount; + int? distanceKM; + + SSCarCheckScheduleModel( + {this.serviceProviderID, + this.serviceProviderBranchID, + this.branchAppointmentScheduleID, + this.branchName, + this.address, + this.latitude, + this.longitude, + this.scheduleServices, + this.branchScheduleSlots, + this.distanceKM, + this.totalItemsCount}); + + SSCarCheckScheduleModel.fromJson(Map json) { + serviceProviderID = json['serviceProviderID']; + serviceProviderBranchID = json['serviceProviderBranchID']; + branchAppointmentScheduleID = json['branchAppointmentScheduleID']; + branchName = json['branchName']; + address = json['address']; + latitude = json['latitude']; + longitude = json['longitude']; + if (json['scheduleServices'] != null) { + scheduleServices = []; + json['scheduleServices'].forEach((v) { + scheduleServices!.add(ScheduleServices.fromJson(v)); + }); + } + if (json['branchScheduleSlots'] != null) { + branchScheduleSlots = []; + json['branchScheduleSlots'].forEach((v) { + branchScheduleSlots!.add(BranchScheduleSlots.fromJson(v)); + }); + } + totalItemsCount = json['totalItemsCount']; + + //TODO: We will update this when Backend team will add this value + distanceKM = 0; + } + + Map toJson() { + final Map data = {}; + data['serviceProviderID'] = serviceProviderID; + data['serviceProviderBranchID'] = serviceProviderBranchID; + data['branchAppointmentScheduleID'] = branchAppointmentScheduleID; + data['branchName'] = branchName; + data['address'] = address; + data['latitude'] = latitude; + data['longitude'] = longitude; + if (scheduleServices != null) { + data['scheduleServices'] = scheduleServices!.map((v) => v.toJson()).toList(); + } + if (branchScheduleSlots != null) { + data['branchScheduleSlots'] = branchScheduleSlots!.map((v) => v.toJson()).toList(); + } + data['totalItemsCount'] = totalItemsCount; + data['distanceKM'] = distanceKM; + + return data; + } +} + +class ScheduleServices { + int? providerServiceID; + String? providerServiceName; + + ScheduleServices({this.providerServiceID, this.providerServiceName}); + + ScheduleServices.fromJson(Map json) { + providerServiceID = json['providerServiceID']; + providerServiceName = json['providerServiceName']; + } + + Map toJson() { + final Map data = {}; + data['providerServiceID'] = providerServiceID; + data['providerServiceName'] = providerServiceName; + return data; + } +} + +class BranchScheduleSlots { + int? id; + String? slotDate; + String? startTime; + String? endTime; + + BranchScheduleSlots({this.id, this.slotDate, this.startTime, this.endTime}); + + BranchScheduleSlots.fromJson(Map json) { + id = json['id']; + slotDate = json['slotDate']; + startTime = json['startTime']; + endTime = json['endTime']; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['slotDate'] = slotDate; + data['startTime'] = startTime; + data['endTime'] = endTime; + return data; + } +} diff --git a/lib/models/advertisment_models/ss_photo_schedule_model.dart b/lib/models/advertisment_models/ss_photo_schedule_model.dart new file mode 100644 index 0000000..468c6fb --- /dev/null +++ b/lib/models/advertisment_models/ss_photo_schedule_model.dart @@ -0,0 +1,95 @@ +class SSPhotoScheduleModel { + int? photoOfficeID; + String? fromDate; + String? toDate; + int? photoOfficeAppointmentScheduleID; + String? photoOfficeName; + String? description; + String? areaName; + String? latitude; + String? longitude; + int? distanceKM; + int? totalItemsCount; + List? photoOfficeScheduleSlots; + + SSPhotoScheduleModel( + {this.photoOfficeID, + this.fromDate, + this.toDate, + this.photoOfficeAppointmentScheduleID, + this.photoOfficeName, + this.description, + this.areaName, + this.latitude, + this.longitude, + this.distanceKM, + this.totalItemsCount, + this.photoOfficeScheduleSlots}); + + SSPhotoScheduleModel.fromJson(Map json) { + photoOfficeID = json['photoOfficeID']; + fromDate = json['fromDate']; + toDate = json['toDate']; + photoOfficeAppointmentScheduleID = json['photoOfficeAppointmentScheduleID']; + photoOfficeName = json['photoOfficeName']; + description = json['description']; + areaName = json['areaName']; + latitude = json['latitude']; + longitude = json['longitude']; + distanceKM = json['distanceKM']; + totalItemsCount = json['totalItemsCount']; + if (json['photoOfficeScheduleSlots'] != null) { + photoOfficeScheduleSlots = []; + json['photoOfficeScheduleSlots'].forEach((v) { + photoOfficeScheduleSlots!.add(PhotoOfficeScheduleSlots.fromJson(v)); + }); + } + } + + Map toJson() { + final Map data = {}; + data['photoOfficeID'] = photoOfficeID; + data['fromDate'] = fromDate; + data['toDate'] = toDate; + data['photoOfficeAppointmentScheduleID'] = + photoOfficeAppointmentScheduleID; + data['photoOfficeName'] = photoOfficeName; + data['description'] = description; + data['areaName'] = areaName; + data['latitude'] = latitude; + data['longitude'] = longitude; + data['distanceKM'] = distanceKM; + data['totalItemsCount'] = totalItemsCount; + if (photoOfficeScheduleSlots != null) { + data['photoOfficeScheduleSlots'] = + photoOfficeScheduleSlots!.map((v) => v.toJson()).toList(); + } + return data; + } +} + +class PhotoOfficeScheduleSlots { + int? id; + String? slotDate; + String? startTime; + String? endTime; + + PhotoOfficeScheduleSlots( + {this.id, this.slotDate, this.startTime, this.endTime}); + + PhotoOfficeScheduleSlots.fromJson(Map json) { + id = json['id']; + slotDate = json['slotDate']; + startTime = json['startTime']; + endTime = json['endTime']; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['slotDate'] = slotDate; + data['startTime'] = startTime; + data['endTime'] = endTime; + return data; + } +} diff --git a/lib/models/appointments_models/appointment_list_model.dart b/lib/models/appointments_models/appointment_list_model.dart new file mode 100644 index 0000000..016393f --- /dev/null +++ b/lib/models/appointments_models/appointment_list_model.dart @@ -0,0 +1,109 @@ +class AppointmentListModel { + int? id; + int? serviceSlotID; + int? appointmentStatusID; + String? appointmentStatusText; + int? serviceProviderID; + int? customerID; + bool? isActive; + bool? isPaymentRequired; + int? paymentStatus; + String? paymentStatusText; + String? customerName; + String? providerName; + String? duration; + String? appointmentDate; + List? serviceAppointmentItems; + + AppointmentListModel( + {this.id, + this.serviceSlotID, + this.appointmentStatusID, + this.appointmentStatusText, + this.serviceProviderID, + this.customerID, + this.isActive, + this.isPaymentRequired, + this.paymentStatus, + this.paymentStatusText, + this.customerName, + this.providerName, + this.duration, + this.appointmentDate, + this.serviceAppointmentItems}); + + AppointmentListModel.fromJson(Map json) { + id = json['id']; + serviceSlotID = json['serviceSlotID']; + appointmentStatusID = json['appointmentStatusID']; + appointmentStatusText = json['appointmentStatusText']; + serviceProviderID = json['serviceProviderID']; + customerID = json['customerID']; + isActive = json['isActive']; + isPaymentRequired = json['isPaymentRequired']; + paymentStatus = json['paymentStatus']; + paymentStatusText = json['paymentStatusText']; + customerName = json['customerName']; + providerName = json['providerName']; + duration = json['duration']; + appointmentDate = json['appointmentDate']; + if (json['serviceAppointmentItems'] != null) { + serviceAppointmentItems = []; + json['serviceAppointmentItems'].forEach((v) { + serviceAppointmentItems!.add(ServiceAppointmentItems.fromJson(v)); + }); + } + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['serviceSlotID'] = serviceSlotID; + data['appointmentStatusID'] = appointmentStatusID; + data['appointmentStatusText'] = appointmentStatusText; + data['serviceProviderID'] = serviceProviderID; + data['customerID'] = customerID; + data['isActive'] = isActive; + data['isPaymentRequired'] = isPaymentRequired; + data['paymentStatus'] = paymentStatus; + data['paymentStatusText'] = paymentStatusText; + data['customerName'] = customerName; + data['providerName'] = providerName; + data['duration'] = duration; + data['appointmentDate'] = appointmentDate; + if (serviceAppointmentItems != null) { + data['serviceAppointmentItems'] = + serviceAppointmentItems!.map((v) => v.toJson()).toList(); + } + return data; + } +} + +class ServiceAppointmentItems { + int? id; + int? serviceItemID; + String? serviceItemName; + String? serviceItemDescription; + + ServiceAppointmentItems( + {this.id, + this.serviceItemID, + this.serviceItemName, + this.serviceItemDescription}); + + ServiceAppointmentItems.fromJson(Map json) { + id = json['id']; + serviceItemID = json['serviceItemID']; + serviceItemName = json['serviceItemName']; + serviceItemDescription = json['serviceItemDescription']; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['serviceItemID'] = serviceItemID; + data['serviceItemName'] = serviceItemName; + data['serviceItemDescription'] = serviceItemDescription; + return data; + } +} diff --git a/lib/models/advertisment_models/ads_generic_model.dart b/lib/models/generic_resp_model.dart similarity index 98% rename from lib/models/advertisment_models/ads_generic_model.dart rename to lib/models/generic_resp_model.dart index d0ac784..7b476d7 100644 --- a/lib/models/advertisment_models/ads_generic_model.dart +++ b/lib/models/generic_resp_model.dart @@ -1,5 +1,5 @@ -class AdsGenericModel { - AdsGenericModel({ +class GenericRespModel { + GenericRespModel({ this.data, this.messageStatus, this.totalItemsCount, @@ -9,7 +9,7 @@ class AdsGenericModel { int? messageStatus; int? totalItemsCount; - factory AdsGenericModel.fromJson(Map json) => AdsGenericModel( + factory GenericRespModel.fromJson(Map json) => GenericRespModel( data: json["data"], messageStatus: json["messageStatus"], totalItemsCount: json["totalItemsCount"], diff --git a/lib/models/provider_category_model.dart b/lib/models/provider_category_model.dart new file mode 100644 index 0000000..2c6ae13 --- /dev/null +++ b/lib/models/provider_category_model.dart @@ -0,0 +1,32 @@ +class ProviderCategoryModel { + int? id; + String? categoryName; + String? categoryNameN; + String? serviceCategoryIconUrl; + String? serviceCategoryImageUrl; + bool? isActive; + bool? isSelected; + + ProviderCategoryModel({this.id, this.categoryName, this.categoryNameN, this.serviceCategoryIconUrl, this.serviceCategoryImageUrl, this.isActive, this.isSelected = false}); + + ProviderCategoryModel.fromJson(Map json) { + id = json['id']; + categoryName = json['categoryName']; + categoryNameN = json['categoryNameN']; + serviceCategoryIconUrl = json['serviceCategoryIconUrl']; + serviceCategoryImageUrl = json['serviceCategoryImageUrl']; + isActive = json['isActive']; + isSelected = false; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['categoryName'] = categoryName; + data['categoryNameN'] = categoryNameN; + data['serviceCategoryIconUrl'] = serviceCategoryIconUrl; + data['serviceCategoryImageUrl'] = serviceCategoryImageUrl; + data['isActive'] = isActive; + return data; + } +} diff --git a/lib/models/provider_service_model.dart b/lib/models/provider_service_model.dart new file mode 100644 index 0000000..4875675 --- /dev/null +++ b/lib/models/provider_service_model.dart @@ -0,0 +1,65 @@ +class ProviderServiceModel { + int? id; + String? description; + String? descriptionN; + String? serviceIconUrl; + String? serviceImageUrl; + int? serviceCategoryID; + bool? isActive; + String? categoryName; + bool? ispartial; + int? appointmentPricePercentage; + int? refundAmountPercentage; + bool? isSelected; + + ProviderServiceModel( + {this.id, + this.description, + this.descriptionN, + this.serviceIconUrl, + this.serviceImageUrl, + this.serviceCategoryID, + this.isActive, + this.categoryName, + this.ispartial, + this.appointmentPricePercentage, + this.refundAmountPercentage, + this.isSelected = false, + }); + + ProviderServiceModel.fromJson(Map json) { + id = json['id']; + description = json['description']; + descriptionN = json['descriptionN']; + serviceIconUrl = json['serviceIconUrl']; + serviceImageUrl = json['serviceImageUrl']; + serviceCategoryID = json['serviceCategoryID']; + isActive = json['isActive']; + categoryName = json['categoryName']; + ispartial = json['ispartial']; + appointmentPricePercentage = json['appointmentPricePercentage']; + refundAmountPercentage = json['refundAmountPercentage']; + isSelected = false; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['description'] = description; + data['descriptionN'] = descriptionN; + data['serviceIconUrl'] = serviceIconUrl; + data['serviceImageUrl'] = serviceImageUrl; + data['serviceCategoryID'] = serviceCategoryID; + data['isActive'] = isActive; + data['categoryName'] = categoryName; + data['ispartial'] = ispartial; + data['appointmentPricePercentage'] = appointmentPricePercentage; + data['refundAmountPercentage'] = refundAmountPercentage; + return data; + } + + @override + String toString() { + return 'ProviderServiceModel{id: $id, description: $description, descriptionN: $descriptionN, serviceIconUrl: $serviceIconUrl, serviceImageUrl: $serviceImageUrl, serviceCategoryID: $serviceCategoryID, isActive: $isActive, categoryName: $categoryName, ispartial: $ispartial, appointmentPricePercentage: $appointmentPricePercentage, refundAmountPercentage: $refundAmountPercentage, isSelected: $isSelected}'; + } +} diff --git a/lib/models/widgets_models.dart b/lib/models/widgets_models.dart index 8ad1289..4bf55eb 100644 --- a/lib/models/widgets_models.dart +++ b/lib/models/widgets_models.dart @@ -1,6 +1,34 @@ class FilterListModel { String title; + int id; bool isSelected; - FilterListModel({required this.isSelected, required this.title}); + FilterListModel({required this.id, required this.isSelected, required this.title}); } + + +class SelectionModel { + String selectedOption; + int selectedId; + String errorValue; + String itemPrice; + + SelectionModel({ + this.selectedOption = "", + this.errorValue = "", + this.selectedId = 0, + this.itemPrice = "", + }); +} + +class TimeSlotModel { + int slotId; + bool isSelected; + String slot; + + TimeSlotModel({ + this.slot = "", + this.slotId = 0, + this.isSelected = false, + }); +} \ No newline at end of file diff --git a/lib/repositories/common_repo.dart b/lib/repositories/common_repo.dart index 5b83e70..7474267 100644 --- a/lib/repositories/common_repo.dart +++ b/lib/repositories/common_repo.dart @@ -4,9 +4,14 @@ import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/config/dependencies.dart'; import 'package:mc_common_app/models/advertisment_models/ad_details_model.dart'; import 'package:mc_common_app/models/advertisment_models/ads_duration_model.dart'; -import 'package:mc_common_app/models/advertisment_models/ads_generic_model.dart'; import 'package:mc_common_app/models/advertisment_models/special_service_model.dart'; +import 'package:mc_common_app/models/advertisment_models/ss_car_check_schedule_model.dart'; +import 'package:mc_common_app/models/advertisment_models/ss_photo_schedule_model.dart'; import 'package:mc_common_app/models/advertisment_models/vehicle_details_models.dart'; +import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart'; +import 'package:mc_common_app/models/generic_resp_model.dart'; +import 'package:mc_common_app/models/provider_category_model.dart'; +import 'package:mc_common_app/models/provider_service_model.dart'; import 'package:mc_common_app/models/user/cities.dart'; import 'package:mc_common_app/models/user/country.dart'; import 'package:mc_common_app/models/user/role.dart'; @@ -46,13 +51,23 @@ abstract class CommonRepo { Future> getAdsDuration(); - Future> getSpecialServices(); + Future> getSpecialServices({required int specialServiceId}); - Future createNewAd({required AdsCreationPayloadModel adsCreationPayloadModel}); + Future createNewAd({required AdsCreationPayloadModel adsCreationPayloadModel}); Future> getAllAds({required bool isMyAds}); Future> getMyAds(); + + Future> getMyAppointments(); + + Future getCarCheckServiceScheduleDetails({required double lat, required double long}); + + Future getPhotographyServiceScheduleDetails({required double lat, required double long}); + + Future> getProviderServiceCategories(); + + Future> getProviderServices({required int categoryId}); } class CommonRepoImp implements CommonRepo { @@ -79,7 +94,7 @@ class CommonRepoImp implements CommonRepo { @override Future> getVehicleTypes() async { - AdsGenericModel adsGenericModel = await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => AdsGenericModel.fromJson(json), ApiConsts.vehicleTypeGet); + GenericRespModel adsGenericModel = await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleTypeGet); List vehicleTypes = List.generate(adsGenericModel.data.length, (index) => VehicleTypeModel.fromJson(adsGenericModel.data[index])); return vehicleTypes; } @@ -89,8 +104,8 @@ class CommonRepoImp implements CommonRepo { var postParams = { "VehicleType": vehicleTypeId.toString(), }; - AdsGenericModel adsGenericModel = - await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => AdsGenericModel.fromJson(json), ApiConsts.vehicleCategoryGet, queryParameters: postParams); + GenericRespModel adsGenericModel = + await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleCategoryGet, queryParameters: postParams); List vehicleCategories = List.generate(adsGenericModel.data.length, (index) => VehicleCategoryModel.fromJson(adsGenericModel.data[index])); return vehicleCategories; } @@ -100,8 +115,8 @@ class CommonRepoImp implements CommonRepo { var postParams = { "CountryID": countryId.toString(), }; - AdsGenericModel adsGenericModel = - await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => AdsGenericModel.fromJson(json), ApiConsts.vehicleCityGet, queryParameters: postParams); + GenericRespModel adsGenericModel = + await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleCityGet, queryParameters: postParams); List vehicleCities = List.generate(adsGenericModel.data.length, (index) => VehicleCityModel.fromJson(adsGenericModel.data[index])); return vehicleCities; } @@ -111,8 +126,8 @@ class CommonRepoImp implements CommonRepo { var postParams = { "VehicleType": vehicleTypeId.toString(), }; - AdsGenericModel adsGenericModel = - await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => AdsGenericModel.fromJson(json), ApiConsts.vehicleColorGet, queryParameters: postParams); + GenericRespModel adsGenericModel = + await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleColorGet, queryParameters: postParams); List vehicleColors = List.generate(adsGenericModel.data.length, (index) => VehicleColorModel.fromJson(adsGenericModel.data[index])); return vehicleColors; } @@ -122,17 +137,17 @@ class CommonRepoImp implements CommonRepo { var postParams = { "VehicleType": vehicleTypeId.toString(), }; - AdsGenericModel adsGenericModel = - await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => AdsGenericModel.fromJson(json), ApiConsts.vehicleConditionGet, queryParameters: postParams); + GenericRespModel adsGenericModel = + await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleConditionGet, queryParameters: postParams); List vehicleConditions = List.generate(adsGenericModel.data.length, (index) => VehicleConditionModel.fromJson(adsGenericModel.data[index])); return vehicleConditions; } @override Future> getVehicleCountries() async { - AdsGenericModel adsGenericModel = await apiClient.getJsonForObject( + GenericRespModel adsGenericModel = await apiClient.getJsonForObject( token: appState.getUser.data!.accessToken, - (json) => AdsGenericModel.fromJson(json), + (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleCountryGet, ); List vehicleConditions = List.generate(adsGenericModel.data.length, (index) => VehicleCountryModel.fromJson(adsGenericModel.data[index])); @@ -144,8 +159,8 @@ class CommonRepoImp implements CommonRepo { var postParams = { "VehicleType": vehicleTypeId.toString(), }; - AdsGenericModel adsGenericModel = - await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => AdsGenericModel.fromJson(json), ApiConsts.vehicleMileageGet, queryParameters: postParams); + GenericRespModel adsGenericModel = + await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleMileageGet, queryParameters: postParams); List vehicleMileages = List.generate(adsGenericModel.data.length, (index) => VehicleMileageModel.fromJson(adsGenericModel.data[index])); return vehicleMileages; } @@ -155,8 +170,8 @@ class CommonRepoImp implements CommonRepo { var postParams = { "VehicleType": vehicleTypeId.toString(), }; - AdsGenericModel adsGenericModel = - await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => AdsGenericModel.fromJson(json), ApiConsts.vehicleModelYearGet, queryParameters: postParams); + GenericRespModel adsGenericModel = + await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleModelYearGet, queryParameters: postParams); List vehicleModelYears = List.generate(adsGenericModel.data.length, (index) => VehicleYearModel.fromJson(adsGenericModel.data[index])); return vehicleModelYears; } @@ -166,8 +181,8 @@ class CommonRepoImp implements CommonRepo { var postParams = { "VehicleType": vehicleTypeId.toString(), }; - AdsGenericModel adsGenericModel = - await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => AdsGenericModel.fromJson(json), ApiConsts.vehicleModelGet, queryParameters: postParams); + GenericRespModel adsGenericModel = + await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleModelGet, queryParameters: postParams); List vehicleModels = List.generate(adsGenericModel.data.length, (index) => VehicleModel.fromJson(adsGenericModel.data[index])); return vehicleModels; } @@ -177,8 +192,8 @@ class CommonRepoImp implements CommonRepo { var postParams = { "VehicleType": vehicleTypeId.toString(), }; - AdsGenericModel adsGenericModel = - await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => AdsGenericModel.fromJson(json), ApiConsts.vehicleSellerTypeGet, queryParameters: postParams); + GenericRespModel adsGenericModel = + await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleSellerTypeGet, queryParameters: postParams); List vehicleSellerTypes = List.generate(adsGenericModel.data.length, (index) => VehicleSellerTypeModel.fromJson(adsGenericModel.data[index])); return vehicleSellerTypes; } @@ -188,8 +203,8 @@ class CommonRepoImp implements CommonRepo { var postParams = { "VehicleType": vehicleTypeId.toString(), }; - AdsGenericModel adsGenericModel = - await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => AdsGenericModel.fromJson(json), ApiConsts.vehicleTransmissionGet, queryParameters: postParams); + GenericRespModel adsGenericModel = + await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleTransmissionGet, queryParameters: postParams); List vehicleTransmissions = List.generate(adsGenericModel.data.length, (index) => VehicleTransmissionModel.fromJson(adsGenericModel.data[index])); return vehicleTransmissions; } @@ -214,8 +229,8 @@ class CommonRepoImp implements CommonRepo { }; String token = appState.getUser.data!.accessToken ?? ""; - AdsGenericModel adsGenericModel = await apiClient.postJsonForObject( - (json) => AdsGenericModel.fromJson(json), + GenericRespModel adsGenericModel = await apiClient.postJsonForObject( + (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleDetailsMaster, postParams, token: token, @@ -226,9 +241,9 @@ class CommonRepoImp implements CommonRepo { @override Future> getVehicleDamageParts() async { - AdsGenericModel adsGenericModel = await apiClient.getJsonForObject( + GenericRespModel adsGenericModel = await apiClient.getJsonForObject( token: appState.getUser.data!.accessToken, - (json) => AdsGenericModel.fromJson(json), + (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleDamagePartGet, ); List vehicleParts = List.generate(adsGenericModel.data.length, (index) => VehiclePartModel.fromJson(adsGenericModel.data[index])); @@ -237,9 +252,9 @@ class CommonRepoImp implements CommonRepo { @override Future> getAdsDuration() async { - AdsGenericModel adsGenericModel = await apiClient.getJsonForObject( + GenericRespModel adsGenericModel = await apiClient.getJsonForObject( token: appState.getUser.data!.accessToken, - (json) => AdsGenericModel.fromJson(json), + (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleAdsDurationGet, ); List vehicleAdsDuration = List.generate(adsGenericModel.data.length, (index) => AdsDurationModel.fromJson(adsGenericModel.data[index])); @@ -247,18 +262,18 @@ class CommonRepoImp implements CommonRepo { } @override - Future> getSpecialServices() async { - AdsGenericModel adsGenericModel = await apiClient.getJsonForObject( - token: appState.getUser.data!.accessToken, - (json) => AdsGenericModel.fromJson(json), - ApiConsts.vehicleAdsSpecialServicesGet, - ); + Future> getSpecialServices({required int specialServiceId}) async { + var params = { + "SpecialServiceType": specialServiceId.toString(), + }; + GenericRespModel adsGenericModel = + await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleAdsSpecialServicesGet, queryParameters: params); List vehicleAdsDuration = List.generate(adsGenericModel.data.length, (index) => SpecialServiceModel.fromJson(adsGenericModel.data[index])); return vehicleAdsDuration; } @override - Future createNewAd({required AdsCreationPayloadModel adsCreationPayloadModel}) async { + Future createNewAd({required AdsCreationPayloadModel adsCreationPayloadModel}) async { List vehiclePostingImages = []; adsCreationPayloadModel.vehiclePosting!.vehiclePostingImages?.forEach((element) { var imageMap = { @@ -321,8 +336,8 @@ class CommonRepoImp implements CommonRepo { }; String token = appState.getUser.data!.accessToken ?? ""; - AdsGenericModel adsGenericModel = await apiClient.postJsonForObject( - (json) => AdsGenericModel.fromJson(json), + GenericRespModel adsGenericModel = await apiClient.postJsonForObject( + (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleAdsSingleStepCreate, postParams, token: token, @@ -337,9 +352,9 @@ class CommonRepoImp implements CommonRepo { "userID": appState.getUser.data!.userInfo!.userId ?? "", }; - AdsGenericModel adsGenericModel = await apiClient.getJsonForObject( + GenericRespModel adsGenericModel = await apiClient.getJsonForObject( token: appState.getUser.data!.accessToken, - (json) => AdsGenericModel.fromJson(json), + (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleAdsGet, queryParameters: isMyAds ? params : null, ); @@ -352,13 +367,78 @@ class CommonRepoImp implements CommonRepo { var params = { "userID": appState.getUser.data!.userInfo!.userId ?? "", }; - AdsGenericModel adsGenericModel = await apiClient.getJsonForObject( + GenericRespModel adsGenericModel = await apiClient.getJsonForObject( token: appState.getUser.data!.accessToken, - (json) => AdsGenericModel.fromJson(json), + (json) => GenericRespModel.fromJson(json), queryParameters: params, ApiConsts.vehicleAdsGet, ); List vehicleAdsDetails = List.generate(adsGenericModel.data.length, (index) => AdDetailsModel.fromJson(adsGenericModel.data[index])); return vehicleAdsDetails; } + + @override + Future> getMyAppointments() async { + var params = { + "userID": appState.getUser.data!.userInfo!.userId ?? "", + }; + GenericRespModel genericRespModel = await apiClient.getJsonForObject( + token: appState.getUser.data!.accessToken, + (json) => GenericRespModel.fromJson(json), + queryParameters: params, + ApiConsts.serviceProvidersAppointmentGet, + ); + List appointmentList = List.generate(genericRespModel.data.length, (index) => AppointmentListModel.fromJson(genericRespModel.data[index])); + return appointmentList; + } + + @override + Future getCarCheckServiceScheduleDetails({required double lat, required double long}) async { + var params = { + "Latitude": lat.toString(), + "Longitude": long.toString(), + }; + GenericRespModel genericRespModel = await apiClient.getJsonForObject( + token: appState.getUser.data!.accessToken, + (json) => GenericRespModel.fromJson(json), + queryParameters: params, + ApiConsts.adsCarCheckupSPBranchScheduleSlotGet, + ); + SSCarCheckScheduleModel ssCarCheckScheduleModel = SSCarCheckScheduleModel.fromJson(genericRespModel.data[0]); + return ssCarCheckScheduleModel; + } + + @override + Future getPhotographyServiceScheduleDetails({required double lat, required double long}) async { + var params = { + "Latitude": lat.toString(), + "Longitude": long.toString(), + }; + GenericRespModel genericRespModel = await apiClient.getJsonForObject( + token: appState.getUser.data!.accessToken, + (json) => GenericRespModel.fromJson(json), + queryParameters: params, + ApiConsts.adsPhotoOfficeAppointmentScheduleSlotGet, + ); + SSPhotoScheduleModel ssPhotoScheduleModel = SSPhotoScheduleModel.fromJson(genericRespModel.data[0]); + return ssPhotoScheduleModel; + } + + @override + Future> getProviderServiceCategories() async { + GenericRespModel adsGenericModel = await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.serviceCategoryGet); + List providerCategories = List.generate(adsGenericModel.data.length, (index) => ProviderCategoryModel.fromJson(adsGenericModel.data[index])); + return providerCategories; + } + + @override + Future> getProviderServices({required int categoryId}) async { + var postParams = { + "ServiceCategoryID": categoryId.toString(), + }; + GenericRespModel adsGenericModel = + await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.serviceCategoryGet, queryParameters: postParams); + List providerServices = List.generate(adsGenericModel.data.length, (index) => ProviderServiceModel.fromJson(adsGenericModel.data[index])); + return providerServices; + } } diff --git a/lib/theme/colors.dart b/lib/theme/colors.dart index 09fc842..c057d05 100644 --- a/lib/theme/colors.dart +++ b/lib/theme/colors.dart @@ -34,6 +34,7 @@ class MyColors { static const Color white = Color(0xffffffff); static const Color green = Color(0xffffffff); static const Color borderColor = Color(0xffE8E8E8); + static const Color greyAddBorderColor = Color(0xffEEEEEE); static Decoration gradient = BoxDecoration( gradient: const LinearGradient(colors: [ diff --git a/lib/utils/enums.dart b/lib/utils/enums.dart index 8c9b0fb..d89d2fe 100644 --- a/lib/utils/enums.dart +++ b/lib/utils/enums.dart @@ -5,6 +5,20 @@ // unverified, // } +enum AdPostStatus { + pendingForReview, + pendingForPayment, + rejected, + cancelled, + pendingForPost, + active, + expired, + sold, + reserved, + buyingService, + reserveCancel, +} + enum AdCreationStepsEnum { vehicleDetails, damageParts, diff --git a/lib/view_models/ad_view_model.dart b/lib/view_models/ad_view_model.dart index 4148bc8..0b91ef1 100644 --- a/lib/view_models/ad_view_model.dart +++ b/lib/view_models/ad_view_model.dart @@ -6,11 +6,14 @@ import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/config/dependencies.dart'; import 'package:mc_common_app/config/routes.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/models/advertisment_models/ad_details_model.dart'; import 'package:mc_common_app/models/advertisment_models/ads_duration_model.dart'; -import 'package:mc_common_app/models/advertisment_models/ads_generic_model.dart'; import 'package:mc_common_app/models/advertisment_models/special_service_model.dart'; +import 'package:mc_common_app/models/advertisment_models/ss_car_check_schedule_model.dart'; +import 'package:mc_common_app/models/advertisment_models/ss_photo_schedule_model.dart'; import 'package:mc_common_app/models/advertisment_models/vehicle_details_models.dart'; +import 'package:mc_common_app/models/generic_resp_model.dart'; import 'package:mc_common_app/models/widgets_models.dart'; import 'package:mc_common_app/repositories/common_repo.dart'; import 'package:mc_common_app/services/services.dart'; @@ -18,6 +21,7 @@ import 'package:mc_common_app/utils/enums.dart'; import 'package:mc_common_app/utils/navigator.dart'; import 'package:mc_common_app/utils/utils.dart'; import 'package:mc_common_app/view_models/base_view_model.dart'; +import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart'; class AdVM extends BaseVM { final CommonRepo commonRepo; @@ -39,10 +43,13 @@ class AdVM extends BaseVM { List vehicleTransmissions = []; List vehicleSellerTypes = []; List vehicleDamageParts = []; + List vehiclePartsSearchResults = []; List vehicleCountries = []; List vehicleCities = []; List vehicleAdsDurations = []; List vehicleAdsSpecialServices = []; + SSCarCheckScheduleModel? ssCarCheckScheduleModel; + SSPhotoScheduleModel? ssPhotoScheduleModel; String demandAmountError = ""; String vehicleVinError = ""; @@ -52,9 +59,12 @@ class AdVM extends BaseVM { String vehicleImageError = ""; String vehicleDamageImageError = ""; String adStartDateError = ""; + String damagePartSearchValue = ""; + String adReservePriceError = ""; - List allAds = []; - List adsFilteredList = []; + List exploreAds = []; + List exploreAdsFilteredList = []; + List myAdsFilteredList = []; List myAds = []; List vehicleDamageCards = []; @@ -97,41 +107,92 @@ class AdVM extends BaseVM { void clearSpecialServiceCard() { specialServiceCards.clear(); + notifyListeners(); + } + + void onSearchChangedForDamagePart(String text) { + vehiclePartsSearchResults.clear(); + damagePartSearchValue = text; + + if (text.isEmpty) { + notifyListeners(); + return; + } + + for (var damagePartDetail in vehicleDamageParts) { + if (damagePartDetail.partName!.toLowerCase().contains(text.toLowerCase())) { + vehiclePartsSearchResults.add(damagePartDetail); + + notifyListeners(); + } + } } bool isExploreAdsTapped = true; void updateIsExploreAds(bool value) async { isExploreAdsTapped = value; + + //To show the Active Ads + applyFilterOnMyAds(index: 0, selectedFilterId: 6); // if (value) { // await getAllAds(); // } notifyListeners(); } - List adsFilterOptions = []; + List exploreAdsFilterOptions = []; + List myAdsFilterOptions = []; populateAdsFilterList() { - adsFilterOptions.clear(); - adsFilterOptions = [ - FilterListModel(title: "All Ads", isSelected: true), - FilterListModel(title: "Customer Ads", isSelected: false), - FilterListModel(title: "Provider Ads", isSelected: false), - FilterListModel(title: "Mowater Ads", isSelected: false), + exploreAdsFilterOptions.clear(); + exploreAdsFilterOptions.clear(); + exploreAdsFilterOptions = [ + FilterListModel(title: "All Ads", isSelected: true, id: -1), + FilterListModel(title: "Customer Ads", isSelected: false, id: 0), + FilterListModel(title: "Provider Ads", isSelected: false, id: 1), + FilterListModel(title: "Mowater Ads", isSelected: false, id: 2), + ]; + + myAdsFilterOptions = [ + // FilterListModel(title: "All Ads", isSelected: true, id: -1), + FilterListModel(title: "Active", isSelected: false, id: 6), + FilterListModel(title: "Pending For Review", isSelected: false, id: 1), + FilterListModel(title: "Pending For Payment", isSelected: false, id: 2), + FilterListModel(title: "Rejected", isSelected: false, id: 3), + FilterListModel(title: "Pending For Post", isSelected: false, id: 5), + FilterListModel(title: "Reserved", isSelected: false, id: 9), ]; notifyListeners(); } - applyFilterOnAds({required int index}) { - if (adsFilterOptions.isEmpty) return; - for (var value in adsFilterOptions) { + applyFilterOnExploreAds({required int index}) { + if (exploreAdsFilterOptions.isEmpty) return; + for (var value in exploreAdsFilterOptions) { value.isSelected = false; } - adsFilterOptions[index].isSelected = true; + exploreAdsFilterOptions[index].isSelected = true; // TODO: --> here we will filter the allAds list // TODO: --> and get the updated list into this new list everytime filter changes - adsFilteredList = allAds; + exploreAdsFilteredList = exploreAds; + notifyListeners(); + } + + applyFilterOnMyAds({required int index, required int selectedFilterId}) { + if (myAdsFilterOptions.isEmpty) return; + for (var value in myAdsFilterOptions) { + value.isSelected = false; + } + myAdsFilterOptions[index].isSelected = true; + + if (selectedFilterId == -1) { + myAdsFilteredList = myAds; + notifyListeners(); + return; + } + + myAdsFilteredList = myAds.where((element) => element.statusID! == selectedFilterId).toList(); notifyListeners(); } @@ -142,8 +203,8 @@ class AdVM extends BaseVM { notifyListeners(); } - Future getAllAds() async { - allAds = await commonRepo.getAllAds(isMyAds: false); + Future getExploreAds() async { + exploreAds = await commonRepo.getAllAds(isMyAds: false); notifyListeners(); } @@ -158,7 +219,7 @@ class AdVM extends BaseVM { } Future getVehicleAdsSpecialServices() async { - vehicleAdsSpecialServices = await commonRepo.getSpecialServices(); + vehicleAdsSpecialServices = await commonRepo.getSpecialServices(specialServiceId: 1); notifyListeners(); } @@ -214,6 +275,14 @@ class AdVM extends BaseVM { notifyListeners(); } + String adReserveAmount = ""; + + void updateAdReservePriceAmount(String date) { + adReserveAmount = date; + if (adReserveAmount.isNotEmpty) adReservePriceError = ""; + notifyListeners(); + } + String adSpecialServiceDate = ""; void updateAdSpecialServiceDate(String date) { @@ -318,7 +387,7 @@ class AdVM extends BaseVM { notifyListeners(); } - // SelectionModel vehicleDamagePartId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); +// SelectionModel vehicleDamagePartId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); void updateSelectionVehicleDamagePartId(SelectionModel id, int index) { vehicleDamageCards[index].partSelectedId = id; @@ -354,11 +423,130 @@ class AdVM extends BaseVM { notifyListeners(); } + SelectionModel vehicleAdReservableId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); + + void updateVehicleAdReservableId(SelectionModel id) { + vehicleAdReservableId = id; + notifyListeners(); + } + SelectionModel vehicleAdsSpecialServicesId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); - void updateVehicleAdsSpecialServicesId(SelectionModel id) { + void updateVehicleAdsSpecialServicesId(SelectionModel id) async { vehicleAdsSpecialServicesId = id; + isFetchingLists = true; + adSSTimeSlots.clear(); + vehicleAdsPhotoServiceDate = SelectionModel(selectedId: -1, selectedOption: ""); + vehicleAdsCarCheckServicesDate = SelectionModel(selectedId: -1, selectedOption: ""); + notifyListeners(); + + if (id.selectedId == 1) { + ssPhotoScheduleModel = await commonRepo.getPhotographyServiceScheduleDetails(lat: 0.0, long: 0.0); + } else if (id.selectedId == 3) { + ssCarCheckScheduleModel = await commonRepo.getCarCheckServiceScheduleDetails(lat: 0.0, long: 0.0); + } else {} + isFetchingLists = false; + notifyListeners(); + } + + List adSSTimeSlots = []; + int? slotSelectedIndex; + + void updateIsSelectedInSlots(int index) { + for (var value in adSSTimeSlots) { + value.isSelected = false; + } + slotSelectedIndex = index; notifyListeners(); + adSSTimeSlots[index].isSelected = true; + } + + SelectionModel vehicleAdsPhotoServiceDate = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); + + void updateVehicleVehicleAdsPhotoServiceDate(SelectionModel id) { + vehicleAdsPhotoServiceDate = id; + + adSSTimeSlots.clear(); + slotSelectedIndex = null; + + for (var value in ssPhotoScheduleModel!.photoOfficeScheduleSlots!) { + if (value.slotDate!.toFormattedDateWithoutTime() == vehicleAdsPhotoServiceDate.selectedOption) { + adSSTimeSlots.add(TimeSlotModel(slot: value.startTime!, isSelected: false, slotId: value.id!)); + } + } + notifyListeners(); + } + + SelectionModel vehicleAdsCarCheckServicesDate = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); + + void updateVehicleAdsCarCheckServicesDate(SelectionModel id) { + vehicleAdsCarCheckServicesDate = id; + + adSSTimeSlots.clear(); + slotSelectedIndex = null; + + for (var value in ssCarCheckScheduleModel!.branchScheduleSlots!) { + if (value.slotDate!.toFormattedDateWithoutTime() == vehicleAdsCarCheckServicesDate.selectedOption) { + adSSTimeSlots.add(TimeSlotModel(slot: value.startTime!, isSelected: false, slotId: value.id!)); + } + } + notifyListeners(); + } + + String selectedTimeSlotForEngineCarCheck = ""; + + void updateSelectedTimeSlotForEngineCarCheck(String timeSlot) { + selectedTimeSlotForEngineCarCheck = timeSlot; + notifyListeners(); + } + + bool isPresentInThisList({required List list, required String item}) { + bool isPresent = false; + + for (var element in list) { + if (element == item) { + isPresent = true; + break; + } + } + + return isPresent; + } + + List populateScheduleDatesForAdPhotoService() { + List vehicleAdsSpecialServiceDates = []; + + List slotDates = []; + + if (ssPhotoScheduleModel!.photoOfficeScheduleSlots == null) { + return []; + } + for (var element in ssPhotoScheduleModel!.photoOfficeScheduleSlots!) { + if (!slotDates.contains(element.slotDate!)) { + slotDates.add(element.slotDate!); + vehicleAdsSpecialServiceDates.add(DropValue(element.id!.toInt(), element.slotDate!.toFormattedDateWithoutTime(), "")); + } + } + + return vehicleAdsSpecialServiceDates; + } + + List populateScheduleDatesForAdCarCheckService() { + List vehicleAdsSpecialServiceDates = []; + + List slotDates = []; + + if (ssCarCheckScheduleModel!.branchScheduleSlots == null) { + return []; + } + for (var element in ssCarCheckScheduleModel!.branchScheduleSlots!) { + if (!slotDates.contains(element.slotDate!)) { + slotDates.add(element.slotDate!); + vehicleAdsSpecialServiceDates.add(DropValue(element.id!.toInt(), element.slotDate!.toFormattedDateWithoutTime(), "")); + } + } + + return vehicleAdsSpecialServiceDates; } bool isVehicleDetailsValidated() { @@ -485,23 +673,23 @@ class AdVM extends BaseVM { bool isDamagePartsValidated() { bool isValidated = true; - vehicleDamageCards.forEach((element) { + for (var element in vehicleDamageCards) { if (element.partSelectedId!.selectedId == -1) { element.partSelectedId!.errorValue = "Please select vehicle part"; isValidated = false; } else { element.partSelectedId!.errorValue = ""; } - }); + } - vehicleDamageCards.forEach((element) { + for (var element in vehicleDamageCards) { if (element.partImages == null || element.partImages!.isEmpty) { element.partImageErrorValue = GlobalConsts.attachDamagePartImage; isValidated = false; } else { element.partImageErrorValue = ""; } - }); + } // if (pickedDamageImages.isEmpty || pickedDamageImages.length < 3) { // vehicleDamageImageError = GlobalConsts.attachImageError; @@ -530,6 +718,20 @@ class AdVM extends BaseVM { adStartDateError = ""; } + if (vehicleAdReservableId.selectedId == -1) { + vehicleAdReservableId.errorValue = "Please select if the Ad is Reservable or not."; + isValidated = false; + } else { + vehicleAdReservableId.errorValue = ""; + } + + if (adReserveAmount.isEmpty) { + adReservePriceError = GlobalConsts.adReservablePriceErrorConst; + isValidated = false; + } else { + adStartDateError = ""; + } + notifyListeners(); return isValidated; } @@ -591,6 +793,7 @@ class AdVM extends BaseVM { Utils.showToast("A new ads has been created."); currentProgressStep = AdCreationStepsEnum.vehicleDetails; resetValues(); + updateIsExploreAds(false); navigateReplaceWithName(context, AppRoutes.dashboard); } catch (e) { Utils.hideLoading(context); @@ -626,8 +829,8 @@ class AdVM extends BaseVM { notifyListeners(); } - // sourceFlag for Camera = 0 - // sourceFlag for Gallery = 1 +// sourceFlag for Camera = 0 +// sourceFlag for Gallery = 1 void pickDamagePartImage(int index) async { List images = await commonServices.pickMultipleImages(); @@ -742,7 +945,7 @@ class AdVM extends BaseVM { List vehicleDamageImages = []; for (var card in vehicleDamageCards) { - if (card.partImages != null && card.partImages!.length > 0) { + if (card.partImages != null && card.partImages!.isNotEmpty) { for (var image in card.partImages!) { VehiclePostingDamageParts stringImage = await convertFileToVehiclePostingDamageParts( file: image, @@ -778,7 +981,7 @@ class AdVM extends BaseVM { ); AdsCreationPayloadModel adsCreationPayloadModel = AdsCreationPayloadModel(ads: ads, vehiclePosting: vehiclePosting); - AdsGenericModel respModel = await commonRepo.createNewAd(adsCreationPayloadModel: adsCreationPayloadModel); + GenericRespModel respModel = await commonRepo.createNewAd(adsCreationPayloadModel: adsCreationPayloadModel); return Future.value(respModel.messageStatus); } @@ -806,19 +1009,7 @@ class AdVM extends BaseVM { } } -class SelectionModel { - String selectedOption; - int selectedId; - String errorValue; - String itemPrice; - - SelectionModel({ - this.selectedOption = "", - this.errorValue = "", - this.selectedId = 0, - this.itemPrice = "", - }); -} + class VehicleDamageCard { List? partImages; @@ -838,6 +1029,9 @@ class SpecialServiceCard { String? serviceDateError; String? serviceTime; String? serviceTimeError; + String? description; + String? duration; + String? address; SpecialServiceCard({ this.serviceSelectedId, @@ -845,6 +1039,8 @@ class SpecialServiceCard { this.serviceDateError = "", this.serviceTime = "", this.serviceTimeError = "", + this.description = "", + this.duration = "", + this.address = "", }); } - diff --git a/lib/views/advertisement/ad_creation_steps/ad_duration_container.dart b/lib/views/advertisement/ad_creation_steps/ad_duration_container.dart index cb8f413..b8a733e 100644 --- a/lib/views/advertisement/ad_creation_steps/ad_duration_container.dart +++ b/lib/views/advertisement/ad_creation_steps/ad_duration_container.dart @@ -1,11 +1,14 @@ -import 'package:mc_common_app/view_models/ad_view_model.dart'; -import 'package:mc_common_app/views/advertisement/bottom_sheet_content.dart'; -import 'package:mc_common_app/views/advertisement/custom_add_button.dart'; import 'package:flutter/material.dart'; +import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/models/widgets_models.dart'; import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/utils/utils.dart'; +import 'package:mc_common_app/view_models/ad_view_model.dart'; +import 'package:mc_common_app/views/advertisement/bottom_sheet_content.dart'; +import 'package:mc_common_app/views/advertisement/custom_add_button.dart'; +import 'package:mc_common_app/widgets/common_widgets/info_bottom_sheet.dart'; import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:mc_common_app/widgets/txt_field.dart'; @@ -20,7 +23,17 @@ class AdDuration extends StatelessWidget { isScrollControlled: true, enableDrag: true, builder: (BuildContext context) { - return BottomSheetServiceContent(); + return const BottomSheetAdSpecialServiceContent(); + }); + } + + void reservePriceInfoClicked(BuildContext context) { + showModalBottomSheet( + context: context, + isScrollControlled: true, + enableDrag: true, + builder: (BuildContext context) { + return InfoBottomSheet(title: "Reserve Ad Price Info", description: GlobalConsts.reserveAdPriceInfo); }); } @@ -62,6 +75,41 @@ class AdDuration extends StatelessWidget { adVM.updateSelectionDurationStartDate(formattedDate); }, ), + + ], + ).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 10)), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Reservable Ad".toText(fontSize: 18, isBold: true), + 8.height, + Builder(builder: (context) { + List adReservableOptions = []; + adReservableOptions.add(DropValue(1, "Yes", "")); + adReservableOptions.add(DropValue(0, "No", "")); + return DropdownField( + (DropValue value) => adVM.updateVehicleAdReservableId(SelectionModel(selectedId: value.id, selectedOption: value.value)), + errorValue: adVM.vehicleAdReservableId.errorValue, + list: adReservableOptions, + hint: "Reservable", + dropdownValue: adVM.vehicleAdReservableId.selectedId != -1 ? DropValue(adVM.vehicleAdReservableId.selectedId, adVM.vehicleAdReservableId.selectedOption, "") : null, + ); + }), + if (adVM.vehicleAdReservableId.selectedId == 1) ...[ + 8.height, + TxtField( + postfixData: Icons.info_outline_rounded, + postFixDataColor: MyColors.grey77Color, + onPostFixPressed: () { + reservePriceInfoClicked(context); + }, + value: adVM.adReserveAmount, + errorValue: adVM.adReservePriceError, + keyboardType: TextInputType.number, + hint: "Ad Reserve Price", + onChanged: (v) => adVM.updateAdReservePriceAmount(v), + ), + ], ], ).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 10)), Column( @@ -77,16 +125,13 @@ class AdDuration extends StatelessWidget { icon: Container( height: 24, width: 24, - decoration: BoxDecoration(shape: BoxShape.circle, color: MyColors.darkTextColor), - child: Icon( - Icons.add, - color: MyColors.white, - ), + decoration: const BoxDecoration(shape: BoxShape.circle, color: MyColors.darkTextColor), + child: const Icon(Icons.add, color: MyColors.white), ), ), 20.height, ListView.builder( - physics: NeverScrollableScrollPhysics(), + physics: const NeverScrollableScrollPhysics(), shrinkWrap: true, itemCount: adVM.specialServiceCards.length, itemBuilder: (BuildContext context, int index) { @@ -100,30 +145,82 @@ class AdDuration extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( - child: specialServicesCard.serviceSelectedId!.selectedOption.toText(fontSize: 18, isBold: true), - ), - InkWell( - onTap: () => adVM.removeSpecialServiceCard(index), - child: Icon(Icons.delete_outline_rounded), + child: specialServicesCard.serviceSelectedId!.selectedOption.toText(fontSize: 16, isBold: true), ), + Align( + alignment: Alignment.topRight, + child: MyAssets.closeWithOrangeBg.buildSvg( + fit: BoxFit.fill, + height: 30, + width: 30, + ), + ).onPress(() => adVM.removeSpecialServiceCard(index)) ], ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - "12 July, 2023 - 09:30AM".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), - Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - (specialServicesCard.serviceSelectedId!.itemPrice).toText(fontSize: 20, isBold: true), - 2.width, - "SAR".toText(color: MyColors.lightTextColor, fontSize: 14), + Builder(builder: (context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (specialServicesCard.serviceSelectedId!.selectedId != 1 && specialServicesCard.serviceSelectedId!.selectedId != 3) ...[ + // Row( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // "Duration: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), + // (specialServicesCard.duration ?? "").toText(fontSize: 12, isBold: true).expand(), + // ], + // ), + 8.height, + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Description: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), + (specialServicesCard.description ?? "").toText(fontSize: 12, isBold: true).expand(), + ], + ), ], - ), - ], - ), - 5.height, - Divider(thickness: 1.5) + if (specialServicesCard.serviceSelectedId!.selectedId == 1 || specialServicesCard.serviceSelectedId!.selectedId == 3) ...[ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Icon( + weight: 2, + Icons.location_on_outlined, + color: MyColors.primaryColor, + size: 17, + ), + "${specialServicesCard.duration} km".toText(fontSize: 10, color: MyColors.primaryColor), + ], + ), + 8.height, + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Branch Address: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), + (specialServicesCard.address ?? "").toText(fontSize: 12, isBold: true).expand(), + ], + ), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Appointment Time: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), + "${specialServicesCard.serviceDate} - ${specialServicesCard.serviceTime}".toText(fontSize: 12, isBold: true).expand(), + ], + ), + ], + 6.height, + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + (specialServicesCard.serviceSelectedId!.itemPrice).toText(fontSize: 20, isBold: true), + 2.width, + "SAR".toText(color: MyColors.lightTextColor, fontSize: 14), + ], + ), + ], + ); + }), + 3.height, + const Divider(thickness: 1.5) ], ), 10.height, diff --git a/lib/views/advertisement/ad_creation_steps/ad_review_containers.dart b/lib/views/advertisement/ad_creation_steps/ad_review_containers.dart index f3b3e5d..4de0e27 100644 --- a/lib/views/advertisement/ad_creation_steps/ad_review_containers.dart +++ b/lib/views/advertisement/ad_creation_steps/ad_review_containers.dart @@ -1,9 +1,9 @@ -import 'package:mc_common_app/view_models/ad_view_model.dart'; -import 'package:mc_common_app/views/advertisement/picked_images_container.dart'; import 'package:flutter/material.dart'; import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/theme/colors.dart'; +import 'package:mc_common_app/view_models/ad_view_model.dart'; +import 'package:mc_common_app/views/advertisement/picked_images_container.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:provider/provider.dart'; @@ -57,7 +57,7 @@ class VehicleDetailsReview extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.start, children: [ Expanded( - flex: 5, + flex: 7, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -75,6 +75,8 @@ class VehicleDetailsReview extends StatelessWidget { 16.height, SingleDetailWidget(text: adVM.vehicleVin, type: "Vehicle VIN"), 16.height, + SingleDetailWidget(text: "${adVM.warrantyDuration} Years", type: "Warranty Available"), + 16.height, ], ), ), @@ -97,17 +99,15 @@ class VehicleDetailsReview extends StatelessWidget { 16.height, SingleDetailWidget(text: adVM.vehicleTitle, type: "Vehicle Title"), 16.height, + SingleDetailWidget(text: adVM.financeAvailableStatus ? "Yes" : "No", type: "Finance Available"), + 16.height, ], ), ), ], ), - SingleDetailWidget(text: adVM.warrantyDuration, type: "Warranty Available"), - 8.height, SingleDetailWidget(text: adVM.vehicleDescription, type: "Description"), 8.height, - SingleDetailWidget(text: adVM.financeAvailableStatus ? "Yes" : "No", type: "Finance Available"), - 8.height, "Vehicle Pictures:".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), if (adVM.pickedVehicleImages.isNotEmpty) ...[ // 10.height, @@ -149,7 +149,7 @@ class DamagePartsReview extends StatelessWidget { onAddImagePressed: () {}, ), ], - Divider(thickness: 2), + if (index != adVM.vehicleDamageCards.length - 1) const Divider(thickness: 2), ], )); @@ -188,23 +188,30 @@ class AdDurationReview extends StatelessWidget { 8.height, Row( children: [ + Expanded( + flex: 7, + child: SingleDetailWidget(type: "Duration", text: adVM.vehicleAdDurationId.selectedOption), + ), Expanded( flex: 5, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SingleDetailWidget(type: "Duration", text: adVM.vehicleAdDurationId.selectedOption), - ], - ), + child: SingleDetailWidget(type: "Start Date", text: adVM.selectionDurationStartDate), + ), + ], + ), + 15.height, + "Reservable Ad".toText(fontSize: 18, isBold: true), + 8.height, + Row( + children: [ + Expanded( + flex: 7, + child: SingleDetailWidget(type: "Reservable", text: adVM.vehicleAdReservableId.selectedId == 1 ? "Yes" : "No"), ), Expanded( flex: 5, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SingleDetailWidget(type: "Start Date", text: adVM.selectionDurationStartDate), - ], - ), + child: adVM.vehicleAdReservableId.selectedId == 1 + ? SingleDetailWidget(type: "Reserve Price", text: adVM.adReserveAmount) + : const SizedBox(), ), ], ), @@ -212,35 +219,66 @@ class AdDurationReview extends StatelessWidget { 15.height, "Special Services".toText(fontSize: 18, isBold: true), ListView.separated( - physics: NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemBuilder: (BuildContext context, int index) { - return Row( - children: [ - Expanded( - flex: 5, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - 8.height, - SingleDetailWidget(type: "Special Service", text: adVM.specialServiceCards[index].serviceSelectedId!.selectedOption), - ], + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + separatorBuilder: (BuildContext context, int index) => const Divider(thickness: 2), + itemCount: adVM.specialServiceCards.length, + itemBuilder: (BuildContext context, int index) { + return Column( + children: [ + 8.height, + + Row( + children: [ + Expanded( + flex: 7, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SingleDetailWidget(type: "Special Service", text: adVM.specialServiceCards[index].serviceSelectedId!.selectedOption), + ], + ), ), - ), - Expanded( - flex: 5, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SingleDetailWidget(type: "Amount", text: adVM.specialServiceCards[index].serviceSelectedId!.itemPrice), - ], + Expanded( + flex: 5, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SingleDetailWidget(type: "Amount", text: adVM.specialServiceCards[index].serviceSelectedId!.itemPrice), + ], + ), ), - ), + ], + ), + if (adVM.specialServiceCards[index].serviceSelectedId!.selectedId == 1 || adVM.specialServiceCards[index].serviceSelectedId!.selectedId == 3) ...[ + Row( + children: [ + Expanded( + flex: 7, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + 8.height, + SingleDetailWidget(type: "Branch Address", text: adVM.specialServiceCards[index].address ?? ""), + ], + ), + ), + Expanded( + flex: 5, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SingleDetailWidget(type: "Appointment Time", text: "${adVM.specialServiceCards[index].serviceDate ?? ""} - ${adVM.specialServiceCards[index].serviceTime}"), + ], + ), + ), + ], + ) ], - ); - }, - separatorBuilder: (BuildContext context, int index) => Divider(thickness: 2), - itemCount: adVM.specialServiceCards.length) + ], + ); + }, + ) ], ], ).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 10)); diff --git a/lib/views/advertisement/ad_creation_steps/damage_parts_container.dart b/lib/views/advertisement/ad_creation_steps/damage_parts_container.dart index 6f21473..ba53e82 100644 --- a/lib/views/advertisement/ad_creation_steps/damage_parts_container.dart +++ b/lib/views/advertisement/ad_creation_steps/damage_parts_container.dart @@ -1,11 +1,12 @@ -import 'package:mc_common_app/view_models/ad_view_model.dart'; -import 'package:mc_common_app/views/advertisement/bottom_sheet_content.dart'; -import 'package:mc_common_app/views/advertisement/custom_add_button.dart'; -import 'package:mc_common_app/views/advertisement/picked_images_container.dart'; import 'package:flutter/material.dart'; +import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/theme/colors.dart'; +import 'package:mc_common_app/view_models/ad_view_model.dart'; +import 'package:mc_common_app/views/advertisement/bottom_sheet_content.dart'; +import 'package:mc_common_app/views/advertisement/custom_add_button.dart'; +import 'package:mc_common_app/views/advertisement/picked_images_container.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:provider/provider.dart'; @@ -28,10 +29,12 @@ class DamageParts extends StatelessWidget { isScrollControlled: true, enableDrag: true, builder: (BuildContext context) { - return BottomSheetListContent(adVM: adVM); + return const BottomSheetListContent(); }); } + + @override Widget build(BuildContext context) { return Consumer( @@ -47,15 +50,12 @@ class DamageParts extends StatelessWidget { icon: Container( height: 24, width: 24, - decoration: BoxDecoration(shape: BoxShape.circle, color: MyColors.darkTextColor), - child: Icon( - Icons.add, - color: MyColors.white, - ), + decoration: const BoxDecoration(shape: BoxShape.circle, color: MyColors.darkTextColor), + child: const Icon(Icons.add, color: MyColors.white), )).horPaddingMain(), 9.height, ListView.builder( - physics: NeverScrollableScrollPhysics(), + physics: const NeverScrollableScrollPhysics(), shrinkWrap: true, itemCount: adVM.vehicleDamageCards.length, itemBuilder: (BuildContext context, int index) { @@ -67,7 +67,14 @@ class DamageParts extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ vehicleDamageCard.partSelectedId!.selectedOption.toText(fontSize: 18, isBold: true), - InkWell(onTap: () => adVM.removeDamagePartCard(index), child: Icon(Icons.delete_outline_rounded)), + Align( + alignment: Alignment.topRight, + child: MyAssets.closeWithOrangeBg.buildSvg( + fit: BoxFit.fill, + height: 30, + width: 30, + ), + ).onPress(() => adVM.removeDamagePartCard(index)) ], ), 10.height, diff --git a/lib/views/advertisement/ad_creation_steps/vehicle_details_container.dart b/lib/views/advertisement/ad_creation_steps/vehicle_details_container.dart index d7f1072..173a777 100644 --- a/lib/views/advertisement/ad_creation_steps/vehicle_details_container.dart +++ b/lib/views/advertisement/ad_creation_steps/vehicle_details_container.dart @@ -1,12 +1,13 @@ -import 'package:mc_common_app/view_models/ad_view_model.dart'; -import 'package:mc_common_app/views/advertisement/ad_creation_steps/ad_creation_steps_containers.dart'; -import 'package:mc_common_app/views/advertisement/picked_images_container.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/models/widgets_models.dart'; import 'package:mc_common_app/theme/colors.dart'; +import 'package:mc_common_app/view_models/ad_view_model.dart'; +import 'package:mc_common_app/views/advertisement/ad_creation_steps/ad_creation_steps_containers.dart'; +import 'package:mc_common_app/views/advertisement/picked_images_container.dart'; import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:mc_common_app/widgets/txt_field.dart'; @@ -200,6 +201,7 @@ class VehicleDetails extends StatelessWidget { TxtField( value: adVM.vehicleDemandAmount, errorValue: adVM.demandAmountError, + keyboardType: TextInputType.number, hint: "Demand Amount", onChanged: (v) => adVM.updateVehicleDemandAmount(v), ), @@ -207,6 +209,7 @@ class VehicleDetails extends StatelessWidget { TxtField( value: adVM.vehicleVin, errorValue: adVM.vehicleVinError, + keyboardType: TextInputType.number, hint: "Vehicle VIN", onChanged: (v) => adVM.updateVehicleVin(v), ), @@ -221,6 +224,7 @@ class VehicleDetails extends StatelessWidget { TxtField( value: adVM.warrantyDuration, errorValue: adVM.warrantyError, + keyboardType: TextInputType.number, hint: "Warranty Available (No. of Years)", onChanged: (v) => adVM.updateVehicleWarrantyDuration(v), ), diff --git a/lib/views/advertisement/ads_detail_view.dart b/lib/views/advertisement/ads_detail_view.dart index 72c901b..a3e8112 100644 --- a/lib/views/advertisement/ads_detail_view.dart +++ b/lib/views/advertisement/ads_detail_view.dart @@ -18,7 +18,6 @@ class AdsDetailView extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: CustomAppBar( - backgroundColor: MyColors.backgroundColor, title: "Ads", profileImageUrl: MyAssets.bnCar, isRemoveBackButton: false, diff --git a/lib/views/advertisement/ads_list.dart b/lib/views/advertisement/ads_list.dart index a59d86f..fecbfb4 100644 --- a/lib/views/advertisement/ads_list.dart +++ b/lib/views/advertisement/ads_list.dart @@ -11,21 +11,28 @@ import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; class BuildAdsList extends StatelessWidget { final List adsList; final ScrollPhysics? scrollPhysics; + final bool isAdsFragment; - const BuildAdsList({Key? key, required this.adsList, this.scrollPhysics}) : super(key: key); + const BuildAdsList({Key? key, required this.adsList, this.scrollPhysics, this.isAdsFragment = false}) : super(key: key); @override Widget build(BuildContext context) { + if (isAdsFragment && adsList.isEmpty) { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + "No Ads to show.".toText(fontSize: 16, color: MyColors.lightTextColor), + ], + ); + } return ListView.builder( itemCount: adsList.length, shrinkWrap: true, physics: scrollPhysics, itemBuilder: (BuildContext context, int index) { return Padding( - padding: const EdgeInsets.only(bottom: 15), - child: AdCard( - adDetails: adsList[index], - ), + padding: const EdgeInsets.only(bottom: 8), + child: AdCard(adDetails: adsList[index]), ).onPress(() { navigateWithName(context, AppRoutes.adsDetailView, arguments: adsList[index]); }); @@ -105,7 +112,7 @@ class AdCard extends StatelessWidget { ? DateTime.parse(adDetails.createdOn!).getTimeAgo().toText( color: MyColors.lightTextColor, ) - : SizedBox(), + : const SizedBox(), ], ), ], @@ -120,7 +127,7 @@ class AdCard extends StatelessWidget { children: [ (adDetails.vehicle!.demandAmount!.toInt().toString()).toText(fontSize: 16, isBold: true), 2.width, - "SAR:".toText( + "SAR".toText( color: MyColors.lightTextColor, ), ], @@ -155,6 +162,6 @@ class AdCard extends StatelessWidget { else const SizedBox(), ], - ).toWhiteContainer(width: double.infinity, allPading: 12); + ).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21)); } } diff --git a/lib/views/advertisement/bottom_sheet_content.dart b/lib/views/advertisement/bottom_sheet_content.dart index 350285e..f3eade5 100644 --- a/lib/views/advertisement/bottom_sheet_content.dart +++ b/lib/views/advertisement/bottom_sheet_content.dart @@ -1,10 +1,10 @@ -import 'package:mc_common_app/view_models/ad_view_model.dart'; import 'package:flutter/material.dart'; import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/models/advertisment_models/vehicle_details_models.dart'; +import 'package:mc_common_app/models/widgets_models.dart'; import 'package:mc_common_app/theme/colors.dart'; -import 'package:mc_common_app/utils/utils.dart'; +import 'package:mc_common_app/view_models/ad_view_model.dart'; import 'package:mc_common_app/widgets/button/show_fill_button.dart'; import 'package:mc_common_app/widgets/common_widgets/time_slots.dart'; import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart'; @@ -13,9 +13,7 @@ import 'package:mc_common_app/widgets/txt_field.dart'; import 'package:provider/provider.dart'; class BottomSheetListContent extends StatefulWidget { - final AdVM adVM; - - const BottomSheetListContent({Key? key, required this.adVM}) : super(key: key); + const BottomSheetListContent({Key? key}) : super(key: key); @override State createState() => _BottomSheetListContentState(); @@ -26,6 +24,7 @@ class _BottomSheetListContentState extends State { @override Widget build(BuildContext context) { + AdVM adVM = context.watch(); return SizedBox( height: MediaQuery.of(context).size.height * 0.85, child: Column( @@ -45,18 +44,21 @@ class _BottomSheetListContentState extends State { ), 8.height, TxtField( - value: "", + value: adVM.damagePartSearchValue, errorValue: "", hint: "Search Part", - onChanged: (value) {}, + onChanged: (value) { + adVM.onSearchChangedForDamagePart(value); + }, ), 8.height, Expanded( child: ListView.builder( shrinkWrap: true, - itemCount: widget.adVM.vehicleDamageParts.length, + itemCount: adVM.vehiclePartsSearchResults.isEmpty ? adVM.vehicleDamageParts.length : adVM.vehiclePartsSearchResults.length, itemBuilder: (BuildContext context, int index) { - VehiclePartModel vehiclePart = widget.adVM.vehicleDamageParts[index]; + VehiclePartModel vehiclePart = adVM.vehiclePartsSearchResults.isEmpty ? adVM.vehicleDamageParts[index] : adVM.vehiclePartsSearchResults[index]; + return Column( children: [ // CheckboxListTile( @@ -75,7 +77,7 @@ class _BottomSheetListContentState extends State { if (vehiclePart.isSelected!) { return; } - widget.adVM.vehicleDamageParts[index].isChecked = !(widget.adVM.vehicleDamageParts[index].isChecked!); + adVM.vehicleDamageParts[index].isChecked = !(adVM.vehicleDamageParts[index].isChecked!); setState(() {}); }, child: Row( @@ -88,7 +90,13 @@ class _BottomSheetListContentState extends State { child: Checkbox( value: vehiclePart.isSelected! ? true : vehiclePart.isChecked, activeColor: vehiclePart.isSelected! ? MyColors.lightTextColor : MyColors.primaryColor, - onChanged: (value) {}, + onChanged: (value) { + if (vehiclePart.isSelected!) { + return; + } + adVM.vehicleDamageParts[index].isChecked = !(adVM.vehicleDamageParts[index].isChecked!); + setState(() {}); + }, ), ), ), @@ -112,9 +120,9 @@ class _BottomSheetListContentState extends State { child: ShowFillButton( title: "Add Damage Part", onPressed: () { - for (var value in widget.adVM.vehicleDamageParts) { + for (var value in adVM.vehicleDamageParts) { if (value.isChecked! && !value.isSelected!) { - widget.adVM.addNewDamagePartCard( + adVM.addNewDamagePartCard( damageCard: VehicleDamageCard( partImageErrorValue: "", partImages: null, @@ -135,17 +143,36 @@ class _BottomSheetListContentState extends State { } } -class BottomSheetServiceContent extends StatelessWidget { - const BottomSheetServiceContent({Key? key}) : super(key: key); +class BottomSheetAdSpecialServiceContent extends StatelessWidget { + const BottomSheetAdSpecialServiceContent({Key? key}) : super(key: key); bool isButtonTappable(AdVM adVM) { - bool status = (adVM.vehicleAdsSpecialServicesId.selectedId != -1) && (adVM.vehicleAdsSpecialServicesId.selectedOption != ""); + bool status = (adVM.vehicleAdsSpecialServicesId.selectedId != -1) && (adVM.vehicleAdsSpecialServicesId.selectedOption != "" && adVM.slotSelectedIndex != null); if (status) { return true; } return false; } + Widget descriptionCard({required String description}) { + return Container( + height: 100, + decoration: BoxDecoration(color: MyColors.greyButtonColor, border: Border.all(width: 2, color: MyColors.greyAddBorderColor)), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Flexible( + child: description.toText( + fontSize: 15, + isBold: true, + color: MyColors.lightTextColor, + ), + ), + ], + ), + ); + } + @override Widget build(BuildContext context) { return Consumer( @@ -167,60 +194,101 @@ class BottomSheetServiceContent extends StatelessWidget { children: [ "Add Special Service".toText(fontSize: 24, isBold: true), 8.height, - Builder(builder: (context) { - List vehicleAdsSpecialServices = []; - for (var element in adVM.vehicleAdsSpecialServices) { - if (!element.isSelected!) { - vehicleAdsSpecialServices.add(DropValue(element.id?.toInt() ?? 0, element.name ?? "", element.price == null ? "" : element.price!.toInt().toString())); + Builder( + builder: (context) { + List vehicleAdsSpecialServices = []; + for (var element in adVM.vehicleAdsSpecialServices) { + if (!element.isSelected!) { + vehicleAdsSpecialServices.add(DropValue(element.id?.toInt() ?? 0, element.name ?? "", element.price == null ? "" : element.price!.toInt().toString())); + } } - } - return DropdownField( - (DropValue value) => adVM.updateVehicleAdsSpecialServicesId(SelectionModel(selectedId: value.id, selectedOption: value.value, itemPrice: value.subValue)), - list: vehicleAdsSpecialServices, - hint: "Select Service", - dropdownValue: - adVM.vehicleAdsSpecialServicesId.selectedId != -1 ? DropValue(adVM.vehicleAdsSpecialServicesId.selectedId, adVM.vehicleAdsSpecialServicesId.selectedOption, "") : null, - ); - }), - 8.height, - TxtField( - errorValue: adVM.adStartDateError, - hint: 'Date', - value: adVM.adSpecialServiceDate, - isNeedClickAll: true, - postfixData: Icons.calendar_month_rounded, - postFixDataColor: MyColors.lightTextColor, - onTap: () async { - final formattedDate = await Utils.pickDateFromDatePicker(context); - adVM.updateAdSpecialServiceDate(formattedDate); + return DropdownField( + (DropValue value) => adVM.updateVehicleAdsSpecialServicesId(SelectionModel(selectedId: value.id, selectedOption: value.value, itemPrice: value.subValue)), + list: vehicleAdsSpecialServices, + hint: "Select Service", + dropdownValue: + adVM.vehicleAdsSpecialServicesId.selectedId != -1 ? DropValue(adVM.vehicleAdsSpecialServicesId.selectedId, adVM.vehicleAdsSpecialServicesId.selectedOption, "") : null, + ); }, ), - 22.height, - "Available slots".toText(fontSize: 15, isBold: true), - 8.height, - const BuildTimeSlots(), - 22.height, - "Service Amount".toText(fontSize: 16, isBold: true, color: MyColors.lightTextColor), if (adVM.vehicleAdsSpecialServicesId.selectedId != -1) ...[ - adVM.vehicleAdsSpecialServicesId.itemPrice.toText(fontSize: 20, isBold: true), - "SAR".toText(fontSize: 10, isBold: true, color: MyColors.lightTextColor), - ], + if (adVM.isFetchingLists) ...[ + Center(child: const CircularProgressIndicator().paddingAll(20)), + ] else ...[ + 8.height, + if ((adVM.vehicleAdsSpecialServicesId.selectedId == 1 && adVM.ssPhotoScheduleModel != null)) ...[ + Builder( + builder: (context) { + List vehicleAdsSpecialServiceDates = adVM.populateScheduleDatesForAdPhotoService(); - // 5.height, - // Divider(thickness: 1.2), - // 5.height, - // DottedRectContainer( - // onTap: () => null, - // text: "Add Service", - // icon: MyAssets.attachmentIcon.buildSvg(), - // ), + return DropdownField( + (DropValue value) => adVM.updateVehicleVehicleAdsPhotoServiceDate(SelectionModel( + selectedId: value.id, + selectedOption: value.value, + )), + list: vehicleAdsSpecialServiceDates, + hint: "Select Date", + dropdownValue: adVM.vehicleAdsPhotoServiceDate.selectedId != -1 + ? DropValue( + adVM.vehicleAdsPhotoServiceDate.selectedId, + adVM.vehicleAdsPhotoServiceDate.selectedOption, + "", + ) + : null, + ); + }, + ), + 22.height, + ] else if ((adVM.vehicleAdsSpecialServicesId.selectedId == 3 && adVM.ssCarCheckScheduleModel != null)) ...[ + Builder( + builder: (context) { + List vehicleAdsSpecialServiceDates = adVM.populateScheduleDatesForAdCarCheckService(); + + return DropdownField( + (DropValue value) => adVM.updateVehicleAdsCarCheckServicesDate(SelectionModel( + selectedId: value.id, + selectedOption: value.value, + )), + list: vehicleAdsSpecialServiceDates, + hint: "Select Date", + dropdownValue: adVM.vehicleAdsCarCheckServicesDate.selectedId != -1 + ? DropValue( + adVM.vehicleAdsCarCheckServicesDate.selectedId, + adVM.vehicleAdsCarCheckServicesDate.selectedOption, + "", + ) + : null, + ); + }, + ), + 22.height, + ], + if (adVM.vehicleAdsSpecialServicesId.selectedId != 3 && adVM.vehicleAdsSpecialServicesId.selectedId != 1) ...[ + descriptionCard( + description: adVM.vehicleAdsSpecialServices.firstWhere((element) => element.id == adVM.vehicleAdsSpecialServicesId.selectedId).description ?? "", + ), + ], + if (adVM.adSSTimeSlots.isNotEmpty) ...[ + "Available slots".toText(fontSize: 15, isBold: true), + 8.height, + BuildTimeSlots( + timeSlots: adVM.adSSTimeSlots, + onPressed: (index) => adVM.updateIsSelectedInSlots(index), + ), + ], + 22.height, + "Service Amount".toText(fontSize: 16, isBold: true, color: MyColors.lightTextColor), + adVM.vehicleAdsSpecialServicesId.itemPrice.toText(fontSize: 20, isBold: true), + "SAR".toText(fontSize: 10, isBold: true, color: MyColors.lightTextColor), + ], + ], ], ), ), SizedBox( width: double.infinity, child: ShowFillButton( - backgroundColor: !isButtonTappable(adVM) ? MyColors.lightTextColor : MyColors.primaryColor, + backgroundColor: !isButtonTappable(adVM) ? MyColors.lightTextColor.withOpacity(0.6) : MyColors.primaryColor, title: "Add Service", onPressed: () { if (!isButtonTappable(adVM)) { @@ -230,26 +298,28 @@ class BottomSheetServiceContent extends StatelessWidget { adVM.addNewSpecialServiceCard( specialServiceCard: SpecialServiceCard( - serviceDate: "", + serviceDate: adVM.vehicleAdsSpecialServicesId.selectedId == 1 + ? adVM.vehicleAdsPhotoServiceDate.selectedOption + : adVM.vehicleAdsSpecialServicesId.selectedId == 3 + ? adVM.vehicleAdsCarCheckServicesDate.selectedOption + : "", serviceDateError: "", serviceSelectedId: adVM.vehicleAdsSpecialServicesId, serviceTimeError: "", - serviceTime: "", + description: adVM.vehicleAdsSpecialServices.firstWhere((element) => element.id == adVM.vehicleAdsSpecialServicesId.selectedId).description ?? "", + duration: adVM.vehicleAdsSpecialServicesId.selectedId == 1 + ? adVM.ssPhotoScheduleModel!.distanceKM.toString() + : adVM.vehicleAdsSpecialServicesId.selectedId == 3 + ? adVM.ssCarCheckScheduleModel!.distanceKM.toString() + : "", + address: adVM.vehicleAdsSpecialServicesId.selectedId == 1 + ? "${adVM.ssPhotoScheduleModel!.photoOfficeName} - ${adVM.ssPhotoScheduleModel!.areaName}" + : adVM.vehicleAdsSpecialServicesId.selectedId == 3 + ? adVM.ssCarCheckScheduleModel!.address + : "", + serviceTime: adVM.slotSelectedIndex == null || adVM.adSSTimeSlots.isEmpty ? "" : adVM.adSSTimeSlots[adVM.slotSelectedIndex!].slot, ), ); - // for (var value in widget.adVM.vehicleDamageParts) { - // if (value.isChecked! && !value.isSelected!) { - // widget.adVM.addNewDamagePartCard( - // damageCard: VehicleDamageCard( - // partImageErrorValue: "", - // partImages: null, - // partSelectedId: SelectionModel(selectedOption: value.partName!, selectedId: value.id!, errorValue: ""), - // ), - // ); - // value.isChecked = false; - // value.isSelected = true; - // } - // } }, ).paddingOnly(bottom: 10), ), diff --git a/lib/views/advertisement/create_ad_progress_steps.dart b/lib/views/advertisement/create_ad_progress_steps.dart index 54efd31..c1b26cc 100644 --- a/lib/views/advertisement/create_ad_progress_steps.dart +++ b/lib/views/advertisement/create_ad_progress_steps.dart @@ -1,10 +1,10 @@ -import 'package:mc_common_app/view_models/ad_view_model.dart'; import 'package:flutter/material.dart'; import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/utils/enums.dart'; +import 'package:mc_common_app/view_models/ad_view_model.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:provider/provider.dart'; @@ -40,6 +40,11 @@ class CreateAdProgressSteps extends StatelessWidget { ); } + bool isStepCompleted({required AdCreationStepsEnum currentStep}) { + + return true; + } + @override Widget build(BuildContext context) { AdVM adVM = context.watch(); diff --git a/lib/views/advertisement/custom_add_button.dart b/lib/views/advertisement/custom_add_button.dart index a502777..9947022 100644 --- a/lib/views/advertisement/custom_add_button.dart +++ b/lib/views/advertisement/custom_add_button.dart @@ -14,13 +14,13 @@ class CustomAddButton extends StatelessWidget { return InkWell( onTap: onTap, child: Container( - height: 86, - decoration: BoxDecoration(border: Border.all(width: 2, color: MyColors.primaryColor)), + height: 110, + decoration: BoxDecoration(color: MyColors.greyButtonColor, border: Border.all(width: 2, color: MyColors.greyAddBorderColor)), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ icon, - SizedBox(width: 10), + const SizedBox(width: 10), text.toText( fontSize: 15, isBold: true, diff --git a/lib/views/advertisement/picked_images_container.dart b/lib/views/advertisement/picked_images_container.dart index 95b20d1..257bec8 100644 --- a/lib/views/advertisement/picked_images_container.dart +++ b/lib/views/advertisement/picked_images_container.dart @@ -26,7 +26,7 @@ class PickedImagesContainer extends StatelessWidget { @override Widget build(BuildContext context) { return GridView.count( - physics: NeverScrollableScrollPhysics(), + physics: const NeverScrollableScrollPhysics(), shrinkWrap: true, crossAxisCount: 4, crossAxisSpacing: 4.0, @@ -36,17 +36,14 @@ class PickedImagesContainer extends StatelessWidget { (index) { if (index == pickedImages.length && !isReview) { return Container( - margin: EdgeInsets.all(8), - color: MyColors.lightTextColor.withOpacity(0.4), + decoration: BoxDecoration( color: MyColors.greyButtonColor, border: Border.all(width: 2, color: MyColors.greyAddBorderColor)), + margin: const EdgeInsets.all(8), alignment: Alignment.center, child: Container( height: 24, width: 24, - decoration: BoxDecoration(shape: BoxShape.circle, color: MyColors.darkTextColor), - child: Icon( - Icons.add, - color: MyColors.white, - ), + decoration: const BoxDecoration(shape: BoxShape.circle, color: MyColors.darkTextColor), + child: const Icon(Icons.add, color: MyColors.white), ), ).onPress(onAddImagePressed); } @@ -62,17 +59,17 @@ class PickedImagesContainer extends StatelessWidget { }, ), ); - return Wrap( - children: pickedImages - .map((file) => BuildImageContainer( - file: file, - onCrossPressedPrimary: onCrossPressedPrimary, - onCrossPressedSecondary: onCrossPressedSecondary, - index: index, - isReview: isReview, - )) - .toList(), - ); + // return Wrap( + // children: pickedImages + // .map((file) => BuildImageContainer( + // file: file, + // onCrossPressedPrimary: onCrossPressedPrimary, + // onCrossPressedSecondary: onCrossPressedSecondary, + // index: index, + // isReview: isReview, + // )) + // .toList(), + // ); } } @@ -122,7 +119,7 @@ class BuildImageContainer extends StatelessWidget { } onCrossPressedPrimary!(file.path); }) - : SizedBox() + : const SizedBox() ], )), ], diff --git a/lib/views/user/login_with_password_page.dart b/lib/views/user/login_with_password_page.dart index 0009ed9..cc32056 100644 --- a/lib/views/user/login_with_password_page.dart +++ b/lib/views/user/login_with_password_page.dart @@ -1,20 +1,20 @@ import 'dart:async'; -import 'package:mc_common_app/models/user/country.dart'; -import 'package:mc_common_app/theme/colors.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; import 'package:mc_common_app/config/routes.dart'; import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/generated/locale_keys.g.dart'; +import 'package:mc_common_app/models/user/country.dart'; +import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/utils/navigator.dart'; import 'package:mc_common_app/view_models/user_view_model.dart'; +import 'package:mc_common_app/widgets/button/show_fill_button.dart'; import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart'; -import 'package:mc_common_app/widgets/button/show_fill_button.dart'; import 'package:mc_common_app/widgets/tab/login_email_tab.dart'; import 'package:mc_common_app/widgets/txt_field.dart'; -import 'package:easy_localization/easy_localization.dart'; -import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; class LoginWithPassword extends StatefulWidget { @@ -53,7 +53,7 @@ class _LoginWithPasswordState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: CustomAppBar( isRemoveBackButton: true, title: ""), + appBar: CustomAppBar(isRemoveBackButton: true, title: ""), body: Container( width: double.infinity, height: double.infinity, @@ -62,9 +62,12 @@ class _LoginWithPasswordState extends State { child: Column( children: [ 12.height, - LocaleKeys.login.tr().toText(fontSize: 20, letterSpacing: -1.44,), + LocaleKeys.login.tr().toText( + fontSize: 20, + letterSpacing: -1.44, + ), // 20.height, - // (type == ClassType.NUMBER ? LocaleKeys.enterPhoneNumber.tr() : LocaleKeys.enterEmail.tr()).toText14( + // (type == ClassType.NUMBER ? LocaleKeys.\enterPhoneNumber.tr() : LocaleKeys.enterEmail.tr()).toText14( // color: MyColors.lightTextColor, // textAlign: TextAlign.center, // ), @@ -82,6 +85,7 @@ class _LoginWithPasswordState extends State { if (type == ClassType.NUMBER) getCountry(context), 10.height, TxtField( + keyboardType: type == ClassType.NUMBER ? TextInputType.phone : null, hint: type == ClassType.NUMBER ? LocaleKeys.enterPhoneNumber.tr() : LocaleKeys.enterEmail.tr(), value: phoneNum, isSidePaddingZero: true, @@ -106,7 +110,7 @@ class _LoginWithPasswordState extends State { LocaleKeys.forgetPasswordQ.tr().toText( color: MyColors.textColor, fontSize: 14, - height: 23 / 24, + height: 23 / 24, letterSpacing: -0.48, ), ShowFillButton( diff --git a/lib/widgets/common_widgets/app_bar.dart b/lib/widgets/common_widgets/app_bar.dart index a30c28d..114538a 100644 --- a/lib/widgets/common_widgets/app_bar.dart +++ b/lib/widgets/common_widgets/app_bar.dart @@ -133,6 +133,7 @@ class CustomAppBar extends StatelessWidget with PreferredSizeWidget { Navigator.pop(context); }, ).toContainer( + paddingAll: 0, borderRadius: 100, borderColor: MyColors.lightGreyEFColor, diff --git a/lib/widgets/common_widgets/categories_list.dart b/lib/widgets/common_widgets/categories_list.dart index 47d7fbc..0bc133f 100644 --- a/lib/widgets/common_widgets/categories_list.dart +++ b/lib/widgets/common_widgets/categories_list.dart @@ -5,7 +5,7 @@ import 'package:mc_common_app/theme/colors.dart'; class FiltersList extends StatelessWidget { final List filterList; - final Function(int) onFilterTapped; + final Function(int, int) onFilterTapped; final bool needLeftPadding; const FiltersList({Key? key, required this.filterList, this.needLeftPadding = true, required this.onFilterTapped}) : super(key: key); @@ -22,12 +22,12 @@ class FiltersList extends StatelessWidget { itemBuilder: (BuildContext context, int index) { return InkWell( onTap: () { - onFilterTapped(index); + onFilterTapped(index, filterList[index].id); }, child: Container( alignment: Alignment.center, padding: const EdgeInsets.symmetric(horizontal: 8), - margin: const EdgeInsets.symmetric(horizontal: 8), + margin: const EdgeInsets.symmetric(horizontal: 4), decoration: BoxDecoration( color: filterList[index].isSelected ? MyColors.darkIconColor : null, border: Border.all( diff --git a/lib/widgets/common_widgets/customer_appointment_slider_widget.dart b/lib/widgets/common_widgets/customer_appointment_slider_widget.dart deleted file mode 100644 index f88dcb2..0000000 --- a/lib/widgets/common_widgets/customer_appointment_slider_widget.dart +++ /dev/null @@ -1,143 +0,0 @@ -import 'package:carousel_slider/carousel_slider.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_svg/svg.dart'; -import 'package:mc_common_app/classes/consts.dart'; -import 'package:mc_common_app/extensions/int_extensions.dart'; -import 'package:mc_common_app/extensions/string_extensions.dart'; -import 'package:mc_common_app/theme/colors.dart'; -import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; - -class CustomerAppointmentSliderWidget extends StatelessWidget { - const CustomerAppointmentSliderWidget({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return CarouselSlider.builder( - options: CarouselOptions( - height: 140, - viewportFraction: 1.0, - enlargeCenterPage: false, - enableInfiniteScroll: false, - // - // onPageChanged: (index) { - // setState(() { - // _current = index; - // }); - // }, - ), - itemCount: 10, - itemBuilder: (BuildContext context, int itemIndex, int pageViewIndex) => BuildAppointmentContainerForCustomer( - isForHome: true, - onTapped: () {}, - ), - ); - } -} - -class BuildAppointmentContainerForCustomer extends StatelessWidget { - final bool? isForHome; - final Function() onTapped; - - const BuildAppointmentContainerForCustomer({Key? key, this.isForHome = false, required this.onTapped}) : super(key: key); - - Widget showServices(String title, String icon) { - return Row( - children: [ - SvgPicture.asset(icon), - 8.width, - title.toText( - fontSize: 14, - isBold: true, - ), - ], - ); - } - - @override - Widget build(BuildContext context) { - return Container( - margin: const EdgeInsets.only( - bottom: 10, - left: 21, - right: 21, - ), - child: Column( - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - isForHome != null && isForHome! - ? Image.asset( - MyAssets.bnCar, - width: 56, - height: 56, - fit: BoxFit.fill, - ).toCircle(borderRadius: 100) - : Image.asset( - MyAssets.bnCar, - width: 80, - height: 85, - fit: BoxFit.cover, - ), - 8.width, - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - "Al Aziz Service Station".toText(color: MyColors.black, isBold: true, fontSize: 16), - Row( - children: [ - MyAssets.miniClock.buildSvg(height: 12), - 2.width, - "08:00 to 08:30 25 July, 2023".toText( - color: MyColors.lightTextColor, - fontSize: 12, - ), - ], - ), - 9.height, - isForHome != null && isForHome! - ? Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - "Appointment Details".toText( - color: MyColors.primaryColor, - isUnderLine: true, - isBold: true, - fontSize: 14, - ), - const Icon(Icons.arrow_forward), - ], - ) - : Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Expanded( - child: Column( - children: [ - showServices("Maintenance", MyAssets.maintenanceIcon), - 2.height, - showServices( - "Accessories and Modification", - MyAssets.modificationsIcon, - ), - ], - ), - ), - const Icon( - Icons.arrow_forward, - ), - ], - ), - ], - ), - ), - ], - ), - ], - ).onPress(onTapped).toWhiteContainer(width: double.infinity, allPading: 12), - ); - } -} diff --git a/lib/widgets/common_widgets/info_bottom_sheet.dart b/lib/widgets/common_widgets/info_bottom_sheet.dart new file mode 100644 index 0000000..26b81a4 --- /dev/null +++ b/lib/widgets/common_widgets/info_bottom_sheet.dart @@ -0,0 +1,43 @@ +import 'package:flutter/material.dart'; +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/theme/colors.dart'; +import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; + +class InfoBottomSheet extends StatelessWidget { + final String title; + final String description; + + const InfoBottomSheet({Key? key, required this.title, required this.description}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SizedBox( + height: MediaQuery.of(context).size.height * 0.4, + child: Column( + children: [ + Container( + margin: const EdgeInsets.all(8), + height: 8, + width: 60, + decoration: const BoxDecoration(color: MyColors.lightTextColor, borderRadius: BorderRadius.all(Radius.circular(20))), + ), + 12.height, + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + title.toText(fontSize: 24, isBold: true), + ], + ), + 8.height, + Flexible( + child: description.toText( + textAlign: TextAlign.justify, + fontSize: 16, + color: MyColors.lightTextColor, + isBold: true, + )), + ], + ).horPaddingMain()); + } +} diff --git a/lib/widgets/common_widgets/provider_details_card.dart b/lib/widgets/common_widgets/provider_details_card.dart index 159ea99..594c1a7 100644 --- a/lib/widgets/common_widgets/provider_details_card.dart +++ b/lib/widgets/common_widgets/provider_details_card.dart @@ -89,7 +89,7 @@ class ProviderDetailsCard extends StatelessWidget { MyAssets.maintenanceIcon.buildSvg(), 8.width, LocaleKeys.maintenance.tr().toText( - fontSize: 14, + fontSize: 12, isBold: true, ), ], @@ -99,7 +99,7 @@ class ProviderDetailsCard extends StatelessWidget { MyAssets.modificationsIcon.buildSvg(), 8.width, LocaleKeys.accessories_modifications.tr().toText( - fontSize: 14, + fontSize: 12, isBold: true, ), ], diff --git a/lib/widgets/common_widgets/time_slots.dart b/lib/widgets/common_widgets/time_slots.dart index e9d285c..0514d69 100644 --- a/lib/widgets/common_widgets/time_slots.dart +++ b/lib/widgets/common_widgets/time_slots.dart @@ -1,8 +1,13 @@ import 'package:flutter/material.dart'; import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/models/widgets_models.dart'; import 'package:mc_common_app/theme/colors.dart'; + class BuildTimeSlots extends StatelessWidget { - const BuildTimeSlots({Key? key}) : super(key: key); + final List timeSlots; + final Function(int) onPressed; + + const BuildTimeSlots({Key? key, required this.timeSlots, required this.onPressed}) : super(key: key); @override Widget build(BuildContext context) { @@ -10,26 +15,28 @@ class BuildTimeSlots extends StatelessWidget { height: 37, width: double.infinity, child: ListView.builder( - itemCount: 20, + itemCount: timeSlots.length, scrollDirection: Axis.horizontal, itemBuilder: (BuildContext context, int index) { return InkWell( - onTap: () {}, + onTap: () { + onPressed(index); + }, child: Container( alignment: Alignment.center, margin: const EdgeInsets.only(right: 8), - width: 50, + // width: 50, + padding: const EdgeInsets.symmetric(horizontal: 9), decoration: BoxDecoration( - color: index < 1 ? MyColors.darkIconColor : null, + color: timeSlots[index].isSelected ? MyColors.darkIconColor : null, border: Border.all( - color: index < 1 ? MyColors.darkIconColor : MyColors.primaryColor, - width: 2, + color: timeSlots[index].isSelected ? MyColors.darkIconColor : MyColors.primaryColor, ), ), - child: "09:00".toText( - fontSize: 12, - color: index < 1 ? MyColors.white : null, - ), + child: timeSlots[index].slot.toText( + fontSize: 12, + color: timeSlots[index].isSelected ? MyColors.white : null, + ), ), ); }), diff --git a/lib/widgets/dropdown/dropdow_field.dart b/lib/widgets/dropdown/dropdow_field.dart index 5457372..e09ba88 100644 --- a/lib/widgets/dropdown/dropdow_field.dart +++ b/lib/widgets/dropdown/dropdow_field.dart @@ -13,6 +13,11 @@ class DropValue { DropValue(this.id, this.value, this.subValue, {this.isEnabled = true}); bool operator ==(o) => o is DropValue && o.value == value && o.id == id; + + @override + String toString() { + return 'DropValue{id: $id, value: $value, subValue: $subValue, isEnabled: $isEnabled}'; + } } class DropdownField extends StatefulWidget { diff --git a/lib/widgets/extensions/extensions_widget.dart b/lib/widgets/extensions/extensions_widget.dart index b86c10c..ab7487b 100644 --- a/lib/widgets/extensions/extensions_widget.dart +++ b/lib/widgets/extensions/extensions_widget.dart @@ -75,12 +75,12 @@ extension ContainerExt on Widget { boxShadow: !isShadowEnabled ? null : [ - BoxShadow( - color: const Color(0xff000000).withOpacity(.05), - blurRadius: 26, - offset: const Offset(0, -3), - ), - ], + BoxShadow( + color: const Color(0xff000000).withOpacity(.05), + blurRadius: 26, + offset: const Offset(0, -3), + ), + ], ), padding: padding ?? EdgeInsets.all(paddingAll), margin: margin ?? EdgeInsets.all(marginAll), @@ -355,104 +355,4 @@ extension WidgetExtensions on Widget { Widget onPress(VoidCallback onTap) => InkWell(onTap: onTap, child: this); } -extension FormatDate on String { - /// get month by - /// [month] convert month number in to month name - /// get month by - /// [month] convert month number in to month name in Arabic - static String getMonthArabic(int month) { - switch (month) { - case 1: - return "يناير"; - case 2: - return " فبراير"; - case 3: - return "مارس"; - case 4: - return "أبريل"; - case 5: - return "مايو"; - case 6: - return "يونيو"; - case 7: - return "يوليو"; - case 8: - return "أغسطس"; - case 9: - return "سبتمبر"; - case 10: - return " اكتوبر"; - case 11: - return " نوفمبر"; - case 12: - return "ديسمبر"; - default: - return ""; - } - } - - static String getMonth(int month) { - switch (month) { - case 1: - return "January"; - case 2: - return "February"; - case 3: - return "March"; - case 4: - return "April"; - case 5: - return "May"; - case 6: - return "June"; - case 7: - return "July"; - case 8: - return "August"; - case 9: - return "September"; - case 10: - return "October"; - case 11: - return "November"; - case 12: - return "December"; - default: - return ""; - } - } - - String getTimeAgo() { - String date = split("T")[0]; - String time = split("T")[1]; - var dates = date.split("-"); - return "${dates[2]} ${getMonth(int.parse(dates[1]))} ${dates[0]} ${DateFormat('hh:mm a', "en_US").format(DateFormat('hh:mm:ss', "en_US").parse(time))}"; - } -} -extension DateTimeConversions on DateTime { - String getTimeAgo({bool numericDates = true}) { - final date2 = DateTime.now(); - final difference = date2.difference(this); - - if ((difference.inDays / 7).floor() >= 1) { - return (numericDates) ? '1 week ago' : 'Last week'; - } else if (difference.inDays >= 2) { - return '${difference.inDays} days ago'; - } else if (difference.inDays >= 1) { - return (numericDates) ? '1 day ago' : 'Yesterday'; - } else if (difference.inHours >= 2) { - return '${difference.inHours} hours ago'; - } else if (difference.inHours >= 1) { - return (numericDates) ? '1 hour ago' : 'An hour ago'; - } else if (difference.inMinutes >= 2) { - return '${difference.inMinutes} minutes ago'; - } else if (difference.inMinutes >= 1) { - return (numericDates) ? '1 minute ago' : 'A minute ago'; - } else if (difference.inSeconds >= 3) { - return '${difference.inSeconds} seconds ago'; - } else { - return 'Just now'; - } - } -} diff --git a/lib/widgets/txt_field.dart b/lib/widgets/txt_field.dart index 15332cf..d6215e0 100644 --- a/lib/widgets/txt_field.dart +++ b/lib/widgets/txt_field.dart @@ -24,8 +24,11 @@ class TxtField extends StatelessWidget { int? maxLines; bool isSidePaddingZero; bool isNeedBorder; + bool isSearchBar; bool? isPasswordEnabled; Function(String)? onChanged; + Function(String)? onSubmitted; + Function()? onPostFixPressed; TextInputType? keyboardType; bool isBackgroundEnabled = false; @@ -48,9 +51,12 @@ class TxtField extends StatelessWidget { this.isSidePaddingZero = false, this.isNeedBorder = true, this.onChanged, + this.onSubmitted, this.isPasswordEnabled, + this.isSearchBar = false, this.keyboardType, this.isBackgroundEnabled = false, + this.onPostFixPressed, }) : super(key: key); @override @@ -76,6 +82,7 @@ class TxtField extends StatelessWidget { borderRadius: const BorderRadius.all(Radius.circular(0)), ), child: TextField( + textInputAction: isSearchBar ? TextInputAction.search : null, keyboardType: keyboardType, autofocus: false, controller: controller, @@ -84,6 +91,7 @@ class TxtField extends StatelessWidget { onTap: () {}, obscureText: isPasswordEnabled ?? false, onChanged: onChanged, + onSubmitted: onSubmitted, decoration: InputDecoration( labelText: lable, alignLabelWithHint: true, @@ -103,14 +111,14 @@ class TxtField extends StatelessWidget { borderRadius: BorderRadius.circular(0.0), ), suffixIcon: postfixData != null - ? Icon( - postfixData, - color: postFixDataColor, + ? InkWell( + onTap: onPostFixPressed, + child: Icon(postfixData, color: postFixDataColor), ) : null, prefixIcon: prefixData != null ? const Icon(Icons.search, color: borderColor) : null, labelStyle: TextStyle(color: borderColor, fontSize: 13.sp), - hintStyle: TextStyle(color: borderColor, fontSize: 9.sp), + hintStyle: TextStyle(color: borderColor, fontSize: 10.sp), hintText: hint ?? "", contentPadding: prefixData == null ? EdgeInsets.only(