diff --git a/assets/icons/payments/apple_pay.png b/assets/icons/payments/apple_pay.png new file mode 100644 index 0000000..1dc7504 Binary files /dev/null and b/assets/icons/payments/apple_pay.png differ diff --git a/assets/icons/payments/installments.png b/assets/icons/payments/installments.png new file mode 100644 index 0000000..b2b231b Binary files /dev/null and b/assets/icons/payments/installments.png differ diff --git a/assets/icons/payments/mada.png b/assets/icons/payments/mada.png new file mode 100644 index 0000000..905a5ba Binary files /dev/null and b/assets/icons/payments/mada.png differ diff --git a/assets/icons/payments/mastercard.png b/assets/icons/payments/mastercard.png new file mode 100644 index 0000000..5d8b1fa Binary files /dev/null and b/assets/icons/payments/mastercard.png differ diff --git a/assets/icons/payments/tamara_ar.png b/assets/icons/payments/tamara_ar.png new file mode 100644 index 0000000..f1587ad Binary files /dev/null and b/assets/icons/payments/tamara_ar.png differ diff --git a/assets/icons/payments/tamara_en.png b/assets/icons/payments/tamara_en.png new file mode 100644 index 0000000..84d85b2 Binary files /dev/null and b/assets/icons/payments/tamara_en.png differ diff --git a/assets/icons/payments/visa.png b/assets/icons/payments/visa.png new file mode 100644 index 0000000..3a6d90d Binary files /dev/null and b/assets/icons/payments/visa.png differ 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..c844f1c 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 { @@ -162,6 +172,14 @@ class MyAssets { static String icWhatsAppPng = "${assetPath}icons/ic_whatsapp.png"; static String icSmsPng = "${assetPath}icons/ic_sms.png"; static String icFingerprintPng = "${assetPath}icons/ic_fingerprint.png"; + + static String applePayPng = "${assetPath}icons/payments/apple_pay.png"; + static String installmentsPng = "${assetPath}icons/payments/installments.png"; + static String madaPng = "${assetPath}icons/payments/mada.png"; + static String mastercardPng = "${assetPath}icons/payments/mastercard.png"; + static String tamaraArPng = "${assetPath}icons/payments/tamara_ar.png"; + static String tamaraEngPng = "${assetPath}icons/payments/tamara_en.png"; + static String visaPng = "${assetPath}icons/payments/visa.png"; } RegExp numReg = RegExp(r".*[0-9].*"); diff --git a/lib/config/constants.dart b/lib/config/constants.dart deleted file mode 100644 index 8b13789..0000000 --- a/lib/config/constants.dart +++ /dev/null @@ -1 +0,0 @@ - diff --git a/lib/config/dependencies.dart b/lib/config/dependencies.dart index ccd7203..6357210 100644 --- a/lib/config/dependencies.dart +++ b/lib/config/dependencies.dart @@ -4,6 +4,7 @@ import 'package:injector/injector.dart'; import 'package:mc_common_app/api/api_client.dart'; import 'package:mc_common_app/classes/app_state.dart'; +import 'package:mc_common_app/repositories/ads_repo.dart'; import 'package:mc_common_app/repositories/common_repo.dart'; import 'package:mc_common_app/repositories/user_repo.dart'; import 'package:mc_common_app/services/services.dart'; @@ -20,5 +21,6 @@ class AppDependencies { //repos injector.registerSingleton(() => UserRepoImp()); injector.registerSingleton(() => CommonRepoImp()); + injector.registerSingleton(() => AdsRepoImp()); } } diff --git a/lib/config/routes.dart b/lib/config/routes.dart index b3d6303..a32a7b2 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -55,6 +55,8 @@ class AppRoutes { static const String appointmentDetailView = "/appointmentDetailView"; static const String adsDetailView = "/adsDetailView"; static const String createAdView = "/createAdView"; + static const String bookAppointmenServicesView = "/bookAppointmenServicesView"; + static const String paymentMethodsView = "/paymentMethodsView"; //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/ads_repo.dart b/lib/repositories/ads_repo.dart new file mode 100644 index 0000000..f4d1520 --- /dev/null +++ b/lib/repositories/ads_repo.dart @@ -0,0 +1,337 @@ +import 'package:mc_common_app/api/api_client.dart'; +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/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/special_service_model.dart'; +import 'package:mc_common_app/models/advertisment_models/vehicle_details_models.dart'; +import 'package:mc_common_app/models/generic_resp_model.dart'; + +abstract class AdsRepo { + Future> getVehicleTypes(); + + Future> getVehicleModels({required int vehicleTypeId}); + + Future> getVehicleModelYears({required int vehicleTypeId}); + + Future> getVehicleColors({required int vehicleTypeId}); + + Future> getVehicleConditions({required int vehicleTypeId}); + + Future> getVehicleCategories({required int vehicleTypeId}); + + Future> getVehicleMileages({required int vehicleTypeId}); + + Future> getVehicleTransmission({required int vehicleTypeId}); + + Future> getVehicleSellerTypes({required int vehicleTypeId}); + + Future> getVehicleCountries(); + + Future> getVehicleCities({required int countryId}); + + Future> getVehicleDamageParts(); + + Future getVehicleDetails({required int vehicleTypeId}); + + Future> getAdsDuration(); + + Future> getSpecialServices({required int specialServiceId}); + + Future createNewAd({required AdsCreationPayloadModel adsCreationPayloadModel}); + + Future> getAllAds({required bool isMyAds}); + + Future> getMyAds(); +} + +class AdsRepoImp implements AdsRepo { + ApiClient apiClient = injector.get(); + AppState appState = injector.get(); + + @override + Future> getVehicleTypes() async { + 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; + } + + @override + Future> getVehicleCategories({required int vehicleTypeId}) async { + var postParams = { + "VehicleType": vehicleTypeId.toString(), + }; + 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; + } + + @override + Future> getVehicleCities({required int countryId}) async { + var postParams = { + "CountryID": countryId.toString(), + }; + 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; + } + + @override + Future> getVehicleColors({required int vehicleTypeId}) async { + var postParams = { + "VehicleType": vehicleTypeId.toString(), + }; + 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; + } + + @override + Future> getVehicleConditions({required int vehicleTypeId}) async { + var postParams = { + "VehicleType": vehicleTypeId.toString(), + }; + 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 { + GenericRespModel adsGenericModel = await apiClient.getJsonForObject( + token: appState.getUser.data!.accessToken, + (json) => GenericRespModel.fromJson(json), + ApiConsts.vehicleCountryGet, + ); + List vehicleConditions = List.generate(adsGenericModel.data.length, (index) => VehicleCountryModel.fromJson(adsGenericModel.data[index])); + return vehicleConditions; + } + + @override + Future> getVehicleMileages({required int vehicleTypeId}) async { + var postParams = { + "VehicleType": vehicleTypeId.toString(), + }; + 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; + } + + @override + Future> getVehicleModelYears({required int vehicleTypeId}) async { + var postParams = { + "VehicleType": vehicleTypeId.toString(), + }; + 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; + } + + @override + Future> getVehicleModels({required int vehicleTypeId}) async { + var postParams = { + "VehicleType": vehicleTypeId.toString(), + }; + 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; + } + + @override + Future> getVehicleSellerTypes({required int vehicleTypeId}) async { + var postParams = { + "VehicleType": vehicleTypeId.toString(), + }; + 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; + } + + @override + Future> getVehicleTransmission({required int vehicleTypeId}) async { + var postParams = { + "VehicleType": vehicleTypeId.toString(), + }; + 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; + } + + @override + Future getVehicleDetails({required int vehicleTypeId}) async { + var postParams = { + "vehicleType": vehicleTypeId.toString(), + "isVehicleBrand": "true", + "vehicleBrand": "0", + "isVehicleCategory": "true", + "isVehicleColor": "true", + "isVehicleCondition": "true", + "isVehicleMileage": "true", + "isVehicleModel": "true", + "isVehicleModelYear": "true", + "isVehiclePriceRange": "true", + "isVehiclePricingMethod": "true", + "isVehcileSellerType": "true", + "isVehicleTransmission": "true", + "isCountry": "true" + }; + + String token = appState.getUser.data!.accessToken ?? ""; + GenericRespModel adsGenericModel = await apiClient.postJsonForObject( + (json) => GenericRespModel.fromJson(json), + ApiConsts.vehicleDetailsMaster, + postParams, + token: token, + ); + VehicleDetailsModel vehicleDetails = VehicleDetailsModel.fromJson(adsGenericModel.data); + return vehicleDetails; + } + + @override + Future> getVehicleDamageParts() async { + GenericRespModel adsGenericModel = await apiClient.getJsonForObject( + token: appState.getUser.data!.accessToken, + (json) => GenericRespModel.fromJson(json), + ApiConsts.vehicleDamagePartGet, + ); + List vehicleParts = List.generate(adsGenericModel.data.length, (index) => VehiclePartModel.fromJson(adsGenericModel.data[index])); + return vehicleParts; + } + + @override + Future> getAdsDuration() async { + GenericRespModel adsGenericModel = await apiClient.getJsonForObject( + token: appState.getUser.data!.accessToken, + (json) => GenericRespModel.fromJson(json), + ApiConsts.vehicleAdsDurationGet, + ); + List vehicleAdsDuration = List.generate(adsGenericModel.data.length, (index) => AdsDurationModel.fromJson(adsGenericModel.data[index])); + return vehicleAdsDuration; + } + + @override + 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 { + List vehiclePostingImages = []; + adsCreationPayloadModel.vehiclePosting!.vehiclePostingImages?.forEach((element) { + var imageMap = { + "id": 0, + "imageName": element.imageName, + "imageUrl": element.imageUrl, + "imageStr": element.imageStr, + "vehiclePostingID": 0, + "vehiclePosting": null, + }; + vehiclePostingImages.add(imageMap); + }); + + List vehiclePostingDamageParts = []; + adsCreationPayloadModel.vehiclePosting!.vehiclePostingDamageParts?.forEach((element) { + var imageMap = { + "id": 0, + "comment": element.comment, + "vehicleImageBase64": element.vehicleImageBase64, + "vehicleDamagePartID": element.vehicleDamagePartID, + "vehiclePostingID": 0, + "isActive": true + }; + vehiclePostingDamageParts.add(imageMap); + }); + var postParams = { + "ads": { + "id": 0, + "adsDurationID": adsCreationPayloadModel.ads!.adsDurationID, + "startDate": adsCreationPayloadModel.ads!.startDate, + "countryId": adsCreationPayloadModel.ads!.countryId, + "specialServiceIDs": adsCreationPayloadModel.ads!.specialServiceIDs, + "isMCHandled": false + }, + "vehiclePosting": { + "id": 0, + "userID": adsCreationPayloadModel.vehiclePosting!.userID, + "vehicleType": adsCreationPayloadModel.vehiclePosting!.vehicleType, + "vehicleModelID": adsCreationPayloadModel.vehiclePosting!.vehicleModelID, + "vehicleModelYearID": adsCreationPayloadModel.vehiclePosting!.vehicleModelYearID, + "vehicleColorID": adsCreationPayloadModel.vehiclePosting!.vehicleColorID, + "vehicleCategoryID": adsCreationPayloadModel.vehiclePosting!.vehicleCategoryID, + "vehicleConditionID": adsCreationPayloadModel.vehiclePosting!.vehicleConditionID, + "vehicleMileageID": adsCreationPayloadModel.vehiclePosting!.vehicleMileageID, + "vehicleTransmissionID": adsCreationPayloadModel.vehiclePosting!.vehicleTransmissionID, + "vehicleSellerTypeID": adsCreationPayloadModel.vehiclePosting!.vehicleSellerTypeID, + "cityID": adsCreationPayloadModel.vehiclePosting!.cityID, + "price": adsCreationPayloadModel.vehiclePosting!.price, + "vehicleVIN": adsCreationPayloadModel.vehiclePosting!.vehicleVIN, + "vehicleDescription": adsCreationPayloadModel.vehiclePosting!.vehicleDescription, + "vehicleTitle": adsCreationPayloadModel.vehiclePosting!.vehicleTitle, + "vehicleDescriptionN": adsCreationPayloadModel.vehiclePosting!.vehicleDescription, + "isFinanceAvailable": adsCreationPayloadModel.vehiclePosting!.isFinanceAvailable, + "warantyYears": adsCreationPayloadModel.vehiclePosting!.warantyYears, + "demandAmount": adsCreationPayloadModel.vehiclePosting!.demandAmount, + // "adStatus": 1, + "vehiclePostingImages": vehiclePostingImages, + "vehiclePostingDamageParts": vehiclePostingDamageParts + } + }; + + String token = appState.getUser.data!.accessToken ?? ""; + GenericRespModel adsGenericModel = await apiClient.postJsonForObject( + (json) => GenericRespModel.fromJson(json), + ApiConsts.vehicleAdsSingleStepCreate, + postParams, + token: token, + ); + + return Future.value(adsGenericModel); + } + + @override + Future> getAllAds({required isMyAds}) async { + var params = { + "userID": appState.getUser.data!.userInfo!.userId ?? "", + }; + + GenericRespModel adsGenericModel = await apiClient.getJsonForObject( + token: appState.getUser.data!.accessToken, + (json) => GenericRespModel.fromJson(json), + ApiConsts.vehicleAdsGet, + queryParameters: isMyAds ? params : null, + ); + List vehicleAdsDetails = List.generate(adsGenericModel.data.length, (index) => AdDetailsModel.fromJson(adsGenericModel.data[index])); + return vehicleAdsDetails; + } + + @override + Future> getMyAds() async { + var params = { + "userID": appState.getUser.data!.userInfo!.userId ?? "", + }; + GenericRespModel adsGenericModel = await apiClient.getJsonForObject( + token: appState.getUser.data!.accessToken, + (json) => GenericRespModel.fromJson(json), + queryParameters: params, + ApiConsts.vehicleAdsGet, + ); + List vehicleAdsDetails = List.generate(adsGenericModel.data.length, (index) => AdDetailsModel.fromJson(adsGenericModel.data[index])); + return vehicleAdsDetails; + } +} diff --git a/lib/repositories/common_repo.dart b/lib/repositories/common_repo.dart index 5b83e70..7101638 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'; @@ -18,41 +23,16 @@ abstract class CommonRepo { Future getRoles(); - Future> getVehicleTypes(); - Future> getVehicleModels({required int vehicleTypeId}); + Future> getMyAppointments(); - Future> getVehicleModelYears({required int vehicleTypeId}); + Future getCarCheckServiceScheduleDetails({required double lat, required double long}); - Future> getVehicleColors({required int vehicleTypeId}); + Future getPhotographyServiceScheduleDetails({required double lat, required double long}); - Future> getVehicleConditions({required int vehicleTypeId}); + Future> getProviderServiceCategories(); - Future> getVehicleCategories({required int vehicleTypeId}); - - Future> getVehicleMileages({required int vehicleTypeId}); - - Future> getVehicleTransmission({required int vehicleTypeId}); - - Future> getVehicleSellerTypes({required int vehicleTypeId}); - - Future> getVehicleCountries(); - - Future> getVehicleCities({required int countryId}); - - Future> getVehicleDamageParts(); - - Future getVehicleDetails({required int vehicleTypeId}); - - Future> getAdsDuration(); - - Future> getSpecialServices(); - - Future createNewAd({required AdsCreationPayloadModel adsCreationPayloadModel}); - - Future> getAllAds({required bool isMyAds}); - - Future> getMyAds(); + Future> getProviderServices({required int categoryId}); } class CommonRepoImp implements CommonRepo { @@ -77,288 +57,69 @@ class CommonRepoImp implements CommonRepo { return await apiClient.getJsonForObject((json) => Role.fromJson(json), ApiConsts.GetProviderRoles); } - @override - Future> getVehicleTypes() async { - AdsGenericModel adsGenericModel = await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => AdsGenericModel.fromJson(json), ApiConsts.vehicleTypeGet); - List vehicleTypes = List.generate(adsGenericModel.data.length, (index) => VehicleTypeModel.fromJson(adsGenericModel.data[index])); - return vehicleTypes; - } - - @override - Future> getVehicleCategories({required int vehicleTypeId}) async { - var postParams = { - "VehicleType": vehicleTypeId.toString(), - }; - AdsGenericModel adsGenericModel = - await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => AdsGenericModel.fromJson(json), ApiConsts.vehicleCategoryGet, queryParameters: postParams); - List vehicleCategories = List.generate(adsGenericModel.data.length, (index) => VehicleCategoryModel.fromJson(adsGenericModel.data[index])); - return vehicleCategories; - } - - @override - Future> getVehicleCities({required int countryId}) async { - var postParams = { - "CountryID": countryId.toString(), - }; - AdsGenericModel adsGenericModel = - await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => AdsGenericModel.fromJson(json), ApiConsts.vehicleCityGet, queryParameters: postParams); - List vehicleCities = List.generate(adsGenericModel.data.length, (index) => VehicleCityModel.fromJson(adsGenericModel.data[index])); - return vehicleCities; - } - - @override - Future> getVehicleColors({required int vehicleTypeId}) async { - var postParams = { - "VehicleType": vehicleTypeId.toString(), - }; - AdsGenericModel adsGenericModel = - await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => AdsGenericModel.fromJson(json), ApiConsts.vehicleColorGet, queryParameters: postParams); - List vehicleColors = List.generate(adsGenericModel.data.length, (index) => VehicleColorModel.fromJson(adsGenericModel.data[index])); - return vehicleColors; - } @override - Future> getVehicleConditions({required int vehicleTypeId}) async { - var postParams = { - "VehicleType": vehicleTypeId.toString(), + Future> getMyAppointments() async { + var params = { + "userID": appState.getUser.data!.userInfo!.userId ?? "", }; - AdsGenericModel adsGenericModel = - await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => AdsGenericModel.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 genericRespModel = await apiClient.getJsonForObject( token: appState.getUser.data!.accessToken, - (json) => AdsGenericModel.fromJson(json), - ApiConsts.vehicleCountryGet, + (json) => GenericRespModel.fromJson(json), + queryParameters: params, + ApiConsts.serviceProvidersAppointmentGet, ); - List vehicleConditions = List.generate(adsGenericModel.data.length, (index) => VehicleCountryModel.fromJson(adsGenericModel.data[index])); - return vehicleConditions; - } - - @override - Future> getVehicleMileages({required int vehicleTypeId}) async { - var postParams = { - "VehicleType": vehicleTypeId.toString(), - }; - AdsGenericModel adsGenericModel = - await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => AdsGenericModel.fromJson(json), ApiConsts.vehicleMileageGet, queryParameters: postParams); - List vehicleMileages = List.generate(adsGenericModel.data.length, (index) => VehicleMileageModel.fromJson(adsGenericModel.data[index])); - return vehicleMileages; - } - - @override - Future> getVehicleModelYears({required int vehicleTypeId}) async { - var postParams = { - "VehicleType": vehicleTypeId.toString(), - }; - AdsGenericModel adsGenericModel = - await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => AdsGenericModel.fromJson(json), ApiConsts.vehicleModelYearGet, queryParameters: postParams); - List vehicleModelYears = List.generate(adsGenericModel.data.length, (index) => VehicleYearModel.fromJson(adsGenericModel.data[index])); - return vehicleModelYears; - } - - @override - Future> getVehicleModels({required int vehicleTypeId}) async { - var postParams = { - "VehicleType": vehicleTypeId.toString(), - }; - AdsGenericModel adsGenericModel = - await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => AdsGenericModel.fromJson(json), ApiConsts.vehicleModelGet, queryParameters: postParams); - List vehicleModels = List.generate(adsGenericModel.data.length, (index) => VehicleModel.fromJson(adsGenericModel.data[index])); - return vehicleModels; - } - - @override - Future> getVehicleSellerTypes({required int vehicleTypeId}) async { - var postParams = { - "VehicleType": vehicleTypeId.toString(), - }; - AdsGenericModel adsGenericModel = - await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => AdsGenericModel.fromJson(json), ApiConsts.vehicleSellerTypeGet, queryParameters: postParams); - List vehicleSellerTypes = List.generate(adsGenericModel.data.length, (index) => VehicleSellerTypeModel.fromJson(adsGenericModel.data[index])); - return vehicleSellerTypes; - } - - @override - Future> getVehicleTransmission({required int vehicleTypeId}) async { - var postParams = { - "VehicleType": vehicleTypeId.toString(), - }; - AdsGenericModel adsGenericModel = - await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => AdsGenericModel.fromJson(json), ApiConsts.vehicleTransmissionGet, queryParameters: postParams); - List vehicleTransmissions = List.generate(adsGenericModel.data.length, (index) => VehicleTransmissionModel.fromJson(adsGenericModel.data[index])); - return vehicleTransmissions; + List appointmentList = List.generate(genericRespModel.data.length, (index) => AppointmentListModel.fromJson(genericRespModel.data[index])); + return appointmentList; } @override - Future getVehicleDetails({required int vehicleTypeId}) async { - var postParams = { - "vehicleType": vehicleTypeId.toString(), - "isVehicleBrand": "true", - "vehicleBrand": "0", - "isVehicleCategory": "true", - "isVehicleColor": "true", - "isVehicleCondition": "true", - "isVehicleMileage": "true", - "isVehicleModel": "true", - "isVehicleModelYear": "true", - "isVehiclePriceRange": "true", - "isVehiclePricingMethod": "true", - "isVehcileSellerType": "true", - "isVehicleTransmission": "true", - "isCountry": "true" + Future getCarCheckServiceScheduleDetails({required double lat, required double long}) async { + var params = { + "Latitude": lat.toString(), + "Longitude": long.toString(), }; - - String token = appState.getUser.data!.accessToken ?? ""; - AdsGenericModel adsGenericModel = await apiClient.postJsonForObject( - (json) => AdsGenericModel.fromJson(json), - ApiConsts.vehicleDetailsMaster, - postParams, - token: token, - ); - VehicleDetailsModel vehicleDetails = VehicleDetailsModel.fromJson(adsGenericModel.data); - return vehicleDetails; - } - - @override - Future> getVehicleDamageParts() async { - AdsGenericModel adsGenericModel = await apiClient.getJsonForObject( + GenericRespModel genericRespModel = await apiClient.getJsonForObject( token: appState.getUser.data!.accessToken, - (json) => AdsGenericModel.fromJson(json), - ApiConsts.vehicleDamagePartGet, + (json) => GenericRespModel.fromJson(json), + queryParameters: params, + ApiConsts.adsCarCheckupSPBranchScheduleSlotGet, ); - List vehicleParts = List.generate(adsGenericModel.data.length, (index) => VehiclePartModel.fromJson(adsGenericModel.data[index])); - return vehicleParts; + SSCarCheckScheduleModel ssCarCheckScheduleModel = SSCarCheckScheduleModel.fromJson(genericRespModel.data[0]); + return ssCarCheckScheduleModel; } @override - Future> getAdsDuration() async { - AdsGenericModel adsGenericModel = await apiClient.getJsonForObject( + 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) => AdsGenericModel.fromJson(json), - ApiConsts.vehicleAdsDurationGet, + (json) => GenericRespModel.fromJson(json), + queryParameters: params, + ApiConsts.adsPhotoOfficeAppointmentScheduleSlotGet, ); - List vehicleAdsDuration = List.generate(adsGenericModel.data.length, (index) => AdsDurationModel.fromJson(adsGenericModel.data[index])); - return vehicleAdsDuration; + SSPhotoScheduleModel ssPhotoScheduleModel = SSPhotoScheduleModel.fromJson(genericRespModel.data[0]); + return ssPhotoScheduleModel; } @override - Future> getSpecialServices() async { - AdsGenericModel adsGenericModel = await apiClient.getJsonForObject( - token: appState.getUser.data!.accessToken, - (json) => AdsGenericModel.fromJson(json), - ApiConsts.vehicleAdsSpecialServicesGet, - ); - List vehicleAdsDuration = List.generate(adsGenericModel.data.length, (index) => SpecialServiceModel.fromJson(adsGenericModel.data[index])); - return vehicleAdsDuration; + 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 createNewAd({required AdsCreationPayloadModel adsCreationPayloadModel}) async { - List vehiclePostingImages = []; - adsCreationPayloadModel.vehiclePosting!.vehiclePostingImages?.forEach((element) { - var imageMap = { - "id": 0, - "imageName": element.imageName, - "imageUrl": element.imageUrl, - "imageStr": element.imageStr, - "vehiclePostingID": 0, - "vehiclePosting": null, - }; - vehiclePostingImages.add(imageMap); - }); - - List vehiclePostingDamageParts = []; - adsCreationPayloadModel.vehiclePosting!.vehiclePostingDamageParts?.forEach((element) { - var imageMap = { - "id": 0, - "comment": element.comment, - "vehicleImageBase64": element.vehicleImageBase64, - "vehicleDamagePartID": element.vehicleDamagePartID, - "vehiclePostingID": 0, - "isActive": true - }; - vehiclePostingDamageParts.add(imageMap); - }); + Future> getProviderServices({required int categoryId}) async { var postParams = { - "ads": { - "id": 0, - "adsDurationID": adsCreationPayloadModel.ads!.adsDurationID, - "startDate": adsCreationPayloadModel.ads!.startDate, - "countryId": adsCreationPayloadModel.ads!.countryId, - "specialServiceIDs": adsCreationPayloadModel.ads!.specialServiceIDs, - "isMCHandled": false - }, - "vehiclePosting": { - "id": 0, - "userID": adsCreationPayloadModel.vehiclePosting!.userID, - "vehicleType": adsCreationPayloadModel.vehiclePosting!.vehicleType, - "vehicleModelID": adsCreationPayloadModel.vehiclePosting!.vehicleModelID, - "vehicleModelYearID": adsCreationPayloadModel.vehiclePosting!.vehicleModelYearID, - "vehicleColorID": adsCreationPayloadModel.vehiclePosting!.vehicleColorID, - "vehicleCategoryID": adsCreationPayloadModel.vehiclePosting!.vehicleCategoryID, - "vehicleConditionID": adsCreationPayloadModel.vehiclePosting!.vehicleConditionID, - "vehicleMileageID": adsCreationPayloadModel.vehiclePosting!.vehicleMileageID, - "vehicleTransmissionID": adsCreationPayloadModel.vehiclePosting!.vehicleTransmissionID, - "vehicleSellerTypeID": adsCreationPayloadModel.vehiclePosting!.vehicleSellerTypeID, - "cityID": adsCreationPayloadModel.vehiclePosting!.cityID, - "price": adsCreationPayloadModel.vehiclePosting!.price, - "vehicleVIN": adsCreationPayloadModel.vehiclePosting!.vehicleVIN, - "vehicleDescription": adsCreationPayloadModel.vehiclePosting!.vehicleDescription, - "vehicleTitle": adsCreationPayloadModel.vehiclePosting!.vehicleTitle, - "vehicleDescriptionN": adsCreationPayloadModel.vehiclePosting!.vehicleDescription, - "isFinanceAvailable": adsCreationPayloadModel.vehiclePosting!.isFinanceAvailable, - "warantyYears": adsCreationPayloadModel.vehiclePosting!.warantyYears, - "demandAmount": adsCreationPayloadModel.vehiclePosting!.demandAmount, - // "adStatus": 1, - "vehiclePostingImages": vehiclePostingImages, - "vehiclePostingDamageParts": vehiclePostingDamageParts - } - }; - - String token = appState.getUser.data!.accessToken ?? ""; - AdsGenericModel adsGenericModel = await apiClient.postJsonForObject( - (json) => AdsGenericModel.fromJson(json), - ApiConsts.vehicleAdsSingleStepCreate, - postParams, - token: token, - ); - - return Future.value(adsGenericModel); - } - - @override - Future> getAllAds({required isMyAds}) async { - var params = { - "userID": appState.getUser.data!.userInfo!.userId ?? "", + "ServiceCategoryID": categoryId.toString(), }; - - AdsGenericModel adsGenericModel = await apiClient.getJsonForObject( - token: appState.getUser.data!.accessToken, - (json) => AdsGenericModel.fromJson(json), - ApiConsts.vehicleAdsGet, - queryParameters: isMyAds ? params : null, - ); - List vehicleAdsDetails = List.generate(adsGenericModel.data.length, (index) => AdDetailsModel.fromJson(adsGenericModel.data[index])); - return vehicleAdsDetails; - } - - @override - Future> getMyAds() async { - var params = { - "userID": appState.getUser.data!.userInfo!.userId ?? "", - }; - AdsGenericModel adsGenericModel = await apiClient.getJsonForObject( - token: appState.getUser.data!.accessToken, - (json) => AdsGenericModel.fromJson(json), - queryParameters: params, - ApiConsts.vehicleAdsGet, - ); - List vehicleAdsDetails = List.generate(adsGenericModel.data.length, (index) => AdDetailsModel.fromJson(adsGenericModel.data[index])); - return vehicleAdsDetails; + 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/utils/utils.dart b/lib/utils/utils.dart index 9bdd7a7..ae599e0 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -156,6 +156,7 @@ class Utils { ); } + static InputDecoration txtField(String label) { return InputDecoration( border: InputBorder.none, diff --git a/lib/view_models/ad_view_model.dart b/lib/view_models/ad_view_model.dart index 4148bc8..4b6bf5b 100644 --- a/lib/view_models/ad_view_model.dart +++ b/lib/view_models/ad_view_model.dart @@ -6,24 +6,31 @@ 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/ads_repo.dart'; import 'package:mc_common_app/repositories/common_repo.dart'; import 'package:mc_common_app/services/services.dart'; 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; + final AdsRepo adsRepo; + final CommonServices commonServices; - AdVM({required this.commonServices, required this.commonRepo}); + AdVM({required this.commonServices, required this.commonRepo, required this.adsRepo}); AdCreationStepsEnum currentProgressStep = AdCreationStepsEnum.vehicleDetails; @@ -39,10 +46,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 +62,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,68 +110,119 @@ 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(); } Future getMyAds() async { isFetchingLists = true; - myAds = await commonRepo.getAllAds(isMyAds: true); + myAds = await adsRepo.getAllAds(isMyAds: true); isFetchingLists = true; notifyListeners(); } - Future getAllAds() async { - allAds = await commonRepo.getAllAds(isMyAds: false); + Future getExploreAds() async { + exploreAds = await adsRepo.getAllAds(isMyAds: false); notifyListeners(); } Future getVehicleTypes() async { - vehicleTypes = await commonRepo.getVehicleTypes(); + vehicleTypes = await adsRepo.getVehicleTypes(); notifyListeners(); } Future getVehicleAdsDuration() async { - vehicleAdsDurations = await commonRepo.getAdsDuration(); + vehicleAdsDurations = await adsRepo.getAdsDuration(); notifyListeners(); } Future getVehicleAdsSpecialServices() async { - vehicleAdsSpecialServices = await commonRepo.getSpecialServices(); + vehicleAdsSpecialServices = await adsRepo.getSpecialServices(specialServiceId: 1); notifyListeners(); } @@ -171,14 +235,14 @@ class AdVM extends BaseVM { } isFetchingLists = true; notifyListeners(); - vehicleModels = await commonRepo.getVehicleModels(vehicleTypeId: vehicleTypeId.selectedId); - vehicleModelYears = await commonRepo.getVehicleModelYears(vehicleTypeId: vehicleTypeId.selectedId); - vehicleColors = await commonRepo.getVehicleColors(vehicleTypeId: vehicleTypeId.selectedId); - vehicleConditions = await commonRepo.getVehicleConditions(vehicleTypeId: vehicleTypeId.selectedId); - vehicleCategories = await commonRepo.getVehicleCategories(vehicleTypeId: vehicleTypeId.selectedId); - vehicleMileages = await commonRepo.getVehicleMileages(vehicleTypeId: vehicleTypeId.selectedId); - vehicleTransmissions = await commonRepo.getVehicleTransmission(vehicleTypeId: vehicleTypeId.selectedId); - vehicleCountries = await commonRepo.getVehicleCountries(); + vehicleModels = await adsRepo.getVehicleModels(vehicleTypeId: vehicleTypeId.selectedId); + vehicleModelYears = await adsRepo.getVehicleModelYears(vehicleTypeId: vehicleTypeId.selectedId); + vehicleColors = await adsRepo.getVehicleColors(vehicleTypeId: vehicleTypeId.selectedId); + vehicleConditions = await adsRepo.getVehicleConditions(vehicleTypeId: vehicleTypeId.selectedId); + vehicleCategories = await adsRepo.getVehicleCategories(vehicleTypeId: vehicleTypeId.selectedId); + vehicleMileages = await adsRepo.getVehicleMileages(vehicleTypeId: vehicleTypeId.selectedId); + vehicleTransmissions = await adsRepo.getVehicleTransmission(vehicleTypeId: vehicleTypeId.selectedId); + vehicleCountries = await adsRepo.getVehicleCountries(); isFetchingLists = false; notifyListeners(); } @@ -189,7 +253,7 @@ class AdVM extends BaseVM { } isFetchingLists = true; notifyListeners(); - vehicleDetails = await commonRepo.getVehicleDetails(vehicleTypeId: vehicleTypeId.selectedId); + vehicleDetails = await adsRepo.getVehicleDetails(vehicleTypeId: vehicleTypeId.selectedId); if (vehicleDetails != null) { vehicleModels = vehicleDetails!.vehicleModels!; @@ -214,6 +278,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 +390,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; @@ -335,7 +407,7 @@ class AdVM extends BaseVM { vehicleCountryId = id; isCountryFetching = true; notifyListeners(); - vehicleCities = await commonRepo.getVehicleCities(countryId: vehicleCountryId.selectedId); + vehicleCities = await adsRepo.getVehicleCities(countryId: vehicleCountryId.selectedId); isCountryFetching = false; notifyListeners(); } @@ -354,13 +426,132 @@ 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() { bool isValidated = true; if (vehicleTypeId.selectedId == -1) { @@ -485,23 +676,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 +721,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 +796,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 +832,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(); @@ -716,7 +922,7 @@ class AdVM extends BaseVM { } Future getVehicleDamagePartsList() async { - vehicleDamageParts = await commonRepo.getVehicleDamageParts(); + vehicleDamageParts = await adsRepo.getVehicleDamageParts(); notifyListeners(); } @@ -742,7 +948,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 +984,7 @@ class AdVM extends BaseVM { ); AdsCreationPayloadModel adsCreationPayloadModel = AdsCreationPayloadModel(ads: ads, vehiclePosting: vehiclePosting); - AdsGenericModel respModel = await commonRepo.createNewAd(adsCreationPayloadModel: adsCreationPayloadModel); + GenericRespModel respModel = await adsRepo.createNewAd(adsCreationPayloadModel: adsCreationPayloadModel); return Future.value(respModel.messageStatus); } @@ -806,20 +1012,6 @@ 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; SelectionModel? partSelectedId; @@ -838,6 +1030,9 @@ class SpecialServiceCard { String? serviceDateError; String? serviceTime; String? serviceTimeError; + String? description; + String? duration; + String? address; SpecialServiceCard({ this.serviceSelectedId, @@ -845,6 +1040,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..53f0e29 100644 --- a/lib/views/advertisement/ads_detail_view.dart +++ b/lib/views/advertisement/ads_detail_view.dart @@ -1,10 +1,12 @@ -import 'package:mc_common_app/views/advertisement/ads_images_slider.dart'; import 'package:flutter/material.dart'; import 'package:mc_common_app/classes/consts.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/models/advertisment_models/ad_details_model.dart'; import 'package:mc_common_app/theme/colors.dart'; +import 'package:mc_common_app/utils/navigator.dart'; +import 'package:mc_common_app/views/advertisement/ads_images_slider.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/extensions/extensions_widget.dart'; @@ -18,7 +20,6 @@ class AdsDetailView extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: CustomAppBar( - backgroundColor: MyColors.backgroundColor, title: "Ads", profileImageUrl: MyAssets.bnCar, isRemoveBackButton: false, @@ -109,7 +110,9 @@ class AdsDetailView extends StatelessWidget { child: ShowFillButton( maxHeight: 55, title: "Reserve Ad", - onPressed: () {}, + onPressed: () { + navigateWithName(context, AppRoutes.paymentMethodsView); + }, ), ), 12.width, 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( diff --git a/pubspec.lock b/pubspec.lock index 580abde..e5998c8 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -206,6 +206,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.3.0" + flutter_inappwebview: + dependency: "direct main" + description: + name: flutter_inappwebview + sha256: f73505c792cf083d5566e1a94002311be497d984b5607f25be36d685cf6361cf + url: "https://pub.dev" + source: hosted + version: "5.7.2+3" flutter_lints: dependency: "direct dev" description: diff --git a/pubspec.yaml b/pubspec.yaml index 1f4ccf5..74ab43b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -35,6 +35,7 @@ dependencies: badges: ^3.0.2 carousel_slider: ^4.2.1 dropdown_button2: ^2.0.0 + flutter_inappwebview: ^5.7.2+3 # google @@ -57,6 +58,7 @@ flutter: - assets/ - assets/langs/ - assets/icons/ + - assets/icons/payments/ - assets/images/ - assets/fonts/Poppins-Medium.ttf