diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index c48ffc0..dce03ae 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -745,6 +745,16 @@ "active": "نشط", "paymentType": "نوع الدفع", "searchByCreatedDate": "البحث حسب تاريخ الإنشاء", + "cityNameMandatory": "المدينة إلزامية", + "genderMandatory": "الجنس إلزامي", + "updateCity": "تحديث المدينة", + "userGender": "جنس", + "userMale": "ذكر", + "userFemale": "أنثى", + "maxFileSelection": "يمكنك تحديد الحد الأقصى لملفات 7", + "maxFileSize": "يجب أن يكون حجم كل ملف أقل من 2 ميغابايت", + "onlyJPGandPNG": "يُسمح فقط بملفات JPG وPNG", + "expiryDate": "تاريخ انتهاء الصلاحية", "dealCompleted": "تم إتمام الصفقة", "theDealNotCompleted": "لم تكتمل الصفقة", "cancelRequest": "أريد إلغاء الطلب.", @@ -765,16 +775,16 @@ "tapToSelect": "اضغط للاختيار", "noteCopyItemsExplanation": "ملاحظة: ستتمكن من نسخ العناصر من خدمة إلى أخرى في الفئة المحددة. يجب عليك إنشاء الخدمات أولاً ويجب أن تكون معتمدة. ثم ستتمكن من الحصول على الخدمات المتاحة التي يمكنك نسخ جميع العناصر منها أو تحديد العناصر التي تريد نسخها.", "requestCreatedOn": "تم إنشاء الطلب في", - "cityNameMandatory": "المدينة إلزامية", - "genderMandatory": "الجنس إلزامي", - "updateCity": "تحديث المدينة", - "userGender": "جنس", - "userMale": "ذكر", - "userFemale": "أنثى", - "maxFileSelection" :"يمكنك تحديد الحد الأقصى لملفات 7", - "maxFileSize": "يجب أن يكون حجم كل ملف أقل من 2 ميغابايت", - "onlyJPGandPNG": "يُسمح فقط بملفات JPG وPNG", - "expiryDate": "تاريخ انتهاء الصلاحية" + "online": "عبر الإنترنت", + "deliveryStatus": "حالة توصيلك / الشحن هي:", + "markAsCompleted": "ضع علامة كمكتمل", + "searchByServiceDelivery": "البحث حسب خدمة التوصيل", + "searchByMobileNumber": "البحث بواسطة رقم الجوال", + "enterMobileNumber": "أدخل رقم الجوال", + "enterCustomerName": "أدخل اسم العميل", + "tapToView": "انقر لعرض", + "noServicesAvailableToCopy": "لا توجد خدمات متاحة في هذا الفرع لنسخها.", + "copySelectedItems": "نسخ العناصر المحددة" } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 0e4472e..92bd07b 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -738,7 +738,6 @@ "blockedByAdmin": "Blocked by admin", "active": "Active", "paymentType": "Payment Type", - "searchByCreatedDate": "Search By Created Date", "dealCompleted": "The Deal Completed", "theDealNotCompleted": "The Deal Not Completed", "cancelRequest": "I want to cancel the request.", @@ -759,6 +758,32 @@ "tapToSeeItems": "Tap to see items", "noteCopyItemsExplanation": "Note: You will be able to copy items from one service to another in a selected category. You must create the services first and they should be approved. Then you will be able to get the available services from which you can copy all or selected items.", "requestCreatedOn": "Request created on", + "online": "Online", + "searchByCreatedDate": "Search By Created Date", + "updateUserDetails": "Update User Details", + "enterNewFirstName": "Enter First Name", + "enterNewLastName": "Enter Last Name", + "userDetailsUpdated": "User Details is Updated", + "cityNameMandatory": "City is mandatory", + "genderMandatory": "Gender is mandatory", + "updateCity": "Update City", + "userGender": "Gender", + "userMale": "Male", + "userFemale": "Female", + "maxFileSelection": "You can select a maximum of 7 files", + "maxFileSize": "Each file size must be less than 2 MB", + "onlyJPGandPNG": "Only JPG and PNG files are allowed", + "expiryDate": "Expiry Date", + "deliveryStatus": "Your Delivery / Shipping Status is:", + "markAsCompleted": "Mark as Completed", + "searchByServiceDelivery": "Search by Service Delivery", + "searchByMobileNumber": "Search by Mobile Number", + "enterMobileNumber": "Enter Mobile Number", + "enterCustomerName": "Enter Customer Name", + "tapToView": "Tap to view", + "noServicesAvailableToCopy": "There are no services available in this branch to copy.", + "copySelectedItems": "Copy Selected Items" + "requestCreatedOn": "Request created on", "updateUserDetails": "Update User Details", "enterNewFirstName": "Enter First Name", "enterNewLastName": "Enter Last Name", diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 74cd78f..9486a7c 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -56,7 +56,7 @@ class ApiConsts { static String servicesGet = "${baseUrlServices}api/ServiceProviders/Services_Get"; static String serviceProviderServiceCreate = "${baseUrlServices}api/ServiceProviders/ServiceProviderService_Create"; static String serviceProviderServiceUpdate = "${baseUrlServices}api/ServiceProviders/ServiceProviderService_Update"; - static String serviceProviderServiceStatusUpdate = "${baseUrlServices}api/ServiceProviders/CategoryAndServiceDeactivateBySP"; + static String serviceProviderServiceStatusUpdate = "${baseUrlServices}api/ServiceProviders/CategoryAndService_ActivateDeactivateBySP"; static String getProviderServices = "${baseUrlServices}api/ServiceProviders/ServiceProviderService_Get"; static String setScheduleInactive = "${baseUrlServices}api/ServiceProviders/BranchAppointmentSchedule_IsActiveUpdate"; static String serviceProviderAppointmentGetByCategoryOrService = "${baseUrlServices}api/ServiceProviders/ServiceProviderAppointment_GetByCategoryOrService"; @@ -257,11 +257,10 @@ class GlobalConsts { return appInvitationMessageEn; } - // Attachment Values - int maxFileCount = 7; - int maxFileSizeInBytes = 2 * 1024 * 1024; + static int maxFileCount = 7; + static int maxFileSizeInBytes = 2 * 1024 * 1024; } class MyAssets { @@ -403,6 +402,4 @@ class SignalrConsts { // General static String sendMessageGeneral = "SendMessageGeneral"; static String receiveMessageGeneral = "ReceiveMessageGeneral"; - - } diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index bf4948a..70ca99d 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -998,3 +998,12 @@ extension ShippingStatusEnumToInt on ShippingRequestStatusEnum { } } } + +extension CapitalizeFirstLetter on String { + String capitalizeFirstLetter() { + if (isEmpty) { + return this; // Return the string as-is if it's empty + } + return this[0].toUpperCase() + substring(1).toLowerCase(); + } +} diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index c41e084..da2a1b6 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -761,6 +761,16 @@ class CodegenLoader extends AssetLoader{ "active": "نشط", "paymentType": "نوع الدفع", "searchByCreatedDate": "البحث حسب تاريخ الإنشاء", + "cityNameMandatory": "المدينة إلزامية", + "genderMandatory": "الجنس إلزامي", + "updateCity": "تحديث المدينة", + "userGender": "جنس", + "userMale": "ذكر", + "userFemale": "أنثى", + "maxFileSelection": "يمكنك تحديد الحد الأقصى لملفات 7", + "maxFileSize": "يجب أن يكون حجم كل ملف أقل من 2 ميغابايت", + "onlyJPGandPNG": "يُسمح فقط بملفات JPG وPNG", + "expiryDate": "تاريخ انتهاء الصلاحية", "dealCompleted": "تم إتمام الصفقة", "theDealNotCompleted": "لم تكتمل الصفقة", "cancelRequest": "أريد إلغاء الطلب.", @@ -780,6 +790,17 @@ class CodegenLoader extends AssetLoader{ "tapToSeeItems": "اضغط لرؤية العناصر", "tapToSelect": "اضغط للاختيار", "noteCopyItemsExplanation": "ملاحظة: ستتمكن من نسخ العناصر من خدمة إلى أخرى في الفئة المحددة. يجب عليك إنشاء الخدمات أولاً ويجب أن تكون معتمدة. ثم ستتمكن من الحصول على الخدمات المتاحة التي يمكنك نسخ جميع العناصر منها أو تحديد العناصر التي تريد نسخها.", + "requestCreatedOn": "تم إنشاء الطلب في", + "online": "عبر الإنترنت", + "deliveryStatus": "حالة توصيلك / الشحن هي:", + "markAsCompleted": "ضع علامة كمكتمل", + "searchByServiceDelivery": "البحث حسب خدمة التوصيل", + "searchByMobileNumber": "البحث بواسطة رقم الجوال", + "enterMobileNumber": "أدخل رقم الجوال", + "enterCustomerName": "أدخل اسم العميل", + "tapToView": "انقر لعرض", + "noServicesAvailableToCopy": "لا توجد خدمات متاحة في هذا الفرع لنسخها.", + "copySelectedItems": "نسخ العناصر المحددة" "requestCreatedOn": "تم إنشاء الطلب في" "searchByCreatedDate": "البحث حسب تاريخ الإنشاء", "cityNameMandatory": "المدينة إلزامية", @@ -1533,7 +1554,6 @@ static const Map en_US = { "blockedByAdmin": "Blocked by admin", "active": "Active", "paymentType": "Payment Type", - "searchByCreatedDate": "Search By Created Date", "dealCompleted": "The Deal Completed", "theDealNotCompleted": "The Deal Not Completed", "cancelRequest": "I want to cancel the request.", @@ -1554,6 +1574,32 @@ static const Map en_US = { "tapToSeeItems": "Tap to see items", "noteCopyItemsExplanation": "Note: You will be able to copy items from one service to another in a selected category. You must create the services first and they should be approved. Then you will be able to get the available services from which you can copy all or selected items.", "requestCreatedOn": "Request created on", + "online": "Online", + "searchByCreatedDate": "Search By Created Date", + "updateUserDetails": "Update User Details", + "enterNewFirstName": "Enter First Name", + "enterNewLastName": "Enter Last Name", + "userDetailsUpdated": "User Details is Updated", + "cityNameMandatory": "City is mandatory", + "genderMandatory": "Gender is mandatory", + "updateCity": "Update City", + "userGender": "Gender", + "userMale": "Male", + "userFemale": "Female", + "maxFileSelection": "You can select a maximum of 7 files", + "maxFileSize": "Each file size must be less than 2 MB", + "onlyJPGandPNG": "Only JPG and PNG files are allowed", + "expiryDate": "Expiry Date", + "deliveryStatus": "Your Delivery / Shipping Status is:", + "markAsCompleted": "Mark as Completed", + "searchByServiceDelivery": "Search by Service Delivery", + "searchByMobileNumber": "Search by Mobile Number", + "enterMobileNumber": "Enter Mobile Number", + "enterCustomerName": "Enter Customer Name", + "tapToView": "Tap to view", + "noServicesAvailableToCopy": "There are no services available in this branch to copy.", + "copySelectedItems": "Copy Selected Items" + "requestCreatedOn": "Request created on", "updateUserDetails": "Update User Details", "enterNewFirstName": "Enter First Name", "enterNewLastName": "Enter Last Name", diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index ba90d60..a2c3d5e 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -724,6 +724,16 @@ abstract class LocaleKeys { static const active = 'active'; static const paymentType = 'paymentType'; static const searchByCreatedDate = 'searchByCreatedDate'; + static const cityNameMandatory = 'cityNameMandatory'; + static const genderMandatory = 'genderMandatory'; + static const updateCity = 'updateCity'; + static const userGender = 'userGender'; + static const userMale = 'userMale'; + static const userFemale = 'userFemale'; + static const maxFileSelection = 'maxFileSelection'; + static const maxFileSize = 'maxFileSize'; + static const onlyJPGandPNG = 'onlyJPGandPNG'; + static const expiryDate = 'expiryDate'; static const dealCompleted = 'dealCompleted'; static const theDealNotCompleted = 'theDealNotCompleted'; static const cancelRequest = 'cancelRequest'; @@ -744,15 +754,16 @@ abstract class LocaleKeys { static const tapToSelect = 'tapToSelect'; static const noteCopyItemsExplanation = 'noteCopyItemsExplanation'; static const requestCreatedOn = 'requestCreatedOn'; - static const cityNameMandatory = 'cityNameMandatory'; - static const genderMandatory = 'genderMandatory'; - static const updateCity = 'updateCity'; - static const userGender = 'userGender'; - static const userMale = 'userMale'; - static const userFemale = 'userFemale'; - static const maxFileSelection = 'maxFileSelection'; - static const maxFileSize = 'maxFileSize'; - static const onlyJPGandPNG = 'onlyJPGandPNG'; - static const expiryDate = 'expiryDate'; + static const online = 'online'; + static const deliveryStatus = 'deliveryStatus'; + static const markAsCompleted = 'markAsCompleted'; + static const searchByServiceDelivery = 'searchByServiceDelivery'; + static const searchByMobileNumber = 'searchByMobileNumber'; + static const enterMobileNumber = 'enterMobileNumber'; + static const enterCustomerName = 'enterCustomerName'; + static const tapToView = 'tapToView'; + static const noServicesAvailableToCopy = 'noServicesAvailableToCopy'; + static const copySelectedItems = 'copySelectedItems'; + } diff --git a/lib/models/advertisment_models/ad_details_model.dart b/lib/models/advertisment_models/ad_details_model.dart index fb9ba56..83f4575 100644 --- a/lib/models/advertisment_models/ad_details_model.dart +++ b/lib/models/advertisment_models/ad_details_model.dart @@ -50,6 +50,7 @@ class AdDetailsModel { String? warrantyYears; CreatedByRoleEnum? createdByRoleEnum; List? adMessages; + int? totalItemsCount; AdDetailsModel({ this.id, @@ -95,6 +96,7 @@ class AdDetailsModel { this.createdByRoleEnum, this.modifiedOn, this.adMessages, + this.totalItemsCount, }); int getRandomValue({required int min, required int max}) { @@ -103,7 +105,7 @@ class AdDetailsModel { return randomNumber; } - AdDetailsModel.fromJson(Map json, bool isMyAds) { + AdDetailsModel.fromJson(Map json, bool isMyAds, int totalItems) { id = json['id']; startdate = json['startdate']; enddate = json['enddate']; @@ -150,6 +152,7 @@ class AdDetailsModel { createdByRoleEnum = (json['createdByRole'] as int).toCreatedByRoleEnum(); isMyAd = isMyAds; isReservedByMe = false; + totalItemsCount = totalItems; } } diff --git a/lib/models/chat_models/chat_message_model.dart b/lib/models/chat_models/chat_message_model.dart index 9e7c5ee..b8137b9 100644 --- a/lib/models/chat_models/chat_message_model.dart +++ b/lib/models/chat_models/chat_message_model.dart @@ -80,7 +80,7 @@ class ReqOffer { String? offerStatusText; String? comment; String? serviceItemName; - int? manufacturedById; + String? manufacturedByName; String? manufacturedOn; double? price; bool? isDeliveryAvailable; @@ -96,7 +96,7 @@ class ReqOffer { this.offerStatusText, this.comment, this.serviceItemName, - this.manufacturedById, + this.manufacturedByName, this.manufacturedOn, this.price, this.isDeliveryAvailable, @@ -113,7 +113,7 @@ class ReqOffer { offerStatusText = json['offerStatusText']; comment = json['comment']; serviceItemName = json['serviceItem']; - manufacturedById = json['offeredItemCreatedBy']; + manufacturedByName = json['offeredItemCreatedBy'].toString(); manufacturedOn = json['offeredItemCreatedOn']; price = json['price']; isDeliveryAvailable = json['isDeliveryAvailable']; @@ -138,7 +138,7 @@ class ReqOffer { @override String toString() { - return 'ReqOffer{id: $id, requestID: $requestID, serviceProviderID: $serviceProviderID, offerStatus: $offerStatus, offerStatusText: $offerStatusText, comment: $comment, serviceItemName: $serviceItemName, manufacturedById: $manufacturedById, manufacturedOn: $manufacturedOn, price: $price, requestsTypeEnum: $requestsTypeEnum, requestOfferStatusEnum: $requestOfferStatusEnum}'; + return 'ReqOffer{id: $id, requestID: $requestID, serviceProviderID: $serviceProviderID, offerStatus: $offerStatus, offerStatusText: $offerStatusText, comment: $comment, serviceItemName: $serviceItemName, manufacturedById: $manufacturedByName, manufacturedOn: $manufacturedOn, price: $price, requestsTypeEnum: $requestsTypeEnum, requestOfferStatusEnum: $requestOfferStatusEnum}'; } } diff --git a/lib/models/requests_models/request_model.dart b/lib/models/requests_models/request_model.dart index 8f4bd01..5322442 100644 --- a/lib/models/requests_models/request_model.dart +++ b/lib/models/requests_models/request_model.dart @@ -101,7 +101,7 @@ class RequestModel { requestStatusName: json["requestStatusName"], requestStatus: (json['requestStatus'] as int).toRequestStatusEnum(), shippingStatus: json['shippingRequestStatus'], - shippingStatusEnum: json['shippingRequestStatus'] != null ? (json['shippingRequestStatus'] as int).toShippingStatusEnum() : ShippingRequestStatusEnum.initiated, + shippingStatusEnum: json['shippingRequestStatus'] != null ? (json['shippingRequestStatus'] as int).toShippingStatusEnum() : ShippingRequestStatusEnum.pending, cityName: json["cityName"], vehicleTypeName: json["vehicleTypeName"], countryName: json["countryName"], diff --git a/lib/repositories/ads_repo.dart b/lib/repositories/ads_repo.dart index d5d83be..8a48c49 100644 --- a/lib/repositories/ads_repo.dart +++ b/lib/repositories/ads_repo.dart @@ -1,10 +1,12 @@ import 'dart:developer'; +import 'package:easy_localization/easy_localization.dart'; 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/dependency_injection.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/advertisment_models/ad_details_model.dart'; import 'package:mc_common_app/models/advertisment_models/ads_bank_details_model.dart'; import 'package:mc_common_app/models/advertisment_models/ads_duration_model.dart'; @@ -14,15 +16,22 @@ import 'package:mc_common_app/models/advertisment_models/special_service_model.d import 'package:mc_common_app/models/chat_models/buyers_chat_for_ads_model.dart'; import 'package:mc_common_app/models/general_models/generic_resp_model.dart'; import 'package:mc_common_app/utils/enums.dart'; +import 'package:mc_common_app/utils/utils.dart'; abstract class AdsRepo { Future> getAdsDuration({required int? countryId}); - Future> getSpecialServices({required int specialServiceType}); + Future> getSpecialServices({required int specialServiceType, required int cityId, required int countryId}); Future createOrUpdateAd({required AdsCreationPayloadModel adsCreationPayloadModel, required bool isCreateNew}); - Future> getAllAds({required bool isMyAds, AdPostStatus? adPostStatus, CreatedByRoleEnum? createdByRoleEnum}); + Future> getAllAds({ + required bool isMyAds, + AdPostStatus? adPostStatus, + CreatedByRoleEnum? createdByRoleEnum, + int? vehicleBrandId, + int? page, + }); Future> getExploreAdsBasedOnFilters({ List? cityIdsList, @@ -31,6 +40,8 @@ abstract class AdsRepo { List? createdByRolesIdsList, List? vehicleAdConditionIdsList, List? vehicleAdCreatedDateList, + int page, + bool isMyAds = false, }); Future> getMyReservedAds(); @@ -62,10 +73,10 @@ class AdsRepoImp implements AdsRepo { @override Future> getAdsDuration({required int? countryId}) async { - int roleID = appState.getUser!.data!.userInfo!.roleId ?? 0; + int roleID = appState.getUser.data!.userInfo!.roleId ?? 0; var param = { - "CountryID": countryId.toString() ?? "0", - "roleID": roleID.toString() ?? "0", + "CountryID": countryId.toString(), + "roleID": roleID.toString(), }; GenericRespModel adsGenericModel = await apiClient.getJsonForObject( token: appState.getUser.data!.accessToken, @@ -78,14 +89,34 @@ class AdsRepoImp implements AdsRepo { } @override - Future> getSpecialServices({required int specialServiceType}) async { + Future> getSpecialServices({required int specialServiceType, required int cityId, required int countryId}) async { + log("getSpecialServices cityId: $cityId"); var params = { "SpecialServiceType": specialServiceType.toString(), + "CountryID": countryId.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; + List list = List.generate(adsGenericModel.data.length, (index) => SpecialServiceModel.fromJson(adsGenericModel.data[index])); + + List specialServicesByCity = getOfficesOnlyByCity(list, cityId); + + return specialServicesByCity; + } + + List getOfficesOnlyByCity(List allServices, int cityId) { + List list = []; + + for (var service in allServices) { + if (service.office != null && service.office!.isNotEmpty) { + for (var office in service.office!) { + if (office.cityID == cityId) { + list.add(service); + } + } + } + } + return list; } @override @@ -168,7 +199,13 @@ class AdsRepoImp implements AdsRepo { } @override - Future> getAllAds({required isMyAds, AdPostStatus? adPostStatus, CreatedByRoleEnum? createdByRoleEnum}) async { + Future> getAllAds({ + required isMyAds, + AdPostStatus? adPostStatus, + CreatedByRoleEnum? createdByRoleEnum, + int? vehicleBrandId, + int? page, + }) async { Map onlyMyAdsParams = { "userID": appState.getUser.data!.userInfo!.userId ?? "", }; @@ -176,6 +213,7 @@ class AdsRepoImp implements AdsRepo { onlyMyAdsParams.addAll({ "AdsStatuses": ["${adPostStatus.getIdFromAdPostStatusEnum()}"], "PageSize": "30", + "PageIndex": page != null ? page.toString() : "0", }); } var allAdsParams = { @@ -183,6 +221,7 @@ class AdsRepoImp implements AdsRepo { "isActive": "true", //only Active ADS "isExplore": "true", "PageSize": "30", + "PageIndex": page != null ? page.toString() : "0", }; if (!isMyAds && createdByRoleEnum != null) { @@ -190,13 +229,18 @@ class AdsRepoImp implements AdsRepo { "CreatedByRoles": ["${createdByRoleEnum.getIdFromCreatedByRoleEnum()}"], }); } + if (!isMyAds && vehicleBrandId != null && vehicleBrandId != 0) { + allAdsParams.addAll({ + "VehicleBrandIDs": ["$vehicleBrandId"], + }); + } GenericRespModel adsGenericModel = await apiClient.getJsonForObject( token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleAdsGet, queryParameters: isMyAds ? onlyMyAdsParams : allAdsParams, ); - List vehicleAdsDetails = List.generate(adsGenericModel.data.length, (index) => AdDetailsModel.fromJson(adsGenericModel.data[index], isMyAds)); + List vehicleAdsDetails = List.generate(adsGenericModel.data.length, (index) => AdDetailsModel.fromJson(adsGenericModel.data[index], isMyAds, adsGenericModel.totalItemsCount ?? 1)); return vehicleAdsDetails; } @@ -208,6 +252,8 @@ class AdsRepoImp implements AdsRepo { List? createdByRolesIdsList, List? vehicleAdConditionIdsList, List? vehicleAdCreatedDateList, + int? page, + bool isMyAds = false, }) async { var parameters = { "CityIDs": cityIdsList ?? [], @@ -218,17 +264,29 @@ class AdsRepoImp implements AdsRepo { "VehicleNew": vehicleAdConditionIdsList ?? [], "CreatedOn": (vehicleAdCreatedDateList != null && vehicleAdCreatedDateList.isNotEmpty) ? vehicleAdCreatedDateList.first.toString() : "", "isActive": "true", //only Active ADS - "isExplore": "true", + "isExplore": (!isMyAds).toString(), "PageSize": "30", + "PageIndex": page != null ? page.toString() : "1", }; + if (isMyAds) { + parameters.addAll({ + "userID": appState.getUser.data!.userInfo!.userId ?? "", + }); + } + GenericRespModel adsGenericModel = await apiClient.getJsonForObject( token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleAdsGet, queryParameters: parameters, ); - List vehicleAdsDetails = List.generate(adsGenericModel.data.length, (index) => AdDetailsModel.fromJson(adsGenericModel.data[index], false)); + + if (adsGenericModel.messageStatus != 1 || adsGenericModel.data == null) { + Utils.showToast(adsGenericModel.message ?? LocaleKeys.somethingWrong.tr()); + return []; + } + List vehicleAdsDetails = List.generate(adsGenericModel.data.length, (index) => AdDetailsModel.fromJson(adsGenericModel.data[index], false, adsGenericModel.totalItemsCount ?? 1)); return vehicleAdsDetails; } @@ -244,6 +302,11 @@ class AdsRepoImp implements AdsRepo { ApiConsts.myAdsReserveGet, queryParameters: params, ); + + if (adsGenericModel.messageStatus != 1 || adsGenericModel.data == null) { + Utils.showToast(adsGenericModel.message ?? LocaleKeys.somethingWrong.tr()); + return []; + } List reservedAds = List.generate(adsGenericModel.data.length, (index) => MyReservedAdsRespModel.fromJson(adsGenericModel.data[index])); List selectedIdsString = reservedAds.map((component) => component.adsID.toString()).toList(); @@ -266,7 +329,11 @@ class AdsRepoImp implements AdsRepo { queryParameters: params, ApiConsts.vehicleAdsGet, ); - List vehicleAdsDetails = List.generate(adsGenericModel.data.length, (index) => AdDetailsModel.fromJson(adsGenericModel.data[index], true)); + if (adsGenericModel.messageStatus != 1 || adsGenericModel.data == null) { + Utils.showToast(adsGenericModel.message ?? LocaleKeys.somethingWrong.tr()); + return []; + } + List vehicleAdsDetails = List.generate(adsGenericModel.data.length, (index) => AdDetailsModel.fromJson(adsGenericModel.data[index], true, adsGenericModel.totalItemsCount ?? 1)); for (int i = 0; i < vehicleAdsDetails.length; i++) { vehicleAdsDetails[i].adReserveStatus = (reservedAds[i].adsReserveStatus ?? 0).toAdRserveStatusEnum(); @@ -288,7 +355,11 @@ class AdsRepoImp implements AdsRepo { queryParameters: params, ApiConsts.vehicleAdsGet, ); - List vehicleAdsDetails = List.generate(adsGenericModel.data.length, (index) => AdDetailsModel.fromJson(adsGenericModel.data[index], true)); + if (adsGenericModel.messageStatus != 1 || adsGenericModel.data == null) { + Utils.showToast(adsGenericModel.message ?? LocaleKeys.somethingWrong.tr()); + return []; + } + List vehicleAdsDetails = List.generate(adsGenericModel.data.length, (index) => AdDetailsModel.fromJson(adsGenericModel.data[index], true, adsGenericModel.totalItemsCount ?? 1)); return vehicleAdsDetails; } diff --git a/lib/repositories/appointment_repo.dart b/lib/repositories/appointment_repo.dart index cf99abe..9e1c798 100644 --- a/lib/repositories/appointment_repo.dart +++ b/lib/repositories/appointment_repo.dart @@ -15,6 +15,16 @@ import 'package:mc_common_app/utils/enums.dart'; abstract class AppointmentRepo { Future> getMyAppointmentsForProvider(Map map); + Future> getMyAppointmentsForProvidersByFilters({ + required int branchID, + List? serviceProviderServiceIdsList, + List? customerNamesList, + List? customerPhonesList, + List? deliveryTypeIdsList, + String? fromDate, + String? toDate, + }); + Future> getMyAppointmentsForCustomersByFilters({ List? providerIdsList, List? categoryIdsList, @@ -27,7 +37,7 @@ abstract class AppointmentRepo { Future updateAppointmentPaymentStatus(Map map); - Future getAppointmentSlots(Map map); + Future getAppointmentSlots({required int branchID, required String fromDate, required String toDate}); Future createMergeAppointment(Map map); @@ -219,6 +229,40 @@ class AppointmentRepoImp implements AppointmentRepo { return appointmentList; } + @override + Future> getMyAppointmentsForProvidersByFilters({ + required int branchID, + List? serviceProviderServiceIdsList, + List? customerNamesList, + List? customerPhonesList, + List? deliveryTypeIdsList, + String? fromDate, + String? toDate, + }) async { + String t = appState.getUser.data!.accessToken ?? ""; + String providerId = appState.getUser.data!.userInfo!.providerId.toString(); + var params = { + "ServiceProviderID": providerId.toString(), + "ProviderBranchID": branchID.toString(), + "IsSearchFilter": true.toString(), + "SPServiceIDs": serviceProviderServiceIdsList ?? [], + "CustomerNames": customerNamesList ?? [], + "CustomerMobileNos": customerPhonesList ?? [], + "AppointmentTypes": deliveryTypeIdsList ?? [], + "FromDate": fromDate ?? "", + "DateTo": toDate ?? "", + }; + + GenericRespModel genericRespModel = await apiClient.getJsonForObject( + token: t, + (json) => GenericRespModel.fromJson(json), + queryParameters: params, + ApiConsts.serviceProvidersAppointmentGet, + ); + List appointmentList = List.generate(genericRespModel.data.length, (index) => AppointmentListModel.fromJson(genericRespModel.data[index])); + return appointmentList; + } + @override Future> getMyAppointmentsForCustomersByFilters({ List? providerIdsList, @@ -246,8 +290,9 @@ class AppointmentRepoImp implements AppointmentRepo { } @override - Future getAppointmentSlots(Map map) async { + Future getAppointmentSlots({required int branchID, required String fromDate, required String toDate}) async { String t = appState.getUser.data!.accessToken ?? ""; + final map = {"ProviderBranchID": branchID.toString(), "FromDate": fromDate, "ToDate": toDate}; GenericRespModel adsGenericModel = await apiClient.getJsonForObject( (json) => GenericRespModel.fromJson(json), diff --git a/lib/repositories/branch_repo.dart b/lib/repositories/branch_repo.dart index 8443a6c..eb0e352 100644 --- a/lib/repositories/branch_repo.dart +++ b/lib/repositories/branch_repo.dart @@ -75,6 +75,8 @@ abstract class BranchRepo { Future updateServiceStatus({required int branchId, required List serviceIds, required ServiceStatusEnum serviceStatusEnum}); + Future updateCategoryStatus({required int branchId, required int categoryId, required ServiceStatusEnum serviceStatusEnum}); + Future> getAppointmentsByCategoryOrService({required int branchId, required int serviceId}); Future getMatchedServices(int oldBranchId, int newBranchId, int categoryId); @@ -237,7 +239,7 @@ class BranchRepoImp implements BranchRepo { GenericRespModel adsGenericModel = await apiClient.getJsonForObject( token: t, - (json) => GenericRespModel.fromJson(json), + (json) => GenericRespModel.fromJson(json), ApiConsts.serviceProviderDDLGet, ); List providersList = List.generate(adsGenericModel.data.length, (index) => ProviderBasicDataModel.fromJson(adsGenericModel.data[index])); @@ -269,8 +271,7 @@ class BranchRepoImp implements BranchRepo { serviceProviderBranchImages.add(imageMap); } - String lat = "0", - long = "0"; + String lat = "0", long = "0"; try { lat = latitude.toString().substring(0, 9); long = longitude.toString().substring(0, 9); @@ -333,6 +334,19 @@ class BranchRepoImp implements BranchRepo { return await apiClient.getJsonForObject((json) => GenericRespModel.fromJson(json), ApiConsts.serviceProviderServiceStatusUpdate, queryParameters: map, token: t); } + @override + Future updateCategoryStatus({required int branchId, required int categoryId, required ServiceStatusEnum serviceStatusEnum}) async { + int providerID = AppState().getUser.data!.userInfo!.providerId; + var map = { + "ServiceProviderID": providerID.toString(), + "ProviderBranchID": branchId.toString(), + "ServiceCategoryID": categoryId.toString(), + "Status": serviceStatusEnum.getIdFromServiceStatusEnum().toString(), + }; + String t = AppState().getUser.data!.accessToken ?? ""; + return await apiClient.getJsonForObject((json) => GenericRespModel.fromJson(json), ApiConsts.serviceProviderServiceStatusUpdate, queryParameters: map, token: t); + } + @override Future> getAppointmentsByCategoryOrService({required int branchId, required int serviceId}) async { var map = { @@ -342,7 +356,7 @@ class BranchRepoImp implements BranchRepo { String t = AppState().getUser.data!.accessToken ?? ""; GenericRespModel genericRespModel = await apiClient.getJsonForObject( - (json) => GenericRespModel.fromJson(json), + (json) => GenericRespModel.fromJson(json), ApiConsts.serviceProviderAppointmentGetByCategoryOrService, queryParameters: map, token: t, @@ -417,7 +431,7 @@ class BranchRepoImp implements BranchRepo { String t = AppState().getUser.data!.accessToken ?? ""; GenericRespModel adsGenericModel = await apiClient.getJsonForObject( - (json) => GenericRespModel.fromJson(json), + (json) => GenericRespModel.fromJson(json), ApiConsts.getAllNearBranches, token: appState.getUser.data!.accessToken, queryParameters: queryParameters, @@ -445,7 +459,7 @@ class BranchRepoImp implements BranchRepo { "longitude": longitude.toString(), }; GenericRespModel adsGenericModel = await apiClient.getJsonForObject( - (json) => GenericRespModel.fromJson(json), + (json) => GenericRespModel.fromJson(json), ApiConsts.getAllNearBranches, token: appState.getUser.data!.accessToken, queryParameters: queryParameters, @@ -457,7 +471,7 @@ class BranchRepoImp implements BranchRepo { @override Future> getMyRecentBranchesWithServices() async { GenericRespModel adsGenericModel = await apiClient.getJsonForObject( - (json) => GenericRespModel.fromJson(json), + (json) => GenericRespModel.fromJson(json), ApiConsts.getMyRecentBranches, token: appState.getUser.data!.accessToken, ); @@ -472,7 +486,7 @@ class BranchRepoImp implements BranchRepo { }; GenericRespModel adsGenericModel = await apiClient.getJsonForObject( - (json) => GenericRespModel.fromJson(json), + (json) => GenericRespModel.fromJson(json), ApiConsts.getServiceItems, token: appState.getUser.data!.accessToken, queryParameters: serviceId.toString() != "-1" ? queryParameters : null, @@ -492,7 +506,7 @@ class BranchRepoImp implements BranchRepo { postParams.addAll({"Latitude": "$latitude"}); } GenericRespModel adsGenericModel = - await apiClient.getJsonForObject((json) => GenericRespModel.fromJson(json), ApiConsts.branchesAndServices, token: appState.getUser.data!.accessToken, queryParameters: postParams); + await apiClient.getJsonForObject((json) => GenericRespModel.fromJson(json), ApiConsts.branchesAndServices, token: appState.getUser.data!.accessToken, queryParameters: postParams); return ProviderProfileModel.fromJson(adsGenericModel.data); } @@ -537,7 +551,7 @@ class BranchRepoImp implements BranchRepo { }; GenericRespModel adsGenericModel = await apiClient.getJsonForObject( - (json) => GenericRespModel.fromJson(json), + (json) => GenericRespModel.fromJson(json), ApiConsts.getAllNearBranches, token: appState.getUser.data!.accessToken, queryParameters: postParams, @@ -551,7 +565,7 @@ class BranchRepoImp implements BranchRepo { var postParams = {"ServiceProviderBranchID": serviceProviderBranchID.toString()}; GenericRespModel adsGenericModel = await apiClient.getJsonForObject( - (json) => GenericRespModel.fromJson(json), + (json) => GenericRespModel.fromJson(json), ApiConsts.getBranchRatings, token: appState.getUser.data!.accessToken, queryParameters: postParams, @@ -565,7 +579,7 @@ class BranchRepoImp implements BranchRepo { final customerID = appState.getUser.data!.userInfo!.customerId; final parameters = {"title": title, "review": review, "ratNo": ratingNo, "serviceProviderBranchID": serviceProviderBranchID, "customerID": "$customerID"}; GenericRespModel adsGenericModel = await apiClient.postJsonForObject( - (json) => GenericRespModel.fromJson(json), + (json) => GenericRespModel.fromJson(json), ApiConsts.createBranchRatings, parameters, token: appState.getUser.data!.accessToken, @@ -581,7 +595,7 @@ class BranchRepoImp implements BranchRepo { "customerID": customerID.toString(), }; GenericRespModel adsGenericModel = await apiClient.postJsonForObject( - (json) => GenericRespModel.fromJson(json), + (json) => GenericRespModel.fromJson(json), ApiConsts.favouriteServiceProviderCreate, parameters, token: appState.getUser.data!.accessToken, @@ -593,7 +607,7 @@ class BranchRepoImp implements BranchRepo { Future removeProviderFromFavourite({required int providerID}) async { final parameters = {"id": providerID.toString()}; GenericRespModel adsGenericModel = await apiClient.postJsonForObject( - (json) => GenericRespModel.fromJson(json), + (json) => GenericRespModel.fromJson(json), ApiConsts.unFavouriteServiceProvider, parameters, token: appState.getUser.data!.accessToken, @@ -608,7 +622,7 @@ class BranchRepoImp implements BranchRepo { var postParams = {"customerID": customerID.toString()}; GenericRespModel adsGenericModel = await apiClient.getJsonForObject( - (json) => GenericRespModel.fromJson(json), + (json) => GenericRespModel.fromJson(json), ApiConsts.favouriteServiceProviderGet, token: appState.getUser.data!.accessToken, queryParameters: postParams, diff --git a/lib/repositories/request_repo.dart b/lib/repositories/request_repo.dart index 4e26420..16c121b 100644 --- a/lib/repositories/request_repo.dart +++ b/lib/repositories/request_repo.dart @@ -63,7 +63,7 @@ abstract class RequestRepo { required String offerPrice, required bool isDeliveryAvailable, required String serviceItemName, - required int manufacturedById, + required String manufacturedByName, required String manufacturedOn, required List requestImages, required RequestOfferStatusEnum requestOfferStatusEnum, @@ -354,7 +354,7 @@ class RequestRepoImp implements RequestRepo { required String offerPrice, required bool isDeliveryAvailable, required String serviceItemName, - required int manufacturedById, + required String manufacturedByName, required String manufacturedOn, required List requestImages, required RequestOfferStatusEnum requestOfferStatusEnum, @@ -369,7 +369,7 @@ class RequestRepoImp implements RequestRepo { "serviceItem": serviceItemName, "comment": message, "price": offerPrice, - "offeredItemCreatedBy": manufacturedById.toString(), + "offeredItemCreatedBy": manufacturedByName.toString(), "offeredItemCreatedOn": manufacturedOn.toString(), "reqOfferImages": requestImages, "isDeliveryAvailable": isDeliveryAvailable diff --git a/lib/services/common_auth_service.dart b/lib/services/common_auth_service.dart index c1b5969..b4c7cad 100644 --- a/lib/services/common_auth_service.dart +++ b/lib/services/common_auth_service.dart @@ -6,7 +6,6 @@ import 'package:local_auth/local_auth.dart'; import 'package:local_auth_android/local_auth_android.dart'; import 'package:local_auth_darwin/types/auth_messages_ios.dart'; import 'package:mc_common_app/generated/locale_keys.g.dart'; -import 'package:mc_common_app/main.dart'; import 'package:easy_localization/easy_localization.dart'; abstract class CommonAuthServices { @@ -18,10 +17,11 @@ abstract class CommonAuthServices { class CommonAuthImp implements CommonAuthServices { final LocalAuthentication localAuth = LocalAuthentication(); + @override Future authenticate() async { try { final availableBiometrics = await localAuth.getAvailableBiometrics(); - if (availableBiometrics == null || availableBiometrics.isEmpty) { + if (availableBiometrics.isEmpty) { return false; } diff --git a/lib/services/common_services.dart b/lib/services/common_services.dart index ccc77ea..81f2e8c 100644 --- a/lib/services/common_services.dart +++ b/lib/services/common_services.dart @@ -58,8 +58,7 @@ class CommonServicesImp implements CommonAppServices { return pickedFiles; } - - + @override Future> pickMultipleImages() async { final picker = ImagePicker(); List imageModels = []; @@ -74,16 +73,16 @@ class CommonServicesImp implements CommonAppServices { return []; } - if (await element.length() > GlobalConsts().maxFileSizeInBytes) { + if (await element.length() > GlobalConsts.maxFileSizeInBytes) { Utils.showToast(LocaleKeys.maxFileSize); return []; } imageModels.add(File(element.path)); } - if (imageModels.length > GlobalConsts().maxFileCount) { + if (imageModels.length > GlobalConsts.maxFileCount) { Utils.showToast(LocaleKeys.maxFileSelection); - imageModels = imageModels.sublist(0, GlobalConsts().maxFileCount); // Keep only the first 7 images + imageModels = imageModels.sublist(0, GlobalConsts.maxFileCount); // Keep only the first 7 images } pickedImages.addAll(imageModels); @@ -120,7 +119,7 @@ class CommonServicesImp implements CommonAppServices { destLongitude, ); - return (distance / 1000) ?? 0.0; + return (distance / 1000); } catch (e) { logger.e(e.toString()); return 0.0; diff --git a/lib/utils/enums.dart b/lib/utils/enums.dart index cbb19c1..8370c45 100644 --- a/lib/utils/enums.dart +++ b/lib/utils/enums.dart @@ -13,10 +13,11 @@ class AppEnums { static const int requestFilterEnumId = 16; // Requests Filter Enums static const int branchServicesEnumId = 6; // Branch Services Filter Enums static const int myAdsFilterEnumId = 18; // My Ads Filter Enums - static const int exploreAdsFilterEnumId = 23; // Explore Ads Filter Enums + static const int adOwnersFilterEnumId = 23; // Explore Ads Filter Enums static const int appointmentsFilterEnumId = 13; // Appointments Filter Enums static const int requestStatusesFilterEnumId = 15; // Appointments Filter Enums static const int conditionEnumId = -1; // to get the Condition Filter Enums + static const int serviceDeliveryTypeEnumId = 24; // to get the serviceDeliveryType static const int shippingStatusEnumId = 30; // to get the Shipping Filter Enums } diff --git a/lib/view_models/ad_view_model.dart b/lib/view_models/ad_view_model.dart index af993de..0cd6a00 100644 --- a/lib/view_models/ad_view_model.dart +++ b/lib/view_models/ad_view_model.dart @@ -165,9 +165,8 @@ class AdVM extends BaseVM { notifyListeners(); } - List exploreAdsEnums = []; - - List myAdsEnums = []; + List myAdsStatusEnums = []; + List vehicleBrandsForFilters = []; List exploreAdsFilterOptions = []; List myAdsFilterOptions = []; @@ -177,60 +176,119 @@ class AdVM extends BaseVM { return; } - if (myAdsEnums.isEmpty) { - myAdsEnums = await commonRepo.getEnumTypeValues(enumTypeID: AppEnums.myAdsFilterEnumId); + if (myAdsStatusEnums.isEmpty) { + myAdsStatusEnums = await commonRepo.getEnumTypeValues(enumTypeID: AppEnums.myAdsFilterEnumId); } - if (exploreAdsEnums.isEmpty) { - exploreAdsEnums = await commonRepo.getEnumTypeValues(enumTypeID: AppEnums.exploreAdsFilterEnumId); + if (vehicleBrandsForFilters.isEmpty) { + vehicleBrandsForFilters = await commonRepo.getVehicleBrands(vehicleTypeId: -1); // to get all the brands } exploreAdsFilterOptions.clear(); myAdsFilterOptions.clear(); - for (int i = 0; i < myAdsEnums.length; i++) { - myAdsFilterOptions.add(FilterListModel(title: myAdsEnums[i].enumValueStr, isSelected: false, id: myAdsEnums[i].enumValue)); + for (int i = 0; i < myAdsStatusEnums.length; i++) { + myAdsFilterOptions.add(FilterListModel(title: myAdsStatusEnums[i].enumValueStr, isSelected: false, id: myAdsStatusEnums[i].enumValue)); } myAdsFilterOptions.insert(0, FilterListModel(title: "All Ads", isSelected: true, id: 0)); - log("myAdsFilterOptions: ${myAdsFilterOptions.last.id}"); - - for (int i = 0; i < exploreAdsEnums.length; i++) { - exploreAdsFilterOptions.add(FilterListModel(title: "${exploreAdsEnums[i].enumValueStr} Ads", isSelected: false, id: exploreAdsEnums[i].enumValue)); + for (int i = 0; i < vehicleBrandsForFilters.length; i++) { + exploreAdsFilterOptions.add(FilterListModel( + id: vehicleBrandsForFilters[i].id!, + title: "${vehicleBrandsForFilters[i].vehicleBrandDescription}", + iconUrl: "", + isSelected: false, + )); } exploreAdsFilterOptions.insert(0, FilterListModel(title: "All Ads", isSelected: true, id: 0)); notifyListeners(); } - applyFilterOnExploreAds({required CreatedByRoleEnum createdByRoleFilter}) async { + applyFilterOnExploreAds({required int vehicleBrandId}) async { + pageIndexForExploreAds = 1; + hasMoreDataForExploreAds = true; if (exploreAdsFilterOptions.isEmpty) return; - int index = exploreAdsFilterOptions.indexWhere((element) => element.id.toCreatedByRoleEnum() == createdByRoleFilter); + int index = exploreAdsFilterOptions.indexWhere((element) => element.id == vehicleBrandId); for (var value in exploreAdsFilterOptions) { value.isSelected = false; } exploreAdsFilterOptions[index].isSelected = true; - if (createdByRoleFilter == CreatedByRoleEnum.allAds) { + if (vehicleBrandId == 0) { + // all ads getExploreAds(); return; } setState(ViewState.busy); - exploreAdsFilteredList = await getAdsByFilter(createdByRoleEnum: createdByRoleFilter, isMyAds: false); + exploreAdsFilteredList = await getAdsByFilter(vehicleBrandId: vehicleBrandId, isMyAds: false); setState(ViewState.idle); notifyListeners(); } - int currentPageForExploreAds = 1; - int currentPageForMyAds = 1; + int pageIndexForExploreAds = 1; + int pageIndexForMyAds = 1; + bool hasMoreDataForExploreAds = true; + bool hasMoreDataForMyAds = true; bool isLoadingMore = false; - bool hasMoreData = true; - fetchMoreAds() async {} + Future fetchMoreExploreAds() async { + if (isLoadingMore) return; + isLoadingMore = true; + hasMoreDataForExploreAds = true; + notifyListeners(); + try { + final List newAds = await getAdsBasedOnFilters(pageIndex: pageIndexForExploreAds, isFromLazyLoad: true); + if (newAds.isEmpty) { + hasMoreDataForExploreAds = false; + } else { + exploreAdsFilteredList.addAll(newAds); + pageIndexForExploreAds++; + if (exploreAdsFilteredList.length < exploreAdsFilteredList.last.totalItemsCount!) { + hasMoreDataForExploreAds = true; + } else { + hasMoreDataForExploreAds = false; + } + } + } catch (error) { + isLoadingMore = false; + Utils.showToast(error.toString()); + } + isLoadingMore = false; + notifyListeners(); + } - Future> getAdsByFilter({AdPostStatus? adPostStatus, required bool isMyAds, CreatedByRoleEnum? createdByRoleEnum}) async { - return await adsRepo.getAllAds(isMyAds: isMyAds, adPostStatus: adPostStatus, createdByRoleEnum: createdByRoleEnum); + Future fetchMoreMyAds({required AdPostStatus adsStatus}) async { + if (isLoadingMore) return; + hasMoreDataForMyAds = true; + isLoadingMore = true; + notifyListeners(); + try { + final List newAds = await adsRepo.getAllAds(page: pageIndexForMyAds, isMyAds: true, adPostStatus: adsStatus); + if (newAds.isEmpty) { + hasMoreDataForMyAds = false; + } else { + myAdsFilteredList.addAll(newAds); + pageIndexForMyAds++; + if (myAdsFilteredList.length < myAdsFilteredList.last.totalItemsCount!) { + hasMoreDataForMyAds = true; + } else { + hasMoreDataForMyAds = false; + } + } + } catch (error) { + isLoadingMore = false; + Utils.showToast(error.toString()); + } + isLoadingMore = false; + notifyListeners(); + } + + Future> getAdsByFilter({AdPostStatus? adPostStatus, required bool isMyAds, CreatedByRoleEnum? createdByRoleEnum, int? vehicleBrandId}) async { + return await adsRepo.getAllAds(isMyAds: isMyAds, adPostStatus: adPostStatus, createdByRoleEnum: createdByRoleEnum, vehicleBrandId: vehicleBrandId); } applyFilterOnMyAds({required AdPostStatus adPostStatusEnum}) async { + pageIndexForMyAds = 1; + hasMoreDataForMyAds = true; if (myAdsFilterOptions.isEmpty) return; int index = myAdsFilterOptions.indexWhere((element) => element.id.toAdPostEnum() == adPostStatusEnum); @@ -265,7 +323,7 @@ class AdVM extends BaseVM { if (genericRespModel.messageStatus == null) { Utils.hideLoading(context); - Utils.showToast(genericRespModel.message ?? "Something went wrong!"); + Utils.showToast(genericRespModel.message ?? LocaleKeys.somethingWrong.tr()); return false; } Utils.hideLoading(context); @@ -273,6 +331,8 @@ class AdVM extends BaseVM { } Future getExploreAds() async { + pageIndexForExploreAds = 1; + hasMoreDataForExploreAds = true; setState(ViewState.busy); exploreAds = await adsRepo.getAllAds(isMyAds: false); exploreAdsFilteredList = exploreAds; @@ -281,6 +341,8 @@ class AdVM extends BaseVM { } Future getMyAds() async { + pageIndexForMyAds = 1; + hasMoreDataForMyAds = true; setState(ViewState.busy); myAds = await adsRepo.getAllAds(isMyAds: true); myAdsFilteredList = myAds; @@ -316,8 +378,8 @@ class AdVM extends BaseVM { notifyListeners(); } - Future getVehicleAdsSpecialServices() async { - vehicleAdsSpecialServices = await adsRepo.getSpecialServices(specialServiceType: 1); + Future getVehicleAdsSpecialServices({required int cityId, required int countryId, required int specialServiceType}) async { + vehicleAdsSpecialServices = await adsRepo.getSpecialServices(specialServiceType: specialServiceType, countryId: countryId, cityId: cityId); notifyListeners(); } @@ -1126,9 +1188,7 @@ class AdVM extends BaseVM { getVehicleAdsDuration(); } - if (vehicleAdsSpecialServices.isEmpty) { - getVehicleAdsSpecialServices(); - } + getVehicleAdsSpecialServices(countryId: vehicleCountryId.selectedId, cityId: vehicleCityId.selectedId, specialServiceType: 1); notifyListeners(); } @@ -1205,8 +1265,8 @@ class AdVM extends BaseVM { pickedPostingImages.addAll(imageModels); // Added By Aamir - if (pickedPostingImages.length > GlobalConsts().maxFileCount) { - pickedPostingImages = pickedPostingImages.sublist(0, GlobalConsts().maxFileCount); + if (pickedPostingImages.length > GlobalConsts.maxFileCount) { + pickedPostingImages = pickedPostingImages.sublist(0, GlobalConsts.maxFileCount); Utils.showToast(LocaleKeys.maxFileSelection); } @@ -1253,8 +1313,8 @@ class AdVM extends BaseVM { } else { vehicleDamageCards[index].partImages!.addAll(imageModels); // Added By Aamir - if (vehicleDamageCards[index].partImages!.length > GlobalConsts().maxFileCount) { - vehicleDamageCards[index].partImages = vehicleDamageCards[index].partImages!.sublist(0, GlobalConsts().maxFileCount); + if (vehicleDamageCards[index].partImages!.length > GlobalConsts.maxFileCount) { + vehicleDamageCards[index].partImages = vehicleDamageCards[index].partImages!.sublist(0, GlobalConsts.maxFileCount); Utils.showToast(LocaleKeys.maxFileSelection); } } @@ -1309,8 +1369,8 @@ class AdVM extends BaseVM { List images = await commonServices.pickMultipleImages(); pickedDamageImages.addAll(images); - if (pickedDamageImages.length > GlobalConsts().maxFileCount) { - pickedDamageImages = pickedDamageImages.sublist(0, GlobalConsts().maxFileCount); + if (pickedDamageImages.length > GlobalConsts.maxFileCount) { + pickedDamageImages = pickedDamageImages.sublist(0, GlobalConsts.maxFileCount); Utils.showToast(LocaleKeys.maxFileSelection); } if (pickedDamageImages.isNotEmpty) vehicleDamageImageError = ""; @@ -1596,20 +1656,32 @@ class AdVM extends BaseVM { // ************ ADS SEARCH VIEW **************** List vehicleConditionsEnum = []; + List adOwnerEnumsFilter = []; Future populateDataForAdFilter() async { setState(ViewState.busy); + pageIndexForExploreAds = 1; + pageIndexForMyAds = 1; + hasMoreDataForExploreAds = true; + hasMoreDataForMyAds = true; + isLoadingMore = false; + + if (adOwnerEnumsFilter.isEmpty) { + adOwnerEnumsFilter = await commonRepo.getEnumTypeValues(enumTypeID: AppEnums.adOwnersFilterEnumId); + } if (vehicleConditionsEnum.isEmpty) { vehicleConditionsEnum = await commonRepo.getEnumTypeValues(enumTypeID: AppEnums.conditionEnumId); } - if (vehicleBrands.isEmpty) { - vehicleBrands = await commonRepo.getVehicleBrands(vehicleTypeId: -1); + if (vehicleBrandsForFilters.isEmpty) { + vehicleBrandsForFilters = await commonRepo.getVehicleBrands(vehicleTypeId: -1); // to get all the brands } + if (vehicleModelYears.isEmpty) { vehicleModelYears = await commonRepo.getVehicleModelYears(vehicleTypeId: -1); } + vehicleCities = await commonRepo.getVehicleCities(countryId: -1); // fetch all the cities setState(ViewState.idle); } @@ -1678,9 +1750,9 @@ class AdVM extends BaseVM { SelectionModel vehicleOwnerId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); - void updateSelectionVehicleAdOwnerId(SelectionModel id, {bool isForSearch = false}) { + void updateSelectionVehicleAdOwnerId(SelectionModel id, {bool showSelectionInDropdown = true, bool isForSearch = false}) { if (isForSearch) { - EnumsModel owner = exploreAdsEnums.firstWhere((element) => element.enumValue == id.selectedId); + EnumsModel owner = adOwnerEnumsFilter.firstWhere((element) => element.enumValue == id.selectedId); DropValue ownerValue = DropValue(owner.enumValue, "${owner.enumValueStr} Ads", ""); if (!ifAlreadyExist(list: vehicleAdOwnerSearchHistory, value: ownerValue)) { addToVehicleAdOwnerSearchHistory(value: ownerValue); @@ -1688,7 +1760,9 @@ class AdVM extends BaseVM { notifyListeners(); return; } - vehicleOwnerId = id; + if (showSelectionInDropdown) { + vehicleOwnerId = id; + } notifyListeners(); } @@ -1819,9 +1893,14 @@ class AdVM extends BaseVM { vehicleOwnerId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); } - Future getAdsBasedOnFilters() async { - exploreAdsFilteredList.clear(); - setState(ViewState.busy); + Future> getAdsBasedOnFilters({ + required int pageIndex, + required bool isFromLazyLoad, + }) async { + if (!isFromLazyLoad) { + exploreAdsFilteredList.clear(); + setState(ViewState.busy); + } List cityIdsList = []; if (vehicleLocationAdSearchHistory.isNotEmpty) { for (var element in vehicleLocationAdSearchHistory) { @@ -1863,15 +1942,25 @@ class AdVM extends BaseVM { } } - exploreAdsFilteredList = await adsRepo.getExploreAdsBasedOnFilters( + List list = await adsRepo.getExploreAdsBasedOnFilters( cityIdsList: cityIdsList, createdByRolesIdsList: adOwnerIdsList, vehicleBrandIdsList: brandsIdsList, vehicleModelYearIdsList: vehicleYearIdsList, vehicleAdConditionIdsList: conditionsIdsList, vehicleAdCreatedDateList: createdDatesList, + page: pageIndex, ); - setState(ViewState.idle); + + if (!isFromLazyLoad) { + exploreAdsFilteredList.clear(); + exploreAdsFilteredList = list; + setState(ViewState.idle); + } else { + return list; + } + + return []; } void onEditUpdateAdPressed({required BuildContext context, required AdDetailsModel previousDetails, required bool isFromExtendAd}) { @@ -1962,7 +2051,9 @@ class AdVM extends BaseVM { updateSelectionVehicleConditionId(SelectionModel(selectedId: previousAdDetails!.vehicle!.condition!.id!, selectedOption: previousAdDetails!.vehicle!.condition!.label ?? "")); updateSelectionVehicleCategoryId(SelectionModel(selectedId: previousAdDetails!.vehicle!.category!.id!, selectedOption: previousAdDetails!.vehicle!.category!.label ?? "")); updateSelectionVehicleMileageId(SelectionModel( - selectedId: previousAdDetails!.vehicle!.mileage!.id!, selectedOption: "${previousAdDetails!.vehicle!.mileage!.mileageStart} - ${previousAdDetails!.vehicle!.mileage!.mileageEnd}")); + selectedId: previousAdDetails!.vehicle!.mileage!.id!, + selectedOption: "${previousAdDetails!.vehicle!.mileage!.mileageStart} - ${previousAdDetails!.vehicle!.mileage!.mileageEnd}", + )); updateSelectionVehicleTransmissionId(SelectionModel(selectedId: previousAdDetails!.vehicle!.transmission!.id!, selectedOption: previousAdDetails!.vehicle!.transmission!.label ?? "")); updateSelectionVehicleSellerTypeId(SelectionModel(selectedId: previousAdDetails!.vehicle!.sellertype!.id!, selectedOption: previousAdDetails!.vehicle!.sellertype!.label ?? "")); int indexCountry = vehicleCountries.indexWhere((element) => element.id == previousAdDetails!.vehicle!.countryID); diff --git a/lib/view_models/appointments_view_model.dart b/lib/view_models/appointments_view_model.dart index e5f6606..83bfa2a 100644 --- a/lib/view_models/appointments_view_model.dart +++ b/lib/view_models/appointments_view_model.dart @@ -55,20 +55,17 @@ class AppointmentsVM extends BaseVM { bool isUpcomingEnabled = true; bool isFetchingLists = false; - int selectedBranch = 0; int selectedAppointmentIndex = 0; int selectedAppointmentSubIndex = 0; int selectedAppointmentId = 0; + int selectedBranchIdForAppointments = 0; List myAppointments = []; List myUpComingAppointments = []; List myFilteredAppointments = []; List appointmentsFilterOptions = []; - List customersAppointments = []; List myFilteredAppointments2 = []; - // List availableSchedules = []; - bool isFetchingServices = false; List branchCategories = []; @@ -234,7 +231,6 @@ class AppointmentsVM extends BaseVM { Utils.showToast(genericRespModel.message.toString()); await getMyAppointmentsForCustomer(); Utils.hideLoading(context); - getMyAppointmentsForCustomer(); navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard); } } catch (e) { @@ -374,7 +370,7 @@ class AppointmentsVM extends BaseVM { // appointmentStatusEnum.getIdFromAppointmentStatusEnum()] // .isSelected = true; - if (appointmentStatusEnum.getIdFromAppointmentStatusEnum() == 0) { + if (appointmentStatusEnum == AppointmentStatusEnum.allAppointments) { myFilteredAppointments = myAppointments; if (isNeedCustomerFilter) findAppointmentsBasedOnCustomers(); notifyListeners(); @@ -459,10 +455,10 @@ class AppointmentsVM extends BaseVM { AppointmentSlots? appointmentSlots; - Future getAppointmentSlotsInfo({required Map map, required BuildContext context, bool isNeedToRebuild = false}) async { + Future getAppointmentSlotsInfo({required int branchID, required BuildContext context, bool isNeedToRebuild = false}) async { if (isNeedToRebuild) setState(ViewState.busy); try { - GenericRespModel genericRespModel = await appointmentRepo.getAppointmentSlots(map); + GenericRespModel genericRespModel = await appointmentRepo.getAppointmentSlots(branchID: branchID, fromDate: selectedDateForAppointments, toDate: selectedDateForAppointments); if (genericRespModel.messageStatus == 1) { appointmentSlots = AppointmentSlots.fromJson(genericRespModel.data); } else { @@ -473,9 +469,9 @@ class AppointmentsVM extends BaseVM { } } - Future getMyAppointmentsForProvider(Map map) async { + Future getMyAppointmentsForProvider({required int branchID}) async { setState(ViewState.busy); - myAppointments = await appointmentRepo.getMyAppointmentsForProvider(map); + myAppointments = await appointmentRepo.getMyAppointmentsForProvidersByFilters(branchID: branchID); myFilteredAppointments = myAppointments; myUpComingAppointments = myAppointments .where((element) => @@ -1272,6 +1268,21 @@ class AppointmentsVM extends BaseVM { return false; } + ifAlreadyExistForStringValue({required List list, required String value}) { + int index = list.indexWhere((element) { + log("element: $element"); + log("value: $value"); + + return element == value; + }); + + if (index != -1) { + return true; + } + + return false; + } + // Rating filter double branchFilterByRating = 4.0; @@ -1285,6 +1296,7 @@ class AppointmentsVM extends BaseVM { List providersDropList = []; List servicesDropList = []; List itemsDropList = []; + List serviceDeliveryTypesDropList = []; Future fetchAllProviders() async { if (providersDropList.isNotEmpty) return; @@ -1351,6 +1363,25 @@ class AppointmentsVM extends BaseVM { setState(ViewState.idle); } + Future fetchAllServiceDeliveryTypes() async { + if (serviceDeliveryTypesDropList.isNotEmpty) return; + serviceDeliveryTypesDropList.clear(); + setState(ViewState.busy); + + List enums = await commonRepo.getEnumTypeValues(enumTypeID: AppEnums.serviceDeliveryTypeEnumId); + + for (EnumsModel element in enums) { + serviceDeliveryTypesDropList.add( + DropValue( + element.enumValue, + element.enumValueStr, + "", + ), + ); + } + setState(ViewState.idle); + } + Future populateDataForBranchesFilter() async { await fetchAllProviders(); await fetchAllCategories(); @@ -1440,7 +1471,6 @@ class AppointmentsVM extends BaseVM { branchesDropList.add(DropValue(element.id ?? 0, element.branchName ?? "N/A", "")); } setState(ViewState.idle); - log("branchesDropList: ${branchesDropList.length}"); } @@ -1449,6 +1479,7 @@ class AppointmentsVM extends BaseVM { await fetchAllCategories(); await fetchAllServices(); await fetchAllItems(); + await fetchAllServiceDeliveryTypes(); } int appointmentFiltersCounter = 0; @@ -1661,15 +1692,132 @@ class AppointmentsVM extends BaseVM { notifyListeners(); } + // Customer Name Filter for PROVIDER ONLY + + List appointmentFilterCustomerNameSearchHistory = []; + String currentCustomerNameFilter = ''; + + void onCurrentCustomerNameFilterChanged(var value) { + currentCustomerNameFilter = value; + notifyListeners(); + } + + void removeAppointmentFilterCustomerNameSearchHistory({bool isClear = false, required int index}) { + if (isClear) { + appointmentFilterCustomerNameSearchHistory.clear(); + notifyListeners(); + return; + } + appointmentFilterCustomerNameSearchHistory.removeAt(index); + if (appointmentFilterCustomerNameSearchHistory.isEmpty) { + updateAppointmentFiltersCounter(appointmentFiltersCounter - 1); + // appointmentFilterSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); + } + notifyListeners(); + } + + void addAppointmentFilterCustomerNameSearchHistory({required String value}) { + if (appointmentFilterCustomerNameSearchHistory.isEmpty) { + updateAppointmentFiltersCounter(appointmentFiltersCounter + 1); + } + + if (!ifAlreadyExistForStringValue(list: appointmentFilterCustomerNameSearchHistory, value: value)) { + appointmentFilterCustomerNameSearchHistory.add(value); + currentCustomerNameFilter = ""; + } + notifyListeners(); + } + + // MOBILE PHONE Filter for PROVIDER ONLY + + String currentMobilePhoneFilter = ''; + + void onCurrentMobilePhoneFilterChanged(var value) { + currentMobilePhoneFilter = value; + notifyListeners(); + } + + List appointmentFilterMobilePhoneSearchHistory = []; + + void removeAppointmentFilterMobilePhoneSearchHistory({bool isClear = false, required int index}) { + if (isClear) { + appointmentFilterMobilePhoneSearchHistory.clear(); + notifyListeners(); + return; + } + appointmentFilterMobilePhoneSearchHistory.removeAt(index); + if (appointmentFilterMobilePhoneSearchHistory.isEmpty) { + updateAppointmentFiltersCounter(appointmentFiltersCounter - 1); + // appointmentFilterSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); + } + notifyListeners(); + } + + void addAppointmentFilterMobilePhoneSearchHistory({required String value}) { + if (appointmentFilterMobilePhoneSearchHistory.isEmpty) { + updateAppointmentFiltersCounter(appointmentFiltersCounter + 1); + } + + if (!ifAlreadyExistForStringValue(list: appointmentFilterMobilePhoneSearchHistory, value: value)) { + appointmentFilterMobilePhoneSearchHistory.add(value); + currentMobilePhoneFilter = ""; + } + notifyListeners(); + } + + // Service Delivery Types For PROVIDER ONLY + + List appointmentFilterServiceDeliverySearchHistory = []; + + void removeAppointmentFilterServiceDeliverySearchHistory({bool isClear = false, required int index}) { + if (isClear) { + appointmentFilterServiceDeliverySearchHistory.clear(); + notifyListeners(); + return; + } + appointmentFilterServiceDeliverySearchHistory.removeAt(index); + if (appointmentFilterServiceDeliverySearchHistory.isEmpty) { + updateAppointmentFiltersCounter(appointmentFiltersCounter - 1); + // appointmentFilterSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); + } + notifyListeners(); + } + + void addAppointmentFilterServiceDeliverySearchHistory({required DropValue value}) { + if (appointmentFilterServiceDeliverySearchHistory.isEmpty) { + updateAppointmentFiltersCounter(appointmentFiltersCounter + 1); + } + + appointmentFilterServiceDeliverySearchHistory.add(value); + notifyListeners(); + } + + SelectionModel appointmentFilterSelectedServiceDeliveryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); + + void updateAppointmentFilterSelectedServiceDeliveryId(SelectionModel id, {bool isForSearch = false}) async { + if (isForSearch) { + DropValue itemsDrop = serviceDeliveryTypesDropList.firstWhere((element) => element.id == id.selectedId); + if (!ifAlreadyExist(list: appointmentFilterServiceDeliverySearchHistory, value: itemsDrop)) { + addAppointmentFilterServiceDeliverySearchHistory(value: itemsDrop); + } + } + // appointmentFilterSelectedServiceId = id; + notifyListeners(); + } + void clearAppointmentFilterSelections() { appointmentFilterSelectedProviderId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); appointmentFilterSelectedCategoryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); appointmentFilterSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); appointmentFilterSelectedItemId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); + appointmentFilterSelectedServiceDeliveryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); appointmentFilterSelectedBranchId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); } void clearAppointmentFilters() { + appointmentFilterServiceDeliverySearchHistory.clear(); + appointmentFilterCustomerNameSearchHistory.clear(); + appointmentFilterMobilePhoneSearchHistory.clear(); appointmentFilterItemsSearchHistory.clear(); appointmentFilterServicesSearchHistory.clear(); appointmentFilterCategorySearchHistory.clear(); @@ -1677,11 +1825,16 @@ class AppointmentsVM extends BaseVM { appointmentFilterBranchSearchHistory.clear(); appointmentFiltersCounter = 0; clearAppointmentFilterSelections(); - getMyAppointmentsForCustomer(); + + if (AppState().currentAppType == AppType.provider) { + getMyAppointmentsForProvider(branchID: selectedBranchIdForAppointments); + } else { + getMyAppointmentsForCustomer(); + } notifyListeners(); } - Future getAppointmentsBasedOnFilters() async { + Future getAppointmentsBasedOnFiltersForCustomer() async { setState(ViewState.busy); List providersIdsList = []; if (appointmentFilterProviderSearchHistory.isNotEmpty) { @@ -1725,6 +1878,56 @@ class AppointmentsVM extends BaseVM { setState(ViewState.idle); } + String selectedDateForAppointments = ""; + + Future getAppointmentsBasedOnFiltersForProviders({required int branchID}) async { + setState(ViewState.busy); + + List servicesIdsList = []; + if (appointmentFilterServicesSearchHistory.isNotEmpty) { + for (var element in appointmentFilterServicesSearchHistory) { + servicesIdsList.add(element.id.toString()); + } + } + + List customerNamesList = []; + if (appointmentFilterCustomerNameSearchHistory.isNotEmpty) { + for (var element in appointmentFilterCustomerNameSearchHistory) { + customerNamesList.add(element.toString()); + } + } + + List customerPhonesList = []; + if (appointmentFilterMobilePhoneSearchHistory.isNotEmpty) { + for (var element in appointmentFilterMobilePhoneSearchHistory) { + customerPhonesList.add(element.toString()); + } + } + List customerDeliveryTypesList = []; + if (appointmentFilterServiceDeliverySearchHistory.isNotEmpty) { + for (var element in appointmentFilterServiceDeliverySearchHistory) { + customerDeliveryTypesList.add(element.id.toString()); + } + } + + log("customerNamesList: $customerNamesList"); + log("customerPhonesList: $customerPhonesList"); + log("customerDeliveryTypesList: $customerDeliveryTypesList"); + log("servicesIdsList: $servicesIdsList"); + myAppointments = await appointmentRepo.getMyAppointmentsForProvidersByFilters( + branchID: branchID, + customerNamesList: customerNamesList, + customerPhonesList: customerPhonesList, + deliveryTypeIdsList: customerDeliveryTypesList, + serviceProviderServiceIdsList: servicesIdsList, + fromDate: selectedDateForAppointments, + toDate: selectedDateForAppointments); + + log(" myFilteredAppointments : ${myFilteredAppointments.length}"); + applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.allAppointments, isNeedCustomerFilter: true); + setState(ViewState.idle); + } + Future addProviderToFavorite({required int serviceProviderID, required BuildContext context}) async { Utils.showLoading(context); try { diff --git a/lib/view_models/chat_view_model.dart b/lib/view_models/chat_view_model.dart index 763b0d3..20bbc7e 100644 --- a/lib/view_models/chat_view_model.dart +++ b/lib/view_models/chat_view_model.dart @@ -97,8 +97,8 @@ class ChatVM extends BaseVM { notifyListeners(); } - List indexesForCancelSpecialCarOffer = [0, 1, 5, 6, 10]; - List indexesForCancelSparePartOffer = [2, 5, 6, 10]; + List indexesForCancelSpecialCarOffer = [0, 1, 6, 10]; + List indexesForCancelSparePartOffer = [2, 10]; List indexesForRejectOffer = [3, 4, 10]; List indexesForDealNotCompleted = [7, 4, 8, 9, 10]; @@ -363,7 +363,7 @@ class ChatVM extends BaseVM { required String offerPrice, required bool isDeliveryAvailable, required String serviceItemName, - required int manufacturedById, + required String manufacturedByName, required String manufacturedOn, required List offerImages, required BuildContext context, @@ -387,7 +387,7 @@ class ChatVM extends BaseVM { "IsDeliveryAvailable": isDeliveryAvailable, "ServiceItem": serviceItemName, "ReqOfferImages": offerImages, - "OfferedItemCreatedBy": manufacturedById, // TODO: The ID should be used from the manufacturer database + "OfferedItemCreatedBy": manufacturedByName, // "OfferedItemCreatedOn": manufacturedOn, // TODO: This should be in String on Server, Right now it is in DateTime "ServiceProviderID": providerId, "OfferStatus": RequestOfferStatusEnum.offer.getIdFromRequestOfferStatusEnum(), @@ -443,8 +443,8 @@ class ChatVM extends BaseVM { imageModels.add(ImageModel(filePath: element.path, isFromNetwork: false)); } pickedImagesForMessage.addAll(imageModels); - if (pickedImagesForMessage.length > GlobalConsts().maxFileCount) { - pickedImagesForMessage = pickedImagesForMessage.sublist(0, GlobalConsts().maxFileCount); + if (pickedImagesForMessage.length > GlobalConsts.maxFileCount) { + pickedImagesForMessage = pickedImagesForMessage.sublist(0, GlobalConsts.maxFileCount); Utils.showToast(LocaleKeys.maxFileSelection); } @@ -652,7 +652,7 @@ class ChatVM extends BaseVM { required int requestOfferID, required String offerPrice, required String serviceItemName, - required int manufacturedById, + required String manufacturedByName, required String manufacturedOn, required RequestOfferStatusEnum requestOfferStatusEnum, required BuildContext context, @@ -674,8 +674,8 @@ class ChatVM extends BaseVM { "RequestID": requestId, "Price": double.parse(offerPrice), "ServiceItem": serviceItemName, - "OfferedItemCreatedBy": manufacturedById, // TODO: The ID should be used from the manufacturer database - // "OfferedItemCreatedOn": manufacturedOn, // TODO: This should be in String on Server, Right now it is in DateTime + "OfferedItemCreatedBy": manufacturedByName, + // "OfferedItemCreatedOn": manufacturedOn, "ServiceProviderID": serviceProviderID, "OfferStatus": requestOfferStatusEnum.getIdFromRequestOfferStatusEnum(), "Comment": comments, diff --git a/lib/view_models/dashboard_view_model_provider.dart b/lib/view_models/dashboard_view_model_provider.dart index afc0755..b43e2d5 100644 --- a/lib/view_models/dashboard_view_model_provider.dart +++ b/lib/view_models/dashboard_view_model_provider.dart @@ -83,7 +83,7 @@ class DashboardVMProvider extends BaseVM { shippingManagementVM.populateShippingRequestFilterList(); await serviceVM.getBranchAndServices(); await serviceVM.populateBranchServiceFilters(); - await appointmentVM.getMyAppointmentsForProvider({"ServiceProviderID": injector.get().getUser.data?.userInfo?.providerId.toString() ?? "0"}); + await appointmentVM.getMyAppointmentsForProvider(branchID: appointmentVM.selectedBranchIdForAppointments); adVM.populateAdsFilterList(); await subscriptionsVM.getSubscriptionBySP(AppState().getUser.data?.userInfo?.providerId.toString() ?? "", true); if (dashboardRouteEnum != DashboardRouteEnum.fromAdsPayment && dashboardRouteEnum != DashboardRouteEnum.fromAdsSubmit) { diff --git a/lib/view_models/requests_view_model.dart b/lib/view_models/requests_view_model.dart index 282c282..d502c99 100644 --- a/lib/view_models/requests_view_model.dart +++ b/lib/view_models/requests_view_model.dart @@ -39,7 +39,6 @@ class RequestsVM extends BaseVM { RequestsVM({required this.commonServices, required this.commonRepo, required this.requestRepo}); - List myRequests = []; List myFilteredRequests = []; List requestsTypeFilterOptions = []; @@ -92,8 +91,39 @@ class RequestsVM extends BaseVM { setState(ViewState.idle); } + int pageIndexForRequests = 1; + bool hasMoreDataRequests = true; + bool isLoadingMore = false; + + // Future fetchMoreRequests() async { + // log("isLoadingMore: $isLoadingMore"); + // log("hasMoreDataRequests: $hasMoreDataRequests"); + // if (isLoadingMore) return; + // isLoadingMore = true; + // hasMoreDataRequests = true; + // notifyListeners(); + // try { + // final List newRequests = await requestRepo.getRequestsBasedOnFilters(requestedDate: requestedDateFilter, requestTypeId: requestTypeId); + // if (newAds.isEmpty) { + // hasMoreDataForExploreAds = false; + // } else { + // exploreAdsFilteredList.addAll(newAds); + // pageIndexForExploreAds++; + // if (exploreAdsFilteredList.length < exploreAdsFilteredList.last.totalItemsCount!) { + // hasMoreDataForExploreAds = true; + // } else { + // hasMoreDataForExploreAds = false; + // } + // } + // } catch (error) { + // isLoadingMore = false; + // Utils.showToast(error.toString()); + // } + // isLoadingMore = false; + // notifyListeners(); + // } + Future getRequestsBasedOnFilters() async { - myFilteredRequests.clear(); setState(ViewState.busy); int requestTypeIdApi = requestsTypeFilterOptions.firstWhere((element) => element.isSelected).id; @@ -127,7 +157,7 @@ class RequestsVM extends BaseVM { ); setState(ViewState.idle); return true; - } catch (e, s) { + } catch (e) { logger.i("e: ${e.toString()}"); setState(ViewState.idle); return false; @@ -186,7 +216,7 @@ class RequestsVM extends BaseVM { } overwriteChatMessagesInRequestsModel({required List messages, required int index, required BuildContext context}) { - myFilteredRequests[index].chatMessages.clear(); + if (myFilteredRequests.isEmpty) return; myFilteredRequests[index].chatMessages = messages; if (myFilteredRequests[index].chatMessages.isNotEmpty) { for (var message in myFilteredRequests[index].chatMessages) { @@ -237,8 +267,8 @@ class RequestsVM extends BaseVM { imageModels.add(ImageModel(filePath: element.path, isFromNetwork: false)); } pickedVehicleImages.addAll(imageModels); - if (pickedVehicleImages.length > GlobalConsts().maxFileCount) { - pickedVehicleImages = pickedVehicleImages.sublist(0, GlobalConsts().maxFileCount); + if (pickedVehicleImages.length > GlobalConsts.maxFileCount) { + pickedVehicleImages = pickedVehicleImages.sublist(0, GlobalConsts.maxFileCount); Utils.showToast(LocaleKeys.maxFileSelection); } @@ -246,8 +276,6 @@ class RequestsVM extends BaseVM { notifyListeners(); } - - bool isFetchingRequestType = false; bool isFetchingVehicleType = true; bool isFetchingVehicleDetail = false; @@ -914,7 +942,7 @@ class RequestsVM extends BaseVM { return genericRespModel.messageStatus == 1; } catch (e) { logger.i(e.toString()); - // Utils.showToast(e.toString()); + Utils.showToast(e.toString()); if (needLoading) { Utils.hideLoading(context); } @@ -933,7 +961,7 @@ class RequestsVM extends BaseVM { offerPriceError = ""; } - if (offerDescription.isEmpty) { + if (offerDescription.isEmpty || offerDescription.length < 5) { offerDescriptionError = GlobalConsts.descriptionError; isValidated = false; notifyListeners(); @@ -1022,7 +1050,7 @@ class RequestsVM extends BaseVM { required String offerPrice, required bool isDeliveryAvailable, required String serviceItemName, - required int manufacturedById, + required String manufacturedByName, required String manufacturedOn, required int receiverId, required int customerRequestIndex, @@ -1044,7 +1072,7 @@ class RequestsVM extends BaseVM { offerPrice: offerPrice, isDeliveryAvailable: isDeliveryAvailable, serviceItemName: serviceItemName, - manufacturedById: manufacturedById, + manufacturedByName: manufacturedByName, manufacturedOn: manufacturedOn, requestImages: offerImages, requestOfferStatusEnum: RequestOfferStatusEnum.offer, @@ -1068,7 +1096,7 @@ class RequestsVM extends BaseVM { pop(context); } } - } catch (e, s) { + } catch (e) { Utils.hideLoading(context); log(e.toString()); Utils.showToast(e.toString()); @@ -1082,7 +1110,7 @@ class RequestsVM extends BaseVM { required int requestId, required String offerPrice, required String serviceItemName, - required int manufacturedById, + required String manufacturedByName, required String manufacturedOn, required RequestModel requestModel, required bool isDeliveryAvailable, @@ -1105,7 +1133,7 @@ class RequestsVM extends BaseVM { requestId: requestId, offerPrice: offerPrice, isDeliveryAvailable: isDeliveryAvailable, - manufacturedById: manufacturedById, + manufacturedByName: manufacturedByName, manufacturedOn: manufacturedOn, serviceItemName: serviceItemName, offerImages: offerImages, @@ -1139,7 +1167,7 @@ class RequestsVM extends BaseVM { requestID: requestModel.id, price: double.parse(offerPrice), isDeliveryAvailable: isDeliveryAvailable, - manufacturedById: manufacturedById, + manufacturedByName: manufacturedByName, manufacturedOn: manufacturedOn, serviceItemName: serviceItemName, requestOfferStatusEnum: RequestOfferStatusEnum.offer, diff --git a/lib/view_models/service_view_model.dart b/lib/view_models/service_view_model.dart index 75c5109..c29faec 100644 --- a/lib/view_models/service_view_model.dart +++ b/lib/view_models/service_view_model.dart @@ -140,8 +140,8 @@ class ServiceVM extends BaseVM { imageModels.add(ImageModel(filePath: element.path, isFromNetwork: false)); } pickedBranchImages.addAll(imageModels); - if (pickedBranchImages.length > GlobalConsts().maxFileCount) { - pickedBranchImages = pickedBranchImages.sublist(0, GlobalConsts().maxFileCount); + if (pickedBranchImages.length > GlobalConsts.maxFileCount) { + pickedBranchImages = pickedBranchImages.sublist(0, GlobalConsts.maxFileCount); Utils.showToast(LocaleKeys.maxFileSelection); } if (pickedBranchImages.isNotEmpty) branchImageError = ""; @@ -168,7 +168,6 @@ class ServiceVM extends BaseVM { final BranchDetailModel currentBranch = branches!.data!.serviceProviderBranch!.firstWhere((element) => element.id == selectedBranchId); for (var element in currentBranch.branchServices!) { - // TODO: Here , we need to add the category deactivated status. categories.add( CategoryData( id: element.categoryId, @@ -567,6 +566,25 @@ class ServiceVM extends BaseVM { } } + Future updateCategoryStatus({required BuildContext context, required ServiceStatusEnum serviceStatusEnum, required int branchId, required int categoryId}) async { + try { + Utils.showLoading(context); + GenericRespModel genericRespModel = await branchRepo.updateCategoryStatus( + branchId: branchId, + categoryId: categoryId, + serviceStatusEnum: serviceStatusEnum, + ); + Utils.hideLoading(context); + Utils.showToast(genericRespModel.message ?? ""); + return genericRespModel.messageStatus == 1; + } catch (e) { + Utils.hideLoading(context); + log(e.toString()); + Utils.showToast(e.toString()); + return false; + } + } + Future buildDealNotCompletedBottomSheetOptions({required BuildContext mainContext, required List appointments, required String branchName}) async { return actionConfirmationBottomSheet( isOnlyOneButton: true, @@ -628,6 +646,7 @@ class ServiceVM extends BaseVM { } List? matchedServices; + bool isAllSelected = false; Future getAllMatchedServices({required int oldBranchId, required int newBranchId, required int categoryId}) async { diff --git a/lib/views/advertisement/ads_detail_view/components.dart b/lib/views/advertisement/ads_detail_view/components.dart index fd3be94..dc379f6 100644 --- a/lib/views/advertisement/ads_detail_view/components.dart +++ b/lib/views/advertisement/ads_detail_view/components.dart @@ -294,7 +294,7 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget { adVM.state == ViewState.busy ? const Center(child: CircularProgressIndicator()) : adVM.photoSSSchedulesByOffices.isEmpty - ? LocaleKeys.noAvailableOfficesInCity.tr().toText(fontSize: 14, height: 1.2) + ? LocaleKeys.noAvailableOfficesInCity.tr().toText(fontSize: 14, height: 1.2, color: MyColors.lightTextColor) : Builder( builder: (context) { List vehicleCitiesDrop = []; diff --git a/lib/views/advertisement/ads_filter_view.dart b/lib/views/advertisement/ads_filter_view.dart index 479195b..f1fbaeb 100644 --- a/lib/views/advertisement/ads_filter_view.dart +++ b/lib/views/advertisement/ads_filter_view.dart @@ -78,13 +78,13 @@ class _AdsFilterViewState extends State { SearchEntityWidget( title: LocaleKeys.searchByCity.tr(), actionWidget: Builder(builder: (context) { - List vehicleBrandsDrop = []; + List vehicleCitiesDrop = []; for (var element in adVM.vehicleCities) { - vehicleBrandsDrop.add(DropValue(element.id?.toInt() ?? 0, element.cityName ?? "", "")); + vehicleCitiesDrop.add(DropValue(element.id?.toInt() ?? 0, element.cityName ?? "", "")); } return DropdownField( (DropValue value) => adVM.updateSelectionVehicleCityId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true), - list: vehicleBrandsDrop, + list: vehicleCitiesDrop, dropdownValue: adVM.vehicleCityId.selectedId != -1 ? DropValue(adVM.vehicleCityId.selectedId, adVM.vehicleCityId.selectedOption, "") : null, hint: LocaleKeys.selectCity.tr(), errorValue: adVM.vehicleCityId.errorValue, @@ -99,7 +99,7 @@ class _AdsFilterViewState extends State { title: LocaleKeys.searchByBrandName.tr(), actionWidget: Builder(builder: (context) { List vehicleBrandsDrop = []; - for (var element in adVM.vehicleBrands) { + for (var element in adVM.vehicleBrandsForFilters) { vehicleBrandsDrop.add(DropValue(element.id?.toInt() ?? 0, element.vehicleBrandDescription ?? "", "")); } return DropdownField( @@ -160,6 +160,29 @@ class _AdsFilterViewState extends State { onHistoryItemTapped: (DropValue value) => null, ), const Divider(thickness: 1.2).paddingOnly(top: 7, bottom: 7), + SearchEntityWidget( + title: LocaleKeys.searchByAdOwner.tr(), + actionWidget: Builder( + builder: (context) { + List vehicleOwnerDrop = []; + for (var element in adVM.adOwnerEnumsFilter) { + vehicleOwnerDrop.add(DropValue(element.enumValue.toInt(), element.enumValueStr, "")); + } + return DropdownField( + (DropValue value) => + adVM.updateSelectionVehicleAdOwnerId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true, showSelectionInDropdown: false), + list: vehicleOwnerDrop, + dropdownValue: adVM.vehicleOwnerId.selectedId != -1 ? DropValue(adVM.vehicleOwnerId.selectedId, adVM.vehicleOwnerId.selectedOption, "") : null, + hint: LocaleKeys.selectOwner.tr(), + errorValue: adVM.vehicleOwnerId.errorValue, + ); + }, + ), + historyContent: adVM.vehicleAdOwnerSearchHistory, + onHistoryItemDeleted: (index) => adVM.removeVehicleAdOwnerSearchHistory(index: index), + onHistoryItemTapped: (DropValue value) => null, + ), + const Divider(thickness: 1.2).paddingOnly(top: 7, bottom: 7), SearchEntityWidget( title: LocaleKeys.searchByCreatedDate.tr(), actionWidget: TxtField( @@ -197,7 +220,7 @@ class _AdsFilterViewState extends State { title: LocaleKeys.search.tr(), onPressed: () { Navigator.pop(context); - adVM.getAdsBasedOnFilters(); + adVM.getAdsBasedOnFilters(isFromLazyLoad: false, pageIndex: 0); }, backgroundColor: MyColors.darkPrimaryColor, txtColor: MyColors.white, diff --git a/lib/views/advertisement/components/ads_list_widget.dart b/lib/views/advertisement/components/ads_list_widget.dart index fff78fb..d3fce48 100644 --- a/lib/views/advertisement/components/ads_list_widget.dart +++ b/lib/views/advertisement/components/ads_list_widget.dart @@ -10,6 +10,7 @@ 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/advertisment_models/ad_details_model.dart'; import 'package:mc_common_app/theme/colors.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/ad_view_model.dart'; @@ -21,12 +22,14 @@ class AdsListWidget extends StatelessWidget { final ScrollPhysics? scrollPhysics; final bool isAdsFragment; final bool shouldShowAdStatus; + final bool hasMoreData; final Function()? onFetchMoreAds; const AdsListWidget({ super.key, required this.adsList, required this.shouldShowAdStatus, + required this.hasMoreData, this.onFetchMoreAds, this.scrollPhysics, this.isAdsFragment = false, @@ -44,7 +47,8 @@ class AdsListWidget extends StatelessWidget { } return NotificationListener( onNotification: (ScrollNotification scrollInfo) { - if (scrollInfo.metrics.pixels == scrollInfo.metrics.maxScrollExtent && context.read().hasMoreData) { + log("hasMoreData: $hasMoreData"); + if (scrollInfo.metrics.pixels == scrollInfo.metrics.maxScrollExtent && hasMoreData) { if (onFetchMoreAds != null) { onFetchMoreAds!(); } @@ -104,7 +108,9 @@ class AdCard extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, children: [ - if (isAdsFragment && !context.read().isExploreAdsTapped) ...[ + if (isAdsFragment && adDetails.adPostStatus! == AdPostStatus.sold) ...[ + Utils.statusContainerChip(text: adDetails.statuslabel!, chipColor: Utils.getChipColorByAdStatus(adDetails.adPostStatus!)), + ] else if (isAdsFragment && !context.read().isExploreAdsTapped) ...[ Utils.statusContainerChip(text: adDetails.statuslabel!, chipColor: Utils.getChipColorByAdStatus(adDetails.adPostStatus!)), ], (adDetails.vehicle!.vehicleTitle ?? "").toText( diff --git a/lib/views/appointments/appointments_filter_view.dart b/lib/views/appointments/appointments_filter_view.dart index 3523174..3ac7b7c 100644 --- a/lib/views/appointments/appointments_filter_view.dart +++ b/lib/views/appointments/appointments_filter_view.dart @@ -1,7 +1,9 @@ import 'dart:async'; +import 'dart:developer'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; +import 'package:mc_common_app/classes/app_state.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'; @@ -16,6 +18,7 @@ import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; import 'package:mc_common_app/widgets/common_widgets/search_entity_widget.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'; import 'package:provider/provider.dart'; import 'package:sizer/sizer.dart'; @@ -33,6 +36,7 @@ class _AppointmentsFilterViewState extends State { void initState() { appointmentsVM = context.read(); scheduleMicrotask(() async { + log('herre called'); await appointmentsVM.populateDataForAppointmentsFilter(); }); super.initState(); @@ -44,6 +48,21 @@ class _AppointmentsFilterViewState extends State { super.dispose(); } + // Provider filters + + // * Service + // * Customer name + // * Mobile number + // * Type of service Delivery + + // Customer filters + + // * Provider + // * Branch + // * Category + // * Service + // * Item + @override Widget build(BuildContext context) { return Scaffold( @@ -59,96 +78,154 @@ class _AppointmentsFilterViewState extends State { ), body: Consumer( builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) { - return WillPopScope( - onWillPop: () async { - context.read().resetValues(); - return true; + return PopScope( + onPopInvokedWithResult: (bool result, dynamic) { + if (result) { + context.read().resetValues(); + } }, child: Column( children: [ ListView( children: [ 20.height, - SearchEntityWidget( - title: LocaleKeys.searchByProvider.tr(), - actionWidget: Builder( - builder: (context) { - return DropdownField( - (DropValue value) => appointmentsVM.updateAppointmentFilterSelectedProviderId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true), - list: appointmentsVM.providersDropList, - dropdownValue: appointmentsVM.appointmentFilterSelectedProviderId.selectedId != -1 - ? DropValue(appointmentsVM.appointmentFilterSelectedProviderId.selectedId, appointmentsVM.appointmentFilterSelectedProviderId.selectedOption, "") - : null, - hint: LocaleKeys.selectProvider.tr(), - ); + if (AppState().currentAppType == AppType.provider) ...[ + SearchEntityWidget( + title: LocaleKeys.searchByCustomerName.tr(), + isForString: true, + actionWidget: TxtField( + value: appointmentsVM.currentCustomerNameFilter, + onChanged: (value) => appointmentsVM.onCurrentCustomerNameFilterChanged(value), + hint: LocaleKeys.enterCustomerName.tr(), + postfixWidget: Consumer( + builder: (BuildContext context, AppointmentsVM appointmentVm, Widget? child) { + if (appointmentsVM.currentCustomerNameFilter.isEmpty) { + return const SizedBox(); + } + return IconButton( + onPressed: () => appointmentsVM.addAppointmentFilterCustomerNameSearchHistory(value: appointmentsVM.currentCustomerNameFilter), + icon: const Icon(Icons.done, color: MyColors.lightIconColor), + ); + }, + ), + ), + historyContentString: appointmentsVM.appointmentFilterCustomerNameSearchHistory, + onHistoryItemDeleted: (index) { + appointmentsVM.removeAppointmentFilterCustomerNameSearchHistory(index: index); }, + onHistoryItemTapped: (DropValue value) => null, + historyContent: const [], // ignore in the case of TEXT FIELD ), - historyContent: appointmentsVM.appointmentFilterProviderSearchHistory, - onHistoryItemDeleted: (index) { - appointmentsVM.removeAppointmentFilterProviderSearchHistory(index: index); - }, - onHistoryItemTapped: (DropValue value) => - appointmentsVM.updateAppointmentFilterSelectedProviderId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true), - ), - if (appointmentsVM.state == ViewState.busy) ...[ - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SizedBox( - height: 5.h, - width: 5.h, - child: const CircularProgressIndicator(), + const Divider(thickness: 1.2).paddingOnly(top: 5, bottom: 5), + SearchEntityWidget( + title: LocaleKeys.searchByMobileNumber.tr(), + isForString: true, + actionWidget: TxtField( + onChanged: (value) => appointmentsVM.onCurrentMobilePhoneFilterChanged(value), + value: appointmentsVM.currentMobilePhoneFilter, + hint: LocaleKeys.enterMobileNumber.tr(), + postfixWidget: Consumer( + builder: (BuildContext context, AppointmentsVM appointmentVm, Widget? child) { + if (appointmentsVM.currentMobilePhoneFilter.isEmpty) { + return const SizedBox(); + } + return IconButton( + onPressed: () => appointmentsVM.addAppointmentFilterMobilePhoneSearchHistory(value: appointmentsVM.currentMobilePhoneFilter), + icon: const Icon(Icons.done, color: MyColors.lightIconColor), + ); + }, ), - ], + ), + historyContentString: appointmentsVM.appointmentFilterMobilePhoneSearchHistory, + onHistoryItemDeleted: (index) { + appointmentsVM.removeAppointmentFilterMobilePhoneSearchHistory(index: index); + }, + onHistoryItemTapped: (DropValue value) => null, + historyContent: const [], // ignore in the case of TEXT FIELD ), - ], - if (appointmentsVM.appointmentFilterProviderSearchHistory.isNotEmpty) ...[ const Divider(thickness: 1.2).paddingOnly(top: 5, bottom: 5), + ] else ...[ SearchEntityWidget( - title: LocaleKeys.searchByBranch.tr(), + title: LocaleKeys.searchByProvider.tr(), actionWidget: Builder( builder: (context) { return DropdownField( - (DropValue value) => appointmentsVM.updateAppointmentFilterSelectedBranchId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true), - list: appointmentsVM.branchesDropList, - dropdownValue: appointmentsVM.appointmentFilterSelectedBranchId.selectedId != -1 - ? DropValue(appointmentsVM.appointmentFilterSelectedBranchId.selectedId, appointmentsVM.appointmentFilterSelectedBranchId.selectedOption, "") + (DropValue value) => appointmentsVM.updateAppointmentFilterSelectedProviderId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true), + list: appointmentsVM.providersDropList, + dropdownValue: appointmentsVM.appointmentFilterSelectedProviderId.selectedId != -1 + ? DropValue(appointmentsVM.appointmentFilterSelectedProviderId.selectedId, appointmentsVM.appointmentFilterSelectedProviderId.selectedOption, "") : null, - hint: LocaleKeys.selectBranch.tr(), + hint: LocaleKeys.selectProvider.tr(), ); }, ), - historyContent: appointmentsVM.appointmentFilterBranchSearchHistory, + historyContent: appointmentsVM.appointmentFilterProviderSearchHistory, onHistoryItemDeleted: (index) { - appointmentsVM.removeAppointmentFilterBranchSearchHistory(index: index); + appointmentsVM.removeAppointmentFilterProviderSearchHistory(index: index); }, onHistoryItemTapped: (DropValue value) => - appointmentsVM.updateAppointmentFilterSelectedBranchId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true), + appointmentsVM.updateAppointmentFilterSelectedProviderId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true), ), - ], - const Divider(thickness: 1.2).paddingOnly(top: 5, bottom: 5), - SearchEntityWidget( - title: LocaleKeys.searchByCategory.tr(), - actionWidget: Builder( - builder: (context) { - return DropdownField( - (DropValue value) => appointmentsVM.updateAppointmentFilterSelectedCategoryId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true), - list: appointmentsVM.categoryDropList, - dropdownValue: appointmentsVM.appointmentFilterSelectedCategoryId.selectedId != -1 - ? DropValue(appointmentsVM.appointmentFilterSelectedCategoryId.selectedId, appointmentsVM.appointmentFilterSelectedCategoryId.selectedOption, "") - : null, - hint: LocaleKeys.selectCategory.tr(), - ); + if (appointmentsVM.state == ViewState.busy) ...[ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox( + height: 5.h, + width: 5.h, + child: const CircularProgressIndicator(), + ), + ], + ), + ], + if (appointmentsVM.appointmentFilterProviderSearchHistory.isNotEmpty) ...[ + const Divider(thickness: 1.2).paddingOnly(top: 5, bottom: 5), + SearchEntityWidget( + title: LocaleKeys.searchByBranch.tr(), + actionWidget: Builder( + builder: (context) { + return DropdownField( + (DropValue value) => appointmentsVM.updateAppointmentFilterSelectedBranchId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true), + list: appointmentsVM.branchesDropList, + dropdownValue: appointmentsVM.appointmentFilterSelectedBranchId.selectedId != -1 + ? DropValue(appointmentsVM.appointmentFilterSelectedBranchId.selectedId, appointmentsVM.appointmentFilterSelectedBranchId.selectedOption, "") + : null, + hint: LocaleKeys.selectBranch.tr(), + ); + }, + ), + historyContent: appointmentsVM.appointmentFilterBranchSearchHistory, + onHistoryItemDeleted: (index) { + appointmentsVM.removeAppointmentFilterBranchSearchHistory(index: index); + }, + onHistoryItemTapped: (DropValue value) => + appointmentsVM.updateAppointmentFilterSelectedBranchId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true), + ), + ], + const Divider(thickness: 1.2).paddingOnly(top: 5, bottom: 5), + SearchEntityWidget( + title: LocaleKeys.searchByCategory.tr(), + actionWidget: Builder( + builder: (context) { + return DropdownField( + (DropValue value) => appointmentsVM.updateAppointmentFilterSelectedCategoryId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true), + list: appointmentsVM.categoryDropList, + dropdownValue: appointmentsVM.appointmentFilterSelectedCategoryId.selectedId != -1 + ? DropValue(appointmentsVM.appointmentFilterSelectedCategoryId.selectedId, appointmentsVM.appointmentFilterSelectedCategoryId.selectedOption, "") + : null, + hint: LocaleKeys.selectCategory.tr(), + ); + }, + ), + historyContent: appointmentsVM.appointmentFilterCategorySearchHistory, + onHistoryItemDeleted: (index) { + appointmentsVM.removeAppointmentFilterCategorySearchHistory(index: index); }, + onHistoryItemTapped: (DropValue value) => + appointmentsVM.updateAppointmentFilterSelectedCategoryId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true), ), - historyContent: appointmentsVM.appointmentFilterCategorySearchHistory, - onHistoryItemDeleted: (index) { - appointmentsVM.removeAppointmentFilterCategorySearchHistory(index: index); - }, - onHistoryItemTapped: (DropValue value) => - appointmentsVM.updateAppointmentFilterSelectedCategoryId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true), - ), - const Divider(thickness: 1.2).paddingOnly(top: 5, bottom: 5), + const Divider(thickness: 1.2).paddingOnly(top: 5, bottom: 5), + ], SearchEntityWidget( title: LocaleKeys.searchByService.tr(), actionWidget: Builder(builder: (context) { @@ -166,22 +243,41 @@ class _AppointmentsFilterViewState extends State { onHistoryItemTapped: (DropValue value) => null, ), const Divider(thickness: 1.2).paddingOnly(top: 5, bottom: 5), - SearchEntityWidget( - title: LocaleKeys.searchByItem.tr(), - actionWidget: Builder(builder: (context) { - return DropdownField( - (DropValue value) => appointmentsVM.updateAppointmentFilterSelectedItemId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true), - list: appointmentsVM.itemsDropList, - dropdownValue: appointmentsVM.appointmentFilterSelectedItemId.selectedId != -1 - ? DropValue(appointmentsVM.appointmentFilterSelectedItemId.selectedId, appointmentsVM.appointmentFilterSelectedItemId.selectedOption, "") - : null, - hint: LocaleKeys.selectItems.tr(), - ); - }), - historyContent: appointmentsVM.appointmentFilterItemsSearchHistory, - onHistoryItemDeleted: (index) => appointmentsVM.removeAppointmentFilterItemsSearchHistory(index: index), - onHistoryItemTapped: (DropValue value) => null, - ), + if (AppState().currentAppType == AppType.customer) ...[ + SearchEntityWidget( + title: LocaleKeys.searchByItem.tr(), + actionWidget: Builder(builder: (context) { + return DropdownField( + (DropValue value) => appointmentsVM.updateAppointmentFilterSelectedItemId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true), + list: appointmentsVM.itemsDropList, + dropdownValue: appointmentsVM.appointmentFilterSelectedItemId.selectedId != -1 + ? DropValue(appointmentsVM.appointmentFilterSelectedItemId.selectedId, appointmentsVM.appointmentFilterSelectedItemId.selectedOption, "") + : null, + hint: LocaleKeys.selectItems.tr(), + ); + }), + historyContent: appointmentsVM.appointmentFilterItemsSearchHistory, + onHistoryItemDeleted: (index) => appointmentsVM.removeAppointmentFilterItemsSearchHistory(index: index), + onHistoryItemTapped: (DropValue value) => null, + ), + ] else ...[ + SearchEntityWidget( + title: LocaleKeys.searchByServiceDelivery.tr(), + actionWidget: Builder(builder: (context) { + return DropdownField( + (DropValue value) => appointmentsVM.updateAppointmentFilterSelectedServiceDeliveryId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true), + list: appointmentsVM.serviceDeliveryTypesDropList, + dropdownValue: appointmentsVM.appointmentFilterSelectedServiceDeliveryId.selectedId != -1 + ? DropValue(appointmentsVM.appointmentFilterSelectedServiceDeliveryId.selectedId, appointmentsVM.appointmentFilterSelectedServiceDeliveryId.selectedOption, "") + : null, + hint: LocaleKeys.selectDeliveryType.tr(), + ); + }), + historyContent: appointmentsVM.appointmentFilterServiceDeliverySearchHistory, + onHistoryItemDeleted: (index) => appointmentsVM.removeAppointmentFilterServiceDeliverySearchHistory(index: index), + onHistoryItemTapped: (DropValue value) => null, + ), + ], ], ).expand(), Container( @@ -197,7 +293,12 @@ class _AppointmentsFilterViewState extends State { title: LocaleKeys.search.tr(), onPressed: () { Navigator.pop(context); - appointmentsVM.getAppointmentsBasedOnFilters(); + + if (AppState().currentAppType == AppType.provider) { + appointmentsVM.getAppointmentsBasedOnFiltersForProviders(branchID: appointmentsVM.selectedBranchIdForAppointments); + } else { + appointmentsVM.getAppointmentsBasedOnFiltersForCustomer(); + } }, backgroundColor: MyColors.darkPrimaryColor, txtColor: MyColors.white, @@ -208,7 +309,9 @@ class _AppointmentsFilterViewState extends State { ), 8.height, InkWell( - onTap: () => appointmentsVM.clearAppointmentFilters(), + onTap: () { + appointmentsVM.clearAppointmentFilters(); + }, child: LocaleKeys.clearFilters.tr().toText( fontSize: 14, isBold: true, diff --git a/lib/views/chat/chat_view.dart b/lib/views/chat/chat_view.dart index 60861cc..3cdc2c7 100644 --- a/lib/views/chat/chat_view.dart +++ b/lib/views/chat/chat_view.dart @@ -13,6 +13,7 @@ import 'package:mc_common_app/utils/utils.dart'; import 'package:mc_common_app/view_models/chat_view_model.dart'; import 'package:mc_common_app/view_models/payment_view_model.dart'; import 'package:mc_common_app/view_models/requests_view_model.dart'; +import 'package:mc_common_app/views/advertisement/ads_buyer_chats_view.dart'; import 'package:mc_common_app/views/advertisement/components/picked_images_container_widget.dart'; import 'package:mc_common_app/views/chat/widgets/chat_bottom_sheets.dart'; import 'package:mc_common_app/views/chat/widgets/chat_message_widget.dart'; @@ -111,16 +112,37 @@ class _ChatViewState extends State { padding: const EdgeInsets.symmetric(horizontal: 21, vertical: 10), child: Row( crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - "Your Delivery / Shipping Status is: ".toText( - fontSize: 12, - color: Colors.white, - decorationColor: MyColors.white, - ), - Utils.getNameByShippingRequestStatusEnum(requestVM.currentSelectedRequest?.shippingStatusEnum ?? ShippingRequestStatusEnum.initiated).toText( - fontSize: 16, - color: Colors.white, + Expanded( + flex: 4, + child: Row( + children: [ + Flexible( + child: "${LocaleKeys.deliveryStatus.tr()} ${Utils.getNameByShippingRequestStatusEnum(requestVM.currentSelectedRequest?.shippingStatusEnum ?? ShippingRequestStatusEnum.pending)}" + .toText( + fontSize: 12, + color: Colors.white, + decorationColor: MyColors.white, + ), + ), + ], + ), ), + 10.width, + if ((requestVM.currentSelectedRequest?.shippingStatusEnum ?? ShippingRequestStatusEnum.pending) == ShippingRequestStatusEnum.delivered) ...[ + Expanded( + flex: 2, + child: "${LocaleKeys.markAsCompleted.tr()} ".toText(isUnderLine: true, fontSize: 12, color: Colors.white, decorationColor: MyColors.white).onPress(() { + return dealCompletedConsentBottomSheet( + mainContext: context, + requestStatusEnum: RequestStatusEnum.completed, + requestId: requestVM.currentSelectedRequest!.id, + showAcknowledgement: false, + ); + }), + ), + ], ], ), ); @@ -138,7 +160,9 @@ class _ChatViewState extends State { if (AppState().currentAppType == AppType.customer && chatVM.serviceProviderOffersList.isNotEmpty) { chatMessages = chatVM.serviceProviderOffersList[chatViewArgumentsForRequest!.providerIndex].chatMessages ?? []; } else { - chatMessages = requestVM.myFilteredRequests[chatViewArgumentsForRequest!.requestIndex].chatMessages; + if (requestVM.myFilteredRequests.isNotEmpty) { + chatMessages = requestVM.myFilteredRequests[chatViewArgumentsForRequest!.requestIndex].chatMessages; + } } } return Column( @@ -151,20 +175,20 @@ class _ChatViewState extends State { child: chatMessages.isEmpty ? Center(child: LocaleKeys.noChatMessage.tr().toText(fontSize: 16, color: MyColors.lightTextColor, textAlign: TextAlign.center)).paddingAll(22) : ListView.separated( - controller: chatVM.scrollController, - itemCount: chatMessages.length, - separatorBuilder: (BuildContext context, int index) => 20.height, - itemBuilder: (BuildContext context, int index) { - ChatMessageModel chatMessageModel = chatMessages[index]; - return ChatMessageCustomWidget( - chatMessageModel: chatMessageModel, - requestModel: chatTypeEnum == ChatTypeEnum.requestOffer ? chatViewArgumentsForRequest!.requestModel! : null, - requestStatusEnum: requestVM.currentSelectedRequest?.requestStatus, - chatTypeEnum: chatTypeEnum, - requestsTypeEnum: chatTypeEnum == ChatTypeEnum.requestOffer ? chatViewArgumentsForRequest!.requestModel!.requestType.toRequestTypeEnum() : RequestsTypeEnum.specialCarRequest, - ); - }, - ).horPaddingMain(), + controller: chatVM.scrollController, + itemCount: chatMessages.length, + separatorBuilder: (BuildContext context, int index) => 20.height, + itemBuilder: (BuildContext context, int index) { + ChatMessageModel chatMessageModel = chatMessages[index]; + return ChatMessageCustomWidget( + chatMessageModel: chatMessageModel, + requestModel: chatTypeEnum == ChatTypeEnum.requestOffer ? chatViewArgumentsForRequest!.requestModel! : null, + requestStatusEnum: requestVM.currentSelectedRequest?.requestStatus, + chatTypeEnum: chatTypeEnum, + requestsTypeEnum: chatTypeEnum == ChatTypeEnum.requestOffer ? chatViewArgumentsForRequest!.requestModel!.requestType.toRequestTypeEnum() : RequestsTypeEnum.specialCarRequest, + ); + }, + ).horPaddingMain(), ), 10.height, Row( @@ -208,88 +232,90 @@ class _ChatViewState extends State { // ), // ] // - else ...[ - if (AppState().currentAppType == AppType.provider && - chatTypeEnum == ChatTypeEnum.requestOffer && - requestVM.currentSelectedRequest!.requestStatus == RequestStatusEnum.submitted && - chatVM.pickedImagesForMessage.isEmpty) ...[ - Expanded( - flex: 1, - child: const Icon( - Icons.local_offer_rounded, - color: MyColors.darkPrimaryColor, - size: 30, - ).onPress( - () { - requestVM.resetSendOfferBottomSheet(); - RequestDetailPageArguments requestDetailArguments = RequestDetailPageArguments( - requestIndex: chatViewArgumentsForRequest!.requestIndex, - requestModel: chatViewArgumentsForRequest!.requestModel!, - ); - buildSendOfferBottomSheet( - context: context, - requestDetailPageArguments: requestDetailArguments, - isFromChatScreen: true, - offerId: null, // null means creating new offer - ); - }, + else + ...[ + if (AppState().currentAppType == AppType.provider && + chatTypeEnum == ChatTypeEnum.requestOffer && + requestVM.currentSelectedRequest!.requestStatus == RequestStatusEnum.submitted && + chatVM.pickedImagesForMessage.isEmpty) ...[ + Expanded( + flex: 1, + child: const Icon( + Icons.local_offer_rounded, + color: MyColors.darkPrimaryColor, + size: 30, + ).onPress( + () { + requestVM.resetSendOfferBottomSheet(); + RequestDetailPageArguments requestDetailArguments = RequestDetailPageArguments( + requestIndex: chatViewArgumentsForRequest!.requestIndex, + requestModel: chatViewArgumentsForRequest!.requestModel!, + ); + buildSendOfferBottomSheet( + context: context, + requestDetailPageArguments: requestDetailArguments, + isFromChatScreen: true, + offerId: null, // null means creating new offer + ); + }, + ), ), - ), - ], - if (chatVM.pickedImagesForMessage.isNotEmpty) ...[ - Expanded( - flex: 8, - child: PickedFilesContainer( - pickedFiles: chatVM.pickedImagesForMessage, - onCrossPressedPrimary: chatVM.removeImageFromList, - onAddFilePressed: () => chatVM.pickMultipleImages(), + ], + if (chatVM.pickedImagesForMessage.isNotEmpty) ...[ + Expanded( + flex: 8, + child: PickedFilesContainer( + pickedFiles: chatVM.pickedImagesForMessage, + onCrossPressedPrimary: chatVM.removeImageFromList, + onAddFilePressed: () => chatVM.pickMultipleImages(), + ), ), - ), - ] else if (chatTypeEnum == ChatTypeEnum.requestOffer) ...[ + ] else + if (chatTypeEnum == ChatTypeEnum.requestOffer) ...[ + Expanded( + flex: 1, + child: const Icon( + Icons.photo_library_rounded, + color: MyColors.darkPrimaryColor, + size: 30, + ).onPress(() => chatVM.pickMultipleImages()), + ), + ], + if (chatVM.pickedImagesForMessage.isEmpty) ...[ + Expanded( + flex: 8, + child: TxtField( + value: chatVM.chatMessageText, + hint: LocaleKeys.typeMessageHere.tr(), + keyboardType: TextInputType.text, + isNeedBorder: false, + onChanged: (v) => chatVM.updateChatMessageText(v), + ), + ), + ], Expanded( flex: 1, - child: const Icon( - Icons.photo_library_rounded, - color: MyColors.darkPrimaryColor, - size: 30, - ).onPress(() => chatVM.pickMultipleImages()), - ), - ], - if (chatVM.pickedImagesForMessage.isEmpty) ...[ - Expanded( - flex: 8, - child: TxtField( - value: chatVM.chatMessageText, - hint: LocaleKeys.typeMessageHere.tr(), - keyboardType: TextInputType.text, - isNeedBorder: false, - onChanged: (v) => chatVM.updateChatMessageText(v), - ), - ), - ], - Expanded( - flex: 1, - child: const Icon(Icons.send_rounded, color: MyColors.darkPrimaryColor, size: 30).onPress( - () async { - ChatMessageTypeEnum chatMessageTypeEnum = ChatMessageTypeEnum.freeText; + child: const Icon(Icons.send_rounded, color: MyColors.darkPrimaryColor, size: 30).onPress( + () async { + ChatMessageTypeEnum chatMessageTypeEnum = ChatMessageTypeEnum.freeText; - if (chatVM.pickedImagesForMessage.isNotEmpty) { - chatMessageTypeEnum = ChatMessageTypeEnum.image; - } - final status = await onMessageSend(chatMessageType: chatMessageTypeEnum); + if (chatVM.pickedImagesForMessage.isNotEmpty) { + chatMessageTypeEnum = ChatMessageTypeEnum.image; + } + final status = await onMessageSend(chatMessageType: chatMessageTypeEnum); - if (status) { - chatVM.scrollChatDown(); - if (chatMessageTypeEnum == ChatMessageTypeEnum.freeText) { - chatVM.clearChatMessageText(); - } else if (chatMessageTypeEnum == ChatMessageTypeEnum.image) { - chatVM.clearPickedImagesForMessage(); + if (status) { + chatVM.scrollChatDown(); + if (chatMessageTypeEnum == ChatMessageTypeEnum.freeText) { + chatVM.clearChatMessageText(); + } else if (chatMessageTypeEnum == ChatMessageTypeEnum.image) { + chatVM.clearPickedImagesForMessage(); + } } - } - }, + }, + ), ), - ), - ], + ], ], ).toContainer(isShadowEnabled: true) ], diff --git a/lib/views/chat/widgets/chat_bottom_sheets.dart b/lib/views/chat/widgets/chat_bottom_sheets.dart index 1d59e4c..1a534ca 100644 --- a/lib/views/chat/widgets/chat_bottom_sheets.dart +++ b/lib/views/chat/widgets/chat_bottom_sheets.dart @@ -18,14 +18,20 @@ import 'package:mc_common_app/widgets/button/show_fill_button.dart'; import 'package:mc_common_app/widgets/checkbox_with_title_desc.dart'; import 'package:provider/provider.dart'; -void dealCompletedConsentBottomSheet({required BuildContext mainContext, required RequestStatusEnum requestStatusEnum, required int requestId, Function()? acceptRequestOffer}) { +void dealCompletedConsentBottomSheet({ + required BuildContext mainContext, + required RequestStatusEnum requestStatusEnum, + required int requestId, + required bool showAcknowledgement, + Function()? acceptRequestOffer, +}) { final requestVM = mainContext.read(); return actionConfirmationBottomSheet( - isOnlyOneButton: AppState().currentAppType == AppType.customer, + isOnlyOneButton: showAcknowledgement, context: mainContext, title: LocaleKeys.doYouWantToCompleteThisDeal.tr().toText(fontSize: 26, isBold: true, letterSpacing: -1.44), subtitle: AppState().currentAppType == AppType.provider ? LocaleKeys.providerCompletingDealMeansThat.tr() : LocaleKeys.customerCompletingDealMeansThat.tr(), - checkBoxConfirmationWidget: AppState().currentAppType == AppType.customer + checkBoxConfirmationWidget: showAcknowledgement ? Consumer(builder: (BuildContext context, ChatVM chatVM, Widget? child) { return Row( children: [ @@ -47,14 +53,13 @@ void dealCompletedConsentBottomSheet({required BuildContext mainContext, require return Expanded( child: ShowFillButton( maxHeight: 55, - isDisabled: !chatVM.acknowledgePaymentToMowaterStatus, - title: AppState().currentAppType == AppType.customer ? LocaleKeys.submit.tr() : LocaleKeys.yes.tr(), + isDisabled: showAcknowledgement == false ? false : !chatVM.acknowledgePaymentToMowaterStatus, + title: showAcknowledgement ? LocaleKeys.submit.tr() : LocaleKeys.yes.tr(), fontSize: 15, onPressed: () async { pop(context); bool statusForReqAccept = false; - - if (acceptRequestOffer != null) { + if (acceptRequestOffer != null && showAcknowledgement) { statusForReqAccept = await acceptRequestOffer(); if (statusForReqAccept) { bool status = await requestVM.onActionRequestTapped( @@ -79,7 +84,7 @@ void dealCompletedConsentBottomSheet({required BuildContext mainContext, require context: mainContext, requestStatusEnum: requestStatusEnum, requestId: requestId, - needLoading: false, + needLoading: showAcknowledgement ? true : false, ); log("status: $status"); if (status) { diff --git a/lib/views/chat/widgets/chat_message_widget.dart b/lib/views/chat/widgets/chat_message_widget.dart index 05ef366..1b0fe88 100644 --- a/lib/views/chat/widgets/chat_message_widget.dart +++ b/lib/views/chat/widgets/chat_message_widget.dart @@ -129,7 +129,7 @@ class _ChatMessageCustomWidgetState extends State { offerPrice: chatMessageModel.reqOffer!.price.toString(), serviceItemName: chatMessageModel.reqOffer!.serviceItemName ?? "", manufacturedOn: chatMessageModel.reqOffer!.manufacturedOn ?? "", - manufacturedById: chatMessageModel.reqOffer!.manufacturedById ?? 0, + manufacturedByName: chatMessageModel.reqOffer!.manufacturedByName ?? "", requestOfferStatusEnum: RequestOfferStatusEnum.rejected, context: context, ); @@ -208,6 +208,7 @@ class _ChatMessageCustomWidgetState extends State { mainContext: context, requestStatusEnum: RequestStatusEnum.completed, requestId: requestVM.currentSelectedRequest!.id, + showAcknowledgement: AppState().currentAppType == AppType.customer, ); } else { final requestVM = context.read(); @@ -215,6 +216,7 @@ class _ChatMessageCustomWidgetState extends State { mainContext: context, requestStatusEnum: RequestStatusEnum.completed, requestId: requestVM.currentSelectedRequest!.id, + showAcknowledgement: AppState().currentAppType == AppType.customer, acceptRequestOffer: () async { bool status = await chatVM.onSendMessageForActionOnRequestOffer( receiverId: chatMessageModel.senderUserID ?? "", @@ -226,7 +228,7 @@ class _ChatMessageCustomWidgetState extends State { offerPrice: chatMessageModel.reqOffer!.price.toString(), serviceItemName: chatMessageModel.reqOffer!.serviceItemName ?? "", manufacturedOn: chatMessageModel.reqOffer!.manufacturedOn ?? "", - manufacturedById: chatMessageModel.reqOffer!.manufacturedById ?? 0, + manufacturedByName: chatMessageModel.reqOffer!.manufacturedByName ?? "", requestOfferStatusEnum: RequestOfferStatusEnum.accepted, context: context, ); @@ -373,7 +375,7 @@ class _ChatMessageCustomWidgetState extends State { offerPrice: chatMessageModel.reqOffer!.price.toString(), serviceItemName: chatMessageModel.reqOffer!.serviceItemName ?? "", manufacturedOn: chatMessageModel.reqOffer!.manufacturedOn ?? "", - manufacturedById: chatMessageModel.reqOffer!.manufacturedById ?? 0, + manufacturedByName: chatMessageModel.reqOffer!.manufacturedByName ?? "", requestOfferStatusEnum: requestOfferStatusEnum, context: context, ); @@ -427,7 +429,7 @@ class _ChatMessageCustomWidgetState extends State { offerPrice: chatMessageModel.reqOffer!.price.toString(), serviceItemName: chatMessageModel.reqOffer!.serviceItemName ?? "", manufacturedOn: chatMessageModel.reqOffer!.manufacturedOn ?? "", - manufacturedById: chatMessageModel.reqOffer!.manufacturedById ?? 0, + manufacturedByName: chatMessageModel.reqOffer!.manufacturedByName ?? "", requestOfferStatusEnum: RequestOfferStatusEnum.accepted, context: context, ); @@ -736,7 +738,7 @@ class _ChatMessageCustomWidgetState extends State { ReqOffer offer = widget.chatMessageModel.reqOffer!; requestVM.updateOfferPrice((offer.price ?? "").toString()); requestVM.updateServiceItem((offer.serviceItemName ?? "").toString()); - requestVM.updateItemManufacturer((offer.manufacturedById ?? "").toString()); + requestVM.updateItemManufacturer((offer.manufacturedByName ?? "").toString()); requestVM.updateServiceItemCreatedOn((offer.manufacturedOn ?? "").toString()); requestVM.updateOfferDescription((widget.chatMessageModel.chatText ?? "").toString()); requestVM.updateIsDeliveryAvailableStatus((offer.isDeliveryAvailable ?? false)); @@ -747,8 +749,6 @@ class _ChatMessageCustomWidgetState extends State { id: element.id, filePath: element.imageStr != null && element.imageStr!.isNotEmpty ? element.imageStr : element.imageUrl, isFromNetwork: element.imageStr != null && element.imageStr!.isNotEmpty ? false : true); - - log("imageModelimageModel: ${imageModel.toString()}"); requestVM.addImageToPickedVehicleImages(imageModel); } } @@ -771,7 +771,7 @@ class _ChatMessageCustomWidgetState extends State { ] else if (AppState().currentAppType == AppType.provider && chatMessageTypeEnum == ChatMessageTypeEnum.offer && widget.chatMessageModel.reqOffer!.requestOfferStatusEnum == RequestOfferStatusEnum.offer && - (widget.chatMessageModel.isMyMessage == true)) ...[ + (widget.chatMessageModel.isMyMessage == true && widget.chatMessageModel.reqOffer != null && widget.chatMessageModel.reqOffer!.id != null)) ...[ MyAssets.icEdit.buildSvg(color: MyColors.white, height: 15).onPress(() => onOfferEditIconPressed()), ], Expanded( diff --git a/lib/views/common_fragments/ads_fragment.dart b/lib/views/common_fragments/ads_fragment.dart index b0e29d4..df84976 100644 --- a/lib/views/common_fragments/ads_fragment.dart +++ b/lib/views/common_fragments/ads_fragment.dart @@ -79,7 +79,9 @@ class AdsFragment extends StatelessWidget { title: LocaleKeys.exploreAds.tr(), txtColor: adVM.isExploreAdsTapped ? MyColors.white : MyColors.darkTextColor, onPressed: () { - print("accessToken: ${AppState().getUser.data!.accessToken}"); + log("accessToken: ${AppState().getUser.data!.accessToken}"); + log("AppState().getUser.data!.userInfo!.userId;: ${AppState().getUser.data!.userInfo!.userId}"); + if (adVM.myAds.isEmpty) { adVM.getMyAds(); } @@ -107,7 +109,9 @@ class AdsFragment extends StatelessWidget { 16.height, FiltersList( filterList: adVM.exploreAdsFilterOptions, - onFilterTapped: (index, selectedFilterId) => adVM.applyFilterOnExploreAds(createdByRoleFilter: selectedFilterId.toCreatedByRoleEnum()), + onFilterTapped: (index, selectedFilterId) { + adVM.applyFilterOnExploreAds(vehicleBrandId: selectedFilterId); + }, needLeftPadding: false, ).paddingOnly(left: 21), ] @@ -115,7 +119,9 @@ class AdsFragment extends StatelessWidget { 16.height, FiltersList( filterList: adVM.myAdsFilterOptions, - onFilterTapped: (index, selectedFilterId) => adVM.applyFilterOnMyAds(adPostStatusEnum: selectedFilterId.toAdPostEnum()), + onFilterTapped: (index, selectedFilterId) { + adVM.applyFilterOnMyAds(adPostStatusEnum: selectedFilterId.toAdPostEnum()); + }, needLeftPadding: false, ).paddingOnly(left: 21), ], @@ -128,8 +134,8 @@ class AdsFragment extends StatelessWidget { child: RefreshIndicator( onRefresh: () async { if (adVM.isExploreAdsTapped) { - CreatedByRoleEnum createdByRoleEnum = adVM.exploreAdsFilterOptions.firstWhere((element) => element.isSelected).id.toCreatedByRoleEnum(); - adVM.applyFilterOnExploreAds(createdByRoleFilter: createdByRoleEnum); + int vehicleBrandId = adVM.exploreAdsFilterOptions.firstWhere((element) => element.isSelected).id; + adVM.applyFilterOnExploreAds(vehicleBrandId: vehicleBrandId); } else { AdPostStatus adPostStatusEnum = adVM.myAdsFilterOptions.firstWhere((element) => element.isSelected).id.toAdPostEnum(); adVM.applyFilterOnMyAds(adPostStatusEnum: adPostStatusEnum); @@ -141,12 +147,26 @@ class AdsFragment extends StatelessWidget { isAdsFragment: true, shouldShowAdStatus: !adVM.isExploreAdsTapped, adsList: getAdsList(adVM), - onFetchMoreAds: () { - log("fetch more ads"); + hasMoreData: adVM.isExploreAdsTapped ? adVM.hasMoreDataForExploreAds : adVM.hasMoreDataForMyAds, + onFetchMoreAds: () async { + AdPostStatus adPostStatusEnum = adVM.myAdsFilterOptions.firstWhere((element) => element.isSelected).id.toAdPostEnum(); + + if (adVM.isExploreAdsTapped) { + await adVM.fetchMoreExploreAds(); + } else { + await adVM.fetchMoreMyAds(adsStatus: adPostStatusEnum); + } }, ), ), - ) + ), + if (adVM.isLoadingMore) ...[ + const Center( + child: Padding( + padding: EdgeInsets.all(8.0), + child: CircularProgressIndicator(), + )) + ] ], ), ), diff --git a/lib/views/common_fragments/requests_fragment.dart b/lib/views/common_fragments/requests_fragment.dart index 3d7544c..a1f397a 100644 --- a/lib/views/common_fragments/requests_fragment.dart +++ b/lib/views/common_fragments/requests_fragment.dart @@ -158,7 +158,7 @@ class MyRequestsFragment extends StatelessWidget { }, child: RequestItem( request: requestsVM.myFilteredRequests[index], - shouldShowStatuses: AppState().currentAppType == AppType.customer, + shouldShowStatuses: true, onTap: () async { RequestModel request = requestsVM.myFilteredRequests[index]; requestsVM.updateCurrentSelectedRequest(request); diff --git a/lib/views/requests/request_bottomsheets.dart b/lib/views/requests/request_bottomsheets.dart index 725760e..0a358d3 100644 --- a/lib/views/requests/request_bottomsheets.dart +++ b/lib/views/requests/request_bottomsheets.dart @@ -56,14 +56,14 @@ Future buildSendOfferBottomSheet({ numbersOnly: true, onChanged: (v) => requestsVM.updateOfferPrice(v), ), + 12.height, + TxtField( + value: requestsVM.serviceItem, + errorValue: requestsVM.offerPriceError, + hint: LocaleKeys.serviceItem.tr(), + onChanged: (v) => requestsVM.updateServiceItem(v), + ), if (requestDetail.requestType == RequestsTypeEnum.serviceRequest.getIdFromRequestTypeEnum()) ...[ - 12.height, - TxtField( - value: requestsVM.serviceItem, - errorValue: requestsVM.offerPriceError, - hint: LocaleKeys.serviceItem.tr(), - onChanged: (v) => requestsVM.updateServiceItem(v), - ), 12.height, TxtField( value: requestsVM.itemManufacturer, @@ -157,8 +157,7 @@ Future buildSendOfferBottomSheet({ isDeliveryAvailable: requestsVM.isDeliveryAvailableStatus, requestIndex: requestDetailPageArguments.requestIndex, isFromChatScreen: isFromChatScreen, - manufacturedById: 1, - // Todo: It should be the ID of the manufacturer + manufacturedByName: requestsVM.itemManufacturer, manufacturedOn: requestsVM.serviceItemCreatedOn, serviceItemName: requestsVM.serviceItem, ); @@ -170,8 +169,7 @@ Future buildSendOfferBottomSheet({ offerPrice: requestsVM.offerPrice, isDeliveryAvailable: requestsVM.isDeliveryAvailableStatus, serviceItemName: requestsVM.serviceItem, - manufacturedById: 1, - // Todo: It should be the ID of the manufacturer + manufacturedByName: requestsVM.itemManufacturer, manufacturedOn: requestsVM.serviceItemCreatedOn, receiverId: requestDetail.customerId, customerRequestIndex: requestIndex, diff --git a/lib/views/requests/request_detail_page.dart b/lib/views/requests/request_detail_page.dart index 28ce552..c9c7841 100644 --- a/lib/views/requests/request_detail_page.dart +++ b/lib/views/requests/request_detail_page.dart @@ -29,6 +29,7 @@ class RequestDetailPage extends StatelessWidget { required int requestId, required RequestStatusEnum requestStatus, required RequestsTypeEnum requestTypeEnum, + required ShippingRequestStatusEnum shippingRequestStatusEnum, required String statusText, required BuildContext context, }) { @@ -47,6 +48,7 @@ class RequestDetailPage extends StatelessWidget { if (requestTypeEnum == RequestsTypeEnum.serviceRequest) { return Utils.buildStatusContainer(LocaleKeys.awaitingPaymentFromCustomer.tr()); } else { + return Utils.buildStatusContainer(LocaleKeys.awaitingResponseFromCustomer.tr()); } @@ -68,7 +70,28 @@ class RequestDetailPage extends StatelessWidget { case RequestStatusEnum.shipping: case RequestStatusEnum.delivery: - if (AppState().currentAppType == AppType.provider) { + if (AppState().currentAppType == AppType.provider && shippingRequestStatusEnum == ShippingRequestStatusEnum.delivered) { + return Column( + children: [ + Utils.buildStatusContainer("${LocaleKeys.deliveryStatus.tr()} ${Utils.getNameByShippingRequestStatusEnum(shippingRequestStatusEnum).capitalizeFirstLetter()}") + .paddingOnly(left: 8, right: 8), + ShowFillButton( + maxWidth: double.infinity, + margin: const EdgeInsets.all(15), + maxHeight: 55, + title: LocaleKeys.markAsCompleted.tr(), + onPressed: () { + return dealCompletedConsentBottomSheet( + mainContext: context, + requestStatusEnum: RequestStatusEnum.completed, + requestId: requestId, + showAcknowledgement: AppState().currentAppType == AppType.customer, + ); + }, + ) + ], + ); + } else if (AppState().currentAppType == AppType.provider) { return Utils.buildStatusContainer(LocaleKeys.shippingManagementInstruction.tr()); } else { return ShowFillButton( @@ -81,7 +104,7 @@ class RequestDetailPage extends StatelessWidget { mainContext: context, requestStatusEnum: RequestStatusEnum.completed, requestId: requestId, - acceptRequestOffer: () {}, + showAcknowledgement: AppState().currentAppType == AppType.customer, ); }, ); @@ -176,8 +199,9 @@ class RequestDetailPage extends StatelessWidget { requestId: requestDetailPageArguments.requestModel.id, requestStatus: requestDetailPageArguments.requestModel.requestStatus, statusText: "Offer ${requestDetailPageArguments.requestModel.requestStatusName}", - context: context, requestTypeEnum: requestDetailPageArguments.requestModel.requestType.toRequestTypeEnum(), + shippingRequestStatusEnum: requestDetailPageArguments.requestModel.shippingStatusEnum ?? ShippingRequestStatusEnum.pending, + context: context, ), ], ], diff --git a/lib/views/requests/review_request_offer.dart b/lib/views/requests/review_request_offer.dart index 4fef205..891236d 100644 --- a/lib/views/requests/review_request_offer.dart +++ b/lib/views/requests/review_request_offer.dart @@ -153,15 +153,16 @@ class _ReviewRequestOfferState extends State { SingleDetailWidget(text: requestVM.currentSelectedRequest!.vehicleTypeName, type: LocaleKeys.vehicleType.tr()), 16.height, SingleDetailWidget(text: '${requestVM.currentSelectedRequest!.model} ${requestVM.currentSelectedRequest!.year}', type: LocaleKeys.model.tr()), - if (requestVM.acceptedRequestOffer!.manufacturedById != null) ...[ + if (requestVM.acceptedRequestOffer!.manufacturedByName != null) ...[ 16.height, - SingleDetailWidget(text: (requestVM.acceptedRequestOffer!.manufacturedById ?? "").toString(), type: LocaleKeys.manufacturedBy.tr()), + SingleDetailWidget(text: (requestVM.acceptedRequestOffer!.manufacturedByName ?? "").toString(), type: LocaleKeys.manufacturedBy.tr()), ], // 16.height, // SingleDetailWidget(text: "${requestVM.acceptedRequestOffer!.price.toString()} ${LocaleKeys.sar.tr()}", type: LocaleKeys.offerPrice.tr()), 16.height, SingleDetailWidget(text: requestVM.acceptedRequestOfferProviderName ?? "", type: LocaleKeys.providerName.tr()), 16.height, + SingleDetailWidget(text: requestVM.currentSelectedRequest!.description, type: LocaleKeys.description.tr()), ], ), ), @@ -186,12 +187,14 @@ class _ReviewRequestOfferState extends State { 16.height, SingleDetailWidget(text: requestCreatedOn, type: LocaleKeys.requestCreatedOn.tr()), ], + + 16.height, + SingleDetailWidget(text: LocaleKeys.online.tr(), type: LocaleKeys.paymentType.tr()), ], ), ), ], ), - SingleDetailWidget(text: requestVM.currentSelectedRequest!.description, type: LocaleKeys.description.tr()), ], ); } diff --git a/lib/views/setting_options/provider_accepted_requests_view.dart b/lib/views/setting_options/provider_accepted_requests_view.dart index ce38770..f9dba42 100644 --- a/lib/views/setting_options/provider_accepted_requests_view.dart +++ b/lib/views/setting_options/provider_accepted_requests_view.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:developer'; import 'package:flutter/gestures.dart'; import 'package:mc_common_app/classes/app_state.dart'; @@ -63,20 +64,6 @@ class _ProviderAcceptedRequestsViewState extends State 0) ...[ - 8.height, - InkWell( - onTap: () async { - requestsVM.clearRequestsFilters(); - await requestsVM.getRequestsBasedOnFilters(); - }, - child: LocaleKeys.clearFilters.tr().toText( - fontSize: 14, - isBold: true, - color: MyColors.darkPrimaryColor, - ), - ), - ], ], ) : ListView.separated( @@ -84,7 +71,7 @@ class _ProviderAcceptedRequestsViewState extends State SplashPageState(); +} + +class SplashPageState extends State with WidgetsBindingObserver { + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addObserver(this); performTimer(context); + } + + @override + void dispose() { + WidgetsBinding.instance.removeObserver(this); + super.dispose(); + } + + @override + void didChangeAppLifecycleState(AppLifecycleState state) { + super.didChangeAppLifecycleState(state); + if (state == AppLifecycleState.resumed) { + final chatVM = context.read(); + chatVM.buildHubConnection(context); + } + } + + // Timer function to navigate after a delay + performTimer(BuildContext context) { + Utils.delay(3).whenComplete(() { + navigateReplaceWithName(context, AppRoutes.registerSelection); + }); + } + + @override + Widget build(BuildContext context) { return Scaffold( body: Container( width: double.infinity, @@ -17,37 +53,36 @@ class SplashPage extends StatelessWidget { color: Colors.black, child: Column( children: [ - Utils. mExp(1), + // Spacer widget for flexible spacing + Utils.mExp(1), + // Logo Image Expanded( child: Image.asset( MyAssets.icLogoWhitePng, ), ), + // Car Image (flex value adjusted to make it more responsive) Expanded( flex: 10, child: Image.asset( MyAssets.bnCar, fit: BoxFit.cover, width: double.infinity, - height: 00, + height: double.infinity, // Use full height in this expanded section ), ), + // Engine Image Expanded( flex: 3, child: Image.asset( MyAssets.icEnginePng, ), ), + // Spacer widget again for spacing Utils.mExp(1), ], ), ), ); } - - performTimer(BuildContext context) { - Utils.delay(3).whenComplete(() { - navigateReplaceWithName(context, AppRoutes.registerSelection); - }); - } } diff --git a/lib/views/user/complete_profile_page.dart b/lib/views/user/complete_profile_page.dart index e78392e..0ce12a0 100644 --- a/lib/views/user/complete_profile_page.dart +++ b/lib/views/user/complete_profile_page.dart @@ -46,7 +46,6 @@ class _CompleteProfilePageState extends State { @override Widget build(BuildContext context) { return Consumer(builder: (BuildContext context, UserVM userVM, Widget? child) { - print("Country ID = " + AppState().getUserRegisterCountrySelection.id.toString()); userVM.getAllCitiesForUser(AppState().getUserRegisterCountrySelection.id); return Scaffold( appBar: CustomAppBar( diff --git a/lib/widgets/bottom_sheet.dart b/lib/widgets/bottom_sheet.dart index 6016334..9580d58 100644 --- a/lib/widgets/bottom_sheet.dart +++ b/lib/widgets/bottom_sheet.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:mc_common_app/extensions/int_extensions.dart'; -void showMyBottomSheet(BuildContext context, {bool isDismissible = true, required Widget child, VoidCallback? callBackFunc}) { +void showMyBottomSheet(BuildContext context, {bool isDismissible = true,bool isScrollControlled = true, required Widget child, VoidCallback? callBackFunc}) { showModalBottomSheet( context: context, isScrollControlled: true, diff --git a/lib/widgets/common_widgets/categories_list.dart b/lib/widgets/common_widgets/categories_list.dart index bb00d63..f3d0039 100644 --- a/lib/widgets/common_widgets/categories_list.dart +++ b/lib/widgets/common_widgets/categories_list.dart @@ -2,20 +2,21 @@ import 'package:flutter/material.dart'; import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/models/general_models/widgets_models.dart'; import 'package:mc_common_app/theme/colors.dart'; +import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; class FiltersList extends StatelessWidget { final List filterList; final Function(int, int) onFilterTapped; final bool needLeftPadding; - EdgeInsets? padding; + final EdgeInsets? padding; - FiltersList({ - Key? key, + const FiltersList({ + super.key, this.padding, required this.filterList, this.needLeftPadding = true, required this.onFilterTapped, - }) : super(key: key); + }); @override Widget build(BuildContext context) { @@ -23,38 +24,50 @@ class FiltersList extends StatelessWidget { height: 37, width: double.infinity, child: ListView.builder( - padding: padding ?? EdgeInsets.only(left: needLeftPadding ? 12 : 0), - itemCount: filterList.length, - scrollDirection: Axis.horizontal, - itemBuilder: (BuildContext context, int index) { - return InkWell( - onTap: () { - onFilterTapped(index, filterList[index].id); - }, + padding: padding ?? EdgeInsets.only(left: needLeftPadding ? 12 : 0), + itemCount: filterList.length, + scrollDirection: Axis.horizontal, + itemBuilder: (BuildContext context, int index) { + return InkWell( + onTap: () { + onFilterTapped(index, filterList[index].id); + }, + child: ConstrainedBox( + constraints: const BoxConstraints(minWidth: 80), // Set a minimum width for each filter chip child: Container( alignment: Alignment.center, padding: const EdgeInsets.symmetric(horizontal: 8), margin: const EdgeInsets.symmetric(horizontal: 4), decoration: BoxDecoration( - color: filterList[index].isSelected - ? MyColors.darkIconColor - : null, + color: filterList[index].isSelected ? MyColors.darkIconColor : null, border: Border.all( - color: filterList[index].isSelected - ? MyColors.darkIconColor - : MyColors.primaryColor, + color: filterList[index].isSelected ? MyColors.darkIconColor : MyColors.primaryColor, width: 2, ), ), - child: filterList[index].title.toText( - fontSize: 12, - letterSpacing: -0.14, - color: - filterList[index].isSelected ? MyColors.white : null, - ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + // Icon before the text + + // if (index != 0 || filterList[index].iconUrl.isNotEmpty) ...[ + // filterList[index].iconUrl.buildNetworkImage(height: 16, width: 16, fit: BoxFit.cover), + // const SizedBox(width: 4), // Space between icon and text + // ], + + // Text displayed in the chip + filterList[index].title.toText( + fontSize: 13, + letterSpacing: -0.14, + color: filterList[index].isSelected ? MyColors.white : null, + ), + ], + ), ), - ); - }), + ), + ); + }, + ), ); } } diff --git a/lib/widgets/common_widgets/search_entity_widget.dart b/lib/widgets/common_widgets/search_entity_widget.dart index d675d11..71bee77 100644 --- a/lib/widgets/common_widgets/search_entity_widget.dart +++ b/lib/widgets/common_widgets/search_entity_widget.dart @@ -9,16 +9,20 @@ class SearchEntityWidget extends StatelessWidget { final String title; final Widget actionWidget; final List historyContent; + final List? historyContentString; final Function(int) onHistoryItemDeleted; final Function(DropValue) onHistoryItemTapped; + final bool isForString; const SearchEntityWidget({ super.key, required this.title, required this.actionWidget, required this.historyContent, + this.historyContentString, required this.onHistoryItemDeleted, required this.onHistoryItemTapped, + this.isForString = false, }); @override @@ -30,26 +34,45 @@ class SearchEntityWidget extends StatelessWidget { 8.height, actionWidget, 10.height, - historyContent.isNotEmpty - ? SizedBox( - height: 33, - child: ListView.builder( - shrinkWrap: true, - scrollDirection: Axis.horizontal, - itemCount: historyContent.length, - itemBuilder: (BuildContext context, int index) { - return CustomRectangleChip( - text: historyContent[index].value, - onHistoryItemDeleted: () { - onHistoryItemDeleted(index); - }, - onHistoryItemTapped: () { - onHistoryItemTapped(historyContent[index]); - }, - ).paddingOnly(right: 10); - }), - ) - : const SizedBox.shrink(), + if (isForString && historyContentString != null && historyContentString!.isNotEmpty) ...[ + SizedBox( + height: 33, + child: ListView.builder( + shrinkWrap: true, + scrollDirection: Axis.horizontal, + itemCount: historyContentString!.length, + itemBuilder: (BuildContext context, int index) { + return CustomRectangleChip( + text: historyContentString![index], + onHistoryItemDeleted: () { + onHistoryItemDeleted(index); + }, + onHistoryItemTapped: () {}, + ).paddingOnly(right: 10); + }), + ) + ] else ...[ + historyContent.isNotEmpty + ? SizedBox( + height: 33, + child: ListView.builder( + shrinkWrap: true, + scrollDirection: Axis.horizontal, + itemCount: historyContent.length, + itemBuilder: (BuildContext context, int index) { + return CustomRectangleChip( + text: historyContent[index].value, + onHistoryItemDeleted: () { + onHistoryItemDeleted(index); + }, + onHistoryItemTapped: () { + onHistoryItemTapped(historyContent[index]); + }, + ).paddingOnly(right: 10); + }), + ) + : const SizedBox.shrink(), + ] ], ); } diff --git a/lib/widgets/image_viewer/image_viewer_screen.dart b/lib/widgets/image_viewer/image_viewer_screen.dart index 48dddd4..6aa98b2 100644 --- a/lib/widgets/image_viewer/image_viewer_screen.dart +++ b/lib/widgets/image_viewer/image_viewer_screen.dart @@ -56,7 +56,7 @@ class MediaViewerScreenState extends State { borderRadius: BorderRadius.circular(16), child: (widget.images[index].isFromNetwork ?? false) ? widget.images[index].imageUrl.buildNetworkImage( - fit: BoxFit.cover, + fit: BoxFit.contain, width: double.infinity, height: double.infinity, ) diff --git a/lib/widgets/txt_field.dart b/lib/widgets/txt_field.dart index 2bbbd2b..fcca91c 100644 --- a/lib/widgets/txt_field.dart +++ b/lib/widgets/txt_field.dart @@ -39,7 +39,7 @@ class TxtField extends StatelessWidget { bool allowOnlyOneDigit; TxtField({ - Key? key, + super.key, this.value, this.lable, this.hint, @@ -67,7 +67,7 @@ class TxtField extends StatelessWidget { this.onPostFixPressed, this.numbersOnly = false, this.allowOnlyOneDigit = false, - }) : super(key: key); + }); @override Widget build(BuildContext context) {