Merge branch 'master' into haroon_dev

# Conflicts:
#	lib/core/app_assets.dart
#	lib/widgets/input_widget.dart
pull/67/head
haroon amjad 4 weeks ago
commit 8166369f85

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 1.25C6.06294 1.25 1.25 6.06294 1.25 12C1.25 17.9371 6.06294 22.75 12 22.75C17.9371 22.75 22.75 17.9371 22.75 12C22.75 6.06294 17.9371 1.25 12 1.25ZM9.20711 7.79289C8.81658 7.40237 8.18342 7.40237 7.79289 7.79289C7.40237 8.18342 7.40237 8.81658 7.79289 9.20711L10.5858 12L7.79289 14.7929C7.40237 15.1834 7.40237 15.8166 7.79289 16.2071C8.18342 16.5976 8.81658 16.5976 9.20711 16.2071L12 13.4142L14.7929 16.2071C15.1834 16.5976 15.8166 16.5976 16.2071 16.2071C16.5976 15.8166 16.5976 15.1834 16.2071 14.7929L13.4142 12L16.2071 9.20711C16.5976 8.81658 16.5976 8.18342 16.2071 7.79289C15.8166 7.40237 15.1834 7.40237 14.7929 7.79289L12 10.5858L9.20711 7.79289Z" fill="#8F9AA3"/>
</svg>

After

Width:  |  Height:  |  Size: 835 B

