Merge branch 'master' into dev_aamir
# Conflicts: # assets/langs/ar-SA.json # assets/langs/en-US.json # lib/generated/locale_keys.g.dartpull/45/head
						commit
						b9b0dfd1fa
					
				| @ -0,0 +1,5 @@ | ||||
| <svg width="10" height="13" viewBox="0 0 10 13" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||||
| <path fill-rule="evenodd" clip-rule="evenodd" d="M5 2.85449C3.79188 2.85449 2.8125 3.83387 2.8125 5.04199C2.8125 6.25011 3.79188 7.22949 5 7.22949C6.20812 7.22949 7.1875 6.25011 7.1875 5.04199C7.1875 3.83387 6.20812 2.85449 5 2.85449ZM3.6875 5.04199C3.6875 4.31712 4.27513 3.72949 5 3.72949C5.72487 3.72949 6.3125 4.31712 6.3125 5.04199C6.3125 5.76687 5.72487 6.35449 5 6.35449C4.27513 6.35449 3.6875 5.76687 3.6875 5.04199Z" fill="#ED1C2B"/> | ||||
| <path fill-rule="evenodd" clip-rule="evenodd" d="M5 0.229492C2.38798 0.229492 0.1875 2.42783 0.1875 5.09268C0.1875 7.8228 2.43772 9.64709 4.31579 10.8329L4.32334 10.8377L4.33107 10.8422C4.5346 10.9593 4.76514 11.0212 5 11.0212C5.23486 11.0212 5.4654 10.9593 5.66893 10.8422L5.67567 10.8383L5.68227 10.8342C7.56769 9.65737 9.8125 7.81358 9.8125 5.09268C9.8125 2.42783 7.61202 0.229492 5 0.229492ZM1.0625 5.09268C1.0625 2.90553 2.87676 1.10449 5 1.10449C7.12324 1.10449 8.9375 2.90553 8.9375 5.09268C8.9375 7.29808 7.10717 8.91207 5.22662 10.0871C5.15694 10.1259 5.079 10.1462 5 10.1462C4.92132 10.1462 4.84369 10.1261 4.77422 10.0876C2.89372 8.89884 1.0625 7.30546 1.0625 5.09268Z" fill="#ED1C2B"/> | ||||
| <path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 10.7295C1.73936 10.7295 1.93382 10.9217 1.93745 11.1602C1.94159 11.1712 1.96197 11.2114 2.04585 11.2775C2.16816 11.3739 2.37227 11.4798 2.66348 11.5769C3.24132 11.7695 4.06744 11.8962 5 11.8962C5.93256 11.8962 6.75868 11.7695 7.33652 11.5769C7.62773 11.4798 7.83184 11.3739 7.95415 11.2775C8.03803 11.2114 8.05841 11.1712 8.06255 11.1602C8.06618 10.9217 8.26064 10.7295 8.5 10.7295C8.74162 10.7295 8.9375 10.9254 8.9375 11.167C8.9375 11.5196 8.72273 11.7859 8.49575 11.9647C8.26385 12.1475 7.95539 12.2929 7.61322 12.407C6.92432 12.6366 6.00044 12.7712 5 12.7712C3.99956 12.7712 3.07568 12.6366 2.38678 12.407C2.04461 12.2929 1.73615 12.1475 1.50425 11.9647C1.27727 11.7859 1.0625 11.5196 1.0625 11.167C1.0625 10.9254 1.25838 10.7295 1.5 10.7295ZM8.06349 11.1572C8.06349 11.1571 8.06349 11.1572 8.06349 11.1572V11.1572Z" fill="#ED1C2B"/> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 2.1 KiB | 
| @ -0,0 +1,5 @@ | ||||
| <svg width="14" height="13" viewBox="0 0 14 13" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||||
| <path fill-rule="evenodd" clip-rule="evenodd" d="M1.47635 0.357633C1.3055 0.186779 1.02849 0.186779 0.857633 0.357633C0.686779 0.528487 0.686779 0.805497 0.857633 0.976351L2.46119 2.57991C1.74908 3.50857 1.31283 4.60696 1.31283 5.87371C1.31283 7.46181 1.98475 8.7894 2.92684 9.88512C3.86488 10.9761 5.08602 11.856 6.2293 12.5637L6.23681 12.5684L6.24451 12.5727C6.47506 12.7029 6.73552 12.7712 7.00033 12.7712C7.26514 12.7712 7.52559 12.7029 7.75614 12.5727L7.76285 12.5689L7.76943 12.5649C8.63521 12.0351 9.66148 11.3872 10.4965 10.6152L12.5243 12.643C12.6952 12.8139 12.9722 12.8139 13.143 12.643C13.3139 12.4722 13.3139 12.1952 13.143 12.0243L8.48292 7.3642C8.47847 7.35955 8.47393 7.35501 8.46931 7.35059L5.56673 4.44802C5.5623 4.44339 5.55776 4.43884 5.5531 4.43438L1.47635 0.357633ZM4.72223 4.84095L3.08613 3.20485C2.51802 3.9791 2.18783 4.86436 2.18783 5.87371C2.18783 7.19521 2.74204 8.32806 3.59032 9.31467C4.44051 10.3035 5.57042 11.1262 6.68141 11.8145C6.77877 11.868 6.88851 11.8962 7.00033 11.8962C7.11248 11.8962 7.22255 11.8678 7.32013 11.814C8.18224 11.2864 9.12483 10.6862 9.87729 9.99601L8.07636 8.19508C7.73263 8.32898 7.33404 8.39615 7.00033 8.39615C5.63112 8.39615 4.52116 7.28619 4.52116 5.91698C4.52116 5.58326 4.58833 5.18468 4.72223 4.84095ZM7.36809 7.48681L5.4305 5.54922C5.40846 5.67294 5.39616 5.79917 5.39616 5.91698C5.39616 6.80294 6.11437 7.52115 7.00033 7.52115C7.11814 7.52115 7.24437 7.50884 7.36809 7.48681Z" fill="#2E3039"/> | ||||
| <path d="M7.0004 1.10449C6.13419 1.10449 5.31049 1.34359 4.59613 1.76103C4.38751 1.88294 4.11957 1.81265 3.99766 1.60403C3.87575 1.39541 3.94605 1.12747 4.15466 1.00556C4.99638 0.513701 5.97157 0.229492 7.0004 0.229492C10.0778 0.229492 12.6879 2.77256 12.6879 5.87369C12.6879 6.94853 12.3781 7.91037 11.8817 8.76226C11.76 8.97103 11.4922 9.04165 11.2834 8.92C11.0746 8.79834 11.004 8.53049 11.1257 8.32172C11.5556 7.58384 11.8129 6.77241 11.8129 5.87369C11.8129 3.26657 9.60535 1.10449 7.0004 1.10449Z" fill="#2E3039"/> | ||||
| <path d="M7.00038 4.31283C6.92215 4.31283 6.84547 4.31839 6.77066 4.32909C6.53147 4.36331 6.30984 4.19714 6.27562 3.95795C6.24141 3.71876 6.40758 3.49712 6.64677 3.46291C6.76248 3.44636 6.88056 3.43783 7.00038 3.43783C8.36959 3.43783 9.47955 4.54779 9.47955 5.91699C9.47955 6.03681 9.47102 6.15489 9.45446 6.27061C9.42025 6.5098 9.19861 6.67596 8.95942 6.64175C8.72023 6.60754 8.55407 6.3859 8.58828 6.14671C8.59898 6.07191 8.60455 5.99523 8.60455 5.91699C8.60455 5.03103 7.88634 4.31283 7.00038 4.31283Z" fill="#2E3039"/> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 2.5 KiB | 
| @ -0,0 +1,207 @@ | ||||
| import 'dart:math'; | ||||
| 
 | ||||
| import 'package:hmg_patient_app_new/core/cache_consts.dart' show CacheConst; | ||||
| import 'package:hmg_patient_app_new/core/utils/utils.dart' show Utils; | ||||
| import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/doctor_list_api_response.dart' show RegionList, PatientDoctorAppointmentList, DoctorList, PatientDoctorAppointmentListByRegion; | ||||
| import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart' show HospitalsModel; | ||||
| 
 | ||||
