From 70870f1903e3671de92aec96d5d67da60560ae08 Mon Sep 17 00:00:00 2001 From: Faiz Hashmi Date: Sun, 8 Dec 2024 17:27:59 +0300 Subject: [PATCH 1/4] added lazy loading --- assets/langs/ar-SA.json | 3 +- assets/langs/en-US.json | 3 +- lib/classes/consts.dart | 2 +- lib/generated/codegen_loader.g.dart | 6 +- lib/generated/locale_keys.g.dart | 1 + .../advertisment_models/ad_details_model.dart | 5 +- lib/repositories/ads_repo.dart | 64 +++++++++++-- lib/repositories/branch_repo.dart | 44 ++++++--- lib/services/common_auth_service.dart | 4 +- lib/view_models/ad_view_model.dart | 92 ++++++++++++++++--- lib/view_models/requests_view_model.dart | 36 +++++++- lib/view_models/service_view_model.dart | 41 ++++++--- .../components/ads_list_widget.dart | 5 +- .../chat/widgets/chat_message_widget.dart | 2 +- lib/views/common_fragments/ads_fragment.dart | 32 +++++-- lib/views/requests/review_request_offer.dart | 5 +- lib/views/splash/splash_page.dart | 59 +++++++++--- 17 files changed, 321 insertions(+), 83 deletions(-) diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 9eba80f..d45f3c8 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -760,5 +760,6 @@ "tapToSeeItems": "اضغط لرؤية العناصر", "tapToSelect": "اضغط للاختيار", "noteCopyItemsExplanation": "ملاحظة: ستتمكن من نسخ العناصر من خدمة إلى أخرى في الفئة المحددة. يجب عليك إنشاء الخدمات أولاً ويجب أن تكون معتمدة. ثم ستتمكن من الحصول على الخدمات المتاحة التي يمكنك نسخ جميع العناصر منها أو تحديد العناصر التي تريد نسخها.", - "requestCreatedOn": "تم إنشاء الطلب في" + "requestCreatedOn": "تم إنشاء الطلب في", + "online": "عبر الإنترنت" } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 7027c81..d0521bd 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -758,5 +758,6 @@ "tapToSelect": "Tap to select", "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" + "requestCreatedOn": "Request created on", + "online": "Online" } \ No newline at end of file diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index d5033d6..1036905 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -55,7 +55,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"; diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index 905622f..c60600c 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -776,7 +776,8 @@ class CodegenLoader extends AssetLoader{ "tapToSeeItems": "اضغط لرؤية العناصر", "tapToSelect": "اضغط للاختيار", "noteCopyItemsExplanation": "ملاحظة: ستتمكن من نسخ العناصر من خدمة إلى أخرى في الفئة المحددة. يجب عليك إنشاء الخدمات أولاً ويجب أن تكون معتمدة. ثم ستتمكن من الحصول على الخدمات المتاحة التي يمكنك نسخ جميع العناصر منها أو تحديد العناصر التي تريد نسخها.", - "requestCreatedOn": "تم إنشاء الطلب في" + "requestCreatedOn": "تم إنشاء الطلب في", + "online": "عبر الإنترنت" }; static const Map en_US = { "firstTimeLogIn": "First Time Log In", @@ -1538,7 +1539,8 @@ static const Map en_US = { "tapToSelect": "Tap to select", "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" + "requestCreatedOn": "Request created on", + "online": "Online" }; static const Map> mapLocales = {"ar_SA": ar_SA, "en_US": en_US}; } diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 396b4fa..42bf0f8 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -740,5 +740,6 @@ abstract class LocaleKeys { static const tapToSelect = 'tapToSelect'; static const noteCopyItemsExplanation = 'noteCopyItemsExplanation'; static const requestCreatedOn = 'requestCreatedOn'; + static const online = 'online'; } 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/repositories/ads_repo.dart b/lib/repositories/ads_repo.dart index d5d83be..91ab7b4 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,6 +16,7 @@ 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}); @@ -22,7 +25,12 @@ abstract class AdsRepo { 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? page, + }); Future> getExploreAdsBasedOnFilters({ List? cityIdsList, @@ -31,6 +39,8 @@ abstract class AdsRepo { List? createdByRolesIdsList, List? vehicleAdConditionIdsList, List? vehicleAdCreatedDateList, + int page, + bool isMyAds = false, }); Future> getMyReservedAds(); @@ -62,10 +72,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, @@ -168,7 +178,12 @@ class AdsRepoImp implements AdsRepo { } @override - Future> getAllAds({required isMyAds, AdPostStatus? adPostStatus, CreatedByRoleEnum? createdByRoleEnum}) async { + Future> getAllAds({ + required isMyAds, + AdPostStatus? adPostStatus, + CreatedByRoleEnum? createdByRoleEnum, + int? page, + }) async { Map onlyMyAdsParams = { "userID": appState.getUser.data!.userInfo!.userId ?? "", }; @@ -176,6 +191,7 @@ class AdsRepoImp implements AdsRepo { onlyMyAdsParams.addAll({ "AdsStatuses": ["${adPostStatus.getIdFromAdPostStatusEnum()}"], "PageSize": "30", + "PageIndex": page != null ? page.toString() : "0", }); } var allAdsParams = { @@ -183,6 +199,7 @@ class AdsRepoImp implements AdsRepo { "isActive": "true", //only Active ADS "isExplore": "true", "PageSize": "30", + "PageIndex": page != null ? page.toString() : "0", }; if (!isMyAds && createdByRoleEnum != null) { @@ -196,7 +213,7 @@ class AdsRepoImp implements AdsRepo { 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 +225,8 @@ class AdsRepoImp implements AdsRepo { List? createdByRolesIdsList, List? vehicleAdConditionIdsList, List? vehicleAdCreatedDateList, + int? page, + bool isMyAds = false, }) async { var parameters = { "CityIDs": cityIdsList ?? [], @@ -218,17 +237,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 +275,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 +302,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 +328,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/branch_repo.dart b/lib/repositories/branch_repo.dart index 068c285..37f720d 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); @@ -236,7 +238,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])); @@ -268,8 +270,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); @@ -332,6 +333,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 = { @@ -341,7 +355,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, @@ -416,7 +430,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, @@ -444,7 +458,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, @@ -456,7 +470,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, ); @@ -471,7 +485,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, @@ -491,7 +505,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); } @@ -536,7 +550,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, @@ -550,7 +564,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, @@ -564,7 +578,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, @@ -580,7 +594,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, @@ -592,7 +606,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, @@ -607,7 +621,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/services/common_auth_service.dart b/lib/services/common_auth_service.dart index 17baf4a..14b5ea2 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/view_models/ad_view_model.dart b/lib/view_models/ad_view_model.dart index c7b4568..9bbfe19 100644 --- a/lib/view_models/ad_view_model.dart +++ b/lib/view_models/ad_view_model.dart @@ -201,6 +201,8 @@ class AdVM extends BaseVM { } applyFilterOnExploreAds({required CreatedByRoleEnum createdByRoleFilter}) async { + pageIndexForExploreAds = 1; + hasMoreDataForExploreAds = true; if (exploreAdsFilterOptions.isEmpty) return; int index = exploreAdsFilterOptions.indexWhere((element) => element.id.toCreatedByRoleEnum() == createdByRoleFilter); @@ -219,18 +221,71 @@ class AdVM extends BaseVM { 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 adsRepo.getExploreAdsBasedOnFilters(page: pageIndexForExploreAds); + 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 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}) async { return await adsRepo.getAllAds(isMyAds: isMyAds, adPostStatus: adPostStatus, createdByRoleEnum: createdByRoleEnum); } applyFilterOnMyAds({required AdPostStatus adPostStatusEnum}) async { + pageIndexForMyAds = 1; + hasMoreDataForMyAds = true; if (myAdsFilterOptions.isEmpty) return; int index = myAdsFilterOptions.indexWhere((element) => element.id.toAdPostEnum() == adPostStatusEnum); @@ -265,7 +320,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 +328,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 +338,8 @@ class AdVM extends BaseVM { } Future getMyAds() async { + pageIndexForMyAds = 1; + hasMoreDataForMyAds = true; setState(ViewState.busy); myAds = await adsRepo.getAllAds(isMyAds: true); myAdsFilteredList = myAds; @@ -1581,6 +1640,11 @@ class AdVM extends BaseVM { Future populateDataForAdFilter() async { setState(ViewState.busy); + pageIndexForExploreAds = 1; + pageIndexForMyAds = 1; + hasMoreDataForExploreAds = true; + hasMoreDataForMyAds = true; + isLoadingMore = false; if (vehicleConditionsEnum.isEmpty) { vehicleConditionsEnum = await commonRepo.getEnumTypeValues(enumTypeID: AppEnums.conditionEnumId); @@ -1846,13 +1910,13 @@ class AdVM extends BaseVM { } exploreAdsFilteredList = await adsRepo.getExploreAdsBasedOnFilters( - cityIdsList: cityIdsList, - createdByRolesIdsList: adOwnerIdsList, - vehicleBrandIdsList: brandsIdsList, - vehicleModelYearIdsList: vehicleYearIdsList, - vehicleAdConditionIdsList: conditionsIdsList, - vehicleAdCreatedDateList: createdDatesList, - ); + cityIdsList: cityIdsList, + createdByRolesIdsList: adOwnerIdsList, + vehicleBrandIdsList: brandsIdsList, + vehicleModelYearIdsList: vehicleYearIdsList, + vehicleAdConditionIdsList: conditionsIdsList, + vehicleAdCreatedDateList: createdDatesList, + page: pageIndexForExploreAds); setState(ViewState.idle); } @@ -1944,7 +2008,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/requests_view_model.dart b/lib/view_models/requests_view_model.dart index 9a1e7f1..600465f 100644 --- a/lib/view_models/requests_view_model.dart +++ b/lib/view_models/requests_view_model.dart @@ -92,6 +92,38 @@ 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); @@ -127,7 +159,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; @@ -1061,7 +1093,7 @@ class RequestsVM extends BaseVM { pop(context); } } - } catch (e, s) { + } catch (e) { Utils.hideLoading(context); log(e.toString()); Utils.showToast(e.toString()); diff --git a/lib/view_models/service_view_model.dart b/lib/view_models/service_view_model.dart index 11a5015..99b7d48 100644 --- a/lib/view_models/service_view_model.dart +++ b/lib/view_models/service_view_model.dart @@ -272,11 +272,7 @@ class ServiceVM extends BaseVM { context, allowMultiple: false, ); - if (files != null && files.any((element) => - element.path - .split('.') - .last - .toLowerCase() != 'pdf')) { + if (files != null && files.any((element) => element.path.split('.').last.toLowerCase() != 'pdf')) { Utils.showToast("Only PDF Files are allowed"); return; } @@ -290,8 +286,8 @@ class ServiceVM extends BaseVM { documentID == 1 ? commerceCertificates.addAll(imageModels) : documentID == 2 - ? commercialCertificates.addAll(imageModels) - : vatCertificates.addAll(imageModels); + ? commercialCertificates.addAll(imageModels) + : vatCertificates.addAll(imageModels); document!.data![index].document = Utils.convertFileToBase64(files.first); document!.data![index].fileExt = Utils.checkFileExt(files.first.path); document!.data![index].documentUrl = files.first.path; @@ -467,10 +463,10 @@ class ServiceVM extends BaseVM { DropValue( element.id ?? 0, ((element.categoryName!.isEmpty - ? "N/A" - : countryCode == "SA" - ? element.categoryNameN - : element.categoryName) ?? + ? "N/A" + : countryCode == "SA" + ? element.categoryNameN + : element.categoryName) ?? "N/A"), "", ), @@ -567,6 +563,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, @@ -751,9 +766,7 @@ class ServiceVM extends BaseVM { File file = File(imageModel.filePath!); List imageBytes = await file.readAsBytes(); String image = base64Encode(imageBytes); - String fileName = file.path - .split('/') - .last; + String fileName = file.path.split('/').last; branchPostingImages = BranchPostingImages( imageName: fileName, imageStr: image, diff --git a/lib/views/advertisement/components/ads_list_widget.dart b/lib/views/advertisement/components/ads_list_widget.dart index fff78fb..fb2f995 100644 --- a/lib/views/advertisement/components/ads_list_widget.dart +++ b/lib/views/advertisement/components/ads_list_widget.dart @@ -21,12 +21,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 +46,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!(); } diff --git a/lib/views/chat/widgets/chat_message_widget.dart b/lib/views/chat/widgets/chat_message_widget.dart index 05ef366..9f169a0 100644 --- a/lib/views/chat/widgets/chat_message_widget.dart +++ b/lib/views/chat/widgets/chat_message_widget.dart @@ -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..9a30037 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(createdByRoleFilter: selectedFilterId.toCreatedByRoleEnum()); + }, 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), ], @@ -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/requests/review_request_offer.dart b/lib/views/requests/review_request_offer.dart index 4fef205..f7c689e 100644 --- a/lib/views/requests/review_request_offer.dart +++ b/lib/views/requests/review_request_offer.dart @@ -162,6 +162,7 @@ class _ReviewRequestOfferState extends State { 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/splash/splash_page.dart b/lib/views/splash/splash_page.dart index e97cf7f..9c84fd5 100644 --- a/lib/views/splash/splash_page.dart +++ b/lib/views/splash/splash_page.dart @@ -1,15 +1,51 @@ +import 'package:flutter/material.dart'; import 'package:mc_common_app/classes/consts.dart'; import 'package:mc_common_app/config/routes.dart'; import 'package:mc_common_app/utils/navigator.dart'; import 'package:mc_common_app/utils/utils.dart'; -import 'package:flutter/material.dart'; +import 'package:mc_common_app/view_models/ad_view_model.dart'; +import 'package:mc_common_app/view_models/chat_view_model.dart'; +import 'package:provider/provider.dart'; -class SplashPage extends StatelessWidget { - const SplashPage({Key? key}) : super(key: key); +class SplashPage extends StatefulWidget { + const SplashPage({super.key}); @override - Widget build(BuildContext context) { + SplashPageState createState() => 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); - }); - } } From 4901e8a0fb2b8137cf05e53fb81157948f47d9e4 Mon Sep 17 00:00:00 2001 From: Faiz Hashmi Date: Mon, 9 Dec 2024 09:06:20 +0300 Subject: [PATCH 2/4] added lazy loading --- assets/langs/en-US.json | 5 ++-- lib/classes/consts.dart | 4 +-- lib/generated/codegen_loader.g.dart | 33 +++++++++++------------ lib/view_models/ad_view_model.dart | 12 ++++----- lib/view_models/chat_view_model.dart | 4 +-- lib/view_models/requests_view_model.dart | 4 +-- lib/view_models/service_view_model.dart | 4 +-- lib/views/user/complete_profile_page.dart | 1 - 8 files changed, 32 insertions(+), 35 deletions(-) diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 8b4c75e..057bc66 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,7 +758,7 @@ "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" + "online": "Online", "searchByCreatedDate": "Search By Created Date", "updateUserDetails": "Update User Details", "enterNewFirstName": "Enter First Name", @@ -771,7 +770,7 @@ "userGender": "Gender", "userMale": "Male", "userFemale": "Female", - "maxFileSelection" :"You can select a maximum of 7 files", + "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" diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index f34a0c9..3ca87cb 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -260,8 +260,8 @@ class GlobalConsts { // Attachment Values - int maxFileCount = 7; - int maxFileSizeInBytes = 2 * 1024 * 1024; + static int maxFileCount = 7; + static int maxFileSizeInBytes = 2 * 1024 * 1024; } class MyAssets { diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index 002a71f..bdf7219 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -1533,22 +1533,6 @@ static const Map en_US = { "blockedByAdmin": "Blocked by admin", "active": "Active", "paymentType": "Payment Type", - "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" - "searchByCreatedDate": "Search By Created Date", "dealCompleted": "The Deal Completed", "theDealNotCompleted": "The Deal Not Completed", "cancelRequest": "I want to cancel the request.", @@ -1569,7 +1553,22 @@ 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" + "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" }; static const Map> mapLocales = {"ar_SA": ar_SA, "en_US": en_US}; } diff --git a/lib/view_models/ad_view_model.dart b/lib/view_models/ad_view_model.dart index da64be3..0dbfee6 100644 --- a/lib/view_models/ad_view_model.dart +++ b/lib/view_models/ad_view_model.dart @@ -1264,8 +1264,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); } @@ -1312,8 +1312,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); } } @@ -1368,8 +1368,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 = ""; diff --git a/lib/view_models/chat_view_model.dart b/lib/view_models/chat_view_model.dart index 763b0d3..c9751f3 100644 --- a/lib/view_models/chat_view_model.dart +++ b/lib/view_models/chat_view_model.dart @@ -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); } diff --git a/lib/view_models/requests_view_model.dart b/lib/view_models/requests_view_model.dart index 4a6e619..f636661 100644 --- a/lib/view_models/requests_view_model.dart +++ b/lib/view_models/requests_view_model.dart @@ -269,8 +269,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); } diff --git a/lib/view_models/service_view_model.dart b/lib/view_models/service_view_model.dart index 628dc51..59397ea 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 = ""; 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( From e51df0651cc95a454de085ec942bf136a64be221 Mon Sep 17 00:00:00 2001 From: Faiz Hashmi Date: Mon, 9 Dec 2024 17:45:31 +0300 Subject: [PATCH 3/4] Check appointmnet filter for provider --- assets/langs/ar-SA.json | 6 +- assets/langs/en-US.json | 5 +- lib/extensions/string_extensions.dart | 9 ++ lib/generated/codegen_loader.g.dart | 8 +- lib/generated/locale_keys.g.dart | 2 + lib/models/requests_models/request_model.dart | 2 +- lib/repositories/ads_repo.dart | 9 +- lib/repositories/appointment_repo.dart | 17 +++ lib/services/common_services.dart | 11 +- lib/utils/enums.dart | 2 +- lib/view_models/ad_view_model.dart | 101 +++++++++++------- lib/views/advertisement/ads_filter_view.dart | 33 +++++- .../components/ads_list_widget.dart | 5 +- lib/views/chat/chat_view.dart | 38 +++++-- .../chat/widgets/chat_bottom_sheets.dart | 21 ++-- .../chat/widgets/chat_message_widget.dart | 2 + lib/views/common_fragments/ads_fragment.dart | 6 +- .../common_fragments/requests_fragment.dart | 2 +- lib/views/requests/request_detail_page.dart | 29 ++++- .../common_widgets/categories_list.dart | 65 ++++++----- 20 files changed, 267 insertions(+), 106 deletions(-) diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 4c3ca3b..cf41afa 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -751,7 +751,7 @@ "userGender": "جنس", "userMale": "ذكر", "userFemale": "أنثى", - "maxFileSelection" :"يمكنك تحديد الحد الأقصى لملفات 7", + "maxFileSelection": "يمكنك تحديد الحد الأقصى لملفات 7", "maxFileSize": "يجب أن يكون حجم كل ملف أقل من 2 ميغابايت", "onlyJPGandPNG": "يُسمح فقط بملفات JPG وPNG", "expiryDate": "تاريخ انتهاء الصلاحية", @@ -775,5 +775,7 @@ "tapToSelect": "اضغط للاختيار", "noteCopyItemsExplanation": "ملاحظة: ستتمكن من نسخ العناصر من خدمة إلى أخرى في الفئة المحددة. يجب عليك إنشاء الخدمات أولاً ويجب أن تكون معتمدة. ثم ستتمكن من الحصول على الخدمات المتاحة التي يمكنك نسخ جميع العناصر منها أو تحديد العناصر التي تريد نسخها.", "requestCreatedOn": "تم إنشاء الطلب في", - "online": "عبر الإنترنت" + "online": "عبر الإنترنت", + "deliveryStatus": "حالة توصيلك / الشحن هي:", + "markAsCompleted": "ضع علامة كمكتمل" } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 057bc66..3ce5eca 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -773,5 +773,8 @@ "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" + "expiryDate": "Expiry Date", + "deliveryStatus": "Your Delivery / Shipping Status is:", + "markAsCompleted": "Mark as Completed" + } \ No newline at end of file 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 bdf7219..cdef4ea 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -791,7 +791,9 @@ class CodegenLoader extends AssetLoader{ "tapToSelect": "اضغط للاختيار", "noteCopyItemsExplanation": "ملاحظة: ستتمكن من نسخ العناصر من خدمة إلى أخرى في الفئة المحددة. يجب عليك إنشاء الخدمات أولاً ويجب أن تكون معتمدة. ثم ستتمكن من الحصول على الخدمات المتاحة التي يمكنك نسخ جميع العناصر منها أو تحديد العناصر التي تريد نسخها.", "requestCreatedOn": "تم إنشاء الطلب في", - "online": "عبر الإنترنت" + "online": "عبر الإنترنت", + "deliveryStatus": "حالة توصيلك / الشحن هي:", + "markAsCompleted": "ضع علامة كمكتمل" }; static const Map en_US = { "firstTimeLogIn": "First Time Log In", @@ -1568,7 +1570,9 @@ static const Map en_US = { "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" + "expiryDate": "Expiry Date", + "deliveryStatus": "Your Delivery / Shipping Status is:", + "markAsCompleted": "Mark as Completed" }; static const Map> mapLocales = {"ar_SA": ar_SA, "en_US": en_US}; } diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 086e1fc..d9ee1b2 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -755,5 +755,7 @@ abstract class LocaleKeys { static const noteCopyItemsExplanation = 'noteCopyItemsExplanation'; static const requestCreatedOn = 'requestCreatedOn'; static const online = 'online'; + static const deliveryStatus = 'deliveryStatus'; + static const markAsCompleted = 'markAsCompleted'; } 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 91ab7b4..f0534ec 100644 --- a/lib/repositories/ads_repo.dart +++ b/lib/repositories/ads_repo.dart @@ -29,6 +29,7 @@ abstract class AdsRepo { required bool isMyAds, AdPostStatus? adPostStatus, CreatedByRoleEnum? createdByRoleEnum, + int? vehicleBrandId, int? page, }); @@ -182,6 +183,7 @@ class AdsRepoImp implements AdsRepo { required isMyAds, AdPostStatus? adPostStatus, CreatedByRoleEnum? createdByRoleEnum, + int? vehicleBrandId, int? page, }) async { Map onlyMyAdsParams = { @@ -207,6 +209,11 @@ 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), @@ -237,7 +244,7 @@ class AdsRepoImp implements AdsRepo { "VehicleNew": vehicleAdConditionIdsList ?? [], "CreatedOn": (vehicleAdCreatedDateList != null && vehicleAdCreatedDateList.isNotEmpty) ? vehicleAdCreatedDateList.first.toString() : "", "isActive": "true", //only Active ADS - "isExplore": isMyAds.toString(), + "isExplore": (!isMyAds).toString(), "PageSize": "30", "PageIndex": page != null ? page.toString() : "1", }; diff --git a/lib/repositories/appointment_repo.dart b/lib/repositories/appointment_repo.dart index cf99abe..288a877 100644 --- a/lib/repositories/appointment_repo.dart +++ b/lib/repositories/appointment_repo.dart @@ -15,6 +15,8 @@ import 'package:mc_common_app/utils/enums.dart'; abstract class AppointmentRepo { Future> getMyAppointmentsForProvider(Map map); + Future> getMyProviderAppointmentsByFilters({required int serviceProviderID}); + Future> getMyAppointmentsForCustomersByFilters({ List? providerIdsList, List? categoryIdsList, @@ -219,6 +221,21 @@ class AppointmentRepoImp implements AppointmentRepo { return appointmentList; } + @override + Future> getMyProviderAppointmentsByFilters({required int serviceProviderID}) async { + String t = appState.getUser.data!.accessToken ?? ""; + + final map = {"ServiceProviderID": "$serviceProviderID"}; + GenericRespModel genericRespModel = await apiClient.getJsonForObject( + token: t, + (json) => GenericRespModel.fromJson(json), + queryParameters: map, + ApiConsts.serviceProvidersAppointmentGet, + ); + List appointmentList = List.generate(genericRespModel.data.length, (index) => AppointmentListModel.fromJson(genericRespModel.data[index])); + return appointmentList; + } + @override Future> getMyAppointmentsForCustomersByFilters({ List? providerIdsList, 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..86ba205 100644 --- a/lib/utils/enums.dart +++ b/lib/utils/enums.dart @@ -13,7 +13,7 @@ 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 diff --git a/lib/view_models/ad_view_model.dart b/lib/view_models/ad_view_model.dart index 0dbfee6..240355d 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,45 +176,49 @@ 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(); @@ -233,7 +236,7 @@ class AdVM extends BaseVM { hasMoreDataForExploreAds = true; notifyListeners(); try { - final List newAds = await adsRepo.getExploreAdsBasedOnFilters(page: pageIndexForExploreAds); + final List newAds = await getAdsBasedOnFilters(pageIndex: pageIndexForExploreAds, isFromLazyLoad: true); if (newAds.isEmpty) { hasMoreDataForExploreAds = false; } else { @@ -279,8 +282,8 @@ class AdVM extends BaseVM { notifyListeners(); } - Future> getAdsByFilter({AdPostStatus? adPostStatus, required bool isMyAds, CreatedByRoleEnum? createdByRoleEnum}) async { - return await adsRepo.getAllAds(isMyAds: isMyAds, adPostStatus: adPostStatus, createdByRoleEnum: createdByRoleEnum); + 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 { @@ -1655,6 +1658,7 @@ class AdVM extends BaseVM { // ************ ADS SEARCH VIEW **************** List vehicleConditionsEnum = []; + List adOwnerEnumsFilter = []; Future populateDataForAdFilter() async { setState(ViewState.busy); @@ -1664,16 +1668,22 @@ class AdVM extends BaseVM { 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); } @@ -1742,9 +1752,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); @@ -1752,7 +1762,9 @@ class AdVM extends BaseVM { notifyListeners(); return; } - vehicleOwnerId = id; + if (showSelectionInDropdown) { + vehicleOwnerId = id; + } notifyListeners(); } @@ -1883,9 +1895,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) { @@ -1927,15 +1944,25 @@ class AdVM extends BaseVM { } } - exploreAdsFilteredList = await adsRepo.getExploreAdsBasedOnFilters( - cityIdsList: cityIdsList, - createdByRolesIdsList: adOwnerIdsList, - vehicleBrandIdsList: brandsIdsList, - vehicleModelYearIdsList: vehicleYearIdsList, - vehicleAdConditionIdsList: conditionsIdsList, - vehicleAdCreatedDateList: createdDatesList, - page: pageIndexForExploreAds); - setState(ViewState.idle); + List list = await adsRepo.getExploreAdsBasedOnFilters( + cityIdsList: cityIdsList, + createdByRolesIdsList: adOwnerIdsList, + vehicleBrandIdsList: brandsIdsList, + vehicleModelYearIdsList: vehicleYearIdsList, + vehicleAdConditionIdsList: conditionsIdsList, + vehicleAdCreatedDateList: createdDatesList, + page: pageIndex, + ); + + if (!isFromLazyLoad) { + exploreAdsFilteredList.clear(); + exploreAdsFilteredList = list; + setState(ViewState.idle); + } else { + return list; + } + + return []; } void onEditUpdateAdPressed({required BuildContext context, required AdDetailsModel previousDetails, required bool isFromExtendAd}) { 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 fb2f995..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'; @@ -107,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/chat/chat_view.dart b/lib/views/chat/chat_view.dart index 60861cc..a7d501b 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, + ); + }), + ), + ], ], ), ); 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 9f169a0..c384417 100644 --- a/lib/views/chat/widgets/chat_message_widget.dart +++ b/lib/views/chat/widgets/chat_message_widget.dart @@ -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 ?? "", diff --git a/lib/views/common_fragments/ads_fragment.dart b/lib/views/common_fragments/ads_fragment.dart index 9a30037..df84976 100644 --- a/lib/views/common_fragments/ads_fragment.dart +++ b/lib/views/common_fragments/ads_fragment.dart @@ -110,7 +110,7 @@ class AdsFragment extends StatelessWidget { FiltersList( filterList: adVM.exploreAdsFilterOptions, onFilterTapped: (index, selectedFilterId) { - adVM.applyFilterOnExploreAds(createdByRoleFilter: selectedFilterId.toCreatedByRoleEnum()); + adVM.applyFilterOnExploreAds(vehicleBrandId: selectedFilterId); }, needLeftPadding: false, ).paddingOnly(left: 21), @@ -134,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); 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_detail_page.dart b/lib/views/requests/request_detail_page.dart index 28ce552..953e38b 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, }) { @@ -68,7 +69,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 +103,7 @@ class RequestDetailPage extends StatelessWidget { mainContext: context, requestStatusEnum: RequestStatusEnum.completed, requestId: requestId, - acceptRequestOffer: () {}, + showAcknowledgement: AppState().currentAppType == AppType.customer, ); }, ); @@ -176,8 +198,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/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, + ), + ], + ), ), - ); - }), + ), + ); + }, + ), ); } } From a1d7dcab13da4c93e976c1e3497aa6598f9bb8ca Mon Sep 17 00:00:00 2001 From: Faiz Hashmi Date: Thu, 12 Dec 2024 17:03:31 +0300 Subject: [PATCH 4/4] Minor Fixes --- assets/langs/ar-SA.json | 9 +- assets/langs/en-US.json | 10 +- lib/classes/consts.dart | 7 +- lib/generated/codegen_loader.g.dart | 18 +- lib/generated/locale_keys.g.dart | 7 + .../chat_models/chat_message_model.dart | 8 +- lib/repositories/ads_repo.dart | 28 +- lib/repositories/appointment_repo.dart | 40 ++- lib/repositories/request_repo.dart | 6 +- lib/utils/enums.dart | 1 + lib/view_models/ad_view_model.dart | 8 +- lib/view_models/appointments_view_model.dart | 229 ++++++++++++++- lib/view_models/chat_view_model.dart | 14 +- .../dashboard_view_model_provider.dart | 2 +- lib/view_models/requests_view_model.dart | 20 +- lib/view_models/service_view_model.dart | 1 + .../ads_detail_view/components.dart | 2 +- .../appointments_filter_view.dart | 269 ++++++++++++------ lib/views/chat/chat_view.dart | 182 ++++++------ .../chat/widgets/chat_message_widget.dart | 12 +- lib/views/requests/request_bottomsheets.dart | 20 +- lib/views/requests/request_detail_page.dart | 1 + lib/views/requests/review_request_offer.dart | 4 +- .../provider_accepted_requests_view.dart | 17 +- lib/widgets/bottom_sheet.dart | 2 +- .../common_widgets/search_entity_widget.dart | 63 ++-- .../image_viewer/image_viewer_screen.dart | 2 +- lib/widgets/txt_field.dart | 4 +- 28 files changed, 689 insertions(+), 297 deletions(-) diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index cf41afa..9381824 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -777,5 +777,12 @@ "requestCreatedOn": "تم إنشاء الطلب في", "online": "عبر الإنترنت", "deliveryStatus": "حالة توصيلك / الشحن هي:", - "markAsCompleted": "ضع علامة كمكتمل" + "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 3ce5eca..84263e4 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -775,6 +775,12 @@ "onlyJPGandPNG": "Only JPG and PNG files are allowed", "expiryDate": "Expiry Date", "deliveryStatus": "Your Delivery / Shipping Status is:", - "markAsCompleted": "Mark as Completed" - + "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" } \ No newline at end of file diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 3ca87cb..9486a7c 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -257,11 +257,10 @@ class GlobalConsts { return appInvitationMessageEn; } - // Attachment Values - static int maxFileCount = 7; - static 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/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index cdef4ea..f79e313 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -793,7 +793,14 @@ class CodegenLoader extends AssetLoader{ "requestCreatedOn": "تم إنشاء الطلب في", "online": "عبر الإنترنت", "deliveryStatus": "حالة توصيلك / الشحن هي:", - "markAsCompleted": "ضع علامة كمكتمل" + "markAsCompleted": "ضع علامة كمكتمل", + "searchByServiceDelivery": "البحث حسب خدمة التوصيل", + "searchByMobileNumber": "البحث بواسطة رقم الجوال", + "enterMobileNumber": "أدخل رقم الجوال", + "enterCustomerName": "أدخل اسم العميل", + "tapToView": "انقر لعرض", + "noServicesAvailableToCopy": "لا توجد خدمات متاحة في هذا الفرع لنسخها.", + "copySelectedItems": "نسخ العناصر المحددة" }; static const Map en_US = { "firstTimeLogIn": "First Time Log In", @@ -1572,7 +1579,14 @@ static const Map en_US = { "onlyJPGandPNG": "Only JPG and PNG files are allowed", "expiryDate": "Expiry Date", "deliveryStatus": "Your Delivery / Shipping Status is:", - "markAsCompleted": "Mark as Completed" + "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" }; static const Map> mapLocales = {"ar_SA": ar_SA, "en_US": en_US}; } diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index d9ee1b2..23be5e5 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -757,5 +757,12 @@ abstract class LocaleKeys { 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/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/repositories/ads_repo.dart b/lib/repositories/ads_repo.dart index f0534ec..8a48c49 100644 --- a/lib/repositories/ads_repo.dart +++ b/lib/repositories/ads_repo.dart @@ -21,7 +21,7 @@ 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}); @@ -89,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 diff --git a/lib/repositories/appointment_repo.dart b/lib/repositories/appointment_repo.dart index 288a877..9e1c798 100644 --- a/lib/repositories/appointment_repo.dart +++ b/lib/repositories/appointment_repo.dart @@ -15,7 +15,15 @@ import 'package:mc_common_app/utils/enums.dart'; abstract class AppointmentRepo { Future> getMyAppointmentsForProvider(Map map); - Future> getMyProviderAppointmentsByFilters({required int serviceProviderID}); + Future> getMyAppointmentsForProvidersByFilters({ + required int branchID, + List? serviceProviderServiceIdsList, + List? customerNamesList, + List? customerPhonesList, + List? deliveryTypeIdsList, + String? fromDate, + String? toDate, + }); Future> getMyAppointmentsForCustomersByFilters({ List? providerIdsList, @@ -29,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); @@ -222,14 +230,33 @@ class AppointmentRepoImp implements AppointmentRepo { } @override - Future> getMyProviderAppointmentsByFilters({required int serviceProviderID}) async { + 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 ?? "", + }; - final map = {"ServiceProviderID": "$serviceProviderID"}; GenericRespModel genericRespModel = await apiClient.getJsonForObject( token: t, (json) => GenericRespModel.fromJson(json), - queryParameters: map, + queryParameters: params, ApiConsts.serviceProvidersAppointmentGet, ); List appointmentList = List.generate(genericRespModel.data.length, (index) => AppointmentListModel.fromJson(genericRespModel.data[index])); @@ -263,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/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/utils/enums.dart b/lib/utils/enums.dart index 86ba205..8370c45 100644 --- a/lib/utils/enums.dart +++ b/lib/utils/enums.dart @@ -17,6 +17,7 @@ class AppEnums { 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 240355d..0cd6a00 100644 --- a/lib/view_models/ad_view_model.dart +++ b/lib/view_models/ad_view_model.dart @@ -378,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(); } @@ -1188,9 +1188,7 @@ class AdVM extends BaseVM { getVehicleAdsDuration(); } - if (vehicleAdsSpecialServices.isEmpty) { - getVehicleAdsSpecialServices(); - } + getVehicleAdsSpecialServices(countryId: vehicleCountryId.selectedId, cityId: vehicleCityId.selectedId, specialServiceType: 1); notifyListeners(); } 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 c9751f3..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(), @@ -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 f636661..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 = []; @@ -125,7 +124,6 @@ class RequestsVM extends BaseVM { // } Future getRequestsBasedOnFilters() async { - myFilteredRequests.clear(); setState(ViewState.busy); int requestTypeIdApi = requestsTypeFilterOptions.firstWhere((element) => element.isSelected).id; @@ -218,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) { @@ -278,8 +276,6 @@ class RequestsVM extends BaseVM { notifyListeners(); } - - bool isFetchingRequestType = false; bool isFetchingVehicleType = true; bool isFetchingVehicleDetail = false; @@ -946,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); } @@ -965,7 +961,7 @@ class RequestsVM extends BaseVM { offerPriceError = ""; } - if (offerDescription.isEmpty) { + if (offerDescription.isEmpty || offerDescription.length < 5) { offerDescriptionError = GlobalConsts.descriptionError; isValidated = false; notifyListeners(); @@ -1054,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, @@ -1076,7 +1072,7 @@ class RequestsVM extends BaseVM { offerPrice: offerPrice, isDeliveryAvailable: isDeliveryAvailable, serviceItemName: serviceItemName, - manufacturedById: manufacturedById, + manufacturedByName: manufacturedByName, manufacturedOn: manufacturedOn, requestImages: offerImages, requestOfferStatusEnum: RequestOfferStatusEnum.offer, @@ -1114,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, @@ -1137,7 +1133,7 @@ class RequestsVM extends BaseVM { requestId: requestId, offerPrice: offerPrice, isDeliveryAvailable: isDeliveryAvailable, - manufacturedById: manufacturedById, + manufacturedByName: manufacturedByName, manufacturedOn: manufacturedOn, serviceItemName: serviceItemName, offerImages: offerImages, @@ -1171,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 59397ea..c29faec 100644 --- a/lib/view_models/service_view_model.dart +++ b/lib/view_models/service_view_model.dart @@ -646,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/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 a7d501b..3cdc2c7 100644 --- a/lib/views/chat/chat_view.dart +++ b/lib/views/chat/chat_view.dart @@ -160,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( @@ -173,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( @@ -230,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_message_widget.dart b/lib/views/chat/widgets/chat_message_widget.dart index c384417..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, ); @@ -228,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, ); @@ -375,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, ); @@ -429,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, ); @@ -738,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)); @@ -749,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); } } 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 953e38b..c9c7841 100644 --- a/lib/views/requests/request_detail_page.dart +++ b/lib/views/requests/request_detail_page.dart @@ -48,6 +48,7 @@ class RequestDetailPage extends StatelessWidget { if (requestTypeEnum == RequestsTypeEnum.serviceRequest) { return Utils.buildStatusContainer(LocaleKeys.awaitingPaymentFromCustomer.tr()); } else { + return Utils.buildStatusContainer(LocaleKeys.awaitingResponseFromCustomer.tr()); } diff --git a/lib/views/requests/review_request_offer.dart b/lib/views/requests/review_request_offer.dart index f7c689e..891236d 100644 --- a/lib/views/requests/review_request_offer.dart +++ b/lib/views/requests/review_request_offer.dart @@ -153,9 +153,9 @@ 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()), 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( context: context, isScrollControlled: true, 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) {