@ -0,0 +1,8 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.75 3.47825C16.75 3.26399 16.75 3.06711 16.7387 2.90179C16.7266 2.72415 16.699 2.52881 16.6168 2.33031C16.4392 1.90151 16.0985 1.56083 15.6697 1.38321C15.4712 1.30099 15.2759 1.27338 15.0982 1.26126C14.9329 1.24998 14.7361 1.24999 14.5218 1.25L14.4782 1.25C14.264 1.24999 14.0671 1.24998 13.9018 1.26126C13.7241 1.27338 13.5288 1.30099 13.3303 1.38321C12.9015 1.56083 12.5608 1.90151 12.3832 2.33031C12.301 2.52881 12.2734 2.72415 12.2613 2.90179C12.2541 3.00643 12.2515 3.12369 12.2505 3.25L3 3.25C2.58579 3.25 2.25 3.58579 2.25 4C2.25 4.41421 2.58579 4.75 3 4.75L12.2505 4.75C12.2515 4.87632 12.2541 4.99358 12.2613 5.09821C12.2734 5.27585 12.301 5.4712 12.3832 5.6697C12.5608 6.0985 12.9015 6.43918 13.3303 6.61679C13.5288 6.69902 13.7241 6.72663 13.9018 6.73875C14.0671 6.75003 14.264 6.75002 14.4782 6.75H14.5218C14.736 6.75002 14.9329 6.75003 15.0982 6.73875C15.2759 6.72663 15.4712 6.69902 15.6697 6.61679C16.0985 6.43918 16.4392 6.0985 16.6168 5.6697C16.699 5.4712 16.7266 5.27586 16.7387 5.09821C16.75 4.9329 16.75 4.73607 16.75 4.52182V3.47825ZM13.75 4.00171V4.5C13.75 4.74323 13.7504 4.8881 13.7578 4.9961C13.7623 5.06293 13.7684 5.09134 13.7703 5.09869C13.7956 5.15753 13.8425 5.20442 13.9013 5.2297C13.9087 5.23157 13.9371 5.23767 14.0039 5.24223C14.1119 5.2496 14.2568 5.25 14.5 5.25C14.7432 5.25 14.8881 5.2496 14.9961 5.24223C15.0629 5.23767 15.0913 5.23157 15.0987 5.2297C15.1575 5.20442 15.2044 5.15753 15.2297 5.09869C15.2316 5.09134 15.2377 5.06294 15.2422 4.9961C15.2496 4.8881 15.25 4.74323 15.25 4.5V3.5C15.25 3.25677 15.2496 3.11191 15.2422 3.0039C15.2377 2.93707 15.2316 2.90867 15.2297 2.90131C15.2044 2.84248 15.1575 2.79558 15.0987 2.77031C15.0913 2.76844 15.0629 2.76234 14.9961 2.75778C14.8881 2.75041 14.7432 2.75 14.5 2.75C14.2568 2.75 14.1119 2.75041 14.0039 2.75778C13.9371 2.76234 13.9087 2.76844 13.9013 2.77031C13.8425 2.79558 13.7956 2.84248 13.7703 2.90131C13.7684 2.90867 13.7623 2.93707 13.7578 3.0039C13.7504 3.11191 13.75 3.25677 13.75 3.5V3.99829L13.75 4L13.75 4.00171Z" fill="#2E3039"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.2505 19.75L3 19.75C2.58579 19.75 2.25 19.4142 2.25 19C2.25 18.5858 2.58579 18.25 3 18.25L10.2505 18.25C10.2515 18.1237 10.2541 18.0064 10.2613 17.9018C10.2734 17.7241 10.301 17.5288 10.3832 17.3303C10.5608 16.9015 10.9015 16.5608 11.3303 16.3832C11.5288 16.301 11.7241 16.2734 11.9018 16.2613C12.0671 16.25 12.264 16.25 12.4782 16.25H12.5218C12.736 16.25 12.9329 16.25 13.0982 16.2613C13.2759 16.2734 13.4712 16.301 13.6697 16.3832C14.0985 16.5608 14.4392 16.9015 14.6168 17.3303C14.699 17.5288 14.7266 17.7241 14.7387 17.9018C14.75 18.0671 14.75 18.2639 14.75 18.4782L14.75 19.5218C14.75 19.736 14.75 19.9329 14.7387 20.0982C14.7266 20.2759 14.699 20.4712 14.6168 20.6697C14.4392 21.0985 14.0985 21.4392 13.6697 21.6168C13.4712 21.699 13.2759 21.7266 13.0982 21.7387C12.9329 21.75 12.736 21.75 12.5218 21.75H12.4782C12.264 21.75 12.0671 21.75 11.9018 21.7387C11.7241 21.7266 11.5288 21.699 11.3303 21.6168C10.9015 21.4392 10.5608 21.0985 10.3832 20.6697C10.301 20.4712 10.2734 20.2759 10.2613 20.0982C10.2541 19.9936 10.2515 19.8763 10.2505 19.75ZM11.75 19.5L11.75 19.0017L11.75 19L11.75 18.9983V18.5C11.75 18.2568 11.7504 18.1119 11.7578 18.0039C11.7623 17.9371 11.7684 17.9087 11.7703 17.9013C11.7956 17.8425 11.8425 17.7956 11.9013 17.7703C11.9087 17.7684 11.9371 17.7623 12.0039 17.7578C12.1119 17.7504 12.2568 17.75 12.5 17.75C12.7432 17.75 12.8881 17.7504 12.9961 17.7578C13.0629 17.7623 13.0913 17.7684 13.0987 17.7703C13.1575 17.7956 13.2044 17.8425 13.2297 17.9013C13.2316 17.9087 13.2377 17.9371 13.2422 18.0039C13.2496 18.1119 13.25 18.2568 13.25 18.5L13.25 19.5C13.25 19.7432 13.2496 19.8881 13.2422 19.9961C13.2377 20.0629 13.2316 20.0913 13.2297 20.0987C13.2044 20.1575 13.1575 20.2044 13.0987 20.2297C13.0913 20.2316 13.0629 20.2377 12.9961 20.2422C12.8881 20.2496 12.7432 20.25 12.5 20.25C12.2568 20.25 12.1119 20.2496 12.0039 20.2422C11.9371 20.2377 11.9087 20.2316 11.9013 20.2297C11.8425 20.2044 11.7956 20.1575 11.7703 20.0987C11.7684 20.0913 11.7623 20.0629 11.7578 19.9961C11.7504 19.8881 11.75 19.7432 11.75 19.5Z" fill="#2E3039"/>
<path d="M21 19.75C21.4142 19.75 21.75 19.4142 21.75 19C21.75 18.5858 21.4142 18.25 21 18.25H17C16.5858 18.25 16.25 18.5858 16.25 19C16.25 19.4142 16.5858 19.75 17 19.75H21Z" fill="#2E3039"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M21.75 11.5C21.75 11.9142 21.4142 12.25 21 12.25L11.7495 12.25C11.7485 12.3763 11.7459 12.4936 11.7387 12.5982C11.7266 12.7759 11.699 12.9712 11.6168 13.1697C11.4392 13.5985 11.0985 13.9392 10.6697 14.1168C10.4712 14.199 10.2759 14.2266 10.0982 14.2387C9.93288 14.25 9.73603 14.25 9.52176 14.25H9.47824C9.26396 14.25 9.06711 14.25 8.90179 14.2387C8.72415 14.2266 8.52881 14.199 8.3303 14.1168C7.9015 13.9392 7.56082 13.5985 7.38321 13.1697C7.30099 12.9712 7.27337 12.7759 7.26125 12.5982C7.24997 12.4329 7.24998 12.236 7.25 12.0218V10.9782C7.24998 10.764 7.24997 10.5671 7.26125 10.4018C7.27337 10.2242 7.30099 10.0288 7.38321 9.83031C7.56082 9.40151 7.9015 9.06083 8.3303 8.88321C8.52881 8.80099 8.72415 8.77338 8.90179 8.76126C9.06711 8.74998 9.26396 8.74999 9.47824 8.75H9.52175C9.73603 8.74999 9.93288 8.74998 10.0982 8.76126C10.2759 8.77338 10.4712 8.80099 10.6697 8.88321C11.0985 9.06083 11.4392 9.40151 11.6168 9.83031C11.699 10.0288 11.7266 10.2242 11.7387 10.4018C11.7459 10.5064 11.7485 10.6237 11.7495 10.75L21 10.75C21.4142 10.75 21.75 11.0858 21.75 11.5ZM10.0987 10.2703C10.1575 10.2956 10.2044 10.3425 10.2297 10.4013C10.2316 10.4087 10.2377 10.4371 10.2422 10.5039C10.2496 10.6119 10.25 10.7568 10.25 11V12C10.25 12.2432 10.2496 12.3881 10.2422 12.4961C10.2377 12.5629 10.2316 12.5913 10.2297 12.5987C10.2044 12.6575 10.1575 12.7044 10.0987 12.7297C10.0913 12.7316 10.0629 12.7377 9.9961 12.7422C9.88809 12.7496 9.74323 12.75 9.5 12.75C9.25677 12.75 9.1119 12.7496 9.0039 12.7422C8.93707 12.7377 8.90867 12.7316 8.90131 12.7297C8.84248 12.7044 8.79558 12.6575 8.7703 12.5987C8.76843 12.5913 8.76233 12.5629 8.75777 12.4961C8.7504 12.3881 8.75 12.2432 8.75 12V11C8.75 10.7568 8.7504 10.6119 8.75777 10.5039C8.76233 10.4371 8.76843 10.4087 8.7703 10.4013C8.79558 10.3425 8.84247 10.2956 8.90131 10.2703C8.90866 10.2684 8.93706 10.2623 9.0039 10.2578C9.1119 10.2504 9.25677 10.25 9.5 10.25C9.74323 10.25 9.88809 10.2504 9.9961 10.2578C10.0629 10.2623 10.0913 10.2684 10.0987 10.2703Z" fill="#2E3039"/>
<path d="M21 4.75C21.4142 4.75 21.75 4.41421 21.75 4C21.75 3.58579 21.4142 3.25 21 3.25L19 3.25C18.5858 3.25 18.25 3.58579 18.25 4C18.25 4.41421 18.5858 4.75 19 4.75L21 4.75Z" fill="#2E3039"/>
<path d="M5.75 11.5C5.75 11.9142 5.41421 12.25 5 12.25H3C2.58579 12.25 2.25 11.9142 2.25 11.5C2.25 11.0858 2.58579 10.75 3 10.75H5C5.41421 10.75 5.75 11.0858 5.75 11.5Z" fill="#2E3039"/>
</svg>