| class DoctorMapper{ | ||||
|   static Future<RegionList> getMappedDoctor(List<DoctorList> doctorList, | ||||
|       {bool isArabic = false}) async { | ||||
|     RegionList regionList = RegionList(); | ||||
|     final lat = await Utils.getNumFromPrefs(CacheConst.userLat); | ||||
|     final long = await Utils.getNumFromPrefs(CacheConst.userLat); | ||||
| 
 | ||||
|     for (var element in doctorList) { | ||||
|       String? region = element.getRegionName(isArabic); | ||||
|       if (region == null) continue; | ||||
| 
 | ||||
|       var regionDoctorList = regionList.registeredDoctorMap?.putIfAbsent(region, () => PatientDoctorAppointmentListByRegion()); | ||||
| 
 | ||||
|       List<PatientDoctorAppointmentList>? targetList = element.isHMC == true | ||||
|           ? regionDoctorList?.hmcDoctorList | ||||
|           : regionDoctorList?.hmgDoctorList; | ||||
| 
 | ||||
|       var doctorByHospital = targetList | ||||
|               ?.where((clinic) => | ||||
|                   clinic.filterName == | ||||
|                   element.getProjectCompleteNameWithLocale(isArabic: isArabic)) | ||||
|               .toList() ?? | ||||
|           []; | ||||
| 
 | ||||
|       if (doctorByHospital.isNotEmpty) { | ||||
|         doctorByHospital.first.patientDoctorAppointmentList?.add(element); | ||||
|       } else { | ||||
|         var newAppointment = PatientDoctorAppointmentList( | ||||
|           filterName: | ||||
|               element.getProjectCompleteNameWithLocale(isArabic: isArabic), | ||||
|           distanceInKMs: element.projectDistanceInKiloMeters.toString(), | ||||
|           projectTopName: element.projectTopName, | ||||
|           projectBottomName: element.projectBottomName, | ||||
|           patientDoctorAppointment: element, | ||||
|           isHMC: element.isHMC | ||||
|         ); | ||||
|         if(element.projectDistanceInKiloMeters!= null ){ | ||||
|           if(regionDoctorList!.distance>element.projectDistanceInKiloMeters){ | ||||
|             regionDoctorList.distance = element.projectDistanceInKiloMeters; | ||||
|           } | ||||
|           if (element.isHMC == true && | ||||
|               element.projectDistanceInKiloMeters < | ||||
|                   regionDoctorList.hmcDistance) { | ||||
|             regionDoctorList.hmcDistance = element.projectDistanceInKiloMeters; | ||||
|           } else if (element.projectDistanceInKiloMeters < | ||||
|               regionDoctorList.hmgDistance) { | ||||
|             regionDoctorList.hmgDistance = element.projectDistanceInKiloMeters; | ||||
|           } | ||||
|         }else | ||||
|         if (lat != 0&& | ||||
|             long != 0 && element.latitude != null && element.longitude != null) { | ||||
| 
 | ||||
| 
 | ||||
|           double distance =  calculateDistance(lat.toDouble(), long.toDouble(), double.parse(element.latitude!), double.parse(element.longitude!)); | ||||
|           if(distance<0){ | ||||
|             distance *= -1; | ||||
|           } | ||||
|           if(regionDoctorList!.distance>distance){ | ||||
|             regionDoctorList.distance = distance; | ||||
|           } | ||||
|           if (element.isHMC == true && | ||||
|               element.projectDistanceInKiloMeters < | ||||
|                   regionDoctorList.hmcDistance) { | ||||
|             regionDoctorList.hmcDistance = element.projectDistanceInKiloMeters; | ||||
|           } else if (element.projectDistanceInKiloMeters < | ||||
|               regionDoctorList.hmgDistance) { | ||||
|             regionDoctorList.hmgDistance = element.projectDistanceInKiloMeters; | ||||
|           } | ||||
|         } | ||||
|         targetList?.add(newAppointment); | ||||
|       } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|       regionDoctorList?.hmcSize = regionDoctorList.hmcDoctorList?.length ?? 0; | ||||
|       regionDoctorList?.hmgSize = regionDoctorList.hmgDoctorList?.length ?? 0; | ||||
| 
 | ||||
|       regionList.registeredDoctorMap?[region] = regionDoctorList; | ||||
|     } | ||||
| 
 | ||||
|     return regionList; | ||||
|   } | ||||
|   static double calculateDistance(double lat1, double lon1, double lat2, double lon2) { | ||||
|     var pi = 3.142; | ||||
|     const double R = 6371; | ||||
|     double dLat = (lat2 - lat1) * pi / 180; | ||||
|     double dLon = (lon2 - lon1) * pi / 180; | ||||
|     double a = sin(dLat / 2) * sin(dLat / 2) + | ||||
|         cos(lat1 * pi / 180) * cos(lat2 * pi / 180) * sin(dLon / 2) * sin(dLon / 2); | ||||
|     double c = 2 * atan2(sqrt(a), sqrt(1 - a)); | ||||
|     return R * c; | ||||
|   } | ||||
| 
 | ||||
|   static Future<RegionList> sortList(bool isGPSEnabled, RegionList unsorted, )  async { | ||||
|     if(isGPSEnabled){ | ||||
|       if(unsorted.registeredDoctorMap == null) return unsorted; | ||||
|       var sortedMap = Map.fromEntries( | ||||
|         unsorted.registeredDoctorMap!.entries.toList() | ||||
|           ..sort((a, b) => a.value!.distance.compareTo(b.value!.distance)), | ||||
|       ); | ||||
| 
 | ||||
|       unsorted.registeredDoctorMap = sortedMap; | ||||
|       return unsorted; | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     List<String>? keys = unsorted.registeredDoctorMap?.keys.toList(); | ||||
|     keys?.sort(); | ||||
| 
 | ||||
|     if (keys == null) return unsorted; | ||||
|     Map<String, PatientDoctorAppointmentListByRegion> sortedMap = {}; | ||||
|     for (var key in keys) { | ||||
|       sortedMap[key] = unsorted.registeredDoctorMap![key]!; | ||||
|     } | ||||
|     unsorted.registeredDoctorMap = sortedMap; | ||||
|     return unsorted; | ||||
|   } | ||||
| 
 | ||||
|   static Future<RegionList> getMappedHospitals( | ||||
|     List<HospitalsModel> hospitalList, { | ||||
|     bool isArabic = false, | ||||
|   }) async { | ||||
|     final regionList = RegionList(); | ||||
|     final lat = await Utils.getNumFromPrefs(CacheConst.userLat); | ||||
|     final long = await Utils.getNumFromPrefs(CacheConst.userLat); | ||||
|     for (final hospital in hospitalList) { | ||||
|       final region = hospital.getRegionName(isArabic); | ||||
|       if (region == null) continue; | ||||
| 
 | ||||
|       final regionData = regionList.registeredDoctorMap?.putIfAbsent( | ||||
|         region, | ||||
|         () => PatientDoctorAppointmentListByRegion(), | ||||
|       ); | ||||
| 
 | ||||
|       List<PatientDoctorAppointmentList>? targetList = hospital.isHMC == true | ||||
|           ? regionData?.hmcDoctorList | ||||
|           : regionData?.hmgDoctorList; | ||||
| 
 | ||||
|       List<PatientDoctorAppointmentList> existingEntry = targetList | ||||
|               ?.where( | ||||
|                 (entry) => entry.filterName == hospital.getName(isArabic), | ||||
|               ) | ||||
|               .toList() ?? | ||||
|           []; | ||||
| 
 | ||||
|       if (existingEntry.isNotEmpty) { | ||||
|         existingEntry.first.hospitalList.add(hospital); | ||||
|       } else { | ||||
|         final newEntry = PatientDoctorAppointmentList( | ||||
|             filterName: hospital.name, | ||||
|             distanceInKMs: hospital.distanceInKilometers?.toString(), | ||||
|             projectTopName: hospital.name, | ||||
|             projectBottomName: hospital.name, | ||||
|             model: hospital, | ||||
|         isHMC: hospital.isHMC); | ||||
| 
 | ||||
|         final distance = hospital.distanceInKilometers; | ||||
| 
 | ||||
|         if (distance != null) { | ||||
|           if (regionData!.distance > distance) { | ||||
|             regionData.distance = distance; | ||||
|           } | ||||
|           if (hospital.isHMC == true && distance < regionData.hmcDistance) { | ||||
|             regionData.hmcDistance = distance; | ||||
|           } else if (distance < regionData.hmgDistance) { | ||||
|             regionData.hmgDistance = distance; | ||||
|           } | ||||
|         } else if ( lat != 0&& | ||||
|             long != 0 && | ||||
|             hospital.latitude != null && | ||||
|             hospital.longitude != null) { | ||||
|           double calculatedDistance = calculateDistance( | ||||
|             lat.toDouble(), | ||||
|             long.toDouble(), | ||||
|             double.parse(hospital.latitude!), | ||||
|             double.parse(hospital.longitude!), | ||||
|           ).abs(); | ||||
| 
 | ||||
|           if (regionData!.distance > calculatedDistance) { | ||||
|             regionData.distance = calculatedDistance; | ||||
|           } | ||||
|           if (hospital.isHMC == true && | ||||
|               calculatedDistance < regionData.hmcDistance) { | ||||
|             regionData.hmcDistance = calculatedDistance; | ||||
|           } else if (calculatedDistance < regionData.hmgDistance) { | ||||
|             regionData.hmgDistance = calculatedDistance; | ||||
|           } | ||||
|         } | ||||
|         targetList?.add(newEntry); | ||||
|       } | ||||
| 
 | ||||
|       regionData?.hmcSize = regionData.hmcDoctorList?.length ?? 0; | ||||
|       regionData?.hmgSize = regionData.hmgDoctorList?.length ?? 0; | ||||
|       regionList.registeredDoctorMap?[region] = regionData; | ||||
|     } | ||||
| 
 | ||||
|     return regionList; | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,66 @@ | ||||
| import 'package:flutter/foundation.dart' show ChangeNotifier; | ||||
| 
 | ||||
| enum AppointmentViaRegionState { | ||||
|   REGION_SELECTION, | ||||
|   TYPE_SELECTION, | ||||
|   HOSPITAL_SELECTION, | ||||
|   CLINIC_SELECTION, | ||||
|   DOCTOR_SELECTION | ||||
| } | ||||
| 
 | ||||
| class AppointmentViaRegionViewmodel extends ChangeNotifier { | ||||
|   String? selectedRegionId; | ||||
|   String? selectedFacilityType; | ||||
|   AppointmentViaRegionState bottomSheetState = | ||||
|       AppointmentViaRegionState.REGION_SELECTION; | ||||
| 
 | ||||
|   void setSelectedRegionId(String? regionId) { | ||||
|     selectedRegionId = regionId; | ||||
|     notifyListeners(); | ||||
|   } | ||||
| 
 | ||||
|   void setFacility(String? facility) { | ||||
|     selectedFacilityType = facility; | ||||
|     notifyListeners(); | ||||
|   } | ||||
| 
 | ||||
|   void setBottomSheetState(AppointmentViaRegionState state) { | ||||
|     bottomSheetState = state; | ||||
|     notifyListeners(); | ||||
|   } | ||||
| 
 | ||||
|   void handleBackPress() { | ||||
|     switch (bottomSheetState) { | ||||
|       case AppointmentViaRegionState.REGION_SELECTION: | ||||
|         // Do nothing or exit the bottom sheet | ||||
|         break; | ||||
|       case AppointmentViaRegionState.TYPE_SELECTION: | ||||
|         setBottomSheetState(AppointmentViaRegionState.REGION_SELECTION); | ||||
|         setSelectedRegionId(null); | ||||
|         break; | ||||
|       case AppointmentViaRegionState.HOSPITAL_SELECTION: | ||||
|         setBottomSheetState(AppointmentViaRegionState.TYPE_SELECTION); | ||||
|         break; | ||||
| 
 | ||||
|       // case AppointmentViaRegionState.HOSPITAL_SELECTION: | ||||
|       // case AppointmentViaRegionState.CLINIC_SELECTION: | ||||
|       //   setBottomSheetState(AppointmentViaRegionState.TYPE_SELECTION); | ||||
|       //   setFacility(null); | ||||
|       //   break; | ||||
|       // case AppointmentViaRegionState.DOCTOR_SELECTION: | ||||
|       //   if (selectedFacilityType == 'Hospital') { | ||||
|       //     setBottomSheetState(AppointmentViaRegionState.HOSPITAL_SELECTION); | ||||
|       //   } else if (selectedFacilityType == 'Medical Center') { | ||||
|       //     setBottomSheetState(AppointmentViaRegionState.CLINIC_SELECTION); | ||||
|       //   } | ||||
|       //   break; | ||||
|       default: | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   void flush() { | ||||
|     setSelectedRegionId(null); | ||||
|     setFacility(null); | ||||
|     setBottomSheetState(AppointmentViaRegionState.REGION_SELECTION); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,8 @@ | ||||
| enum FacilitySelection{ | ||||
| ALL('ALL'), | ||||
| HMG('hmg'), | ||||
| HMC('hmc'); | ||||
| 
 | ||||
| final String value; | ||||
| const FacilitySelection(this.value); | ||||
| } | ||||
| @ -0,0 +1,274 @@ | ||||
| 
 | ||||
| import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart' show HospitalsModel; | ||||
| 
 | ||||
| class DoctorList { | ||||
|   int? clinicID; | ||||
|   dynamic appointmentNo; | ||||
|   String? clinicName; | ||||
|   String? doctorTitle; | ||||
|   num? iD; | ||||
|   String? name; | ||||
|   int? projectID; | ||||
|   String? projectName; | ||||
|   int? actualDoctorRate; | ||||
|   num? clinicRoomNo; | ||||
|   dynamic date; | ||||
|   dynamic appointmentDate; | ||||
|   dynamic dayName; | ||||
|   int? doctorID; | ||||
|   String? doctorImageURL; | ||||
|   dynamic doctorProfile; | ||||
|   dynamic doctorProfileInfo; | ||||
|   int? doctorRate; | ||||
|   num? gender; | ||||
|   String? genderDescription; | ||||
|   bool? isAppointmentAllowed; | ||||
|   bool? isDoctorAllowVedioCall; | ||||
|   bool? isDoctorDummy; | ||||
|   bool? isLiveCare; | ||||
|   bool? isLiveCareClinic; | ||||
|   bool? isDoctorHasPrePostImages; | ||||
|   String? latitude; | ||||
|   String? longitude; | ||||
|   String? nationalityFlagURL; | ||||
|   String? nationalityID; | ||||
|   String? nationalityName; | ||||
|   dynamic nearestFreeSlot; | ||||
|   int? noOfPatientsRate; | ||||
|   num? originalClinicID; | ||||
|   num? personRate; | ||||
|   dynamic projectDistanceInKiloMeters; | ||||
|   String? qR; | ||||
|   dynamic qRString; | ||||
|   num? rateNumber; | ||||
|   dynamic serviceID; | ||||
|   String? setupID; | ||||
|   List<String>? speciality; | ||||
|   List<String>? specialityN; | ||||
|   dynamic workingHours; | ||||
|   dynamic decimalDoctorRate; | ||||
|   String? projectBottomName; | ||||
|   String? projectTopName; | ||||
|   bool? isHMC; | ||||
|   String? region; | ||||
|   String? regionArabic; | ||||
|   String? regionEnglish; | ||||
|   String? regionID; | ||||
| 
 | ||||
|   DoctorList( | ||||
|       {this.clinicID, | ||||
|       this.appointmentNo, | ||||
|       this.clinicName, | ||||
|       this.doctorTitle, | ||||
|       this.iD, | ||||
|       this.name, | ||||
|       this.projectID, | ||||
|       this.projectName, | ||||
|       this.actualDoctorRate, | ||||
|       this.clinicRoomNo, | ||||
|       this.date, | ||||
|       this.appointmentDate, | ||||
|       this.dayName, | ||||
|       this.doctorID, | ||||
|       this.doctorImageURL, | ||||
|       this.doctorProfile, | ||||
|       this.doctorProfileInfo, | ||||
|       this.doctorRate, | ||||
|       this.gender, | ||||
|       this.genderDescription, | ||||
|       this.isAppointmentAllowed, | ||||
|       this.isDoctorAllowVedioCall, | ||||
|       this.isDoctorDummy, | ||||
|       this.isLiveCare, | ||||
|       this.isLiveCareClinic, | ||||
|       this.isDoctorHasPrePostImages, | ||||
|       this.latitude, | ||||
|       this.longitude, | ||||
|       this.nationalityFlagURL, | ||||
|       this.nationalityID, | ||||
|       this.nationalityName, | ||||
|       this.nearestFreeSlot, | ||||
|       this.noOfPatientsRate, | ||||
|       this.originalClinicID, | ||||
|       this.personRate, | ||||
|       this.projectDistanceInKiloMeters, | ||||
|       this.qR, | ||||
|       this.qRString, | ||||
|       this.rateNumber, | ||||
|       this.serviceID, | ||||
|       this.setupID, | ||||
|       this.speciality, | ||||
|       this.specialityN, | ||||
|       this.workingHours, | ||||
|       this.decimalDoctorRate, | ||||
|       this.projectBottomName, | ||||
|       this.projectTopName, | ||||
|       this.isHMC, | ||||
|       this.region, | ||||
|     this.regionArabic, | ||||
|     this.regionEnglish, | ||||
|     this.regionID, | ||||
|       }); | ||||
| 
 | ||||
|   DoctorList.fromJson( | ||||
|     Map<String, dynamic> json, | ||||
|   ) { | ||||
|     clinicID = json['ClinicID']; | ||||
|     appointmentNo = json['AppointmentNo']; | ||||
|     clinicName = json['ClinicName']; | ||||
|     doctorTitle = json['DoctorTitle']; | ||||
|     iD = json['ID']; | ||||
|     name = json['DoctorName'] ?? json['Name']; | ||||
|     projectID = json['ProjectID']; | ||||
|     projectName = json['ProjectName']; | ||||
|     actualDoctorRate = json['ActualDoctorRate']; | ||||
|     clinicRoomNo = json['ClinicRoomNo']; | ||||
|     date = json['Date']; | ||||
|     appointmentDate = json['AppointmentDate']; | ||||
|     dayName = json['DayName']; | ||||
|     doctorID = json['DoctorID']; | ||||
|     doctorImageURL = json['DoctorImageURL']; | ||||
|     doctorProfile = json['DoctorProfile']; | ||||
|     doctorProfileInfo = json['DoctorProfileInfo']; | ||||
|     doctorRate = json['DoctorRate']; | ||||
|     gender = json['Gender']; | ||||
|     genderDescription = json['GenderDescription']; | ||||
|     isAppointmentAllowed = json['IsAppointmentAllowed']; | ||||
|     isDoctorAllowVedioCall = json['IsDoctorAllowVedioCall']; | ||||
|     isDoctorDummy = json['IsDoctorDummy']; | ||||
|     isLiveCare = json['IsLiveCare']; | ||||
|     isLiveCareClinic = json['IsLiveCareClinic']; | ||||
|     isDoctorHasPrePostImages = json['IsDoctorHasPrePostImages']; | ||||
|     latitude = json['Latitude']; | ||||
|     longitude = json['Longitude']; | ||||
|     nationalityFlagURL = json['NationalityFlagURL']; | ||||
|     nationalityID = json['NationalityID']; | ||||
|     nationalityName = json['NationalityName']; | ||||
|     nearestFreeSlot = json['NearestFreeSlot']; | ||||
|     noOfPatientsRate = json['NoOfPatientsRate']; | ||||
|     originalClinicID = json['OriginalClinicID']; | ||||
|     personRate = json['PersonRate']; | ||||
|     projectDistanceInKiloMeters = json['ProjectDistanceInKiloMeters']; | ||||
|     qR = json['QR']; | ||||
|     qRString = json['QRString']; | ||||
|     rateNumber = json['RateNumber']; | ||||
|     serviceID = json['ServiceID']; | ||||
|     setupID = json['SetupID']; | ||||
|     if (json.containsKey('Speciality') && json['Speciality'] != null) speciality = json['Speciality'].cast<String>(); | ||||
|     if (json.containsKey('SpecialityN') && json['SpecialityN'] != null) specialityN = json['SpecialityN'].cast<String>(); | ||||
|     workingHours = json['WorkingHours']; | ||||
|     decimalDoctorRate = json['DecimalDoctorRate']; | ||||
|     projectBottomName = json['ProjectNameBottom']; | ||||
|     projectTopName = json['ProjectNameTop']; | ||||
|     this.isHMC = json["IsHMC"]; | ||||
|     this.regionArabic = json['RegionNameN']; | ||||
|     this.regionEnglish = json['RegionName']; | ||||
|   } | ||||
| 
 | ||||
|   String? getRegionName(bool isArabic) { | ||||
|     if (isArabic) { | ||||
|       return regionArabic; | ||||
|     } | ||||
|     return regionEnglish; | ||||
|   } | ||||
| 
 | ||||
|   Map<String, dynamic> toJson() { | ||||
|     final Map<String, dynamic> data = new Map<String, dynamic>(); | ||||
|     data['ClinicID'] = this.clinicID; | ||||
|     data['AppointmentNo'] = this.appointmentNo; | ||||
|     data['ClinicName'] = this.clinicName; | ||||
|     data['DoctorTitle'] = this.doctorTitle; | ||||
|     data['ID'] = this.iD; | ||||
|     data['Name'] = this.name; | ||||
|     data['ProjectID'] = this.projectID; | ||||
|     data['ProjectName'] = this.projectName; | ||||
|     data['ActualDoctorRate'] = this.actualDoctorRate; | ||||
|     data['ClinicRoomNo'] = this.clinicRoomNo; | ||||
|     data['Date'] = this.date; | ||||
|     data['DayName'] = this.dayName; | ||||
|     data['DoctorID'] = this.doctorID; | ||||
|     data['DoctorImageURL'] = this.doctorImageURL; | ||||
|     data['DoctorProfile'] = this.doctorProfile; | ||||
|     data['DoctorProfileInfo'] = this.doctorProfileInfo; | ||||
|     data['DoctorRate'] = this.doctorRate; | ||||
|     data['Gender'] = this.gender; | ||||
|     data['GenderDescription'] = this.genderDescription; | ||||
|     data['IsAppointmentAllowed'] = this.isAppointmentAllowed; | ||||
|     data['IsDoctorAllowVedioCall'] = this.isDoctorAllowVedioCall; | ||||
|     data['IsDoctorDummy'] = this.isDoctorDummy; | ||||
|     data['IsLiveCare'] = this.isLiveCare; | ||||
|     data['IsLiveCareClinic'] = this.isLiveCareClinic; | ||||
|     data['IsDoctorHasPrePostImages'] = this.isDoctorHasPrePostImages; | ||||
|     data['Latitude'] = this.latitude; | ||||
|     data['Longitude'] = this.longitude; | ||||
|     data['NationalityFlagURL'] = this.nationalityFlagURL; | ||||
|     data['NationalityID'] = this.nationalityID; | ||||
|     data['NationalityName'] = this.nationalityName; | ||||
|     data['NearestFreeSlot'] = this.nearestFreeSlot; | ||||
|     data['NoOfPatientsRate'] = this.noOfPatientsRate; | ||||
|     data['OriginalClinicID'] = this.originalClinicID; | ||||
|     data['PersonRate'] = this.personRate; | ||||
|     data['ProjectDistanceInKiloMeters'] = this.projectDistanceInKiloMeters; | ||||
|     data['QR'] = this.qR; | ||||
|     data['QRString'] = this.qRString; | ||||
|     data['RateNumber'] = this.rateNumber; | ||||
|     data['ServiceID'] = this.serviceID; | ||||
|     data['SetupID'] = this.setupID; | ||||
|     data['Speciality'] = this.speciality; | ||||
|     data['SpecialityN'] = this.specialityN; | ||||
|     data['WorkingHours'] = this.workingHours; | ||||
|     data['DecimalDoctorRate'] = this.decimalDoctorRate; | ||||
|     return data; | ||||
|   } | ||||
| 
 | ||||
|   String getProjectCompleteName(){ | ||||
|     return "${this.projectTopName} ${this.projectBottomName}"; | ||||
|   } | ||||
| 
 | ||||
|   String getProjectCompleteNameWithLocale({bool isArabic = false}) { | ||||
|     if (isArabic) { | ||||
|       return "${this.projectBottomName} ${this.projectTopName}"; | ||||
|     } | ||||
|     return "${this.projectTopName} ${this.projectBottomName}"; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class PatientDoctorAppointmentList { | ||||
|   String? filterName = ""; | ||||
|   String? distanceInKMs = ""; | ||||
|   List<DoctorList>? patientDoctorAppointmentList = []; | ||||
|   String? projectTopName = ""; | ||||
|   String? projectBottomName = ""; | ||||
|   bool? isHMC; | ||||
|   List<HospitalsModel> hospitalList = []; | ||||
| 
 | ||||
|   PatientDoctorAppointmentList( | ||||
|       {this.filterName, | ||||
|       this.distanceInKMs, | ||||
|       this.projectTopName, | ||||
|       this.projectBottomName, | ||||
|       DoctorList? patientDoctorAppointment, | ||||
|       HospitalsModel? model, | ||||
|       this.isHMC = false}) { | ||||
|     if (model != null) { | ||||
|       hospitalList.add(model); | ||||
|     } | ||||
|     if (patientDoctorAppointment != null) { | ||||
|       patientDoctorAppointmentList!.add(patientDoctorAppointment!); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class PatientDoctorAppointmentListByRegion { | ||||
|   List<PatientDoctorAppointmentList>? hmgDoctorList = []; | ||||
|   List<PatientDoctorAppointmentList>? hmcDoctorList = []; | ||||
|   int hmcSize = 0; | ||||
|   int hmgSize = 0; | ||||
|   num distance = double.infinity; | ||||
|   num hmgDistance = double.infinity; | ||||
|   num hmcDistance = double.infinity; | ||||
| } | ||||
| 
 | ||||
| class RegionList { | ||||
|   Map<String, PatientDoctorAppointmentListByRegion?>? registeredDoctorMap = {}; | ||||
| } | ||||
| @ -0,0 +1,104 @@ | ||||
| class HospitalsModel { | ||||
|   String? desciption; | ||||
|   dynamic desciptionN; | ||||
|   dynamic iD; | ||||
|   String? legalName; | ||||
|   String? legalNameN; | ||||
|   String? name; | ||||
|   dynamic nameN; | ||||
|   String? phoneNumber; | ||||
|   String? setupID; | ||||
|   dynamic distanceInKilometers; | ||||
|   bool? isActive; | ||||
|   String? latitude; | ||||
|   String? longitude; | ||||
|   dynamic mainProjectID; | ||||
|   bool? projectOutSA; | ||||
|   bool? usingInDoctorApp; | ||||
|   bool? isHMC; | ||||
|   String? region; | ||||
|   String? regionArabic; | ||||
|   String? regionEnglish; | ||||
|   String? regionID; | ||||
| 
 | ||||
|   HospitalsModel({ | ||||
|     this.desciption, | ||||
|     this.desciptionN, | ||||
|     this.iD, | ||||
|     this.legalName, | ||||
|     this.legalNameN, | ||||
|     this.name, | ||||
|     this.nameN, | ||||
|     this.phoneNumber, | ||||
|     this.setupID, | ||||
|     this.distanceInKilometers, | ||||
|     this.isActive, | ||||
|     this.latitude, | ||||
|     this.longitude, | ||||
|     this.mainProjectID, | ||||
|     this.projectOutSA, | ||||
|     this.usingInDoctorApp, | ||||
|     this.isHMC, | ||||
|     this.region, | ||||
|     this.regionArabic, | ||||
|     this.regionEnglish, | ||||
|     this.regionID, | ||||
|   }); | ||||
| 
 | ||||
|   HospitalsModel.fromJson(Map<String, dynamic> json) { | ||||
|     desciption = json['Desciption']; | ||||
|     desciptionN = json['DesciptionN']; | ||||
|     iD = json['ID']; | ||||
|     legalName = json['LegalName']; | ||||
|     legalNameN = json['LegalNameN']; | ||||
|     name = json['Name']; | ||||
|     nameN = json['NameN']; | ||||
|     phoneNumber = json['PhoneNumber']; | ||||
|     setupID = json['SetupID']; | ||||
|     distanceInKilometers = json['DistanceInKilometers']; | ||||
|     isActive = json['IsActive']; | ||||
|     latitude = json['Latitude']; | ||||
|     longitude = json['Longitude']; | ||||
|     mainProjectID = json['MainProjectID']; | ||||
|     projectOutSA = json['ProjectOutSA']; | ||||
|     usingInDoctorApp = json['UsingInDoctorApp']; | ||||
|     this.isHMC = json["IsHMC"]; | ||||
|     this.regionArabic = json['RegionNameN']; | ||||
|     this.regionEnglish = json['RegionName']; | ||||
|   } | ||||
| 
 | ||||
|   String? getRegionName(bool isArabic) { | ||||
|     if (isArabic) { | ||||
|       return regionArabic; | ||||
|     } | ||||
|     return regionEnglish; | ||||
|   } | ||||
| 
 | ||||
|   String? getName(bool isArabic) { | ||||
|     if (isArabic) { | ||||
|       return "$nameN"; | ||||
|     } | ||||
|     return name; | ||||
|   } | ||||
| 
 | ||||
|   Map<String, dynamic> toJson() { | ||||
|     final Map<String, dynamic> data = new Map<String, dynamic>(); | ||||
|     data['Desciption'] = this.desciption; | ||||
|     data['DesciptionN'] = this.desciptionN; | ||||
|     data['ID'] = this.iD; | ||||
|     data['LegalName'] = this.legalName; | ||||
|     data['LegalNameN'] = this.legalNameN; | ||||
|     data['Name'] = this.name; | ||||
|     data['NameN'] = this.nameN; | ||||
|     data['PhoneNumber'] = this.phoneNumber; | ||||
|     data['SetupID'] = this.setupID; | ||||
|     data['DistanceInKilometers'] = this.distanceInKilometers; | ||||
|     data['IsActive'] = this.isActive; | ||||
|     data['Latitude'] = this.latitude; | ||||
|     data['Longitude'] = this.longitude; | ||||
|     data['MainProjectID'] = this.mainProjectID; | ||||
|     data['ProjectOutSA'] = this.projectOutSA; | ||||
|     data['UsingInDoctorApp'] = this.usingInDoctorApp; | ||||
|     return data; | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,88 @@ | ||||
| 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; | ||||
| import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; | ||||
| import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; | ||||
| 
 | ||||
| class FacilitySelectionItem extends StatelessWidget { | ||||
|   final String svgPath; | ||||
|   final String title; | ||||
|   final String subTitle; | ||||
| 
 | ||||
|   const FacilitySelectionItem( | ||||
|       {super.key, | ||||
|       required this.svgPath, | ||||
|       required this.subTitle, | ||||
|       required this.title}); | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return Container( | ||||
|       decoration: RoundedRectangleBorder().toSmoothCornerDecoration( | ||||
|         color: AppColors.whiteColor, | ||||
|         borderRadius: 20.h, | ||||
|         hasShadow: false, | ||||
|       ), | ||||
|       child: Column( | ||||
|         mainAxisAlignment: MainAxisAlignment.start, | ||||
|         crossAxisAlignment: CrossAxisAlignment.start, | ||||
|         children: [ | ||||
|       Utils.buildSvgWithAssets( | ||||
|       icon:  svgPath, | ||||
|         width: 32, | ||||
|         height: 32, | ||||
|         fit: BoxFit.contain, | ||||
|       ), | ||||
|           SizedBox(height: 16,), | ||||
|           Row( | ||||
|             mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||
|             children: [ | ||||
|               info, | ||||
|               Utils.buildSvgWithAssets( | ||||
|                 icon: AppAssets.forward_arrow_icon, | ||||
|                 iconColor: AppColors.blackColor, | ||||
|                 width: 18, | ||||
|                 height: 13, | ||||
|                 fit: BoxFit.contain, | ||||
|               ), | ||||
|             ], | ||||
|           ) | ||||
|         ], | ||||
|       ).paddingAll(16.h), | ||||
|     ); | ||||
|   } | ||||
|    | ||||
| 
 | ||||
|  Widget get info => Column( | ||||
|         mainAxisAlignment: MainAxisAlignment.start, | ||||
|         crossAxisAlignment: CrossAxisAlignment.start, | ||||
|         children: [ | ||||
|           Align( | ||||
|             alignment: Alignment.centerLeft, | ||||
|             child: Text( | ||||
|               title, | ||||
|               style: TextStyle( | ||||
|                 fontSize: 16.h, | ||||
|                 fontWeight: FontWeight.w600, | ||||
|                 color: AppColors.blackColor, | ||||
|               ), | ||||
|             ), | ||||
|           ), | ||||
|           Align( | ||||
|             alignment: Alignment.centerLeft, | ||||
|             child: Text( | ||||
|               subTitle, | ||||
|               style: TextStyle( | ||||
|                 fontSize: 12.h, | ||||
|                 fontWeight: FontWeight.w500, | ||||
|                 color: AppColors.greyTextColor, | ||||
|               ), | ||||
|             ), | ||||
|           ), | ||||
|         ], | ||||
|       ); | ||||
| } | ||||
| @ -0,0 +1,79 @@ | ||||
| import 'package:easy_localization/easy_localization.dart' | ||||
|     show tr, StringTranslateExtension; | ||||
| import 'package:flutter/cupertino.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/string_extensions.dart'; | ||||
| import 'package:hmg_patient_app_new/extensions/widget_extensions.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' | ||||
|     show MyAppointmentsViewModel; | ||||
| import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; | ||||
| import 'package:hmg_patient_app_new/presentation/appointments/widgets/faculity_selection/facility_selection_item.dart'; | ||||
| import 'package:hmg_patient_app_new/theme/colors.dart'; | ||||
| import 'package:provider/provider.dart' show Provider; | ||||
| 
 | ||||
| class FacilityTypeSelectionWidget extends StatelessWidget { | ||||
|   late MyAppointmentsViewModel myAppointmentsViewModel; | ||||
|   late AppointmentViaRegionViewmodel regionalViewModel; | ||||
|   final String selectedRegion; | ||||
| 
 | ||||
|   FacilityTypeSelectionWidget({super.key, required this.selectedRegion}); | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     myAppointmentsViewModel = Provider.of<MyAppointmentsViewModel>(context); | ||||
|     regionalViewModel = Provider.of<AppointmentViaRegionViewmodel>(context); | ||||
|     return Column( | ||||
|       crossAxisAlignment: CrossAxisAlignment.start, | ||||
|       children: [ | ||||
|         Text( | ||||
|           LocaleKeys.selectFacility.tr(), | ||||
|           style: TextStyle( | ||||
|             fontSize: 21, | ||||
|             fontWeight: FontWeight.w600, | ||||
|             color: AppColors.blackColor, | ||||
|           ), | ||||
|         ), | ||||
|         Text( | ||||
|           LocaleKeys.selectFacilitiesSubTitle, | ||||
|           style: TextStyle( | ||||
|             fontSize: 16, | ||||
|             fontWeight: FontWeight.w500, | ||||
|             color: AppColors.greyTextColor, | ||||
|           ), | ||||
|         ), | ||||
|         SizedBox(height: 24.h), | ||||
|         FacilitySelectionItem( | ||||
|           svgPath: AppAssets.hmg, | ||||
|           title: "HMG".needTranslation, | ||||
|           subTitle: LocaleKeys.hospitalsWithCount.tr(namedArgs: { | ||||
|             'count': | ||||
|                 "${myAppointmentsViewModel.hospitalList?.registeredDoctorMap?[selectedRegion]?.hmgSize ?? 0}" | ||||
|           }), | ||||
|         ).onPress( | ||||
|           () { | ||||
|             regionalViewModel.setFacility(FacilitySelection.HMG.name); | ||||
|             regionalViewModel.setBottomSheetState( | ||||
|                 AppointmentViaRegionState.HOSPITAL_SELECTION); | ||||
|           }, | ||||
|         ), | ||||
|         SizedBox(height: 16.h), | ||||
|         FacilitySelectionItem( | ||||
|             svgPath: AppAssets.hmc, | ||||
|             title: "HMC".needTranslation, | ||||
|             subTitle: LocaleKeys.medicalCentersWithCount.tr(namedArgs: { | ||||
|               'count': | ||||
|                   "${myAppointmentsViewModel.hospitalList?.registeredDoctorMap?[selectedRegion]?.hmcSize ?? 0}" | ||||
|             })).onPress( | ||||
|           () { | ||||
|             regionalViewModel.setFacility(FacilitySelection.HMC.name); | ||||
|             regionalViewModel.setBottomSheetState( | ||||
|                 AppointmentViaRegionState.HOSPITAL_SELECTION); | ||||
|           }, | ||||
|         ), | ||||
|       ], | ||||
|     ); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,109 @@ | ||||
| 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/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/lab/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 HospitalBottomSheetBody extends StatelessWidget { | ||||
|   late MyAppointmentsViewModel appointmentsViewModel; | ||||
|   late AppointmentViaRegionViewmodel regionalViewModel; | ||||
|   final TextEditingController searchText = TextEditingController(); | ||||
| 
 | ||||
|   HospitalBottomSheetBody({super.key}); | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     appointmentsViewModel = Provider.of<MyAppointmentsViewModel>(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, | ||||
|           ), | ||||
|         ), | ||||
|         Text( | ||||
|           LocaleKeys.selectHospitalSubTitle.tr(), | ||||
|           style: TextStyle( | ||||
|             fontSize: 16, | ||||
|             fontWeight: FontWeight.w500, | ||||
|             color: AppColors.greyTextColor, | ||||
|           ), | ||||
|         ), | ||||
|         SizedBox(height: 16.h), | ||||
|         TextInputWidget( | ||||
|           labelText: LocaleKeys.search.tr(), | ||||
|           hintText: "Search Hospital".tr(), | ||||
|           controller: searchText, | ||||
|           onChange: (value) { | ||||
|             appointmentsViewModel.filterHospitalListByString(value, regionalViewModel.selectedRegionId , regionalViewModel.selectedFacilityType == | ||||
|                 FacilitySelection.HMG.name); | ||||
|           }, | ||||
|           isEnable: true, | ||||
|           prefix: null, | ||||
|           autoFocus: false, | ||||
|           isBorderAllowed: false, | ||||
|           keyboardType: TextInputType.text, | ||||
|           isAllowLeadingIcon: true, | ||||
|           selectionType: SelectionTypeEnum.search, | ||||
|           padding: EdgeInsets.symmetric( | ||||
|             vertical: ResponsiveExtension(10).h, | ||||
|             horizontal: ResponsiveExtension(15).h, | ||||
|           ), | ||||
|         ), | ||||
|         SizedBox(height: 24.h), | ||||
|         // TypeSelectionWidget( | ||||
|         //   hmcCount: "0", | ||||
|         //   hmgCount: "0", | ||||
|         // ), | ||||
|         // SizedBox(height: 21.h), | ||||
|         SizedBox( | ||||
|           height: MediaQuery.sizeOf(context).height * .4, | ||||
|           child: ListView.separated( | ||||
|               itemBuilder: (_, index) => HospitalListItem( | ||||
|                     hospitalData: regionalViewModel.selectedFacilityType == | ||||
|                             FacilitySelection.HMG.name | ||||
|                         ? appointmentsViewModel | ||||
|                             .filteredHospitalList! | ||||
|                             .registeredDoctorMap![ | ||||
|                                 regionalViewModel.selectedRegionId!]! | ||||
|                             .hmgDoctorList![index] | ||||
|                         : appointmentsViewModel | ||||
|                             .filteredHospitalList | ||||
|                             ?.registeredDoctorMap?[ | ||||
|                                 regionalViewModel.selectedRegionId!] | ||||
|                             ?.hmcDoctorList?[index], | ||||
|                     isLocationEnabled:  appointmentsViewModel.getLocationStatus(), | ||||
|                   ), | ||||
|               separatorBuilder: (_, __) => SizedBox( | ||||
|                     height: 16.h, | ||||
|                   ), | ||||
|               itemCount: (regionalViewModel.selectedFacilityType == | ||||
|                               FacilitySelection.HMG.name | ||||
|                           ? (appointmentsViewModel.filteredHospitalList?.registeredDoctorMap?[ | ||||
|                                   regionalViewModel.selectedRegionId]?.hmgDoctorList) | ||||
|                           : (appointmentsViewModel | ||||
|                               .filteredHospitalList | ||||
|                               ?.registeredDoctorMap?[ | ||||
|                                   regionalViewModel.selectedRegionId]?.hmcDoctorList))?.length ?? | ||||
|                   0), | ||||
|         ) | ||||
|       ], | ||||
|     ); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,113 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:hmg_patient_app_new/core/app_assets.dart'; | ||||
| import 'package:hmg_patient_app_new/core/app_export.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/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/my_appointments/models/resp_models/doctor_list_api_response.dart'; | ||||
| import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart'; | ||||
| import 'package:hmg_patient_app_new/theme/colors.dart'; | ||||
| import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; | ||||
| 
 | ||||
| class HospitalListItem extends StatelessWidget { | ||||
|   final PatientDoctorAppointmentList? hospitalData; | ||||
|   final bool isLocationEnabled; | ||||
| 
 | ||||
|   late AppState appState; | ||||
| 
 | ||||
|   HospitalListItem( | ||||
|       {super.key, required this.hospitalData, required this.isLocationEnabled}); | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     appState = getIt.get<AppState>(); | ||||
|     return DecoratedBox( | ||||
|       decoration: RoundedRectangleBorder().toSmoothCornerDecoration( | ||||
|         color: AppColors.whiteColor, | ||||
|         borderRadius: 20.h, | ||||
|         hasShadow: false, | ||||
|       ), | ||||
|       child: Row( | ||||
|         mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||
|         children: [ | ||||
|           Expanded( | ||||
|             child: Column( | ||||
|               crossAxisAlignment: CrossAxisAlignment.start, | ||||
|               spacing: 8.h, | ||||
|               children: [hospitalName, distanceInfo], | ||||
|             ), | ||||
|           ), | ||||
|           Utils.buildSvgWithAssets( | ||||
|             icon: AppAssets.forward_arrow_icon, | ||||
|             iconColor: AppColors.blackColor, | ||||
|             width: 18, | ||||
|             height: 13, | ||||
|             fit: BoxFit.contain, | ||||
|           ), | ||||
|         ], | ||||
|       ).paddingSymmetrical(16.h, 16.h), | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   Widget get hospitalName => Row( | ||||
|         children: [ | ||||
|           Utils.buildSvgWithAssets( | ||||
|             icon: (hospitalData?.isHMC == true) ? AppAssets.hmc : AppAssets.hmg, | ||||
|           ).paddingOnly(right: 10), | ||||
|           Expanded( | ||||
|             child: Text( | ||||
|               hospitalData?.filterName ?? "", | ||||
|               style: TextStyle( | ||||
|                 fontWeight: FontWeight.w600, | ||||
|                 fontSize: 16, | ||||
|                 color: AppColors.blackColor, | ||||
|               ), | ||||
|             ), | ||||
|           ) | ||||
|         ], | ||||
|       ); | ||||
| 
 | ||||
|   Widget get distanceInfo => Row( | ||||
| 
 | ||||
|         children: [ | ||||
|           Visibility( | ||||
|               visible: (hospitalData?.distanceInKMs != "0"), | ||||
|               child: | ||||
| 
 | ||||
| 
 | ||||
|                 AppCustomChipWidget( | ||||
|                     labelText: | ||||
|                         "${hospitalData?.distanceInKMs ?? ""} km".needTranslation, | ||||
|                     deleteIcon: AppAssets.location_red, | ||||
|                     deleteIconSize: Size(9, 12), | ||||
|                     backgroundColor: AppColors.secondaryLightRedColor, | ||||
|                     textColor: AppColors.errorColor, | ||||
|                   ), | ||||
| 
 | ||||
| 
 | ||||
|   ), | ||||
|           Visibility( | ||||
|               visible: (hospitalData?.distanceInKMs == "0"), | ||||
|               child: Row( | ||||
|                 children: [ | ||||
|                   AppCustomChipWidget( | ||||
|                     labelText: "Distance not available".needTranslation, | ||||
|                     textColor: AppColors.blackColor, | ||||
|                   ), | ||||
|                   SizedBox(width: 8.h,) | ||||
| 
 | ||||
|                 ], | ||||
|               )), | ||||
|           Visibility( | ||||
|               visible: !isLocationEnabled, | ||||
|               child: AppCustomChipWidget( | ||||
|                 labelText: "Location turned off".needTranslation, | ||||
|                 deleteIcon: AppAssets.location_unavailable, | ||||
|                 deleteIconSize: Size(9, 12), | ||||
|                 textColor: AppColors.blackColor, | ||||
|               )), | ||||
|         ], | ||||
|       ); | ||||
| } | ||||
| @ -0,0 +1,93 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:hmg_patient_app_new/core/app_assets.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/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/theme/colors.dart'; | ||||
| import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; | ||||
| import 'package:provider/provider.dart' show Consumer; | ||||
| 
 | ||||
| class TypeSelectionWidget extends StatelessWidget { | ||||
|   final String hmcCount; | ||||
|   final String hmgCount; | ||||
| 
 | ||||
|   const TypeSelectionWidget( | ||||
|       {super.key, required this.hmcCount, required this.hmgCount}); | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return Consumer<MyAppointmentsViewModel>( | ||||
|       builder: (_, data, __) => Row( | ||||
|         spacing: 8, | ||||
|         mainAxisSize: MainAxisSize.max, | ||||
|         children: [ | ||||
|           AppCustomChipWidget( | ||||
|             labelText: "All Facilities".needTranslation, | ||||
|             shape: RoundedRectangleBorder( | ||||
|                 side: BorderSide( | ||||
|                   color: data.currentlySelectedFacility == FacilitySelection.ALL | ||||
|                       ? AppColors.errorColor | ||||
|                       : AppColors.chipBorderColorOpacity20, | ||||
|                   width: 1, | ||||
|                 ), | ||||
|                 borderRadius: BorderRadius.circular(10)), | ||||
|             backgroundColor: | ||||
|                 data.currentlySelectedFacility == FacilitySelection.ALL | ||||
|                     ? AppColors.secondaryLightRedColor | ||||
|                     : AppColors.whiteColor, | ||||
|             textColor: data.currentlySelectedFacility == FacilitySelection.ALL | ||||
|                 ? AppColors.errorColor | ||||
|                 : AppColors.blackColor, | ||||
|           ).onPress((){ | ||||
|             data.setSelectedFacility(FacilitySelection.ALL); | ||||
|           }), | ||||
|           AppCustomChipWidget( | ||||
|             icon: AppAssets.hmg, | ||||
|             iconHasColor: false, | ||||
|             labelText: "Hospitals".needTranslation, | ||||
|             shape: RoundedRectangleBorder( | ||||
|                 side: BorderSide( | ||||
|                   color: data.currentlySelectedFacility == FacilitySelection.HMG | ||||
|                       ? AppColors.errorColor | ||||
|                       : AppColors.chipBorderColorOpacity20, | ||||
|                   width: 1, | ||||
|                 ), | ||||
|                 borderRadius: BorderRadius.circular(10)), | ||||
|             backgroundColor: | ||||
|                 data.currentlySelectedFacility == FacilitySelection.HMG | ||||
|                     ? AppColors.secondaryLightRedColor | ||||
|                     : AppColors.whiteColor, | ||||
|             textColor: data.currentlySelectedFacility == FacilitySelection.HMG | ||||
|                 ? AppColors.errorColor | ||||
|                 : AppColors.blackColor, | ||||
|           ).onPress((){ | ||||
|             data.setSelectedFacility(FacilitySelection.HMG); | ||||
|           }), | ||||
|           AppCustomChipWidget( | ||||
|             icon: AppAssets.hmc, | ||||
|             iconHasColor: false, | ||||
|             labelText: "Medical Centers".needTranslation, | ||||
|             shape: RoundedRectangleBorder( | ||||
|                 side: BorderSide( | ||||
|                   color: data.currentlySelectedFacility == FacilitySelection.HMC | ||||
|                       ? AppColors.errorColor | ||||
|                       : AppColors.chipBorderColorOpacity20, | ||||
|                   width: 1, | ||||
|                 ), | ||||
|                 borderRadius: BorderRadius.circular(10)), | ||||
|             backgroundColor: | ||||
|             data.currentlySelectedFacility == FacilitySelection.HMC | ||||
|                 ? AppColors.secondaryLightRedColor | ||||
|                 : AppColors.whiteColor, | ||||
|             textColor: data.currentlySelectedFacility == FacilitySelection.HMC | ||||
|                 ? AppColors.errorColor | ||||
|                 : AppColors.blackColor, | ||||
|           ).onPress((){ | ||||
|             data.setSelectedFacility(FacilitySelection.HMC); | ||||
|           }), | ||||
|         ], | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,114 @@ | ||||
| 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/generated/locale_keys.g.dart'; | ||||
| import 'package:hmg_patient_app_new/theme/colors.dart' show AppColors; | ||||
| import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; | ||||
| 
 | ||||
| class RegionListItem extends StatelessWidget { | ||||
|   final String title; | ||||
|   final String hmcCount; | ||||
|   final String hmgCount; | ||||
|   final String subTitle; | ||||
| 
 | ||||
|   const RegionListItem( | ||||
|       {super.key, | ||||
|       required this.title, | ||||
|       required this.subTitle, | ||||
|       required this.hmcCount, | ||||
|       required this.hmgCount}); | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return Container( | ||||
|       decoration: RoundedRectangleBorder().toSmoothCornerDecoration( | ||||
|         color: AppColors.whiteColor, | ||||
|         borderRadius: 20.h, | ||||
|         hasShadow: false, | ||||
|       ), | ||||
|       child: Column( | ||||
|         mainAxisAlignment: MainAxisAlignment.start, | ||||
|         children: [ | ||||
|           header, | ||||
|           Row( | ||||
|             mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||
|             children: [ | ||||
|               Row( | ||||
|                 spacing: 8.h, | ||||
|                 children: [ | ||||
|                   placesCountItem( | ||||
|                       AppAssets.hmg, hmgCount, " ${LocaleKeys.hospital.tr()}"), | ||||
|                   placesCountItem(AppAssets.hmc, hmcCount, | ||||
|                       " ${LocaleKeys.medicalCenters.tr()}"), | ||||
|                 ], | ||||
|               ), | ||||
|               Utils.buildSvgWithAssets( | ||||
|                 icon: AppAssets.forward_arrow_icon, | ||||
|                 iconColor: AppColors.blackColor, | ||||
|                 width: 18, | ||||
|                 height: 13, | ||||
|                 fit: BoxFit.contain, | ||||
|               ), | ||||
|             ], | ||||
|           ) | ||||
|         ], | ||||
|       ).paddingAll(16.h), | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   Widget placesCountItem(String svgPath, String count, String title) { | ||||
|     return AppCustomChipWidget( | ||||
|       iconSize: 14, | ||||
|       icon: svgPath, | ||||
|       iconHasColor: false, | ||||
|       richText: RichText( | ||||
|                   text: TextSpan( | ||||
|                       text: count, | ||||
|                       style: TextStyle( | ||||
|                           fontSize: 12.h, | ||||
|                           fontWeight: FontWeight.w700, | ||||
|                           color: AppColors.blackColor), | ||||
|                       children: [ | ||||
|                     TextSpan( | ||||
|                         text: title, | ||||
|                         style: TextStyle( | ||||
|                             fontSize: 12.h, | ||||
|                             fontWeight: FontWeight.w500, | ||||
|                             color: AppColors.blackColor)) | ||||
|                   ])), | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|  Widget get header => Column( | ||||
|         mainAxisAlignment: MainAxisAlignment.start, | ||||
|         crossAxisAlignment: CrossAxisAlignment.start, | ||||
|         children: [ | ||||
|           Align( | ||||
|             alignment: Alignment.centerLeft, | ||||
|             child: Text( | ||||
|               title, | ||||
|               style: TextStyle( | ||||
|                 fontSize: 16.h, | ||||
|                 fontWeight: FontWeight.w600, | ||||
|                 color: AppColors.blackColor, | ||||
|               ), | ||||
|             ), | ||||
|           ), | ||||
|           Align( | ||||
|             alignment: Alignment.centerLeft, | ||||
|             child: Text( | ||||
|               subTitle, | ||||
|               style: TextStyle( | ||||
|                 fontSize: 12.h, | ||||
|                 fontWeight: FontWeight.w500, | ||||
|                 color: AppColors.greyTextColor, | ||||
|               ), | ||||
|             ), | ||||
|           ), | ||||
|         ], | ||||
|       ); | ||||
| } | ||||
| @ -0,0 +1,86 @@ | ||||
| import 'dart:async'; | ||||
| 
 | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; | ||||
| import 'package:hmg_patient_app_new/core/utils/utils.dart' show Utils; | ||||
| import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; | ||||
| import 'package:hmg_patient_app_new/features/my_appointments/appointment_via_region_viewmodel.dart'; | ||||
| import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart' | ||||
|     show MyAppointmentsViewModel; | ||||
| import 'package:hmg_patient_app_new/presentation/appointments/widgets/region_bottomsheet/region_list_item.dart' | ||||
|     show RegionListItem; | ||||
| import 'package:provider/provider.dart'; | ||||
| 
 | ||||
| class RegionBottomSheetBody extends StatefulWidget { | ||||
| 
 | ||||
|   const RegionBottomSheetBody({super.key}); | ||||
| 
 | ||||
|   @override | ||||
|   State<RegionBottomSheetBody> createState() => _RegionBottomSheetBodyState(); | ||||
| } | ||||
| 
 | ||||
| class _RegionBottomSheetBodyState extends State<RegionBottomSheetBody> { | ||||
|   late MyAppointmentsViewModel myAppointmentsViewModel; | ||||
|   late AppointmentViaRegionViewmodel regionalViewModel; | ||||
| 
 | ||||
|   @override | ||||
|   void initState() { | ||||
|     scheduleMicrotask(() { | ||||
|       myAppointmentsViewModel.getRegionMappedProjectList(); | ||||
|     }); | ||||
|     super.initState(); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     myAppointmentsViewModel = Provider.of<MyAppointmentsViewModel>(context); | ||||
|     regionalViewModel = Provider.of<AppointmentViaRegionViewmodel>(context); | ||||
|     return Consumer<MyAppointmentsViewModel>( | ||||
|       builder: (context, myAppointmentsVM, child) { | ||||
|         if (myAppointmentsVM.isRegionListLoading) { | ||||
|           return Container( | ||||
|             height: MediaQuery.of(context).size.height * 0.3, | ||||
|             decoration: const BoxDecoration( | ||||
|               color: Colors.white, | ||||
|               borderRadius: BorderRadius.vertical(top: Radius.circular(16)), | ||||
|             ), | ||||
|             child: Center( | ||||
|               child: Utils.getLoadingWidget(), | ||||
|             ), | ||||
|           ); | ||||
|         } else { | ||||
|           return SizedBox( | ||||
|             height: MediaQuery.of(context).size.height * 0.5, | ||||
|             child: ListView.separated( | ||||
|               itemCount: | ||||
|                   myAppointmentsVM.hospitalList?.registeredDoctorMap?.length ?? | ||||
|                       0, | ||||
|               separatorBuilder: (_, __) { | ||||
|                 return SizedBox( | ||||
|                   height: 16.h, | ||||
|                 ); | ||||
|               }, | ||||
|               itemBuilder: (_, index) { | ||||
|                 String key = myAppointmentsVM | ||||
|                         .hospitalList?.registeredDoctorMap?.keys | ||||
|                         .toList()[index] ?? | ||||
|                     ''; | ||||
|                 return RegionListItem( | ||||
|                   title: key, | ||||
|                   subTitle: "", | ||||
|                   hmcCount: | ||||
|                       "${myAppointmentsVM.hospitalList?.registeredDoctorMap?[key]?.hmcSize ?? 0}", | ||||
|                   hmgCount: | ||||
|                       "${myAppointmentsVM.hospitalList?.registeredDoctorMap?[key]?.hmgSize ?? 0}", | ||||
|                 ).onPress(() { | ||||
|                   regionalViewModel.setSelectedRegionId(key); | ||||
|                   regionalViewModel.setBottomSheetState(AppointmentViaRegionState.TYPE_SELECTION); | ||||
|                 }); | ||||
|               }, | ||||
|             ), | ||||
|           ); | ||||
|         } | ||||
|       }, | ||||
|     ); | ||||
|   } | ||||
| } | ||||
					Loading…
					
					
				
		Reference in New Issue