From 5999804bc6be38f4b2dcaf3db361ff3e27ce4b92 Mon Sep 17 00:00:00 2001 From: "Mirza.Shafique@cloudsolutions.com.sa" <5093@Shf> Date: Tue, 26 Dec 2023 10:46:45 +0300 Subject: [PATCH] Book Appointment 1.0 --- lib/classes/consts.dart | 5 + lib/extensions/string_extensions.dart | 114 +++-- .../appointment_list_model.dart | 52 ++- .../appointment_slots.dart | 24 + lib/repositories/appointment_repo.dart | 167 +++++-- lib/repositories/common_repo.dart | 86 ++-- lib/utils/enums.dart | 11 + lib/view_models/appointments_view_model.dart | 415 ++++++++++++++---- .../appointments/appointment_detail_view.dart | 122 +++-- lib/widgets/bottom_sheet.dart | 4 +- .../common_widgets/categories_list.dart | 22 +- pubspec.lock | 54 ++- pubspec.yaml | 1 + 13 files changed, 850 insertions(+), 227 deletions(-) create mode 100644 lib/models/appointments_models/appointment_slots.dart diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index d24672d..b178ed7 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -46,6 +46,7 @@ class ApiConsts { static String Services_Get = "${baseUrlServices}api/ServiceProviders/Services_Get"; static String ServiceProviderService_Create = "${baseUrlServices}api/ServiceProviders/ServiceProviderService_Create"; static String ServiceProviderService_Update = "${baseUrlServices}api/ServiceProviders/ServiceProviderService_Update"; + static String GetProviderServices = "${baseUrlServices}api/ServiceProviders/ServiceProviderService_Get"; static String ServiceProviderService_Get = "${baseUrlServices}api/ServiceProviders/ServiceProviderService_Get"; static String BranchesAndServices = "${baseUrlServices}api/ServiceProviders/ServiceProviderDetail_Get"; @@ -58,6 +59,7 @@ class ApiConsts { static String GetServiceItemAppointmentScheduleSlots = "${baseUrlServices}api/ServiceProviders/ServiceItemAppointmentScheduleSlots_GetByAppointmentType"; static String ServiceProvidersAppointmentCreate = "${baseUrlServices}api/ServiceProviders/ServiceProvidersAppointmentList_Create"; static String ServiceProviderAppointmentRescheduleCancelAppointment = "${baseUrlServices}api/ServiceProviders/ServiceProviderAppointment_RescheduleCancelAppointment"; + static String AddNewServicesInAppointment = "${baseUrlServices}api/ServiceProviders/ServiceProviderAppointment_ServiceItemAdd"; //ServiceProvidersServiceID as params // static String servicesGet = "${baseUrlServices}api/ServiceProviders/Services_Get"; @@ -103,6 +105,9 @@ class ApiConsts { static String adsPhotoOfficeAppointmentScheduleSlotGet = "${baseUrlServices}api/Advertisement/PhotoOfficeAppointmentScheduleSlot_Get"; static String adsPhotoOfficeAppointmentCreate = "${baseUrlServices}api/Advertisement/PhotoOfficeAppointment_Create"; static String adsMCBankAccountAdGet = "${baseUrlServices}api/Advertisement/MCBankAccountAd_Get"; + static String getAppointmentSlots = "${baseUrlServices}api/ServiceProviders/ScheduleSlotsInfo_Get"; + static String updateAppointmentStatus = "${baseUrlServices}api/ServiceProviders/ServiceProvidersAppointmentStatus_Update"; + static String updateAppointmentPaymentStatus = "${baseUrlServices}api/ServiceProviders/ServiceProviderAppointmentServiceItemPaymentStatus_Update"; //Subscription static String getAllSubscriptions = "${baseUrlServices}api/Common/Subscription_Get"; diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index d25ffd3..3431a3f 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -25,7 +25,9 @@ extension EmailValidator on String { style: TextStyle( fontStyle: isItalic ? FontStyle.italic : null, height: height, - decoration: isUnderLine ? TextDecoration.underline : textDecoration ?? TextDecoration.none, + decoration: isUnderLine + ? TextDecoration.underline + : textDecoration ?? TextDecoration.none, fontSize: fontSize ?? 10, fontWeight: isBold ? FontWeight.bold : fontWeight ?? FontWeight.w600, color: color ?? MyColors.darkTextColor, @@ -34,7 +36,9 @@ extension EmailValidator on String { ); bool isValidEmail() { - return RegExp(r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$').hasMatch(this); + return RegExp( + r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$') + .hasMatch(this); } bool isNum() { @@ -206,6 +210,40 @@ extension AdPostEnum on int { } } +extension AppointmentStatusToInt on AppointmentStatusEnum { + int getIdFromAppointmentStatusEnum() { + switch (this) { + case AppointmentStatusEnum.booked: + return 1; + + case AppointmentStatusEnum.confirmed: + return 2; + + case AppointmentStatusEnum.arrived: + return 3; + + case AppointmentStatusEnum.cancelled: + return 4; + + case AppointmentStatusEnum.rescheduled: + return 5; + + case AppointmentStatusEnum.upcoming: + return 6; + + case AppointmentStatusEnum.inProgress: + return 7; + + case AppointmentStatusEnum.completed: + return 8; + + default: + return 0; + } + } +} + +//TODO: Need to verify Enum on upcoming and inprogress with the database extension AppointmentEnum on int { AppointmentStatusEnum toAppointmentStatusEnum() { if (this == 1) { @@ -218,12 +256,60 @@ extension AppointmentEnum on int { return AppointmentStatusEnum.cancelled; } else if (this == 5) { return AppointmentStatusEnum.rescheduled; + } else if (this == 6) { + return AppointmentStatusEnum.upcoming; + } else if (this == 7) { + return AppointmentStatusEnum.inProgress; + } else if (this == 8) { + return AppointmentStatusEnum.completed; } else { return AppointmentStatusEnum.allAppointments; } } } +extension AppointmentPaymentStatusToInt on AppointmentPaymentStatusEnum { + int getIdFromAppointmentPaymentStatusEnum() { + switch (this) { + case AppointmentPaymentStatusEnum.notConfirmed: + return 1; + + case AppointmentPaymentStatusEnum.payNow: + return 2; + + case AppointmentPaymentStatusEnum.paid: + return 3; + + case AppointmentPaymentStatusEnum.payLater: + return 4; + + case AppointmentPaymentStatusEnum.payPartial: + return 5; + + default: + return 1; + } + } +} + +extension AppointmentPaymentEnum on int { + AppointmentPaymentStatusEnum toAppointmentPaymentStatusEnum() { + if (this == 1) { + return AppointmentPaymentStatusEnum.notConfirmed; + } else if (this == 2) { + return AppointmentPaymentStatusEnum.payNow; + } else if (this == 3) { + return AppointmentPaymentStatusEnum.paid; + } else if (this == 4) { + return AppointmentPaymentStatusEnum.payLater; + } else if (this == 5) { + return AppointmentPaymentStatusEnum.payPartial; + } else { + return AppointmentPaymentStatusEnum.notConfirmed; + } + } +} + extension RequestTypeTypeEnum on int { RequestsTypeEnum toRequestTypeStatusEnum() { if (this == 1) { @@ -314,30 +400,6 @@ extension PaymentTypesToInt on PaymentTypes { } } -extension AppointmentStatusToInt on AppointmentStatusEnum { - int getIdFromAppointmentStatusEnum() { - switch (this) { - case AppointmentStatusEnum.booked: - return 1; - - case AppointmentStatusEnum.confirmed: - return 2; - - case AppointmentStatusEnum.arrived: - return 3; - - case AppointmentStatusEnum.cancelled: - return 4; - - case AppointmentStatusEnum.rescheduled: - return 5; - - default: - return 0; - } - } -} - extension CreatedByRoleEnumToInt on CreatedByRoleEnum { int getIdFromCreatedByRoleEnum() { switch (this) { diff --git a/lib/models/appointments_models/appointment_list_model.dart b/lib/models/appointments_models/appointment_list_model.dart index d3da5c0..b19f957 100644 --- a/lib/models/appointments_models/appointment_list_model.dart +++ b/lib/models/appointments_models/appointment_list_model.dart @@ -14,11 +14,20 @@ class AppointmentListModel { int? paymentStatus; String? paymentStatusText; String? customerName; + String? customerMobileNum; + int? appointmentType; String? providerName; String? duration; String? appointmentDate; + String? branchName; + int? branchId; + int? servicePaymentStatus; + double? totalAmount; + double? remainingAmount; AppointmentStatusEnum? appointmentStatusEnum; + AppointmentPaymentStatusEnum? appointmentPaymentStatusEnum; List? appointmentServicesList; + List? customerAppointmentList; AppointmentListModel( {this.id, @@ -32,10 +41,18 @@ class AppointmentListModel { this.paymentStatus, this.paymentStatusText, this.customerName, + this.customerMobileNum, + this.appointmentType, this.providerName, this.duration, + this.branchName, + this.branchId, + this.servicePaymentStatus, + this.totalAmount, + this.remainingAmount, this.appointmentDate, - this.appointmentServicesList}); + this.appointmentServicesList, + this.customerAppointmentList}); @override String toString() { @@ -54,15 +71,26 @@ class AppointmentListModel { paymentStatus = json['paymentStatus']; paymentStatusText = json['paymentStatusText']; customerName = json['customerName']; + customerMobileNum = json['customerMobile']; + appointmentType = json['appointmentType']; providerName = json['providerName']; duration = json['duration']; appointmentDate = json['appointmentDate']; - appointmentStatusEnum = (json['appointmentStatusID'] as int).toAppointmentStatusEnum(); + branchName = json['branchName']; + branchId = json['branchID']; + servicePaymentStatus = json['servicePaymentStatus']; + totalAmount = json['amountTotal']; + remainingAmount = json['amountRem']; + appointmentStatusEnum = + (json['appointmentStatusID'] as int).toAppointmentStatusEnum(); + appointmentPaymentStatusEnum = + (json['servicePaymentStatus'] as int).toAppointmentPaymentStatusEnum(); if (json['serviceList'] != null) { appointmentServicesList = []; json['serviceList'].forEach((v) { - appointmentServicesList!.add(ServiceModel.fromJson(v, isForAppointment: true)); + appointmentServicesList! + .add(ServiceModel.fromJson(v, isForAppointment: true)); }); } } @@ -74,7 +102,11 @@ class ServiceAppointmentItems { String? serviceItemName; String? serviceItemDescription; - ServiceAppointmentItems({this.id, this.serviceItemID, this.serviceItemName, this.serviceItemDescription}); + ServiceAppointmentItems( + {this.id, + this.serviceItemID, + this.serviceItemName, + this.serviceItemDescription}); ServiceAppointmentItems.fromJson(Map json) { id = json['id']; @@ -92,3 +124,15 @@ class ServiceAppointmentItems { return data; } } + +// Data Model Class with 'customerName' and 'customerID' +class CustomerData { + final int customerID; + final String customerName; + final List appointmentList; + + CustomerData( + {required this.customerID, + required this.customerName, + required this.appointmentList}); +} diff --git a/lib/models/appointments_models/appointment_slots.dart b/lib/models/appointments_models/appointment_slots.dart new file mode 100644 index 0000000..828e579 --- /dev/null +++ b/lib/models/appointments_models/appointment_slots.dart @@ -0,0 +1,24 @@ +class AppointmentSlots { + int totalSlots; + int occupiedSlots; + int emptySlots; + + AppointmentSlots({ + required this.totalSlots, + required this.occupiedSlots, + required this.emptySlots, + }); + + factory AppointmentSlots.fromJson(Map json) => + AppointmentSlots( + totalSlots: json["totalSlots"], + occupiedSlots: json["occupiedSlots"], + emptySlots: json["emptySlots"], + ); + + Map toJson() => { + "totalSlots": totalSlots, + "occupiedSlots": occupiedSlots, + "emptySlots": emptySlots, + }; +} diff --git a/lib/repositories/appointment_repo.dart b/lib/repositories/appointment_repo.dart index 9bd8d14..95d1a24 100644 --- a/lib/repositories/appointment_repo.dart +++ b/lib/repositories/appointment_repo.dart @@ -11,7 +11,20 @@ import 'package:mc_common_app/models/appointments_models/schedule_model.dart'; import 'package:mc_common_app/models/appointments_models/service_schedule_model.dart'; import 'package:mc_common_app/utils/enums.dart'; +import '../models/appointments_models/appointment_list_model.dart'; + abstract class AppointmentRepo { + Future> getMyAppointments( + Map map); + + Future updateAppointmentStatus( + Map map); + + Future updateAppointmentPaymentStatus( + Map map); + + Future getAppointmentSlots(Map map); + Future getAllServices(String branchId); Future createSchedule(Map map); @@ -24,14 +37,20 @@ abstract class AppointmentRepo { Future updateServicesInSchedule(Map map); - Future> mergeServiceIntoAvailableSchedules({ + Future> + mergeServiceIntoAvailableSchedules({ required List serviceItemIdsForHome, required List serviceItemIdsForWorkshop, }); - Future createServiceAppointment({required List schedules, required int serviceProviderID}); + Future createServiceAppointment( + {required List schedules, + required int serviceProviderID}); - Future cancelOrRescheduleServiceAppointment({required int serviceAppointmentID, required int serviceSlotID, required int appointmentScheduleAction}); + Future cancelOrRescheduleServiceAppointment( + {required int serviceAppointmentID, + required int serviceSlotID, + required int appointmentScheduleAction}); } class AppointmentRepoImp implements AppointmentRepo { @@ -39,19 +58,25 @@ class AppointmentRepoImp implements AppointmentRepo { Future getAllServices(String branchId) async { Map map = {"ProviderBranchID": branchId}; String t = AppState().getUser.data!.accessToken ?? ""; - return await injector.get().getJsonForObject((json) => Services.fromJson(json), ApiConsts.getServicesOfBranch, token: t, queryParameters: map); + return await injector.get().getJsonForObject( + (json) => Services.fromJson(json), ApiConsts.getServicesOfBranch, + token: t, queryParameters: map); } @override Future createSchedule(Map map) async { String t = AppState().getUser.data!.accessToken ?? ""; - return await injector.get().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.createSchedule, map, token: t); + return await injector.get().postJsonForObject( + (json) => MResponse.fromJson(json), ApiConsts.createSchedule, map, + token: t); } @override Future addServicesInSchedule(Map map) async { String t = AppState().getUser.data!.accessToken ?? ""; - return await injector.get().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.createGroup, map, token: t); + return await injector.get().postJsonForObject( + (json) => MResponse.fromJson(json), ApiConsts.createGroup, map, + token: t); } @override @@ -59,29 +84,36 @@ class AppointmentRepoImp implements AppointmentRepo { Map map = {"ServiceProviderBranchID": branchId}; String t = AppState().getUser.data!.accessToken ?? ""; - GenericRespModel adsGenericModel = await injector.get().getJsonForObject( - (json) => GenericRespModel.fromJson(json), - ApiConsts.getSchedule, - token: t, - queryParameters: map, - ); + GenericRespModel adsGenericModel = + await injector.get().getJsonForObject( + (json) => GenericRespModel.fromJson(json), + ApiConsts.getSchedule, + token: t, + queryParameters: map, + ); - return List.generate(adsGenericModel.data.length, (index) => ScheduleData.fromJson(adsGenericModel.data[index])); + return List.generate(adsGenericModel.data.length, + (index) => ScheduleData.fromJson(adsGenericModel.data[index])); } @override Future updateSchedule(Map map) async { String t = AppState().getUser.data!.accessToken ?? ""; - return await injector.get().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.updateSchedule, map, token: t); + return await injector.get().postJsonForObject( + (json) => MResponse.fromJson(json), ApiConsts.updateSchedule, map, + token: t); } @override Future updateServicesInSchedule(Map map) async { String t = AppState().getUser.data!.accessToken ?? ""; - return await injector.get().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.updateGroup, map, token: t); + return await injector.get().postJsonForObject( + (json) => MResponse.fromJson(json), ApiConsts.updateGroup, map, + token: t); } - Future> mergeServiceIntoAvailableSchedules({ + Future> + mergeServiceIntoAvailableSchedules({ required List serviceItemIdsForHome, required List serviceItemIdsForWorkshop, }) async { @@ -96,21 +128,28 @@ class AppointmentRepoImp implements AppointmentRepo { "ServiceItemIDs": serviceItemIdsForWorkshop, } ]; - GenericRespModel adsGenericModel = await injector.get().postJsonForObject( - (json) => GenericRespModel.fromJson(json), - ApiConsts.GetServiceItemAppointmentScheduleSlots, - queryParameters, - token: t, - ); + GenericRespModel adsGenericModel = + await injector.get().postJsonForObject( + (json) => GenericRespModel.fromJson(json), + ApiConsts.GetServiceItemAppointmentScheduleSlots, + queryParameters, + token: t, + ); if (adsGenericModel.data == null) { return []; } List serviceAppointmentScheduleModel = - List.generate(adsGenericModel.data.length, (index) => ServiceAppointmentScheduleModel.fromJson(adsGenericModel.data[index], isForAppointment: true)); + List.generate( + adsGenericModel.data.length, + (index) => ServiceAppointmentScheduleModel.fromJson( + adsGenericModel.data[index], + isForAppointment: true)); return serviceAppointmentScheduleModel; } - Future createServiceAppointment({required List schedules, required int serviceProviderID}) async { + Future createServiceAppointment( + {required List schedules, + required int serviceProviderID}) async { String t = AppState().getUser.data!.accessToken ?? ""; int customerId = AppState().getUser.data!.userInfo!.customerId ?? 0; @@ -130,18 +169,22 @@ class AppointmentRepoImp implements AppointmentRepo { }); }); - GenericRespModel adsGenericModel = await injector.get().postJsonForObject( - (json) => GenericRespModel.fromJson(json), - ApiConsts.ServiceProvidersAppointmentCreate, - mapList, - token: t, - ); + GenericRespModel adsGenericModel = + await injector.get().postJsonForObject( + (json) => GenericRespModel.fromJson(json), + ApiConsts.ServiceProvidersAppointmentCreate, + mapList, + token: t, + ); return adsGenericModel; } @override - Future cancelOrRescheduleServiceAppointment({required int serviceAppointmentID, required int serviceSlotID, required int appointmentScheduleAction}) async { + Future cancelOrRescheduleServiceAppointment( + {required int serviceAppointmentID, + required int serviceSlotID, + required int appointmentScheduleAction}) async { String t = AppState().getUser.data!.accessToken ?? ""; final payload = { @@ -150,13 +193,63 @@ class AppointmentRepoImp implements AppointmentRepo { "appointmentScheduleAction": appointmentScheduleAction, }; - GenericRespModel adsGenericModel = await injector.get().postJsonForObject( - (json) => GenericRespModel.fromJson(json), - ApiConsts.ServiceProviderAppointmentRescheduleCancelAppointment, - payload, - token: t, - ); + GenericRespModel adsGenericModel = + await injector.get().postJsonForObject( + (json) => GenericRespModel.fromJson(json), + ApiConsts.ServiceProviderAppointmentRescheduleCancelAppointment, + payload, + token: t, + ); return adsGenericModel; } + + @override + Future> getMyAppointments( + Map map) async { + String t = AppState().getUser.data!.accessToken ?? ""; + + GenericRespModel genericRespModel = + await injector.get().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 getAppointmentSlots(Map map) async { + String t = AppState().getUser.data!.accessToken ?? ""; + + MResponse adsGenericModel = + await injector.get().getJsonForObject( + (json) => MResponse.fromJson(json), + ApiConsts.getAppointmentSlots, + token: t, + queryParameters: map, + ); + + return adsGenericModel; + } + + @override + Future updateAppointmentPaymentStatus(Map map) async { + String t = AppState().getUser.data!.accessToken ?? ""; + return await injector.get().postJsonForObject( + (json) => MResponse.fromJson(json), ApiConsts.updateAppointmentPaymentStatus, map, + token: t); + } + + @override + Future updateAppointmentStatus(Map map) async { + String t = AppState().getUser.data!.accessToken ?? ""; + return await injector.get().postJsonForObject( + (json) => MResponse.fromJson(json), ApiConsts.updateAppointmentStatus, map, + token: t); + } } diff --git a/lib/repositories/common_repo.dart b/lib/repositories/common_repo.dart index b9d5209..0ec703d 100644 --- a/lib/repositories/common_repo.dart +++ b/lib/repositories/common_repo.dart @@ -12,7 +12,6 @@ import 'package:mc_common_app/models/user_models/cities.dart'; import 'package:mc_common_app/models/user_models/country.dart'; import 'package:mc_common_app/models/user_models/role.dart'; - abstract class CommonRepo { Future getAllCountries(); @@ -25,9 +24,12 @@ abstract class CommonRepo { Future> getMyAppointments(); - Future getCarCheckServiceScheduleDetails({required double lat, required double long}); + Future getCarCheckServiceScheduleDetails( + {required double lat, required double long}); - Future> getPhotographyServiceScheduleListByOffices({required double lat, required double long}); + Future> + getPhotographyServiceScheduleListByOffices( + {required double lat, required double long}); // Future> getProviderServiceCategories(); @@ -36,9 +38,11 @@ abstract class CommonRepo { Future> getVehicleTypes(); //TODO: Needs to remove common methods from AD's repo and delete all repeated methods. - Future getVehicleDetails({int? vehicleTypeId, int? vehicleBrandId}); + Future getVehicleDetails( + {int? vehicleTypeId, int? vehicleBrandId}); - Future> getEnumTypeValues({int? enumTypeID, String? enumTypeName}); + Future> getEnumTypeValues( + {int? enumTypeID, String? enumTypeName}); } class CommonRepoImp implements CommonRepo { @@ -47,7 +51,8 @@ class CommonRepoImp implements CommonRepo { @override Future getAllCountries() async { - return await apiClient.getJsonForObject((json) => Country.fromJson(json), ApiConsts.GetAllCountry); + return await apiClient.getJsonForObject( + (json) => Country.fromJson(json), ApiConsts.GetAllCountry); } @override @@ -55,18 +60,22 @@ class CommonRepoImp implements CommonRepo { var postParams = { "CountryID": countryId, }; - return await apiClient.getJsonForObject((json) => Cities.fromJson(json), ApiConsts.GetAllCities, queryParameters: postParams); + return await apiClient.getJsonForObject( + (json) => Cities.fromJson(json), ApiConsts.GetAllCities, + queryParameters: postParams); } @override Future getRoles() async { - return await apiClient.getJsonForObject((json) => Role.fromJson(json), ApiConsts.GetProviderRoles); + return await apiClient.getJsonForObject( + (json) => Role.fromJson(json), ApiConsts.GetProviderRoles); } @override Future> getMyAppointments() async { var params = { - "customerID": appState.getUser.data!.userInfo!.customerId.toString() ?? "", + "customerID": + appState.getUser.data!.userInfo!.customerId.toString() ?? "", }; GenericRespModel genericRespModel = await apiClient.getJsonForObject( token: appState.getUser.data!.accessToken, @@ -74,12 +83,15 @@ class CommonRepoImp implements CommonRepo { queryParameters: params, ApiConsts.serviceProvidersAppointmentGet, ); - List appointmentList = List.generate(genericRespModel.data.length, (index) => AppointmentListModel.fromJson(genericRespModel.data[index])); + List appointmentList = List.generate( + genericRespModel.data.length, + (index) => AppointmentListModel.fromJson(genericRespModel.data[index])); return appointmentList; } @override - Future getCarCheckServiceScheduleDetails({required double lat, required double long}) async { + Future getCarCheckServiceScheduleDetails( + {required double lat, required double long}) async { var params = { "Latitude": lat.toString(), "Longitude": long.toString(), @@ -90,12 +102,15 @@ class CommonRepoImp implements CommonRepo { queryParameters: params, ApiConsts.adsCarCheckupSPBranchScheduleSlotGet, ); - SSCarCheckScheduleModel ssCarCheckScheduleModel = SSCarCheckScheduleModel.fromJson(genericRespModel.data[0]); + SSCarCheckScheduleModel ssCarCheckScheduleModel = + SSCarCheckScheduleModel.fromJson(genericRespModel.data[0]); return ssCarCheckScheduleModel; } @override - Future> getPhotographyServiceScheduleListByOffices({required double lat, required double long}) async { + Future> + getPhotographyServiceScheduleListByOffices( + {required double lat, required double long}) async { var params = { "Latitude": lat.toString(), "Longitude": long.toString(), @@ -109,19 +124,28 @@ class CommonRepoImp implements CommonRepo { if (genericRespModel.data == null) { return []; } - List ssPhotoScheduleModel = List.generate(genericRespModel.data.length, (index) => SSPhotoOfficeScheduleModel.fromJson(genericRespModel.data[index])); + List ssPhotoScheduleModel = List.generate( + genericRespModel.data.length, + (index) => + SSPhotoOfficeScheduleModel.fromJson(genericRespModel.data[index])); return ssPhotoScheduleModel ?? []; } @override Future> getVehicleTypes() async { - GenericRespModel adsGenericModel = await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleTypeGet); - List vehicleTypes = List.generate(adsGenericModel.data.length, (index) => VehicleTypeModel.fromJson(adsGenericModel.data[index])); + GenericRespModel adsGenericModel = await apiClient.getJsonForObject( + token: appState.getUser.data!.accessToken, + (json) => GenericRespModel.fromJson(json), + ApiConsts.vehicleTypeGet); + List vehicleTypes = List.generate( + adsGenericModel.data.length, + (index) => VehicleTypeModel.fromJson(adsGenericModel.data[index])); return vehicleTypes; } @override - Future getVehicleDetails({int? vehicleTypeId, int? vehicleBrandId}) async { + Future getVehicleDetails( + {int? vehicleTypeId, int? vehicleBrandId}) async { var postParams = { "vehicleType": vehicleTypeId ?? 0, "isVehicleBrand": "true", @@ -146,24 +170,35 @@ class CommonRepoImp implements CommonRepo { postParams, token: token, ); - VehicleDetailsModel vehicleDetails = VehicleDetailsModel.fromJson(adsGenericModel.data); + VehicleDetailsModel vehicleDetails = + VehicleDetailsModel.fromJson(adsGenericModel.data); return vehicleDetails; } @override - Future> getVehicleCities({required int countryId}) async { + Future> getVehicleCities( + {required int countryId}) async { var postParams = { "CountryID": countryId.toString(), }; - GenericRespModel adsGenericModel = - await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.vehicleCityGet, queryParameters: postParams); - List vehicleCities = List.generate(adsGenericModel.data.length, (index) => VehicleCityModel.fromJson(adsGenericModel.data[index])); + GenericRespModel adsGenericModel = await apiClient.getJsonForObject( + token: appState.getUser.data!.accessToken, + (json) => GenericRespModel.fromJson(json), + ApiConsts.vehicleCityGet, + queryParameters: postParams); + List vehicleCities = List.generate( + adsGenericModel.data.length, + (index) => VehicleCityModel.fromJson(adsGenericModel.data[index])); return vehicleCities; } @override - Future> getEnumTypeValues({int? enumTypeID, String? enumTypeName}) async { - var postParams = {"enumTypeID": (enumTypeID ?? 0).toString(), "enumTypeName": enumTypeName ?? ""}; + Future> getEnumTypeValues( + {int? enumTypeID, String? enumTypeName}) async { + var postParams = { + "enumTypeID": (enumTypeID ?? 0).toString(), + "enumTypeName": enumTypeName ?? "" + }; GenericRespModel enumGenericModel = await apiClient.postJsonForObject( (json) => GenericRespModel.fromJson(json), ApiConsts.getEnumTypeValues, @@ -171,7 +206,8 @@ class CommonRepoImp implements CommonRepo { token: appState.getUser.data!.accessToken, ); - List vehicleCities = List.generate(enumGenericModel.data.length, (index) => EnumsModel.fromJson(enumGenericModel.data[index])); + List vehicleCities = List.generate(enumGenericModel.data.length, + (index) => EnumsModel.fromJson(enumGenericModel.data[index])); return vehicleCities; } // diff --git a/lib/utils/enums.dart b/lib/utils/enums.dart index 395bb64..1bf4bd0 100644 --- a/lib/utils/enums.dart +++ b/lib/utils/enums.dart @@ -149,6 +149,17 @@ enum AppointmentStatusEnum { cancelled, rescheduled, allAppointments, + upcoming, + inProgress, + completed, +} + +enum AppointmentPaymentStatusEnum { + notConfirmed, + payNow, + paid, + payLater, + payPartial, } enum RequestsTypeEnum { diff --git a/lib/view_models/appointments_view_model.dart b/lib/view_models/appointments_view_model.dart index f55b9d7..2a9fb1b 100644 --- a/lib/view_models/appointments_view_model.dart +++ b/lib/view_models/appointments_view_model.dart @@ -6,6 +6,7 @@ import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart'; import 'package:mc_common_app/models/general_models/enums_model.dart'; import 'package:mc_common_app/models/general_models/generic_resp_model.dart'; +import 'package:mc_common_app/models/general_models/m_response.dart'; import 'package:mc_common_app/models/provider_branches_models/branch_detail_model.dart'; import 'package:mc_common_app/models/provider_branches_models/provider_profile_model.dart'; import 'package:mc_common_app/models/appointments_models/service_schedule_model.dart'; @@ -30,20 +31,31 @@ import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:provider/provider.dart'; +import '../models/appointments_models/appointment_slots.dart'; + class AppointmentsVM extends BaseVM { final CommonRepo commonRepo; final CommonAppServices commonServices; final ProviderRepo providerRepo; final AppointmentRepo scheduleRepo; - AppointmentsVM({required this.commonServices, required this.scheduleRepo, required this.providerRepo, required this.commonRepo}); + AppointmentsVM({required this.commonServices, + required this.scheduleRepo, + required this.providerRepo, + required this.commonRepo}); bool isFetchingLists = false; + int selectedBranch = 0; + int selectedAppointmentIndex = 0; + int selectedAppointmentSubIndex = 0; + int selectedAppointmentId = 0; List myAppointments = []; List myUpComingAppointments = []; List myFilteredAppointments = []; List appointmentsFilterOptions = []; + List customersAppointments = []; + List myFilteredAppointments2 = []; // List availableSchedules = []; @@ -56,7 +68,8 @@ class AppointmentsVM extends BaseVM { List serviceAppointmentScheduleList = []; bool ifItemAlreadySelected(int id) { - int indexFound = allSelectedItemsInAppointments.indexWhere((element) => element.id == id); + int indexFound = allSelectedItemsInAppointments + .indexWhere((element) => element.id == id); if (indexFound != -1) { return true; } @@ -65,9 +78,24 @@ class AppointmentsVM extends BaseVM { List allSelectedItemsInAppointments = []; + setupProviderAppointmentFilter() { + appointmentsFilterOptions.clear(); + appointmentsFilterOptions.add( + FilterListModel(id: 0, title: "All Appointments", isSelected: true)); + appointmentsFilterOptions + .add(FilterListModel(id: 6, title: "Upcoming", isSelected: false)); + appointmentsFilterOptions + .add(FilterListModel(id: 3, title: "Arrived", isSelected: false)); + appointmentsFilterOptions + .add(FilterListModel(id: 7, title: "In Progress", isSelected: false)); + appointmentsFilterOptions + .add(FilterListModel(id: 8, title: "Completed", isSelected: false)); + } + Future onItemsSelectedInService() async { if (currentServiceSelection != null) { - int index = servicesInCurrentAppointment.indexWhere((element) => element.serviceId == currentServiceSelection!.serviceId!); + int index = servicesInCurrentAppointment.indexWhere((element) => + element.serviceId == currentServiceSelection!.serviceId!); if (index == -1) { double totalPrice = 0.0; @@ -88,12 +116,14 @@ class AppointmentsVM extends BaseVM { bool isSuccess = false; List appointmentIdsList = []; try { - GenericRespModel genericRespModel = await scheduleRepo.createServiceAppointment( + GenericRespModel genericRespModel = + await scheduleRepo.createServiceAppointment( schedules: serviceAppointmentScheduleList, serviceProviderID: selectedBranchModel!.serviceProviderId ?? 0, ); - if (genericRespModel.messageStatus == 2 || genericRespModel.data == null) { + if (genericRespModel.messageStatus == 2 || + genericRespModel.data == null) { Utils.hideLoading(context); Utils.showToast("${genericRespModel.message.toString()}"); return; @@ -111,13 +141,17 @@ class AppointmentsVM extends BaseVM { } context.read().onNavbarTapped(1); - applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.booked); + applyFilterOnAppointmentsVM( + appointmentStatusEnum: AppointmentStatusEnum.booked); Utils.hideLoading(context); resetAfterBookingAppointment(); if (isSuccess) { if (amountToPayForAppointment > 0) { - context.read().updateAppointmentIdsForPayment(ids: appointmentIdsList); - navigateWithName(context, AppRoutes.paymentMethodsView, arguments: PaymentTypes.appointment); + context + .read() + .updateAppointmentIdsForPayment(ids: appointmentIdsList); + navigateWithName(context, AppRoutes.paymentMethodsView, + arguments: PaymentTypes.appointment); } else { Utils.showToast("Your appointment has been booked successfully!"); getMyAppointments(); @@ -129,28 +163,36 @@ class AppointmentsVM extends BaseVM { } } - Future onConfirmAppointmentPressed({required BuildContext context, required appointmentId}) async { - context.read().updateAppointmentIdsForPayment(ids: [appointmentId]); - navigateWithName(context, AppRoutes.paymentMethodsView, arguments: PaymentTypes.appointment); + Future onConfirmAppointmentPressed( + {required BuildContext context, required appointmentId}) async { + context + .read() + .updateAppointmentIdsForPayment(ids: [appointmentId]); + navigateWithName(context, AppRoutes.paymentMethodsView, + arguments: PaymentTypes.appointment); } - Future onCancelAppointmentPressed({required BuildContext context, required AppointmentListModel appointmentListModel}) async { + Future onCancelAppointmentPressed({required BuildContext context, + required AppointmentListModel appointmentListModel}) async { Utils.showLoading(context); try { - GenericRespModel genericRespModel = await scheduleRepo.cancelOrRescheduleServiceAppointment( + GenericRespModel genericRespModel = + await scheduleRepo.cancelOrRescheduleServiceAppointment( serviceAppointmentID: appointmentListModel.id ?? 0, serviceSlotID: appointmentListModel.serviceSlotID ?? 0, appointmentScheduleAction: 2, // 1 for Reschedule and 2 for Cancel ); - if (genericRespModel.messageStatus == 2 || genericRespModel.data == null) { + if (genericRespModel.messageStatus == 2 || + genericRespModel.data == null) { Utils.hideLoading(context); Utils.showToast("${genericRespModel.message.toString()}"); return; } if (genericRespModel.data == 1) { context.read().onNavbarTapped(1); - applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.cancelled); + applyFilterOnAppointmentsVM( + appointmentStatusEnum: AppointmentStatusEnum.cancelled); Utils.showToast("${genericRespModel.message.toString()}"); await getMyAppointments(); Utils.hideLoading(context); @@ -181,7 +223,8 @@ class AppointmentsVM extends BaseVM { notifyListeners(); } - SelectionModel branchSelectedCategoryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); + SelectionModel branchSelectedCategoryId = + SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); void updateProviderCategoryId(SelectionModel id) { branchSelectedCategoryId = id; @@ -200,23 +243,30 @@ class AppointmentsVM extends BaseVM { void updateBranchServiceId(SelectionModel id) async { branchSelectedServiceId = id; - currentServiceSelection = branchServices.firstWhere((element) => element.serviceProviderServiceId == id.selectedId); + currentServiceSelection = branchServices.firstWhere( + (element) => element.serviceProviderServiceId == id.selectedId); notifyListeners(); } void removeServiceInCurrentAppointment(int index) { - int serviceId = servicesInCurrentAppointment.elementAt(index).serviceProviderServiceId ?? -1; - allSelectedItemsInAppointments.removeWhere((element) => element.serviceProviderServiceId == serviceId); + int serviceId = servicesInCurrentAppointment + .elementAt(index) + .serviceProviderServiceId ?? + -1; + allSelectedItemsInAppointments.removeWhere( + (element) => element.serviceProviderServiceId == serviceId); servicesInCurrentAppointment.removeAt(index); notifyListeners(); } resetCategorySelectionBottomSheet() { selectedSubServicesCounter = 0; - branchSelectedCategoryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); + branchSelectedCategoryId = + SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); isHomeTapped = false; - branchSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); + branchSelectedServiceId = + SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); currentServiceSelection = null; } @@ -231,76 +281,222 @@ class AppointmentsVM extends BaseVM { populateAppointmentsFilterList() async { appointmentsFilterOptions.clear(); - myAppointmentsEnum = await commonRepo.getEnumTypeValues(enumTypeID: 13); //TODO: 13 is to get Appointments Filter Enums + myAppointmentsEnum = await commonRepo.getEnumTypeValues( + enumTypeID: 13); //TODO: 13 is to get Appointments Filter Enums for (int i = 0; i < myAppointmentsEnum.length; i++) { - appointmentsFilterOptions.add(FilterListModel(title: myAppointmentsEnum[i].enumValueStr, isSelected: false, id: myAppointmentsEnum[i].enumValue)); + appointmentsFilterOptions.add(FilterListModel( + title: myAppointmentsEnum[i].enumValueStr, + isSelected: false, + id: myAppointmentsEnum[i].enumValue)); } - appointmentsFilterOptions.insert(0, FilterListModel(title: "All Appointments", isSelected: true, id: 0)); + appointmentsFilterOptions.insert( + 0, FilterListModel(title: "All Appointments", isSelected: true, id: 0)); notifyListeners(); } - applyFilterOnAppointmentsVM({required AppointmentStatusEnum appointmentStatusEnum}) { + applyFilterOnAppointmentsVM( + {required AppointmentStatusEnum appointmentStatusEnum, + bool isNeedCustomerFilter = false}) { if (appointmentsFilterOptions.isEmpty) return; for (var value in appointmentsFilterOptions) { value.isSelected = false; } - appointmentsFilterOptions[appointmentStatusEnum.getIdFromAppointmentStatusEnum()].isSelected = true; + + appointmentsFilterOptions.forEach((element) { + if (element.id == + appointmentStatusEnum.getIdFromAppointmentStatusEnum()) { + element.isSelected = true; + } + }); + // appointmentsFilterOptions[ + // appointmentStatusEnum.getIdFromAppointmentStatusEnum()] + // .isSelected = true; if (appointmentStatusEnum.getIdFromAppointmentStatusEnum() == 0) { myFilteredAppointments = myAppointments; + if (isNeedCustomerFilter) findAppointmentsBasedOnCustomers(); notifyListeners(); return; } - myFilteredAppointments = myAppointments.where((element) => element.appointmentStatusID! == appointmentStatusEnum.getIdFromAppointmentStatusEnum()).toList(); + myFilteredAppointments = myAppointments + .where((element) => + element.appointmentStatusID! == + appointmentStatusEnum.getIdFromAppointmentStatusEnum()) + .toList(); + if (isNeedCustomerFilter) findAppointmentsBasedOnCustomers(); notifyListeners(); } + findAppointmentsBasedOnCustomers() { + // Use a Set to ensure uniqueness of customerIDs + Set uniqueCustomerIDs = Set(); + + // Extract unique customerIDs + for (var item in myFilteredAppointments) { + uniqueCustomerIDs.add(item.customerID ?? 0); + } + + // Create a list of CustomerData instances + myFilteredAppointments2 = uniqueCustomerIDs.map((id) { + List list = myFilteredAppointments + .where((item) => item.customerID == id) + .toList(); + AppointmentListModel model = list.first; + model.customerAppointmentList = list; + return model; + }).toList(); + // customersAppointments = uniqueCustomerIDs.map((id) { + // List list = myFilteredAppointments + // .where((item) => item.customerID == id) + // .toList(); + // var customerItem = + // myFilteredAppointments.firstWhere((item) => item.customerID == id); + // + // return CustomerData( + // customerID: id, + // customerName: customerItem.customerName ?? "", + // appointmentList: list, + // ); + // }).toList(); + } + Future getMyAppointments({bool isNeedToRebuild = false}) async { if (isNeedToRebuild) setState(ViewState.busy); myAppointments = await commonRepo.getMyAppointments(); myFilteredAppointments = myAppointments; - myUpComingAppointments = myAppointments.where((element) => element.appointmentStatusEnum == AppointmentStatusEnum.booked).toList(); + myUpComingAppointments = myAppointments + .where((element) => + element.appointmentStatusEnum == AppointmentStatusEnum.booked) + .toList(); setState(ViewState.idle); // applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.allAppointments); notifyListeners(); } + AppointmentSlots? appointmentSlots; + + Future getAppointmentSlotsInfo({required Map map, + required BuildContext context, + bool isNeedToRebuild = false}) async { + if (isNeedToRebuild) setState(ViewState.busy); + try { + MResponse genericRespModel = await scheduleRepo.getAppointmentSlots(map); + if (genericRespModel.messageStatus == 1) { + appointmentSlots = AppointmentSlots.fromJson(genericRespModel.data); + } else { + Utils.showToast(genericRespModel.message.toString()); + } + } catch (e) { + Utils.showToast(e.toString()); + } + } + + Future getProviderMyAppointments(Map map, + {bool isNeedToRebuild = false}) async { + if (isNeedToRebuild) setState(ViewState.busy); + + myAppointments = await scheduleRepo.getMyAppointments(map); + myFilteredAppointments = myAppointments; + // myUpComingAppointments = myAppointments + // .where((element) => + // element.appointmentStatusEnum == AppointmentStatusEnum.booked) + // .toList(); + setState(ViewState.idle); + applyFilterOnAppointmentsVM( + appointmentStatusEnum: AppointmentStatusEnum.allAppointments, + isNeedCustomerFilter: true); + notifyListeners(); + } + updateSelectedBranch(BranchDetailModel branchDetailModel) { selectedBranchModel = branchDetailModel; getBranchCategories(); notifyListeners(); } - updateSelectedAppointmentDate({required int dateIndex, required int scheduleIndex}) { - for (var element in serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList!) { + updateAppointmentStatus(Map map,{bool isNeedToRebuild = false}) async { + if (isNeedToRebuild) setState(ViewState.busy); + try { + MResponse genericRespModel = await scheduleRepo.updateAppointmentStatus(map); + + if (genericRespModel.messageStatus == 1) { + Utils.showToast("appointment status updated"); + } else { + Utils.showToast(genericRespModel.message.toString()); + } + } catch (e) { + Utils.showToast(e.toString()); + } + } + + updateAppointmentPaymentStatus(Map map,{bool isNeedToRebuild = false}) async { + if (isNeedToRebuild) setState(ViewState.busy); + try { + MResponse genericRespModel = await scheduleRepo.updateAppointmentPaymentStatus(map); + + if (genericRespModel.messageStatus == 1) { + Utils.showToast("payment status updated"); + } else { + Utils.showToast(genericRespModel.message.toString()); + } + } catch (e) { + Utils.showToast(e.toString()); + } + } + + updateSelectedAppointmentDate( + {required int dateIndex, required int scheduleIndex}) { + for (var element in serviceAppointmentScheduleList[scheduleIndex] + .customTimeDateSlotList!) { element.date!.isSelected = false; } - serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![dateIndex].date!.isSelected = true; + serviceAppointmentScheduleList[scheduleIndex] + .customTimeDateSlotList![dateIndex] + .date! + .isSelected = true; serviceAppointmentScheduleList[scheduleIndex].selectedDateIndex = dateIndex; final date = TimeSlotModel( - date: serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![dateIndex].date!.date, - slotId: serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![dateIndex].date!.slotId, + date: serviceAppointmentScheduleList[scheduleIndex] + .customTimeDateSlotList![dateIndex] + .date! + .date, + slotId: serviceAppointmentScheduleList[scheduleIndex] + .customTimeDateSlotList![dateIndex] + .date! + .slotId, isSelected: true, slot: "", ); - serviceAppointmentScheduleList[scheduleIndex].selectedCustomTimeDateSlotModel = CustomTimeDateSlotModel(date: date); + serviceAppointmentScheduleList[scheduleIndex] + .selectedCustomTimeDateSlotModel = CustomTimeDateSlotModel(date: date); notifyListeners(); } - updateSelectedAppointmentSlotByDate({required int scheduleIndex, required int slotIndex}) { - for (var element in serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList!) { + updateSelectedAppointmentSlotByDate( + {required int scheduleIndex, required int slotIndex}) { + for (var element in serviceAppointmentScheduleList[scheduleIndex] + .customTimeDateSlotList!) { for (var element in element.availableSlots!) { element.isSelected = false; } } - int index = serviceAppointmentScheduleList[scheduleIndex].selectedDateIndex!; - serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![index].availableSlots![slotIndex].isSelected = true; - serviceAppointmentScheduleList[scheduleIndex].selectedCustomTimeDateSlotModel!.availableSlots = serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![index].availableSlots!; + int index = + serviceAppointmentScheduleList[scheduleIndex].selectedDateIndex!; + serviceAppointmentScheduleList[scheduleIndex] + .customTimeDateSlotList![index] + .availableSlots![slotIndex] + .isSelected = true; + serviceAppointmentScheduleList[scheduleIndex] + .selectedCustomTimeDateSlotModel! + .availableSlots = + serviceAppointmentScheduleList[scheduleIndex] + .customTimeDateSlotList![index] + .availableSlots!; notifyListeners(); } @@ -314,7 +510,9 @@ class AppointmentsVM extends BaseVM { int selectedSubServicesCounter = 0; onItemUpdateOrSelected(int index, bool selected, int itemId) { - int serviceIndex = servicesInCurrentAppointment.indexWhere((element) => element.serviceId == currentServiceSelection!.serviceId!); + int serviceIndex = servicesInCurrentAppointment.indexWhere( + (element) => + element.serviceId == currentServiceSelection!.serviceId!); // print("servicesInCurrentAppointment: ${servicesInCurrentAppointment.length}"); // if (serviceIndex == -1) { // return; @@ -329,19 +527,28 @@ class AppointmentsVM extends BaseVM { allSelectedItemsInAppointments.add(serviceItemsFromApi[index]); for (var element in allSelectedItemsInAppointments) { if (!ifItemAlreadySelected(element.id!)) { - servicesInCurrentAppointment[serviceIndex].serviceItems!.add(serviceItemsFromApi[index]); + servicesInCurrentAppointment[serviceIndex] + .serviceItems! + .add(serviceItemsFromApi[index]); servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice = - servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice + double.parse((serviceItemsFromApi[index].price) ?? "0.0"); + servicesInCurrentAppointment[serviceIndex] + .currentTotalServicePrice + + double.parse((serviceItemsFromApi[index].price) ?? "0.0"); } } } if (!selected) { selectedSubServicesCounter = selectedSubServicesCounter - 1; - currentServiceSelection!.serviceItems!.removeWhere((element) => element.id == itemId); - allSelectedItemsInAppointments.removeWhere((element) => element.id == itemId); + currentServiceSelection!.serviceItems! + .removeWhere((element) => element.id == itemId); + allSelectedItemsInAppointments + .removeWhere((element) => element.id == itemId); servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice = - servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice - double.parse((serviceItemsFromApi[index].price) ?? "0.0"); - servicesInCurrentAppointment[serviceIndex].serviceItems!.removeWhere((element) => element.id == itemId); + servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice - + double.parse((serviceItemsFromApi[index].price) ?? "0.0"); + servicesInCurrentAppointment[serviceIndex] + .serviceItems! + .removeWhere((element) => element.id == itemId); } notifyListeners(); } @@ -397,7 +604,8 @@ class AppointmentsVM extends BaseVM { String pickHomeLocationError = ""; String selectSubServicesError = ""; - SelectionModel branchSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); + SelectionModel branchSelectedServiceId = + SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); bool isCategoryAlreadyPresent(int id) { final contain = branchCategories.where((element) => element.id == id); @@ -410,14 +618,16 @@ class AppointmentsVM extends BaseVM { void getBranchCategories() async { for (var value in selectedBranchModel!.branchServices!) { if (!isCategoryAlreadyPresent(value.categoryId!)) { - branchCategories.add(DropValue(value.categoryId!, value.categoryName!, "")); + branchCategories + .add(DropValue(value.categoryId!, value.categoryName!, "")); } } notifyListeners(); } getBranchServices({required int categoryId}) async { - branchSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); + branchSelectedServiceId = + SelectionModel(selectedOption: "", selectedId: -1, errorValue: ""); isHomeTapped = false; pickedHomeLocation = ""; pickHomeLocationError = ""; @@ -430,7 +640,9 @@ class AppointmentsVM extends BaseVM { } List getFilteredBranchServices({required int categoryId}) { - List filteredServices = selectedBranchModel!.branchServices!.where((element) => element.categoryId == categoryId).toList(); + List filteredServices = selectedBranchModel!.branchServices! + .where((element) => element.categoryId == categoryId) + .toList(); return filteredServices; } @@ -472,7 +684,8 @@ class AppointmentsVM extends BaseVM { return totalPrice.toString(); } - void openTheAddServiceBottomSheet(BuildContext context, AppointmentsVM appointmentsVM) { + void openTheAddServiceBottomSheet(BuildContext context, + AppointmentsVM appointmentsVM) { showModalBottomSheet( context: context, isScrollControlled: true, @@ -483,7 +696,8 @@ class AppointmentsVM extends BaseVM { ); } - void priceBreakDownClicked(BuildContext context, ServiceModel selectedService) { + void priceBreakDownClicked(BuildContext context, + ServiceModel selectedService) { showModalBottomSheet( context: context, isScrollControlled: true, @@ -499,19 +713,27 @@ class AppointmentsVM extends BaseVM { Column( children: List.generate( selectedService.serviceItems!.length, - (index) => Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - "${selectedService.serviceItems![index].name}".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), - "${selectedService.serviceItems![index].price} SAR".toText(fontSize: 12, isBold: true), - ], - ), + (index) => + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + "${selectedService.serviceItems![index].name}" + .toText( + fontSize: 12, + color: MyColors.lightTextColor, + isBold: true), + "${selectedService.serviceItems![index] + .price} SAR" + .toText(fontSize: 12, isBold: true), + ], + ), ), ), Row( mainAxisAlignment: MainAxisAlignment.end, children: [ - "${selectedService.currentTotalServicePrice} SAR".toText(fontSize: 16, isBold: true), + "${selectedService.currentTotalServicePrice} SAR" + .toText(fontSize: 16, isBold: true), ], ), if (selectedService.isHomeSelected) ...[ @@ -520,15 +742,20 @@ class AppointmentsVM extends BaseVM { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - "${totalKms}km ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true), - "${selectedService.rangePricePerKm} x $totalKms".toText(fontSize: 12, isBold: true), + "${totalKms}km ".toText( + fontSize: 12, + color: MyColors.lightTextColor, + isBold: true), + "${selectedService.rangePricePerKm} x $totalKms" + .toText(fontSize: 12, isBold: true), ], ), 8.height, Row( mainAxisAlignment: MainAxisAlignment.end, children: [ - "${selectedService.rangePricePerKm ?? 0 * totalKms} SAR".toText(fontSize: 16, isBold: true), + "${selectedService.rangePricePerKm ?? 0 * totalKms} SAR" + .toText(fontSize: 16, isBold: true), ], ), ], @@ -541,11 +768,18 @@ class AppointmentsVM extends BaseVM { crossAxisAlignment: CrossAxisAlignment.end, children: [ (selectedService.isHomeSelected - ? "${(selectedService.currentTotalServicePrice) + (double.parse((selectedService.rangePricePerKm ?? "0.0")) * totalKms)}" - : "${selectedService.currentTotalServicePrice}") + ? "${(selectedService.currentTotalServicePrice) + + (double.parse((selectedService.rangePricePerKm ?? + "0.0")) * totalKms)}" + : "${selectedService.currentTotalServicePrice}") .toText(fontSize: 29, isBold: true), 2.width, - "SAR".toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5), + "SAR" + .toText( + color: MyColors.lightTextColor, + fontSize: 16, + isBold: true) + .paddingOnly(bottom: 5), ], ) ], @@ -565,7 +799,8 @@ class AppointmentsVM extends BaseVM { isValidated = false; break; } - if (schedule.selectedCustomTimeDateSlotModel!.date == null || !schedule.selectedCustomTimeDateSlotModel!.date!.isSelected) { + if (schedule.selectedCustomTimeDateSlotModel!.date == null || + !schedule.selectedCustomTimeDateSlotModel!.date!.isSelected) { isValidated = false; break; } else { @@ -573,7 +808,9 @@ class AppointmentsVM extends BaseVM { isValidated = false; break; } else { - TimeSlotModel slot = schedule.selectedCustomTimeDateSlotModel!.availableSlots!.firstWhere((element) => element.isSelected); + TimeSlotModel slot = schedule + .selectedCustomTimeDateSlotModel!.availableSlots! + .firstWhere((element) => element.isSelected); if (slot.date.isNotEmpty) { isValidated = true; break; @@ -582,7 +819,8 @@ class AppointmentsVM extends BaseVM { } } if (!isValidated) { - Utils.showToast("You must select appointment time for each schedule's appointment."); + Utils.showToast( + "You must select appointment time for each schedule's appointment."); return; } navigateWithName(context, AppRoutes.reviewAppointmentView); @@ -601,30 +839,36 @@ class AppointmentsVM extends BaseVM { } } - serviceAppointmentScheduleList = await scheduleRepo.mergeServiceIntoAvailableSchedules( + serviceAppointmentScheduleList = + await scheduleRepo.mergeServiceIntoAvailableSchedules( serviceItemIdsForHome: serviceItemIdsForHome, serviceItemIdsForWorkshop: serviceItemIdsForWorkshop, ); if (serviceAppointmentScheduleList.isEmpty) { Utils.hideLoading(context); - Utils.showToast("There are no available appointments for selected Items."); + Utils.showToast( + "There are no available appointments for selected Items."); return; } totalAmount = 0.0; amountToPayForAppointment = 0.0; for (var schedule in serviceAppointmentScheduleList) { - amountToPayForAppointment = amountToPayForAppointment + (schedule.amountToPay ?? 0.0); + amountToPayForAppointment = + amountToPayForAppointment + (schedule.amountToPay ?? 0.0); totalAmount = totalAmount + (schedule.amountTotal ?? 0.0); } Utils.hideLoading(context); - navigateWithName(context, AppRoutes.bookAppointmenSchedulesView, arguments: ScreenArgumentsForAppointmentDetailPage(routeFlag: 1, appointmentId: 0)); // 1 For Creating an Appointment + navigateWithName(context, AppRoutes.bookAppointmenSchedulesView, + arguments: ScreenArgumentsForAppointmentDetailPage( + routeFlag: 1, appointmentId: 0)); // 1 For Creating an Appointment notifyListeners(); } - Future onRescheduleAppointmentPressed({required BuildContext context, required AppointmentListModel appointmentListModel}) async { + Future onRescheduleAppointmentPressed({required BuildContext context, + required AppointmentListModel appointmentListModel}) async { Utils.showLoading(context); List serviceItemIdsForHome = []; @@ -641,14 +885,16 @@ class AppointmentsVM extends BaseVM { } } - serviceAppointmentScheduleList = await scheduleRepo.mergeServiceIntoAvailableSchedules( + serviceAppointmentScheduleList = + await scheduleRepo.mergeServiceIntoAvailableSchedules( serviceItemIdsForHome: serviceItemIdsForHome, serviceItemIdsForWorkshop: serviceItemIdsForWorkshop, ); if (serviceAppointmentScheduleList.isEmpty) { Utils.hideLoading(context); - Utils.showToast("There are no available appointments for selected Items."); + Utils.showToast( + "There are no available appointments for selected Items."); return; } Utils.hideLoading(context); @@ -656,29 +902,36 @@ class AppointmentsVM extends BaseVM { navigateWithName( context, AppRoutes.bookAppointmenSchedulesView, - arguments: ScreenArgumentsForAppointmentDetailPage(routeFlag: 2, appointmentId: appointmentListModel.id ?? 0), + arguments: ScreenArgumentsForAppointmentDetailPage( + routeFlag: 2, appointmentId: appointmentListModel.id ?? 0), ); // 2 For Rescheduling an Appointment notifyListeners(); } - Future onRescheduleAppointmentConfirmPressed({required BuildContext context, required int appointmentId, required int selectedSlotId}) async { + Future onRescheduleAppointmentConfirmPressed( + {required BuildContext context, + required int appointmentId, + required int selectedSlotId}) async { Utils.showLoading(context); try { - GenericRespModel genericRespModel = await scheduleRepo.cancelOrRescheduleServiceAppointment( + GenericRespModel genericRespModel = + await scheduleRepo.cancelOrRescheduleServiceAppointment( serviceAppointmentID: appointmentId, serviceSlotID: selectedSlotId, appointmentScheduleAction: 1, // 1 for Reschedule and 2 for Cancel ); - if (genericRespModel.messageStatus == 2 || genericRespModel.data == null) { + if (genericRespModel.messageStatus == 2 || + genericRespModel.data == null) { Utils.hideLoading(context); Utils.showToast("${genericRespModel.message.toString()}"); return; } if (genericRespModel.data == 1) { context.read().onNavbarTapped(1); - applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.cancelled); + applyFilterOnAppointmentsVM( + appointmentStatusEnum: AppointmentStatusEnum.cancelled); Utils.showToast("${genericRespModel.message.toString()}"); getMyAppointments(); Utils.hideLoading(context); diff --git a/lib/views/appointments/appointment_detail_view.dart b/lib/views/appointments/appointment_detail_view.dart index 6cf7f54..1d5f297 100644 --- a/lib/views/appointments/appointment_detail_view.dart +++ b/lib/views/appointments/appointment_detail_view.dart @@ -17,9 +17,14 @@ import 'package:provider/provider.dart'; class AppointmentDetailView extends StatelessWidget { final AppointmentListModel appointmentListModel; - AppointmentDetailView({Key? key, required this.appointmentListModel}) : super(key: key); + AppointmentDetailView({Key? key, required this.appointmentListModel}) + : super(key: key); - Widget getBaseActionButtonWidget({required Color color, required String text, Color textColor = MyColors.white, required Function() onPressed}) { + Widget getBaseActionButtonWidget( + {required Color color, + required String text, + Color textColor = MyColors.white, + required Function() onPressed}) { return Expanded( child: ShowFillButton( maxHeight: 55, @@ -32,19 +37,26 @@ class AppointmentDetailView extends StatelessWidget { ); } - Widget buildBottomActionButton({required AppointmentStatusEnum appointmentStatusEnum, required BuildContext context}) { + Widget buildBottomActionButton( + {required AppointmentStatusEnum appointmentStatusEnum, + required BuildContext context}) { switch (appointmentStatusEnum) { case AppointmentStatusEnum.booked: return Align( alignment: Alignment.bottomCenter, child: Row( children: [ - getBaseActionButtonWidget(color: MyColors.redColor, onPressed: () => appointmentCancelConfirmationSheet(context), text: "Cancel"), + getBaseActionButtonWidget( + color: MyColors.redColor, + onPressed: () => appointmentCancelConfirmationSheet(context), + text: "Cancel"), 12.width, getBaseActionButtonWidget( color: MyColors.greenColor, onPressed: () { - context.read().onConfirmAppointmentPressed(context: context, appointmentId: appointmentListModel.id); + context.read().onConfirmAppointmentPressed( + context: context, + appointmentId: appointmentListModel.id); }, text: "Confirm"), ], @@ -55,7 +67,10 @@ class AppointmentDetailView extends StatelessWidget { alignment: Alignment.bottomCenter, child: Row( children: [ - getBaseActionButtonWidget(color: MyColors.redColor, onPressed: () => appointmentCancelConfirmationSheet(context), text: "Cancel"), + getBaseActionButtonWidget( + color: MyColors.redColor, + onPressed: () => appointmentCancelConfirmationSheet(context), + text: "Cancel"), ], ), ); @@ -64,7 +79,11 @@ class AppointmentDetailView extends StatelessWidget { alignment: Alignment.bottomCenter, child: Row( children: [ - getBaseActionButtonWidget(color: MyColors.grey98Color.withOpacity(0.3), textColor: MyColors.lightTextColor, onPressed: () {}, text: "In Progress"), + getBaseActionButtonWidget( + color: MyColors.grey98Color.withOpacity(0.3), + textColor: MyColors.lightTextColor, + onPressed: () {}, + text: "In Progress"), ], ), ); @@ -73,7 +92,11 @@ class AppointmentDetailView extends StatelessWidget { alignment: Alignment.bottomCenter, child: Row( children: [ - getBaseActionButtonWidget(color: MyColors.grey98Color.withOpacity(0.3), textColor: MyColors.lightTextColor, onPressed: () {}, text: "Cancelled"), + getBaseActionButtonWidget( + color: MyColors.grey98Color.withOpacity(0.3), + textColor: MyColors.lightTextColor, + onPressed: () {}, + text: "Cancelled"), ], ), ); @@ -84,17 +107,24 @@ class AppointmentDetailView extends StatelessWidget { alignment: Alignment.bottomCenter, child: Row( children: [ - getBaseActionButtonWidget(color: MyColors.redColor, onPressed: () => appointmentCancelConfirmationSheet(context), text: "Cancel"), + getBaseActionButtonWidget( + color: MyColors.redColor, + onPressed: () => appointmentCancelConfirmationSheet(context), + text: "Cancel"), 12.width, getBaseActionButtonWidget( color: MyColors.greenColor, onPressed: () { - context.read().onConfirmAppointmentPressed(context: context, appointmentId: appointmentListModel.id); + context.read().onConfirmAppointmentPressed( + context: context, + appointmentId: appointmentListModel.id); }, text: "Confirm"), ], ), ); + default: + return SizedBox(); } } @@ -102,8 +132,10 @@ class AppointmentDetailView extends StatelessWidget { final appointmentsVm = context.read(); return actionConfirmationBottomSheet( context: context, - title: "Do you want to cancel this appointment?".toText(fontSize: 28, isBold: true, letterSpacing: -1.44), - subtitle: "Your appointment will be cancelled and you cannot undo this action.", + title: "Do you want to cancel this appointment?" + .toText(fontSize: 28, isBold: true, letterSpacing: -1.44), + subtitle: + "Your appointment will be cancelled and you cannot undo this action.", actionButtonYes: Expanded( child: ShowFillButton( maxHeight: 55, @@ -111,7 +143,8 @@ class AppointmentDetailView extends StatelessWidget { fontSize: 15, onPressed: () { Navigator.pop(context); - appointmentsVm.onCancelAppointmentPressed(context: context, appointmentListModel: appointmentListModel); + appointmentsVm.onCancelAppointmentPressed( + context: context, appointmentListModel: appointmentListModel); }, ), ), @@ -149,7 +182,8 @@ class AppointmentDetailView extends StatelessWidget { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - appointmentListModel.providerName!.toText(fontSize: 16, isBold: true), + appointmentListModel.providerName! + .toText(fontSize: 16, isBold: true), Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ @@ -159,14 +193,23 @@ class AppointmentDetailView extends StatelessWidget { fit: BoxFit.fill, ), 5.width, - "${appointmentListModel.duration ?? ""} ${appointmentListModel.appointmentDate!.toFormattedDateWithoutTime()}".toText(fontSize: 12, isBold: true, color: MyColors.lightTextColor), + "${appointmentListModel.duration ?? ""} ${appointmentListModel.appointmentDate!.toFormattedDateWithoutTime()}" + .toText( + fontSize: 12, + isBold: true, + color: MyColors.lightTextColor), ], ), 13.height, - if (appointmentListModel.appointmentServicesList != null && appointmentListModel.appointmentServicesList!.isNotEmpty) ...[ + if (appointmentListModel.appointmentServicesList != null && + appointmentListModel + .appointmentServicesList!.isNotEmpty) ...[ Column( - children: List.generate(appointmentListModel.appointmentServicesList!.length, (index) { - ServiceModel service = appointmentListModel.appointmentServicesList![index]; + children: List.generate( + appointmentListModel.appointmentServicesList!.length, + (index) { + ServiceModel service = + appointmentListModel.appointmentServicesList![index]; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -178,14 +221,18 @@ class AppointmentDetailView extends StatelessWidget { // fit: BoxFit.fill, // ), // 10.width, - "${index + 1}. ${service.providerServiceDescription}".toText(fontSize: 14, isBold: true), + "${index + 1}. ${service.providerServiceDescription}" + .toText(fontSize: 14, isBold: true), ], ), - if (service.serviceItems != null && service.serviceItems!.isNotEmpty) ...[ + if (service.serviceItems != null && + service.serviceItems!.isNotEmpty) ...[ Column( children: List.generate( service.serviceItems!.length, - (index) => "${service.serviceItems![index].name}".toText( + (index) => + "${service.serviceItems![index].name}" + .toText( textAlign: TextAlign.start, fontSize: 12, color: MyColors.lightTextColor, @@ -197,15 +244,22 @@ class AppointmentDetailView extends StatelessWidget { Row( crossAxisAlignment: CrossAxisAlignment.end, children: [ - ((service.currentTotalServicePrice).toString()).toText(fontSize: 25, isBold: true), + ((service.currentTotalServicePrice).toString()) + .toText(fontSize: 25, isBold: true), 2.width, - "SAR".toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5), + "SAR" + .toText( + color: MyColors.lightTextColor, + fontSize: 16, + isBold: true) + .paddingOnly(bottom: 5), Icon( Icons.arrow_drop_down, size: 30, ) ], - ).onPress(() => appointmentsVM.priceBreakDownClicked(context, service)), + ).onPress(() => appointmentsVM.priceBreakDownClicked( + context, service)), ], ); }), @@ -217,16 +271,25 @@ class AppointmentDetailView extends StatelessWidget { CardButtonWithIcon( title: "Reschedule Appointment", onCardTapped: () { - context.read().onRescheduleAppointmentPressed(context: context, appointmentListModel: appointmentListModel); + context + .read() + .onRescheduleAppointmentPressed( + context: context, + appointmentListModel: appointmentListModel); }, icon: MyAssets.scheduleAppointmentIcon.buildSvg(), ), - if (appointmentListModel.appointmentStatusEnum == AppointmentStatusEnum.booked) ...[ + if (appointmentListModel.appointmentStatusEnum == + AppointmentStatusEnum.booked) ...[ 10.width, CardButtonWithIcon( title: "Pay for Appointment", onCardTapped: () { - context.read().onConfirmAppointmentPressed(context: context, appointmentId: appointmentListModel.id); + context + .read() + .onConfirmAppointmentPressed( + context: context, + appointmentId: appointmentListModel.id); }, icon: MyAssets.creditCardIcon.buildSvg(), ), @@ -236,7 +299,10 @@ class AppointmentDetailView extends StatelessWidget { 15.height, ], ).toWhiteContainer(width: double.infinity, allPading: 12), - buildBottomActionButton(appointmentStatusEnum: appointmentListModel.appointmentStatusEnum!, context: context), + buildBottomActionButton( + appointmentStatusEnum: + appointmentListModel.appointmentStatusEnum!, + context: context), ], ), ), diff --git a/lib/widgets/bottom_sheet.dart b/lib/widgets/bottom_sheet.dart index cd920ad..6016334 100644 --- a/lib/widgets/bottom_sheet.dart +++ b/lib/widgets/bottom_sheet.dart @@ -12,8 +12,8 @@ void showMyBottomSheet(BuildContext context, {bool isDismissible = true, require decoration: const BoxDecoration( color: Colors.white, borderRadius: BorderRadius.only( - topRight: Radius.circular(25), - topLeft: Radius.circular(25), + topRight: Radius.circular(0), + topLeft: Radius.circular(0), ), ), clipBehavior: Clip.antiAlias, diff --git a/lib/widgets/common_widgets/categories_list.dart b/lib/widgets/common_widgets/categories_list.dart index 051d3be..94888ca 100644 --- a/lib/widgets/common_widgets/categories_list.dart +++ b/lib/widgets/common_widgets/categories_list.dart @@ -7,8 +7,15 @@ class FiltersList extends StatelessWidget { final List filterList; final Function(int, int) onFilterTapped; final bool needLeftPadding; + EdgeInsets? padding; - const FiltersList({Key? key, required this.filterList, this.needLeftPadding = true, required this.onFilterTapped}) : super(key: key); + FiltersList({ + Key? key, + this.padding, + required this.filterList, + this.needLeftPadding = true, + required this.onFilterTapped, + }) : super(key: key); @override Widget build(BuildContext context) { @@ -16,7 +23,7 @@ class FiltersList extends StatelessWidget { height: 37, width: double.infinity, child: ListView.builder( - padding: EdgeInsets.only(left: needLeftPadding ? 12 : 0), + padding: padding ?? EdgeInsets.only(left: needLeftPadding ? 12 : 0), itemCount: filterList.length, scrollDirection: Axis.horizontal, itemBuilder: (BuildContext context, int index) { @@ -29,15 +36,20 @@ class FiltersList extends StatelessWidget { 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, - color: filterList[index].isSelected ? MyColors.white : null, + color: + filterList[index].isSelected ? MyColors.white : null, ), ), ); diff --git a/pubspec.lock b/pubspec.lock index 5aad031..96e49ba 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -93,10 +93,10 @@ packages: dependency: transitive description: name: collection - sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted - version: "1.17.1" + version: "1.18.0" country_code_picker: dependency: "direct main" description: @@ -513,10 +513,10 @@ packages: dependency: "direct main" description: name: intl - sha256: a3715e3bc90294e971cb7dc063fbf3cd9ee0ebf8604ffeafabd9e6f16abbdbe6 + sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" url: "https://pub.dev" source: hosted - version: "0.18.0" + version: "0.18.1" js: dependency: transitive description: @@ -601,26 +601,26 @@ packages: dependency: transitive description: name: matcher - sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" url: "https://pub.dev" source: hosted - version: "0.12.15" + version: "0.12.16" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "0.5.0" meta: dependency: transitive description: name: meta - sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.0" mime: dependency: transitive description: @@ -717,6 +717,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.7" + percent_indicator: + dependency: "direct main" + description: + name: percent_indicator + sha256: c37099ad833a883c9d71782321cb65c3a848c21b6939b6185f0ff6640d05814c + url: "https://pub.dev" + source: hosted + version: "4.2.3" permission_handler: dependency: "direct main" description: @@ -902,10 +910,10 @@ packages: dependency: transitive description: name: source_span - sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.0" sqflite: dependency: transitive description: @@ -934,18 +942,18 @@ packages: dependency: transitive description: name: stack_trace - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.11.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" stream_transform: dependency: transitive description: @@ -990,10 +998,10 @@ packages: dependency: transitive description: name: test_api - sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "0.6.1" tuple: dependency: transitive description: @@ -1098,6 +1106,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + web: + dependency: transitive + description: + name: web + sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 + url: "https://pub.dev" + source: hosted + version: "0.3.0" web_socket_channel: dependency: transitive description: @@ -1131,5 +1147,5 @@ packages: source: hosted version: "6.3.0" sdks: - dart: ">=3.0.0 <4.0.0" + dart: ">=3.2.0-194.0.dev <4.0.0" flutter: ">=3.10.0" diff --git a/pubspec.yaml b/pubspec.yaml index f7f6455..f042568 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -41,6 +41,7 @@ dependencies: intl: any signalr_core: ^1.1.1 logging: ^1.2.0 + percent_indicator: ^4.2.3 # google