After

Width:  |  Height:  |  Size: 6.8 KiB

@ -0,0 +1,3 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.29289 7.29289C7.68342 6.90237 8.31658 6.90237 8.70711 7.29289L16 14.5858L23.2929 7.29289C23.6834 6.90237 24.3166 6.90237 24.7071 7.29289C25.0976 7.68342 25.0976 8.31658 24.7071 8.70711L17.4142 16L24.7071 23.2929C25.0976 23.6834 25.0976 24.3166 24.7071 24.7071C24.3166 25.0976 23.6834 25.0976 23.2929 24.7071L16 17.4142L8.70711 24.7071C8.31658 25.0976 7.68342 25.0976 7.29289 24.7071C6.90237 24.3166 6.90237 23.6834 7.29289 23.2929L14.5858 16L7.29289 8.70711C6.90237 8.31658 6.90237 7.68342 7.29289 7.29289Z" fill="#2E3039"/>
</svg>

After

Width:  |  Height:  |  Size: 684 B

@ -856,5 +856,13 @@
"onboardingHeading1": "حجز المواعيد لم يكن أسهل من قبل",
"onboardingBody1": "ببضع نقرات فقط يمكنك استشارة الطبيب الذي تختاره.",
"onboardingHeading2": "الوصول إلى السجل الطبي بين يديك",
"onboardingBody2": "تتبع تاريخك الطبي بما في ذلك الفحوصات المخبرية، الوصفات الطبية، التأمين، وغيرها."
"onboardingBody2": "تتبع تاريخك الطبي بما في ذلك الفحوصات المخبرية، الوصفات الطبية، التأمين، وغيرها.",
"hmgHospitals": "مستشفيات HMG",
"hmcMedicalClinic": "مراكز HMC الطبية",
"applyFilter": "تطبيق الفلتر",
"facilityAndLocation": "المرفق والموقع",
"regionAndLocation": "المنطقة والمواقع",
"clearAllFilters": "مسح جميع الفلاتر",
"filters": "فلاتر",
"searchClinic": "بحث عن عيادة"
}

