From 6ef9ae813de469af6fd80671ef620b954f62c8b8 Mon Sep 17 00:00:00 2001 From: tahaalam Date: Thu, 2 Oct 2025 15:14:44 +0300 Subject: [PATCH] doctors search filter added --- assets/images/svg/cross_circle.svg | 3 + assets/images/svg/filters.svg | 8 + assets/images/svg/ic_close.svg | 3 + assets/langs/ar-SA.json | 10 +- assets/langs/en-US.json | 10 +- lib/core/app_assets.dart | 3 + .../book_appointments_view_model.dart | 147 +++++++++++ .../doctor_filter_view_model.dart | 110 ++++++++ lib/generated/locale_keys.g.dart | 14 + lib/main.dart | 5 +- ...l_bottom_sheet_body_for_doctor_filter.dart | 66 +++++ .../doctor_filter/RegionChips.dart | 60 +++++ .../doctor_filter/clinic_bottomsheet.dart | 85 ++++++ .../doctor_filter/clinic_item.dart | 52 ++++ .../doctor_filter/doctors_filter.dart | 249 ++++++++++++++++++ .../doctor_filter/facility_Chips.dart | 65 +++++ .../search_doctor_by_name.dart | 122 ++++++--- .../book_appointment/select_doctor_page.dart | 84 ++++-- lib/widgets/chip/app_custom_chip_widget.dart | 2 +- lib/widgets/input_widget.dart | 23 +- 20 files changed, 1050 insertions(+), 71 deletions(-) create mode 100644 assets/images/svg/cross_circle.svg create mode 100644 assets/images/svg/filters.svg create mode 100644 assets/images/svg/ic_close.svg create mode 100644 lib/features/doctor_filter/doctor_filter_view_model.dart create mode 100644 lib/presentation/appointments/widgets/hospital_bottom_sheet/hospital_bottom_sheet_body_for_doctor_filter.dart create mode 100644 lib/presentation/book_appointment/doctor_filter/RegionChips.dart create mode 100644 lib/presentation/book_appointment/doctor_filter/clinic_bottomsheet.dart create mode 100644 lib/presentation/book_appointment/doctor_filter/clinic_item.dart create mode 100644 lib/presentation/book_appointment/doctor_filter/doctors_filter.dart create mode 100644 lib/presentation/book_appointment/doctor_filter/facility_Chips.dart diff --git a/assets/images/svg/cross_circle.svg b/assets/images/svg/cross_circle.svg new file mode 100644 index 0000000..bcf9f90 --- /dev/null +++ b/assets/images/svg/cross_circle.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/svg/filters.svg b/assets/images/svg/filters.svg new file mode 100644 index 0000000..521f6fa --- /dev/null +++ b/assets/images/svg/filters.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/assets/images/svg/ic_close.svg b/assets/images/svg/ic_close.svg new file mode 100644 index 0000000..615b42d --- /dev/null +++ b/assets/images/svg/ic_close.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 8945fee..b08e783 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -856,5 +856,13 @@ "onboardingHeading1": "حجز المواعيد لم يكن أسهل من قبل", "onboardingBody1": "ببضع نقرات فقط يمكنك استشارة الطبيب الذي تختاره.", "onboardingHeading2": "الوصول إلى السجل الطبي بين يديك", - "onboardingBody2": "تتبع تاريخك الطبي بما في ذلك الفحوصات المخبرية، الوصفات الطبية، التأمين، وغيرها." + "onboardingBody2": "تتبع تاريخك الطبي بما في ذلك الفحوصات المخبرية، الوصفات الطبية، التأمين، وغيرها.", + "hmgHospitals": "مستشفيات HMG", + "hmcMedicalClinic": "مراكز HMC الطبية", + "applyFilter": "تطبيق الفلتر", + "facilityAndLocation": "المرفق والموقع", + "regionAndLocation": "المنطقة والمواقع", + "clearAllFilters": "مسح جميع الفلاتر", + "filters": "فلاتر", + "searchClinic": "بحث عن عيادة" } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 843daf8..adab1d5 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -852,5 +852,13 @@ "onboardingHeading1": "Booking appointment has never been easy", "onboardingBody1": "In few clicks find yourself having consultation with the doctor of your choice.", "onboardingHeading2": "Access the medical history on finger tips", - "onboardingBody2": "Keep track on your medical history including labs, prescription, insurance, etc" + "onboardingBody2": "Keep track on your medical history including labs, prescription, insurance, etc", + "hmgHospitals": "HMG Hospitals", + "hmcMedicalClinic": "HMC Medical Centers", + "applyFilter": "AppLy Filter", + "facilityAndLocation": "Facility and Location", + "regionAndLocation": "Region And Locations", + "clearAllFilters": "Clear all filters", + "filters": "Filters", + "searchClinic": "Search Clinic" } \ No newline at end of file diff --git a/lib/core/app_assets.dart b/lib/core/app_assets.dart index 31b4f32..716448d 100644 --- a/lib/core/app_assets.dart +++ b/lib/core/app_assets.dart @@ -145,6 +145,9 @@ class AppAssets { static const String ic_normal_result = '$svgBasePath/normal_result.svg'; static const String ic_low_result = '$svgBasePath/low_result.svg'; static const String ic_critical_low_result = '$svgBasePath/critical_low_result.svg'; + static const String ic_filters = '$svgBasePath/filters.svg'; + static const String ic_close = '$svgBasePath/ic_close.svg'; + static const String ic_cross_circle = '$svgBasePath/cross_circle.svg'; //bottom navigation// static const String homeBottom = '$svgBasePath/home_bottom.svg'; diff --git a/lib/features/book_appointments/book_appointments_view_model.dart b/lib/features/book_appointments/book_appointments_view_model.dart index 5ef653a..bd292ec 100644 --- a/lib/features/book_appointments/book_appointments_view_model.dart +++ b/lib/features/book_appointments/book_appointments_view_model.dart @@ -53,6 +53,7 @@ class BookAppointmentsViewModel extends ChangeNotifier { List get filteredClinicsList => _filteredClinicsList; List doctorsList = []; + List filteredDoctorList = []; List liveCareDoctorsList = []; @@ -87,6 +88,19 @@ class BookAppointmentsViewModel extends ChangeNotifier { bool shouldLoadSpecificClinic = false; String? currentlySelectedHospitalFromRegionFlow; + ///variables for doctor filter + List searchedRegionList = []; + List facilityList = ["hmgHospitals", "hmcMedicalClinic"]; + List searchedHospitalList = []; + List + searchedPatientDoctorAppointmentHospitalsList = []; + List searchedClinicList = []; + + PatientDoctorAppointmentList? selectedHospitalForFilters; + List? selectedFacilityForFilters = [], selectedRegionForFilters = []; + String? selectedClinicForFilters; + bool applyFilters = false; + BookAppointmentsViewModel( {required this.bookAppointmentsRepo, required this.errorHandlerService, required this.navigationService, required this.myAppointmentsViewModel, required this.locationUtils}) { ; @@ -279,8 +293,11 @@ class BookAppointmentsViewModel extends ChangeNotifier { // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); } else if (apiResponse.messageStatus == 1) { doctorsList = apiResponse.data!; + filteredDoctorList = doctorsList; isDoctorsListLoading = false; initializeFilteredList(); + clearSearchFilters(); + getFiltersFromDoctorList(); notifyListeners(); if (onSuccess != null) { onSuccess(apiResponse); @@ -757,4 +774,134 @@ class BookAppointmentsViewModel extends ChangeNotifier { void getLocation() { locationUtils.getLocation(); } + + void clearSearchFilters() { + searchedRegionList.clear(); + searchedHospitalList.clear(); + searchedPatientDoctorAppointmentHospitalsList.clear(); + searchedClinicList.clear(); + notifyListeners(); + } + + void clearSelection() { + selectedFacilityForFilters = []; + selectedClinicForFilters = null; + selectedHospitalForFilters = null; + selectedRegionForFilters = []; + applyFilters = false; + notifyListeners(); + } + + void setSelections( + List? selectedFacilityForFilters, + List? selectedRegionForFilters, + String? selectedClinicForFilters, + PatientDoctorAppointmentList? selectedHospitalForFilters, + bool applyFilters) { + this.selectedFacilityForFilters = selectedFacilityForFilters; + this.selectedClinicForFilters = selectedClinicForFilters; + this.selectedHospitalForFilters = selectedHospitalForFilters; + this.selectedRegionForFilters = selectedRegionForFilters; + this.applyFilters = applyFilters; + notifyListeners(); + } + + void getFiltersFromDoctorList() { + doctorsList.forEach((element) { + if (!searchedRegionList + .contains(element.getRegionName(_appState.isArabic()))) { + searchedRegionList + .add(element.getRegionName(_appState.isArabic()) ?? ""); + } + if (!searchedHospitalList.contains(element.projectName)) { + searchedPatientDoctorAppointmentHospitalsList + .add(PatientDoctorAppointmentList() + ..filterName = element.projectName + ..isHMC = element.isHMC + ..distanceInKMs = "0"); + searchedHospitalList.add(element.projectName ?? ""); + } + if (!searchedClinicList.contains(element.clinicName)) { + searchedClinicList.add(element.clinicName ?? ""); + } + }); + } + + void updateApplyFilters(bool applyFilters) { + this.applyFilters = applyFilters; + notifyListeners(); + } + + void setSelectedRegion(String region) { + if (selectedRegionForFilters?.contains(region) == true) { + selectedRegionForFilters?.remove(region); + } else { + selectedRegionForFilters?.add(region); + } + notifyListeners(); + } + + void setSelectedHospital(PatientDoctorAppointmentList? hospital) { + selectedHospitalForFilters = hospital; + notifyListeners(); + } + + void setSelectedFacilityForFilter(String facility) { + if (selectedFacilityForFilters?.contains(facility) == true) { + selectedFacilityForFilters?.remove(facility); + } else { + selectedFacilityForFilters?.add(facility); + } + + notifyListeners(); + } + + void setSelectedClinicForFilter(String? clinic) { + selectedClinicForFilters = clinic; + notifyListeners(); + } + + bool isArabic() { + return _appState.isArabic(); + } + + List getDoctorListAsPerSelection() { + if (!applyFilters) return doctorsList; + + if ((selectedRegionForFilters?.isEmpty == true) && + (selectedFacilityForFilters?.isEmpty == true) && + selectedClinicForFilters == null && + selectedHospitalForFilters == null) { + return doctorsList; + } + var list = doctorsList.where((element) { + var isInSelectedRegion = (selectedRegionForFilters?.isEmpty == true) + ? true + : selectedRegionForFilters + ?.any((region) => region == element.getRegionName(isArabic())); + var shouldApplyFacilityFilter = + (selectedFacilityForFilters?.isEmpty == true) ? false : true; + var isHMC = (selectedFacilityForFilters?.isEmpty == true) + ? true + : selectedFacilityForFilters?.any((item) => item.contains("hmc")); + var isInSelectedClinic = (selectedClinicForFilters == null) + ? true + : selectedClinicForFilters == element.clinicName; + var isInSelectedHospital = (selectedHospitalForFilters == null) + ? true + : element.projectName == selectedHospitalForFilters?.filterName; + var facilityFilter = ((shouldApplyFacilityFilter == true) ? isHMC : true); + + return (isInSelectedRegion ?? true) && + (facilityFilter ?? true) && + isInSelectedClinic && + isInSelectedHospital; + }).toList(); + return list; + } + + void updateList() { + filteredDoctorList = getDoctorListAsPerSelection(); + notifyListeners(); + } } diff --git a/lib/features/doctor_filter/doctor_filter_view_model.dart b/lib/features/doctor_filter/doctor_filter_view_model.dart new file mode 100644 index 0000000..889ab5a --- /dev/null +++ b/lib/features/doctor_filter/doctor_filter_view_model.dart @@ -0,0 +1,110 @@ +import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/app_state.dart'; +import 'package:hmg_patient_app_new/core/dependencies.dart'; +import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/doctors_list_response_model.dart'; +import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/doctor_list_api_response.dart' show PatientDoctorAppointmentList; + +class DoctorFilterViewModel extends ChangeNotifier{ + + late AppState appState; + DoctorFilterViewModel(){ + appState = getIt(); + } + List searchedRegionList = []; + List facilityList = ["hmgHospitals", "hmcMedicalClinic"]; + List searchedHospitalList = []; + List + searchedPatientDoctorAppointmentHospitalsList = []; + List searchedClinicList = []; + + PatientDoctorAppointmentList? selectedHospitalForFilters; + List? selectedFacilityForFilters = [] , selectedRegionForFilters = []; + String? selectedClinicForFilters; + bool applyFilters = false; + + void clearSearchFilters() { + searchedRegionList.clear(); + searchedHospitalList.clear(); + searchedPatientDoctorAppointmentHospitalsList.clear(); + searchedClinicList.clear(); + notifyListeners(); + } + + void clearSelection() { + selectedFacilityForFilters = []; + selectedClinicForFilters = null; + selectedHospitalForFilters = null; + selectedRegionForFilters = []; + applyFilters = false; + notifyListeners(); + } + + void getFiltersFromDoctorList(List doctorsList) { + doctorsList.forEach((element) { + if (!searchedRegionList + .contains(element.getRegionName(appState.isArabic()))) { + searchedRegionList + .add(element.getRegionName(appState.isArabic()) ?? ""); + } + if (!searchedHospitalList.contains(element.projectName)) { + searchedPatientDoctorAppointmentHospitalsList + .add(PatientDoctorAppointmentList() + ..filterName = element.projectName + ..isHMC = element.isHMC + ..distanceInKMs = "0"); + searchedHospitalList.add(element.projectName ?? ""); + } + if (!searchedClinicList.contains(element.clinicName)) { + searchedClinicList.add(element.clinicName ?? ""); + } + }); + } + + void updateApplyFilters(bool applyFilters) { + this.applyFilters = applyFilters; + notifyListeners(); + } + + void setSelectedRegion(String region) { + if (selectedRegionForFilters?.contains(region) == true) { + selectedRegionForFilters?.remove(region); + } else { + selectedRegionForFilters?.add(region); + } + notifyListeners(); + } + + void setSelectedHospital(PatientDoctorAppointmentList? hospital) { + selectedHospitalForFilters = hospital; + notifyListeners(); + } + + void setSelectedFacilityForFilter(String facility) { + if (selectedFacilityForFilters?.contains(facility) == true) { + selectedFacilityForFilters?.remove(facility); + } else { + selectedFacilityForFilters?.add(facility); + } + + notifyListeners(); + } + + void setSelectedClinicForFilter(String? clinic) { + selectedClinicForFilters = clinic; + notifyListeners(); + } + + void setSelections( + List? selectedFacilityForFilters, + List? selectedRegionForFilters, + String? selectedClinicForFilters, + PatientDoctorAppointmentList? selectedHospitalForFilters, + bool applyFilters) { + this.selectedFacilityForFilters = selectedFacilityForFilters; + this.selectedClinicForFilters = selectedClinicForFilters; + this.selectedHospitalForFilters = selectedHospitalForFilters; + this.selectedRegionForFilters = selectedRegionForFilters; + this.applyFilters = applyFilters; + notifyListeners(); + } +} \ No newline at end of file diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 3d12e5b..9447bd1 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -849,5 +849,19 @@ abstract class LocaleKeys { static const selectCountry = 'selectCountry'; static const forLoginVerification = 'forLoginVerification'; static const searchHospital = 'searchHospital'; + static const skip = 'skip'; + static const getStarted = 'getStarted'; + static const onboardingHeading1 = 'onboardingHeading1'; + static const onboardingBody1 = 'onboardingBody1'; + static const onboardingHeading2 = 'onboardingHeading2'; + static const onboardingBody2 = 'onboardingBody2'; + static const hmgHospitals = 'hmgHospitals'; + static const hmcMedicalClinic = 'hmcMedicalClinic'; + static const applyFilter = 'applyFilter'; + static const facilityAndLocation = 'facilityAndLocation'; + static const regionAndLocation = 'regionAndLocation'; + static const clearAllFilters = 'clearAllFilters'; + static const filters = 'filters'; + static const searchClinic = 'searchClinic'; } diff --git a/lib/main.dart b/lib/main.dart index 3690c72..4dfba4b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -10,6 +10,7 @@ import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart'; import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart'; +import 'package:hmg_patient_app_new/features/doctor_filter/doctor_filter_view_model.dart'; import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_view_model.dart'; import 'package:hmg_patient_app_new/features/insurance/insurance_view_model.dart'; import 'package:hmg_patient_app_new/features/lab/history/lab_history_viewmodel.dart'; @@ -154,7 +155,9 @@ void main() async { ChangeNotifierProvider( create: (_) => LabHistoryViewModel()), ChangeNotifierProvider( - create: (_) => LabRangeViewModel()) + create: (_) => LabRangeViewModel()) , + ChangeNotifierProvider( + create: (_) => DoctorFilterViewModel()) ], child: MyApp()), ), ); diff --git a/lib/presentation/appointments/widgets/hospital_bottom_sheet/hospital_bottom_sheet_body_for_doctor_filter.dart b/lib/presentation/appointments/widgets/hospital_bottom_sheet/hospital_bottom_sheet_body_for_doctor_filter.dart new file mode 100644 index 0000000..58a0d00 --- /dev/null +++ b/lib/presentation/appointments/widgets/hospital_bottom_sheet/hospital_bottom_sheet_body_for_doctor_filter.dart @@ -0,0 +1,66 @@ +import 'package:easy_localization/easy_localization.dart' + show tr, StringTranslateExtension; +import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/enums.dart'; +import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; +import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; +import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; +import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart'; +import 'package:hmg_patient_app_new/features/doctor_filter/doctor_filter_view_model.dart'; +import 'package:hmg_patient_app_new/features/my_appointments/appointment_via_region_viewmodel.dart'; +import 'package:hmg_patient_app_new/features/my_appointments/models/facility_selection.dart'; +import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart'; +import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/presentation/appointments/widgets/hospital_bottom_sheet/hospital_list_items.dart'; +import 'package:hmg_patient_app_new/presentation/appointments/widgets/hospital_bottom_sheet/type_selection_widget.dart'; +import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart' show AppColors; +import 'package:hmg_patient_app_new/widgets/input_widget.dart'; +import 'package:provider/provider.dart'; + +class HospitalBottomSheetBodyForDoctorFilter extends StatelessWidget { + late BookAppointmentsViewModel appointmentsViewModel; + late AppointmentViaRegionViewmodel regionalViewModel; + final TextEditingController searchText = TextEditingController(); + + HospitalBottomSheetBodyForDoctorFilter({super.key}); + + @override + Widget build(BuildContext context) { + appointmentsViewModel = Provider.of(context); + regionalViewModel = Provider.of(context); + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + LocaleKeys.selectHospital.tr(), + style: TextStyle( + fontSize: 21, + fontWeight: FontWeight.w600, + color: AppColors.blackColor, + ), + ), + SizedBox(height: 24.h), + SizedBox( + height: MediaQuery.sizeOf(context).height * .4, + child: ListView.separated( + itemBuilder: (_, index) + { + var hospital = appointmentsViewModel.searchedPatientDoctorAppointmentHospitalsList[index]; + return HospitalListItem( + hospitalData: hospital, + isLocationEnabled: appointmentsViewModel.isLocationEnabled(), + ).onPress(() { + regionalViewModel.setHospitalModel(hospital); + context.read().setSelectedHospital(hospital); + Navigator.pop(context); + });}, + separatorBuilder: (_, __) => SizedBox( + height: 16.h, + ), + itemCount: appointmentsViewModel.searchedPatientDoctorAppointmentHospitalsList?.length ?? 0), + ) + ], + ); + } +} diff --git a/lib/presentation/book_appointment/doctor_filter/RegionChips.dart b/lib/presentation/book_appointment/doctor_filter/RegionChips.dart new file mode 100644 index 0000000..c81e548 --- /dev/null +++ b/lib/presentation/book_appointment/doctor_filter/RegionChips.dart @@ -0,0 +1,60 @@ +import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; +import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; +import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart' + show BookAppointmentsViewModel; +import 'package:hmg_patient_app_new/features/doctor_filter/doctor_filter_view_model.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; +import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; +import 'package:provider/provider.dart'; + +class RegionChips extends StatelessWidget { + const RegionChips({super.key}); + + @override + Widget build(BuildContext context) { + return Selector>( + selector: (_, model) => model.searchedRegionList, + builder: (__, data, ___) => + Selector?>( + selector: (_, model) => model.selectedRegionForFilters, + builder: (context, selectRegion, ___) => Row( + children: [ + Expanded( + child: ListView.separated( + scrollDirection: Axis.horizontal, + itemCount: data.length, + separatorBuilder: (_, __)=>SizedBox(width: 8.h,), + + itemBuilder: (_, index) => AppCustomChipWidget( + labelText: data[index], + textColor: selectRegion?.any((selectedRegion)=>data[index] == selectedRegion) == true + ? AppColors.primaryRedColor + + : AppColors.textColor, + backgroundColor: + selectRegion?.any((selectedRegion)=>data[index] == selectedRegion) == true + ? AppColors.primaryRedColor + .withOpacity(0.1) + : AppColors.whiteColor, + shape: RoundedRectangleBorder( + side: BorderSide( + color: selectRegion?.any((selectedRegion)=>data[index] == selectedRegion) == true + ? AppColors + .primaryRedBorderColor + : AppColors + .chipBorderColorOpacity20, + width: 1, + ), + borderRadius: + BorderRadius.circular(10))) + .onPress(() { + context + .read() + .setSelectedRegion(data[index]); + }))) + ], + ), + )); + } +} diff --git a/lib/presentation/book_appointment/doctor_filter/clinic_bottomsheet.dart b/lib/presentation/book_appointment/doctor_filter/clinic_bottomsheet.dart new file mode 100644 index 0000000..155d8e3 --- /dev/null +++ b/lib/presentation/book_appointment/doctor_filter/clinic_bottomsheet.dart @@ -0,0 +1,85 @@ +import 'package:easy_localization/easy_localization.dart' + show tr, StringTranslateExtension; +import 'package:flutter/material.dart'; +import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; +import 'package:hmg_patient_app_new/core/enums.dart'; +import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; +import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; +import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; +import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart'; +import 'package:hmg_patient_app_new/features/doctor_filter/doctor_filter_view_model.dart'; +import 'package:hmg_patient_app_new/features/my_appointments/appointment_via_region_viewmodel.dart'; +import 'package:hmg_patient_app_new/features/my_appointments/models/facility_selection.dart'; +import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart'; +import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/presentation/appointments/widgets/hospital_bottom_sheet/hospital_list_items.dart'; +import 'package:hmg_patient_app_new/presentation/appointments/widgets/hospital_bottom_sheet/type_selection_widget.dart'; +import 'package:hmg_patient_app_new/presentation/book_appointment/doctor_filter/clinic_item.dart'; +import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/clinic_card.dart'; +import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart' show AppColors; +import 'package:hmg_patient_app_new/widgets/input_widget.dart'; +import 'package:provider/provider.dart'; + +import '../../../features/book_appointments/models/resp_models/get_clinic_list_response_model.dart' show GetClinicsListResponseModel; + +class ClinicBottomSheet extends StatelessWidget { + late BookAppointmentsViewModel appointmentsViewModel; + late AppointmentViaRegionViewmodel regionalViewModel; + final TextEditingController searchText = TextEditingController(); + + ClinicBottomSheet({super.key}); + + @override + Widget build(BuildContext context) { + appointmentsViewModel = Provider.of(context); + regionalViewModel = Provider.of(context); + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + LocaleKeys.selectClinic.tr(), + style: TextStyle( + fontSize: 21, + fontWeight: FontWeight.w600, + color: AppColors.blackColor, + ), + ), + SizedBox(height: 24.h), + SizedBox( + height: MediaQuery.sizeOf(context).height * .4, + child: ListView.separated( + itemBuilder: (_, index) + { + return AnimationConfiguration.staggeredList( + position: index, + duration: const Duration(milliseconds: 500), + child: SlideAnimation( + verticalOffset: 100.0, + child: FadeInAnimation( + child: AnimatedContainer( + duration: Duration(milliseconds: 300), + curve: Curves.easeInOut, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true), + child: ClinicItem( + isArabic: appointmentsViewModel.isArabic(), + clinicName: appointmentsViewModel.searchedClinicList[index], + ), + ), + ), + ), + + ).onPress(() { + context.read() + .setSelectedClinicForFilter(appointmentsViewModel.searchedClinicList[index]); + Navigator.pop(context); + });}, + separatorBuilder: (_, __) => SizedBox( + height: 16.h, + ), + itemCount: appointmentsViewModel.searchedClinicList.length ?? 0), + ) + ], + ); + } +} diff --git a/lib/presentation/book_appointment/doctor_filter/clinic_item.dart b/lib/presentation/book_appointment/doctor_filter/clinic_item.dart new file mode 100644 index 0000000..0d5ba76 --- /dev/null +++ b/lib/presentation/book_appointment/doctor_filter/clinic_item.dart @@ -0,0 +1,52 @@ +import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/app_assets.dart'; +import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; +import 'package:hmg_patient_app_new/core/utils/utils.dart'; +import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; +import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart' show AppColors; + +class ClinicItem extends StatelessWidget { + final String clinicName; + final bool isArabic; + + ClinicItem({super.key, required this.clinicName, required this.isArabic}); + + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsets.all(16.h), + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24.h, + hasShadow: false, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Utils.buildSvgWithAssets( + icon: AppAssets.generic_clinic_icon, + width: 24.h, + height: 24.h, + fit: BoxFit.contain), + SizedBox(height: 16.h), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded(child: clinicName.toText16(isBold: true)), + Transform.flip( + flipX: isArabic, + child: Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon, + width: 15.h, + height: 15.h, + fit: BoxFit.contain, + iconColor: AppColors.textColor), + ), + ], + ), + ], + ), + ); + } +} diff --git a/lib/presentation/book_appointment/doctor_filter/doctors_filter.dart b/lib/presentation/book_appointment/doctor_filter/doctors_filter.dart new file mode 100644 index 0000000..1a772f7 --- /dev/null +++ b/lib/presentation/book_appointment/doctor_filter/doctors_filter.dart @@ -0,0 +1,249 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/app_assets.dart'; +import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; +import 'package:hmg_patient_app_new/core/utils/utils.dart'; +import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; +import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; +import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart'; +import 'package:hmg_patient_app_new/features/doctor_filter/doctor_filter_view_model.dart'; +import 'package:hmg_patient_app_new/features/my_appointments/appointment_via_region_viewmodel.dart'; +import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/presentation/appointments/widgets/hospital_bottom_sheet/hospital_bottom_sheet_body.dart'; +import 'package:hmg_patient_app_new/presentation/appointments/widgets/hospital_bottom_sheet/hospital_bottom_sheet_body_for_doctor_filter.dart'; +import 'package:hmg_patient_app_new/presentation/book_appointment/doctor_filter/RegionChips.dart'; +import 'package:hmg_patient_app_new/presentation/book_appointment/doctor_filter/clinic_bottomsheet.dart'; +import 'package:hmg_patient_app_new/presentation/book_appointment/doctor_filter/facility_Chips.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; +import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart'; +import 'package:hmg_patient_app_new/widgets/input_widget.dart'; +import 'package:provider/provider.dart'; + +import '../../../widgets/buttons/custom_button.dart'; + +class DoctorsFilters extends StatelessWidget{ + + + TextEditingController hospitalController = TextEditingController(); + TextEditingController clinicController = TextEditingController(); + DoctorsFilters({super.key,}); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: AppColors.bgScaffoldColor, + appBar: AppBar( + backgroundColor: AppColors.bgScaffoldColor, + + automaticallyImplyLeading: false, + centerTitle: false, + title: Utils.buildSvgWithAssets(icon: AppAssets.ic_close, height: 32.h, width: 32.h).onPress((){ + context.read() + .clearSelection() + ; + Navigator.pop(context); + }) + + + + ), + + body: Column( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + LocaleKeys.filters.tr(), + style:TextStyle( + fontFamily: 'Poppins', + fontWeight: FontWeight.w600, + fontSize: 27.fSize, + color: AppColors.textColor, + letterSpacing: -1 + ) + ), + Text( + LocaleKeys.clearAllFilters.tr(), + style:TextStyle( + fontFamily: 'Poppins', + fontWeight: FontWeight.w500, + fontSize: 14.fSize, + color: AppColors.errorColor + ) + ).onPress((){ + context.read().clearSelection(); + context.read().updateApplyFilters(false); + // context.read().setSelections( + // context.read().selectedFacilityForFilters, + // context.read().selectedRegionForFilters, + // context.read().selectedClinicForFilters, + // context.read().selectedHospitalForFilters, + // context.read().applyFilters); + context.read().updateList(); + }) + ], + ), + titleWidget(LocaleKeys.regionAndLocation.tr()), + SizedBox( + height: 42.h, + child: RegionChips()), + titleWidget(LocaleKeys.facilityAndLocation.tr()), + SizedBox( + height: 42.h, + child: FacilityChip()), + titleWidget(LocaleKeys.hospital.tr()), + TextInputWidget( + controller: TextEditingController()..text =context.watch().selectedHospitalForFilters?.filterName??'', + labelText: LocaleKeys.hospital.tr(context: context), + hintText: LocaleKeys.searchHospital.tr(context: context), + isEnable: false, + prefix: null, + autoFocus: false, + isBorderAllowed: false, + keyboardType: TextInputType.text, + suffix:context.watch().selectedHospitalForFilters != null + ? GestureDetector( + onTap: () { + context.read().setSelectedHospital(null); + }, + child: Utils.buildSvgWithAssets(icon: AppAssets.ic_cross_circle, width: 24.h, height: 24.h, fit: BoxFit.scaleDown), + ) + : null, + onChange: (value) { + // DoctorFilterViewModel.filterClinics(value!); + }, + padding: EdgeInsets.symmetric( + vertical: ResponsiveExtension(8).h, + horizontal: ResponsiveExtension(10).h, + ), + ).onPress((){ + openRegionListBottomSheet(context, RegionBottomSheetType.FOR_REGION); + }), + + titleWidget(LocaleKeys.clinic.tr()), + TextInputWidget( + controller: TextEditingController()..text =context.watch().selectedClinicForFilters ??'', + labelText: LocaleKeys.clinicName.tr(context: context), + hintText: LocaleKeys.searchClinic.tr().needTranslation, + isEnable: false, + prefix: null, + autoFocus: false, + isBorderAllowed: false, + keyboardType: TextInputType.text, + suffix:context.read().selectedClinicForFilters?.isNotEmpty == true + ? GestureDetector( + onTap: () { + context.read().setSelectedClinicForFilter(null); + }, + child: Utils.buildSvgWithAssets(icon: AppAssets.ic_cross_circle, width: 20.h, height: 20.h, fit: BoxFit.scaleDown), + ) + : null, + onChange: (value) { + // DoctorFilterViewModel.filterClinics(value!); + }, + padding: EdgeInsets.symmetric( + vertical: 8.h, + horizontal: 10.h, + ), + ).onPress((){ + openClinicListBottomSheet(context,); + }), + + + ], + ).paddingSymmetrical(24.h, 0.h), + Spacer(), + DecoratedBox( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: Colors.white, + customBorder: BorderRadius.only(topLeft: Radius.circular(24.h), topRight: Radius.circular(24.h)) , + + ), + child: CustomButton( + text: LocaleKeys.applyFilter.tr(), + onPressed: () { + context.read().updateApplyFilters(true); + context.read().setSelections( + context.read().selectedFacilityForFilters?.toList()??[], + context.read().selectedRegionForFilters?.toList()??[], + context.read().selectedClinicForFilters, + context.read().selectedHospitalForFilters, + context.read().applyFilters); + context.read().updateList(); + Navigator.pop(context); + }, + backgroundColor: AppColors.primaryRedColor, + borderColor: AppColors.primaryRedColor, + textColor: Colors.white, + fontSize: 16, + padding: EdgeInsets.zero, + fontWeight: FontWeight.w500, + borderRadius: 12, + icon: AppAssets.add_icon, + iconColor: AppColors.primaryRedColor, + ).paddingAll(24.h), + ), + ], + ), + ); + } + + Widget titleWidget(String title){ + return Column( + children: [ + SizedBox(height: 24.h,), + Text( + title, + style:TextStyle( + fontFamily: 'Poppins', + fontWeight: FontWeight.w600, + fontSize: 16.fSize, + color: AppColors.textColor, + letterSpacing:-1 + ) + ), + SizedBox(height: 8.h,), + ], + ); + } + + void openRegionListBottomSheet(BuildContext context, RegionBottomSheetType type) { + context.read().flush(); + context.read().setBottomSheetType(type); + context.read().setBottomSheetState(AppointmentViaRegionState.HOSPITAL_SELECTION); + // AppointmentViaRegionViewmodel? viewmodel = null; + showCommonBottomSheetWithoutHeight(context, title: "", titleWidget: Consumer(builder: (_, data, __) => getTitle(data)), isDismissible: false, + child: Consumer(builder: (_, data, __) { + return getRegionalSelectionWidget(data); + }), callBackFunc: () {}); + } + + Widget getRegionalSelectionWidget(AppointmentViaRegionViewmodel data) { + + if (data.bottomSheetState == AppointmentViaRegionState.HOSPITAL_SELECTION) { + return HospitalBottomSheetBodyForDoctorFilter(); + } + if (data.bottomSheetState == AppointmentViaRegionState.CLINIC_SELECTION) { + } else { + SizedBox.shrink(); + } + return SizedBox.shrink(); + } + + getTitle(AppointmentViaRegionViewmodel data) { + return SizedBox.shrink(); + } + + void openClinicListBottomSheet(BuildContext context) { + showCommonBottomSheetWithoutHeight(context, title: "", titleWidget: Consumer(builder: (_, data, __) => getTitle(data)), isDismissible: false, + child: Consumer(builder: (_, data, __) { + return ClinicBottomSheet(); + }), callBackFunc: () {}); + } + +} \ No newline at end of file diff --git a/lib/presentation/book_appointment/doctor_filter/facility_Chips.dart b/lib/presentation/book_appointment/doctor_filter/facility_Chips.dart new file mode 100644 index 0000000..f416ed4 --- /dev/null +++ b/lib/presentation/book_appointment/doctor_filter/facility_Chips.dart @@ -0,0 +1,65 @@ + +import 'package:easy_localization/easy_localization.dart' show tr, StringTranslateExtension; +import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/app_assets.dart'; +import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; +import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; +import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart' + show BookAppointmentsViewModel; +import 'package:hmg_patient_app_new/features/doctor_filter/doctor_filter_view_model.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; +import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; +import 'package:provider/provider.dart'; + +class FacilityChip extends StatelessWidget { + const FacilityChip({super.key}); + + @override + Widget build(BuildContext context) { + return Selector>( + selector: (_, model) => model.facilityList, + builder: (__, data, ___) => + Selector?>( + selector: (_, model) => model.selectedFacilityForFilters, + builder: (context, selectRegion, ___) => Row( + children: [ + Expanded( + child: ListView.separated( + scrollDirection: Axis.horizontal, + + itemCount: data.length, + separatorBuilder: (_, __)=>SizedBox(width: 8.h,), + itemBuilder: (_, index) => AppCustomChipWidget( + icon: data[index].contains("hmg")?AppAssets.hmg: AppAssets.hmc, + iconHasColor: false, + iconSize: 18, + labelText: data[index].tr(), + textColor: selectRegion?.any((selectedRegion)=>data[index] == selectedRegion) == true + ? AppColors.primaryRedColor + : AppColors.textColor, + backgroundColor: + data[index] == selectRegion + ? AppColors.primaryRedColor + .withOpacity(0.1) + : AppColors.whiteColor, + shape: RoundedRectangleBorder( + side: BorderSide( + color: selectRegion?.any((selectedRegion)=>data[index] == selectedRegion) == true + ? AppColors + .primaryRedBorderColor + : AppColors + .chipBorderColorOpacity20, + width: 1, + ), + borderRadius: + BorderRadius.circular(10))) + .onPress(() { + context + .read() + .setSelectedFacilityForFilter(data[index]); + }))) + ], + ), + )); + } +} diff --git a/lib/presentation/book_appointment/search_doctor_by_name.dart b/lib/presentation/book_appointment/search_doctor_by_name.dart index 8f611dc..233aff9 100644 --- a/lib/presentation/book_appointment/search_doctor_by_name.dart +++ b/lib/presentation/book_appointment/search_doctor_by_name.dart @@ -9,7 +9,9 @@ import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart'; +import 'package:hmg_patient_app_new/features/doctor_filter/doctor_filter_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/presentation/book_appointment/doctor_filter/doctors_filter.dart'; import 'package:hmg_patient_app_new/presentation/book_appointment/doctor_profile_page.dart'; import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/doctor_card.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; @@ -33,16 +35,12 @@ class SearchDoctorByName extends StatefulWidget { class _SearchDoctorByNameState extends State { TextEditingController searchEditingController = TextEditingController(); - FocusNode textFocusNode = FocusNode(); - - late AppState appState; late BookAppointmentsViewModel bookAppointmentsViewModel; @override Widget build(BuildContext context) { bookAppointmentsViewModel = Provider.of(context, listen: false); - appState = getIt.get(); return Scaffold( backgroundColor: AppColors.bgScaffoldColor, body: Column( @@ -56,33 +54,85 @@ class _SearchDoctorByNameState extends State { child: Column( children: [ SizedBox(height: 16.h), - TextInputWidget( - labelText: LocaleKeys.search.tr(context: context), - hintText: LocaleKeys.doctorName.tr(context: context), - controller: searchEditingController, - isEnable: true, - prefix: null, - autoFocus: false, - isBorderAllowed: false, - keyboardType: TextInputType.text, - focusNode: textFocusNode, - suffix: searchEditingController.text.isNotEmpty - ? GestureDetector( - onTap: () { - searchEditingController.clear(); - // bookAppointmentsViewModel.filterClinics(""); - textFocusNode.unfocus(); - }, - child: Utils.buildSvgWithAssets(icon: AppAssets.close_bottom_sheet_icon, width: 20.h, height: 20.h, fit: BoxFit.scaleDown), - ) - : null, - onChange: (value) { - // bookAppointmentsViewModel.filterClinics(value!); - }, - padding: EdgeInsets.symmetric( - vertical: ResponsiveExtension(10).h, - horizontal: ResponsiveExtension(15).h, - ), + Row( + spacing: 8.h, + children: [ + Expanded( + child: TextInputWidget( + labelText: LocaleKeys.search.tr(context: context), + hintText: LocaleKeys.doctorName.tr(context: context), + controller: searchEditingController, + isEnable: true, + prefix: null, + autoFocus: false, + isBorderAllowed: false, + keyboardType: TextInputType.text, + focusNode: textFocusNode, + suffix: searchEditingController.text.isNotEmpty + ? GestureDetector( + onTap: () { + searchEditingController.clear(); + // bookAppointmentsViewModel.filterClinics(""); + textFocusNode.unfocus(); + }, + child: Utils.buildSvgWithAssets(icon: AppAssets.close_bottom_sheet_icon, width: 20.h, height: 20.h, fit: BoxFit.scaleDown), + ) + : null, + onChange: (value) { + // bookAppointmentsViewModel.filterClinics(value!); + }, + padding: EdgeInsets.symmetric( + vertical: ResponsiveExtension(10).h, + horizontal: ResponsiveExtension(15).h, + ), + ), + ), + Visibility( + visible: bookAppointmentsViewModel.doctorsList.isNotEmpty, + child: SizedBox( + height: 56.h, + width: 56.h, + child: DecoratedBox(decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 10.h, + hasShadow: false, + ), + child: Utils.buildSvgWithAssets(icon: AppAssets.ic_filters, + height: 24.h, + width: 24.h, ).paddingAll(16.h).onPress((){ + context.read() + ..clearSelection() + ..clearSearchFilters() + ..getFiltersFromDoctorList( + bookAppointmentsViewModel.doctorsList + )..setSelections( + bookAppointmentsViewModel.selectedFacilityForFilters?.toList(), + bookAppointmentsViewModel.selectedRegionForFilters?.toList(), + bookAppointmentsViewModel.selectedClinicForFilters, + bookAppointmentsViewModel.selectedHospitalForFilters, + bookAppointmentsViewModel.applyFilters) ; + Navigator.of(context).push( + PageRouteBuilder( + pageBuilder: (context, animation, secondaryAnimation) => DoctorsFilters(), // Replace YourNewPage with your actual page widget + transitionsBuilder: (context, animation, secondaryAnimation, child) { + const begin = Offset(0.0, 1.0); // Start from the bottom (y=1.0) + const end = Offset.zero; // End at the original position (y=0.0) + final tween = Tween(begin: begin, end: end); + final offsetAnimation = animation.drive(tween); + + return SlideTransition( + position: offsetAnimation, + child: child, + ); + }, + transitionDuration: Duration(milliseconds: 200), // Adjust duration as needed + ), + ); + }), + ), + ), + ) + ], ), SizedBox(height: 16.h), Consumer(builder: (context, bookAppointmentsVM, child) { @@ -94,7 +144,7 @@ class _SearchDoctorByNameState extends State { padding: EdgeInsets.only(top: 24.h), shrinkWrap: true, physics: NeverScrollableScrollPhysics(), - itemCount: bookAppointmentsVM.isDoctorsListLoading ? 5 : bookAppointmentsVM.doctorsList.length, + itemCount: bookAppointmentsVM.isDoctorsListLoading ? 5 : bookAppointmentsVM.filteredDoctorList.length, itemBuilder: (context, index) { return bookAppointmentsVM.isDoctorsListLoading ? DoctorCard( @@ -113,11 +163,11 @@ class _SearchDoctorByNameState extends State { curve: Curves.easeInOut, decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true), child: DoctorCard( - doctorsListResponseModel: bookAppointmentsVM.doctorsList[index], + doctorsListResponseModel: bookAppointmentsVM.filteredDoctorList[index], isLoading: false, bookAppointmentsViewModel: bookAppointmentsViewModel, ).onPress(() async { - bookAppointmentsVM.setSelectedDoctor(bookAppointmentsVM.doctorsList[index]); + bookAppointmentsVM.setSelectedDoctor(bookAppointmentsVM.filteredDoctorList[index]); // bookAppointmentsVM.setSelectedDoctor(DoctorsListResponseModel()); LoaderBottomSheet.showLoader(); await bookAppointmentsVM.getDoctorProfile(onSuccess: (dynamic respData) { @@ -166,7 +216,11 @@ class _SearchDoctorByNameState extends State { text: LocaleKeys.search.tr(context: context), onPressed: () async { textFocusNode.unfocus(); + print("the value is empty ${searchEditingController.text.isNotEmpty}"); if (searchEditingController.text.isNotEmpty) { + bookAppointmentsViewModel.updateApplyFilters(false); + bookAppointmentsViewModel.clearSelection(); + bookAppointmentsViewModel.updateList(); bookAppointmentsViewModel.setIsDoctorSearchByNameStarted(true); bookAppointmentsViewModel.setIsDoctorsListLoading(true); // LoaderBottomSheet.showLoader(); diff --git a/lib/presentation/book_appointment/select_doctor_page.dart b/lib/presentation/book_appointment/select_doctor_page.dart index fd6e691..ec17c61 100644 --- a/lib/presentation/book_appointment/select_doctor_page.dart +++ b/lib/presentation/book_appointment/select_doctor_page.dart @@ -68,33 +68,63 @@ class _SelectDoctorPageState extends State { children: [ // TODO: Implement doctor filter functionality SizedBox(height: 16.h), - TextInputWidget( - labelText: LocaleKeys.search.tr(context: context), - hintText: LocaleKeys.doctorName.tr(context: context), - controller: searchEditingController, - isEnable: true, - prefix: null, - autoFocus: false, - isBorderAllowed: false, - keyboardType: TextInputType.text, - focusNode: textFocusNode, - suffix: searchEditingController.text.isNotEmpty - ? GestureDetector( - onTap: () { - searchEditingController.clear(); - bookAppointmentsViewModel.filterClinics(""); - textFocusNode.unfocus(); - }, - child: Utils.buildSvgWithAssets(icon: AppAssets.close_bottom_sheet_icon, width: 20.h, height: 20.h, fit: BoxFit.scaleDown), - ) - : null, - onChange: (value) { - bookAppointmentsViewModel.filterClinics(value!); - }, - padding: EdgeInsets.symmetric( - vertical: ResponsiveExtension(10).h, - horizontal: ResponsiveExtension(15).h, - ), + Row( + spacing: 8.h, + children: [ + Expanded( + child: TextInputWidget( + labelText: LocaleKeys.search.tr(context: context), + hintText: LocaleKeys.doctorName.tr(context: context), + controller: searchEditingController, + isEnable: true, + prefix: null, + autoFocus: false, + isBorderAllowed: false, + keyboardType: TextInputType.text, + focusNode: textFocusNode, + suffix: searchEditingController.text.isNotEmpty + ? GestureDetector( + onTap: () { + searchEditingController.clear(); + bookAppointmentsViewModel.filterClinics(""); + textFocusNode.unfocus(); + }, + child: Utils.buildSvgWithAssets( + icon: AppAssets.close_bottom_sheet_icon, + width: 20.h, + height: 20.h, + fit: BoxFit.scaleDown), + ) + : null, + onChange: (value) { + bookAppointmentsViewModel.filterClinics(value!); + }, + padding: EdgeInsets.symmetric( + vertical: ResponsiveExtension(10).h, + horizontal: ResponsiveExtension(15).h, + ), + ), + ), + SizedBox( + height: 56.h, + width: 56.h, + child: DecoratedBox( + decoration: + RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 10.h, + hasShadow: false, + ), + child: Utils.buildSvgWithAssets( + icon: AppAssets.ic_filters, + height: 24.h, + width: 24.h, + ).paddingAll(16.h).onPress((){ + + }), + ), + ) + ], ), ListView.separated( padding: EdgeInsets.only(top: 24.h), diff --git a/lib/widgets/chip/app_custom_chip_widget.dart b/lib/widgets/chip/app_custom_chip_widget.dart index a4db172..084f85b 100644 --- a/lib/widgets/chip/app_custom_chip_widget.dart +++ b/lib/widgets/chip/app_custom_chip_widget.dart @@ -62,7 +62,7 @@ class AppCustomChipWidget extends StatelessWidget { // padding: EdgeInsets.all(0.0), padding: padding, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, - labelPadding: EdgeInsetsDirectional.only(start: -4.h, end: deleteIcon?.isNotEmpty == true ? 2.h : 8.h), + labelPadding: EdgeInsetsDirectional.only(start: 0.h, end: deleteIcon?.isNotEmpty == true ? 2.h : 8.h), backgroundColor: backgroundColor, shape: shape ?? SmoothRectangleBorder( diff --git a/lib/widgets/input_widget.dart b/lib/widgets/input_widget.dart index 4a2322c..4b06096 100644 --- a/lib/widgets/input_widget.dart +++ b/lib/widgets/input_widget.dart @@ -114,6 +114,7 @@ class TextInputWidget extends StatelessWidget { children: [ Container( padding: padding, + height: 58.h, alignment: Alignment.center, decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: Colors.white, @@ -134,12 +135,23 @@ class TextInputWidget extends StatelessWidget { // textField: _buildTextField(context), ) : Expanded( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, + child: Row( children: [ - _buildLabelText(labelColor).paddingOnly(right: (appState.getLanguageCode() == "ar" ? 10 : 0)), - _buildTextField(context), + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildLabelText(labelColor).paddingOnly(right: (appState.getLanguageCode() == "ar" ? 10 : 0)), + Row( + children: [ + Expanded(child: _buildTextField(context)), + ], + ), + ], + ), + ), + (suffix!= null )?suffix!:SizedBox.shrink() ], ), ), @@ -218,7 +230,6 @@ class TextInputWidget extends StatelessWidget { fontWeight: FontWeight.w500, color: labelColor ?? AppColors.inputLabelTextColor, letterSpacing: -0.2, - height: 18 / 12, ), ); }