@ -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"
}

@ -149,6 +149,9 @@ class AppAssets {
static const String edit_icon = '$svgBasePath/edit_icon.svg';
static const String waiting_icon = '$svgBasePath/waiting_icon.svg';
static const String forward_arrow_icon_small = '$svgBasePath/forward_arrow_icon_small.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';

@ -51,6 +51,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
List<GetClinicsListResponseModel> get filteredClinicsList => _filteredClinicsList;
List<DoctorsListResponseModel> doctorsList = [];
List<DoctorsListResponseModel> filteredDoctorList = [];
List<DoctorsListResponseModel> liveCareDoctorsList = [];
@ -85,6 +86,19 @@ class BookAppointmentsViewModel extends ChangeNotifier {
bool shouldLoadSpecificClinic = false;
String? currentlySelectedHospitalFromRegionFlow;
///variables for doctor filter
List<String> searchedRegionList = [];
List<String> facilityList = ["hmgHospitals", "hmcMedicalClinic"];
List<String> searchedHospitalList = [];
List<PatientDoctorAppointmentList>
searchedPatientDoctorAppointmentHospitalsList = [];
List<String> searchedClinicList = [];
PatientDoctorAppointmentList? selectedHospitalForFilters;
List<String>? selectedFacilityForFilters = [], selectedRegionForFilters = [];
String? selectedClinicForFilters;
bool applyFilters = false;
BookAppointmentsViewModel(
{required this.bookAppointmentsRepo, required this.errorHandlerService, required this.navigationService, required this.myAppointmentsViewModel, required this.locationUtils}) {
initBookAppointmentViewModel();
@ -276,8 +290,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);
@ -754,4 +771,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<String>? selectedFacilityForFilters,
List<String>? 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<DoctorsListResponseModel> 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();
}
}

@ -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<String> searchedRegionList = [];
List<String> facilityList = ["hmgHospitals", "hmcMedicalClinic"];
List<String> searchedHospitalList = [];
List<PatientDoctorAppointmentList>
searchedPatientDoctorAppointmentHospitalsList = [];
List<String> searchedClinicList = [];
PatientDoctorAppointmentList? selectedHospitalForFilters;
List<String>? 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<DoctorsListResponseModel> 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<String>? selectedFacilityForFilters,
List<String>? selectedRegionForFilters,
String? selectedClinicForFilters,
PatientDoctorAppointmentList? selectedHospitalForFilters,
bool applyFilters) {
this.selectedFacilityForFilters = selectedFacilityForFilters;
this.selectedClinicForFilters = selectedClinicForFilters;
this.selectedHospitalForFilters = selectedHospitalForFilters;
this.selectedRegionForFilters = selectedRegionForFilters;
this.applyFilters = applyFilters;
notifyListeners();
}
}

@ -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';
}

@ -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/immediate_livecare/immediate_livecare_view_model.dart';
import 'package:hmg_patient_app_new/features/insurance/insurance_view_model.dart';
@ -163,7 +164,9 @@ void main() async {
ChangeNotifierProvider<LabHistoryViewModel>(
create: (_) => LabHistoryViewModel()),
ChangeNotifierProvider<LabRangeViewModel>(
create: (_) => LabRangeViewModel())
create: (_) => LabRangeViewModel()) ,
ChangeNotifierProvider<DoctorFilterViewModel>(
create: (_) => DoctorFilterViewModel())
], child: MyApp()),
),
);

@ -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<BookAppointmentsViewModel>(context);
regionalViewModel = Provider.of<AppointmentViaRegionViewmodel>(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<DoctorFilterViewModel>().setSelectedHospital(hospital);
Navigator.pop(context);
});},
separatorBuilder: (_, __) => SizedBox(
height: 16.h,
),
itemCount: appointmentsViewModel.searchedPatientDoctorAppointmentHospitalsList?.length ?? 0),
)
],
);
}
}

@ -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<DoctorFilterViewModel, List<String>>(
selector: (_, model) => model.searchedRegionList,
builder: (__, data, ___) =>
Selector<DoctorFilterViewModel, List<String>?>(
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<DoctorFilterViewModel>()
.setSelectedRegion(data[index]);
})))
],
),
));
}
}

@ -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<BookAppointmentsViewModel>(context);
regionalViewModel = Provider.of<AppointmentViaRegionViewmodel>(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<DoctorFilterViewModel>()
.setSelectedClinicForFilter(appointmentsViewModel.searchedClinicList[index]);
Navigator.pop(context);
});},
separatorBuilder: (_, __) => SizedBox(
height: 16.h,
),
itemCount: appointmentsViewModel.searchedClinicList.length ?? 0),
)
],
);
}
}

@ -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),
),
],
),
],
),
);
}
}

@ -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<DoctorFilterViewModel>()
.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<DoctorFilterViewModel>().clearSelection();
context.read<DoctorFilterViewModel>().updateApplyFilters(false);
// context.read<BookAppointmentsViewModel>().setSelections(
// context.read<DoctorFilterViewModel>().selectedFacilityForFilters,
// context.read<DoctorFilterViewModel>().selectedRegionForFilters,
// context.read<DoctorFilterViewModel>().selectedClinicForFilters,
// context.read<DoctorFilterViewModel>().selectedHospitalForFilters,
// context.read<DoctorFilterViewModel>().applyFilters);
context.read<BookAppointmentsViewModel>().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<DoctorFilterViewModel>().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<DoctorFilterViewModel>().selectedHospitalForFilters != null
? GestureDetector(
onTap: () {
context.read<DoctorFilterViewModel>().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<DoctorFilterViewModel>().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<DoctorFilterViewModel>().selectedClinicForFilters?.isNotEmpty == true
? GestureDetector(
onTap: () {
context.read<DoctorFilterViewModel>().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<DoctorFilterViewModel>().updateApplyFilters(true);
context.read<BookAppointmentsViewModel>().setSelections(
context.read<DoctorFilterViewModel>().selectedFacilityForFilters?.toList()??[],
context.read<DoctorFilterViewModel>().selectedRegionForFilters?.toList()??[],
context.read<DoctorFilterViewModel>().selectedClinicForFilters,
context.read<DoctorFilterViewModel>().selectedHospitalForFilters,
context.read<DoctorFilterViewModel>().applyFilters);
context.read<BookAppointmentsViewModel>().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<AppointmentViaRegionViewmodel>().flush();
context.read<AppointmentViaRegionViewmodel>().setBottomSheetType(type);
context.read<AppointmentViaRegionViewmodel>().setBottomSheetState(AppointmentViaRegionState.HOSPITAL_SELECTION);
// AppointmentViaRegionViewmodel? viewmodel = null;
showCommonBottomSheetWithoutHeight(context, title: "", titleWidget: Consumer<AppointmentViaRegionViewmodel>(builder: (_, data, __) => getTitle(data)), isDismissible: false,
child: Consumer<AppointmentViaRegionViewmodel>(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<AppointmentViaRegionViewmodel>(builder: (_, data, __) => getTitle(data)), isDismissible: false,
child: Consumer<AppointmentViaRegionViewmodel>(builder: (_, data, __) {
return ClinicBottomSheet();
}), callBackFunc: () {});
}
}

@ -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<DoctorFilterViewModel, List<String>>(
selector: (_, model) => model.facilityList,
builder: (__, data, ___) =>
Selector<DoctorFilterViewModel, List<String>?>(
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<DoctorFilterViewModel>()
.setSelectedFacilityForFilter(data[index]);
})))
],
),
));
}
}

@ -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<SearchDoctorByName> {
TextEditingController searchEditingController = TextEditingController();
FocusNode textFocusNode = FocusNode();
late AppState appState;
late BookAppointmentsViewModel bookAppointmentsViewModel;
@override
Widget build(BuildContext context) {
bookAppointmentsViewModel = Provider.of<BookAppointmentsViewModel>(context, listen: false);
appState = getIt.get<AppState>();
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: Column(
@ -56,33 +54,85 @@ class _SearchDoctorByNameState extends State<SearchDoctorByName> {
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: context.watch<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<DoctorFilterViewModel>()
..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<BookAppointmentsViewModel>(builder: (context, bookAppointmentsVM, child) {
@ -94,7 +144,7 @@ class _SearchDoctorByNameState extends State<SearchDoctorByName> {
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<SearchDoctorByName> {
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<SearchDoctorByName> {
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();
@ -210,4 +264,9 @@ class _SearchDoctorByNameState extends State<SearchDoctorByName> {
),
);
}
@override
void dispose() {
bookAppointmentsViewModel.doctorsList.clear();
super.dispose();
}
}

@ -68,33 +68,44 @@ class _SelectDoctorPageState extends State<SelectDoctorPage> {
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,
),
),
),
],
),
ListView.separated(
padding: EdgeInsets.only(top: 24.h),

@ -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(

@ -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,
height: 18 / 12,
),
);
}

Loading…
Cancel
Save