Merge branch 'master' into faiz_dev
# Conflicts: # lib/core/utils/utils.dart # lib/presentation/book_appointment/laser/widgets/body_part_listing.dart # lib/widgets/buttons/custom_button.dart # lib/widgets/common_bottom_sheet.dart # lib/widgets/input_widget.dartpull/86/head
						commit
						21be3a2d06
					
				
											
												
													File diff suppressed because one or more lines are too long
												
											
										
									
								
											
												
													File diff suppressed because one or more lines are too long
												
											
										
									
								
											
												
													File diff suppressed because one or more lines are too long
												
											
										
									
								| @ -0,0 +1,3 @@ | ||||
| <svg width="14" height="15" viewBox="0 0 14 15" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||||
|     <path fill-rule="evenodd" clip-rule="evenodd" d="M6.99996 1.22925C3.53667 1.22925 0.729126 4.0368 0.729126 7.50008C0.729126 10.9634 3.53667 13.7709 6.99996 13.7709C10.4632 13.7709 13.2708 10.9634 13.2708 7.50008C13.2708 4.0368 10.4632 1.22925 6.99996 1.22925ZM9.74577 5.57923C9.97358 5.35142 9.97358 4.98207 9.74577 4.75427C9.51797 4.52646 9.14862 4.52646 8.92081 4.75427L7 6.67509L5.95409 5.62925C5.72628 5.40146 5.35693 5.40147 5.12913 5.62928C4.90133 5.8571 4.90135 6.22644 5.12916 6.45424L6.17504 7.50004L6.00415 7.67094C5.77634 7.89874 5.77634 8.26809 6.00415 8.49589C6.23195 8.7237 6.6013 8.7237 6.8291 8.49589L7.00002 8.32497L7.17076 8.49569C7.39857 8.72349 7.76792 8.72348 7.99571 8.49567C8.22351 8.26785 8.2235 7.89851 7.99569 7.67071L7.82498 7.50002L9.74577 5.57923Z" fill="#2E3039"/> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 902 B | 
| @ -0,0 +1,19 @@ | ||||
| import 'dart:async'; | ||||
| import 'dart:ui'; | ||||
| 
 | ||||
| class Debouncer { | ||||
|   final int milliseconds; | ||||
|   VoidCallback? action; | ||||
|   Timer? _timer; | ||||
| 
 | ||||
|   Debouncer({required this.milliseconds}); | ||||
| 
 | ||||
|   void run(VoidCallback action) { | ||||
|     _timer?.cancel(); | ||||
|     _timer = Timer(Duration(milliseconds: milliseconds), action); | ||||
|   } | ||||
| 
 | ||||
|   void dispose() { | ||||
|     _timer?.cancel(); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,94 @@ | ||||
| import 'package:dartz/dartz.dart'; | ||||
| import 'package:hmg_patient_app_new/core/api/api_client.dart'; | ||||
| import 'package:hmg_patient_app_new/core/api_consts.dart'; | ||||
| import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart'; | ||||
| import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart'; | ||||
| import 'package:hmg_patient_app_new/features/emergency_services/model/resp_model/ProjectAvgERWaitingTime.dart'; | ||||
| import 'package:hmg_patient_app_new/features/emergency_services/models/resp_models/rrt_procedures_response_model.dart'; | ||||
| import 'package:hmg_patient_app_new/services/logger_service.dart'; | ||||
| 
 | ||||
| abstract class EmergencyServicesRepo { | ||||
|   Future<Either<Failure, GenericApiModel<List<RRTProceduresResponseModel>>>> getRRTProcedures(); | ||||
| 
 | ||||
|   Future<Either<Failure, GenericApiModel<List<ProjectAvgERWaitingTime>>>> getNearestEr({int? id, int? projectID}); | ||||
| } | ||||
| 
 | ||||
| class EmergencyServicesRepoImp implements EmergencyServicesRepo { | ||||
|   final ApiClient apiClient; | ||||
|   final LoggerService loggerService; | ||||
| 
 | ||||
|   EmergencyServicesRepoImp({required this.loggerService, required this.apiClient}); | ||||
| 
 | ||||
|   Future<Either<Failure, GenericApiModel<List<ProjectAvgERWaitingTime>>>> getNearestEr({int? id, int? projectID}) async { | ||||
|     Map<String, dynamic> mapDevice = {'IsForER': true}; | ||||
| 
 | ||||
|     try { | ||||
|       GenericApiModel<List<ProjectAvgERWaitingTime>>? apiResponse; | ||||
|       Failure? failure; | ||||
|       await apiClient.post( | ||||
|         GET_NEAREST_HOSPITAL, | ||||
|         body: mapDevice, | ||||
|         onFailure: (error, statusCode, {messageStatus, failureType}) { | ||||
|           failure = failureType; | ||||
|         }, | ||||
|         onSuccess: (response, statusCode, {messageStatus, errorMessage}) { | ||||
|           try { | ||||
|             final list = response['List_ProjectAvgERWaitingTime']; | ||||
| 
 | ||||
|             final clinicsList = list.map((item) => ProjectAvgERWaitingTime.fromJson(item as Map<String, dynamic>)).toList().cast<ProjectAvgERWaitingTime>(); | ||||
|             apiResponse = GenericApiModel<List<ProjectAvgERWaitingTime>>( | ||||
|               messageStatus: messageStatus, | ||||
|               statusCode: statusCode, | ||||
|               errorMessage: null, | ||||
|               data: clinicsList, | ||||
|             ); | ||||
|           } catch (e) { | ||||
|             failure = DataParsingFailure(e.toString()); | ||||
|           } | ||||
|         }, | ||||
|       ); | ||||
|       if (failure != null) return Left(failure!); | ||||
|       if (apiResponse == null) return Left(ServerFailure("Unknown error")); | ||||
|       return Right(apiResponse!); | ||||
|     } catch (e) { | ||||
|       return Left(UnknownFailure(e.toString())); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   Future<Either<Failure, GenericApiModel<List<RRTProceduresResponseModel>>>> getRRTProcedures() async { | ||||
|     Map<String, dynamic> mapDevice = {}; | ||||
| 
 | ||||
|     try { | ||||
|       GenericApiModel<List<RRTProceduresResponseModel>>? apiResponse; | ||||
|       Failure? failure; | ||||
|       await apiClient.post( | ||||
|         GET_RRT_PROCEDURE_LIST, | ||||
|         body: mapDevice, | ||||
|         onFailure: (error, statusCode, {messageStatus, failureType}) { | ||||
|           failure = failureType; | ||||
|         }, | ||||
|         onSuccess: (response, statusCode, {messageStatus, errorMessage}) { | ||||
|           try { | ||||
|             final list = response['Vida_ProcedureList']; | ||||
|             final proceduresList = list.map((item) => RRTProceduresResponseModel.fromJson(item as Map<String, dynamic>)).toList().cast<RRTProceduresResponseModel>(); | ||||
| 
 | ||||
|             apiResponse = GenericApiModel<List<RRTProceduresResponseModel>>( | ||||
|               messageStatus: messageStatus, | ||||
|               statusCode: statusCode, | ||||
|               errorMessage: null, | ||||
|               data: proceduresList, | ||||
|             ); | ||||
|           } catch (e) { | ||||
|             failure = DataParsingFailure(e.toString()); | ||||
|           } | ||||
|         }, | ||||
|       ); | ||||
|       if (failure != null) return Left(failure!); | ||||
|       if (apiResponse == null) return Left(ServerFailure("Unknown error")); | ||||
|       return Right(apiResponse!); | ||||
|     } catch (e) { | ||||
|       return Left(UnknownFailure(e.toString())); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,137 @@ | ||||
| import 'dart:async'; | ||||
| 
 | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:hmg_patient_app_new/core/app_state.dart'; | ||||
| import 'package:hmg_patient_app_new/core/location_util.dart'; | ||||
| import 'package:hmg_patient_app_new/features/emergency_services/emergency_services_repo.dart'; | ||||
| import 'package:hmg_patient_app_new/features/emergency_services/model/resp_model/ProjectAvgERWaitingTime.dart'; | ||||
| import 'package:hmg_patient_app_new/features/emergency_services/models/resp_models/rrt_procedures_response_model.dart'; | ||||
| import 'package:hmg_patient_app_new/presentation/emergency_services/nearest_er_page.dart'; | ||||
| import 'package:hmg_patient_app_new/services/error_handler_service.dart'; | ||||
| import 'package:hmg_patient_app_new/services/navigation_service.dart'; | ||||
| import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; | ||||
| import 'package:url_launcher/url_launcher.dart'; | ||||
| 
 | ||||
| class EmergencyServicesViewModel extends ChangeNotifier { | ||||
|   EmergencyServicesRepo emergencyServicesRepo; | ||||
|   ErrorHandlerService errorHandlerService; | ||||
| 
 | ||||
|   final NavigationService navServices; | ||||
|   final LocationUtils? locationUtils; | ||||
|   final AppState appState; | ||||
|   bool isERListLoading = false; | ||||
|   List<ProjectAvgERWaitingTime> nearestERList = []; | ||||
|   List<ProjectAvgERWaitingTime> nearestERFilteredList = []; | ||||
| 
 | ||||
|   List<RRTProceduresResponseModel> RRTProceduresList = []; | ||||
| 
 | ||||
|   late RRTProceduresResponseModel selectedRRTProcedure; | ||||
| 
 | ||||
|   setSelectedRRTProcedure(RRTProceduresResponseModel procedure) { | ||||
|     selectedRRTProcedure = procedure; | ||||
|     notifyListeners(); | ||||
|   } | ||||
| 
 | ||||
|   EmergencyServicesViewModel({ | ||||
|     required this.emergencyServicesRepo, | ||||
|     required this.errorHandlerService, | ||||
|     required this.navServices, | ||||
|     required this.locationUtils, | ||||
|     required this.appState, | ||||
|   }); | ||||
| 
 | ||||
|   Future<void> getRRTProcedures({Function(dynamic)? onSuccess, Function(String)? onError}) async { | ||||
|     RRTProceduresList.clear(); | ||||
|     notifyListeners(); | ||||
| 
 | ||||
|     final result = await emergencyServicesRepo.getRRTProcedures(); | ||||
| 
 | ||||
|     result.fold( | ||||
|       (failure) async => await errorHandlerService.handleError(failure: failure), | ||||
|       (apiResponse) { | ||||
|         if (apiResponse.messageStatus == 2) { | ||||
|           // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); | ||||
|         } else if (apiResponse.messageStatus == 1) { | ||||
|           RRTProceduresList = apiResponse.data!; | ||||
|           selectedRRTProcedure = RRTProceduresList.first; | ||||
|           notifyListeners(); | ||||
|           if (onSuccess != null) { | ||||
|             onSuccess(apiResponse); | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   void navigateToNearestERPage() { | ||||
|     locationUtils!.getLocation( | ||||
|         isShowConfirmDialog: true, | ||||
|         onSuccess: (position) { | ||||
|           navServices.push( | ||||
|             CustomPageRoute( | ||||
|               page: NearestErPage(), | ||||
|             ), | ||||
|           ); | ||||
|           getNearestER(); | ||||
|         }); | ||||
|   } | ||||
| 
 | ||||
|   void filterErList(String query) { | ||||
|     print("the query is $query"); | ||||
|     if (query.isEmpty) { | ||||
|       nearestERFilteredList = nearestERList; | ||||
|     } else { | ||||
|       nearestERFilteredList = nearestERList.where((er) => er.projectName != null && er.projectName!.toLowerCase().contains(query.toLowerCase())).toList(); | ||||
|     } | ||||
|     notifyListeners(); | ||||
|   } | ||||
| 
 | ||||
|   // Open directions (navigation) from current location to destination. | ||||
|   Future<void> openDirections({ | ||||
|     required double destLat, | ||||
|     required double destLng, | ||||
|     String? travelMode, // driving, walking, bicycling, transit | ||||
|   }) async { | ||||
|     // Try Google Maps app navigation intent (android/iOS) | ||||
|     final modeParam = travelMode == null ? 'driving' : travelMode; | ||||
|     final googleNavUri = Uri.parse('google.navigation:q=$destLat,$destLng&mode=${modeParam.substring(0, 1)}'); // mode: d/w/b/t by scheme | ||||
|     final universalUrl = Uri.parse('https://www.google.com/maps/dir/?api=1&destination=$destLat,$destLng&travelmode=$modeParam'); | ||||
| 
 | ||||
|     if (await canLaunchUrl(googleNavUri)) { | ||||
|       await launchUrl(googleNavUri, mode: LaunchMode.externalApplication); | ||||
|     } else { | ||||
|       await launchUrl(universalUrl, mode: LaunchMode.externalApplication); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   Future<void> openDialer(String phoneNumber) async { | ||||
|     final Uri telUri = Uri(scheme: 'tel', path: phoneNumber); | ||||
| 
 | ||||
|     if (await canLaunchUrl(telUri)) { | ||||
|       await launchUrl(telUri, mode: LaunchMode.externalApplication); | ||||
|     } else { | ||||
|       throw 'Could not open dialer for $phoneNumber'; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   FutureOr<void> getNearestER() async { | ||||
|     isERListLoading = true; | ||||
|     nearestERList = []; | ||||
|     nearestERFilteredList = []; | ||||
|     notifyListeners(); | ||||
|     var response = await emergencyServicesRepo.getNearestEr(); | ||||
|     isERListLoading = false; | ||||
|     notifyListeners(); | ||||
| 
 | ||||
|     response.fold( | ||||
|       (failure) async {}, | ||||
|       (apiResponse) { | ||||
|         isERListLoading = false; | ||||
|         if (apiResponse.messageStatus == 1) { | ||||
|           nearestERList = apiResponse.data!; | ||||
|           nearestERFilteredList = nearestERList; | ||||
|         } | ||||
|       }, | ||||
|     ); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,114 @@ | ||||
| class ProjectAvgERWaitingTime { | ||||
|   int? iD; | ||||
|   int? projectID; | ||||
|   int? avgTimeInMinutes; | ||||
|   String? avgTimeInHHMM; | ||||
|   dynamic distanceInKilometers; | ||||
|   String? latitude; | ||||
|   String? longitude; | ||||
|   String? phonenumber; | ||||
|   String? projectImageURL; | ||||
|   String? projectName; | ||||
| 
 | ||||
|   ProjectAvgERWaitingTime( | ||||
|       {this.iD, | ||||
|         this.projectID, | ||||
|         this.avgTimeInMinutes, | ||||
|         this.avgTimeInHHMM, | ||||
|         this.distanceInKilometers, | ||||
|         this.latitude, | ||||
|         this.longitude, | ||||
|         this.phonenumber, | ||||
|         this.projectImageURL, | ||||
|         this.projectName}); | ||||
| 
 | ||||
|   ProjectAvgERWaitingTime.fromJson(Map<String, dynamic> json) { | ||||
|     iD = json['ID']; | ||||
|     projectID = json['ProjectID']; | ||||
|     avgTimeInMinutes = json['AvgTimeInMinutes']; | ||||
|     avgTimeInHHMM = json['AvgTimeInHHMM']; | ||||
|     distanceInKilometers = json['DistanceInKilometers']; | ||||
|     latitude = json['Latitude']; | ||||
|     longitude = json['Longitude']; | ||||
|     phonenumber = json['PhoneNumber']; | ||||
|     projectImageURL = json['ProjectImageURL']; | ||||
|     projectName = json['ProjectName']; | ||||
|   } | ||||
| 
 | ||||
|   String getTime(){ | ||||
|     print("the name is $projectName"); | ||||
|     print("the avgTimeInMinutes is $avgTimeInMinutes"); | ||||
|     if(avgTimeInMinutes == null) return ""; | ||||
|     int hours = avgTimeInMinutes! ~/ 60; | ||||
|     int minutes = avgTimeInMinutes! % 60; | ||||
|     print("the time is ${"${hours.toString().padLeft(2, '0')}:${minutes.toString().padLeft(2, '0')}"}"); | ||||
|     return "${hours.toString().padLeft(2, '0')}:${minutes.toString().padLeft(2, '0')}"; | ||||
|   } | ||||
| 
 | ||||
|   Map<String, dynamic> toJson() { | ||||
|     final Map<String, dynamic> data = new Map<String, dynamic>(); | ||||
|     data['ID'] = this.iD; | ||||
|     data['ProjectID'] = this.projectID; | ||||
|     data['AvgTimeInMinutes'] = this.avgTimeInMinutes; | ||||
|     data['AvgTimeInHHMM'] = this.avgTimeInHHMM; | ||||
|     data['DistanceInKilometers'] = this.distanceInKilometers; | ||||
|     data['Latitude'] = this.latitude; | ||||
|     data['Longitude'] = this.longitude; | ||||
|     data['PhoneNumber'] = this.phonenumber; | ||||
|     data['ProjectImageURL'] = this.projectImageURL; | ||||
|     data['ProjectName'] = this.projectName; | ||||
|     return data; | ||||
|   } | ||||
| } | ||||
| //class ProjectAvgERWaitingTime { | ||||
| //  int? iD; | ||||
| //  int? projectID; | ||||
| //  int? avgTimeInMinutes; | ||||
| //  String? avgTimeInHHMM; | ||||
| //  String? distanceInKilometers; | ||||
| //  String? latitude; | ||||
| //  String? longitude; | ||||
| //  String? phonenum?ber; | ||||
| //  String? projectImageURL; | ||||
| //  String? projectName; | ||||
| // | ||||
| //  ProjectAvgERWaitingTime( | ||||
| //      {this.iD, | ||||
| //        this.projectID, | ||||
| //        this.avgTimeInMinutes, | ||||
| //        this.avgTimeInHHMM, | ||||
| //        this.distanceInKilometers, | ||||
| //        this.latitude, | ||||
| //        this.longitude, | ||||
| //        this.phonenum?ber, | ||||
| //        this.projectImageURL, | ||||
| //        this.projectName}); | ||||
| // | ||||
| //  ProjectAvgERWaitingTime.fromJson(Map<String, dynamic> json) { | ||||
| //    iD = json['ID']; | ||||
| //    projectID = json['ProjectID']; | ||||
| //    avgTimeInMinutes = json['AvgTimeInMinutes']; | ||||
| //    avgTimeInHHMM = json['AvgTimeInHHMM']; | ||||
| //    distanceInKilometers = json['DistanceInKilometers']; | ||||
| //    latitude = json['Latitude']; | ||||
| //    longitude = json['Longitude']; | ||||
| //    phonenum?ber = json['Phonenum?ber']; | ||||
| //    projectImageURL = json['ProjectImageURL']; | ||||
| //    projectName = json['ProjectName']; | ||||
| //  } | ||||
| // | ||||
| //  Map<String, dynamic> toJson() { | ||||
| //    final Map<String, dynamic> data = new Map<String, dynamic>(); | ||||
| //    data['ID'] = this.iD; | ||||
| //    data['ProjectID'] = this.projectID; | ||||
| //    data['AvgTimeInMinutes'] = this.avgTimeInMinutes; | ||||
| //    data['AvgTimeInHHMM'] = this.avgTimeInHHMM; | ||||
| //    data['DistanceInKilometers'] = this.distanceInKilometers; | ||||
| //    data['Latitude'] = this.latitude; | ||||
| //    data['Longitude'] = this.longitude; | ||||
| //    data['Phonenum?ber'] = this.phonenum?ber; | ||||
| //    data['ProjectImageURL'] = this.projectImageURL; | ||||
| //    data['ProjectName'] = this.projectName; | ||||
| //    return data; | ||||
| //  } | ||||
| //} | ||||
| @ -0,0 +1,27 @@ | ||||
| class RRTProceduresResponseModel { | ||||
|   num? patientShare; | ||||
|   num? patientShareWithTax; | ||||
|   num? patientTaxAmount; | ||||
|   String? procedureID; | ||||
|   String? procedureName; | ||||
| 
 | ||||
|   RRTProceduresResponseModel({this.patientShare, this.patientShareWithTax, this.patientTaxAmount, this.procedureID, this.procedureName}); | ||||
| 
 | ||||
|   RRTProceduresResponseModel.fromJson(Map<String, dynamic> json) { | ||||
|     patientShare = json['PatientShare']; | ||||
|     patientShareWithTax = json['PatientShareWithTax']; | ||||
|     patientTaxAmount = json['PatientTaxAmount']; | ||||
|     procedureID = json['ProcedureID']; | ||||
|     procedureName = json['ProcedureName']; | ||||
|   } | ||||
| 
 | ||||
|   Map<String, dynamic> toJson() { | ||||
|     final Map<String, dynamic> data = new Map<String, dynamic>(); | ||||
|     data['PatientShare'] = this.patientShare; | ||||
|     data['PatientShareWithTax'] = this.patientShareWithTax; | ||||
|     data['PatientTaxAmount'] = this.patientTaxAmount; | ||||
|     data['ProcedureID'] = this.procedureID; | ||||
|     data['ProcedureName'] = this.procedureName; | ||||
|     return data; | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,46 @@ | ||||
| import 'package:flutter/cupertino.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:hmg_patient_app_new/core/app_export.dart'; | ||||
| import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; | ||||
| import 'package:hmg_patient_app_new/features/emergency_services/emergency_services_view_model.dart'; | ||||
| import 'package:hmg_patient_app_new/theme/colors.dart'; | ||||
| import 'package:hmg_patient_app_new/widgets/radio/custom_radio_button.dart'; | ||||
| import 'package:provider/provider.dart'; | ||||
| 
 | ||||
| class RrtRequestTypeSelect extends StatelessWidget { | ||||
|   const RrtRequestTypeSelect({super.key}); | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     // return Consumer<EmergencyServicesViewModel>(builder: (context, emergencyServicesVM, child) { | ||||
|     return Column( | ||||
|       children: [ | ||||
|         Container( | ||||
|           padding: EdgeInsets.all(16.h), | ||||
|           height: 200.h, | ||||
|           decoration: RoundedRectangleBorder().toSmoothCornerDecoration( | ||||
|             color: AppColors.whiteColor, | ||||
|             borderRadius: 24.h, | ||||
|           ), | ||||
|           child: Column( | ||||
|             crossAxisAlignment: CrossAxisAlignment.start, | ||||
|             children: [ | ||||
|               Row( | ||||
|                 children: [ | ||||
|                   CustomRadioOption( | ||||
|                     value: "", | ||||
|                     groupValue: "", | ||||
|                     onChanged: (value) {}, | ||||
|                     text: "Home Visit Emergency", | ||||
|                   ) | ||||
|                 ], | ||||
|               ), | ||||
|             ], | ||||
|           ), | ||||
|         ), | ||||
|         SizedBox(height: 32.h), | ||||
|       ], | ||||
|     ); | ||||
|     // }); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,130 @@ | ||||
| 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/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/emergency_services/emergency_services_view_model.dart'; | ||||
| import 'package:hmg_patient_app_new/features/emergency_services/model/resp_model/ProjectAvgERWaitingTime.dart'; | ||||
| import 'package:hmg_patient_app_new/theme/colors.dart'; | ||||
| import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; | ||||
| import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; | ||||
| import 'package:provider/provider.dart'; | ||||
| 
 | ||||
| class NearestERItem extends StatelessWidget { | ||||
|   final ProjectAvgERWaitingTime nearestERItem; | ||||
|   final bool isLoading; | ||||
| 
 | ||||
| 
 | ||||
|   const NearestERItem({ super.key, | ||||
|     required this.nearestERItem, | ||||
|     required this.isLoading | ||||
|   }) ; | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return Container( | ||||
|       decoration: RoundedRectangleBorder().toSmoothCornerDecoration( | ||||
|         color: Colors.white, | ||||
|         customBorder: BorderRadius.only( | ||||
|           topLeft: Radius.circular(24.h), | ||||
|           topRight: Radius.circular(24.h), | ||||
|         ), | ||||
|       ), | ||||
|       child: Padding( | ||||
|         padding: EdgeInsets.all(16.h), | ||||
|         child: Column( | ||||
|           crossAxisAlignment: CrossAxisAlignment.start, | ||||
|           children: [ | ||||
|             Row( | ||||
|               children: [ | ||||
|                 (isLoading || nearestERItem.projectImageURL?.isEmpty == true) | ||||
|                     ? Container( | ||||
|                   width: 24.h, | ||||
|                   height: 24.h, | ||||
|                   decoration: BoxDecoration( | ||||
|                     color: Colors.grey.shade300, | ||||
|                     shape: BoxShape.circle, | ||||
|                   ), | ||||
|                 ).toShimmer2(isShow: isLoading) | ||||
|                     : Utils.buildImgWithNetwork( | ||||
|                   url: nearestERItem.projectImageURL ?? '', | ||||
|                   iconColor: Colors.transparent, | ||||
|                 ).circle(24.h).toShimmer2(isShow: isLoading), | ||||
|                 const SizedBox(width: 12), | ||||
|                 Expanded( | ||||
|                   child: (nearestERItem.projectName?.toText16( | ||||
|                     color: AppColors.textColor, | ||||
|                     weight: FontWeight.w600, | ||||
|                   ) ?? | ||||
|                       SizedBox.shrink()).toShimmer2(isShow: isLoading), | ||||
|                 ), | ||||
|                 // TODO: Add hospital icon logic here if needed | ||||
|               ], | ||||
|             ), | ||||
|             SizedBox(height: 8.h), | ||||
|             Row( | ||||
|               spacing: 8.h, | ||||
|               children: [ | ||||
|                 AppCustomChipWidget( | ||||
|                   labelText: "${nearestERItem.distanceInKilometers} km".needTranslation, | ||||
|                   icon: AppAssets.location, | ||||
|                   iconHasColor: false, | ||||
|                   labelPadding: EdgeInsetsDirectional.only(start: 4.h, end: 0.h), | ||||
|                   padding: EdgeInsets.all(8.h), | ||||
|                 ).toShimmer2(isShow: isLoading), | ||||
|                 AppCustomChipWidget( | ||||
|                   labelText: "Expected waiting time: ${nearestERItem.getTime()} mins".needTranslation, | ||||
|                   icon: AppAssets.waiting_time_clock, | ||||
|                   iconHasColor: false, | ||||
|                   labelPadding: EdgeInsetsDirectional.only(start: 4.h, end: 0.h), | ||||
|                   padding: EdgeInsets.all(8.h), | ||||
|                 ).toShimmer2(isShow: isLoading), | ||||
|               ], | ||||
|             ), | ||||
|             SizedBox(height: 16.h), | ||||
|             Row( | ||||
|               children: [ | ||||
|                 Expanded( | ||||
|                   child: CustomButton( | ||||
|                     text: "View Location on Google Maps".needTranslation, | ||||
|                     iconSize: 18.h, | ||||
|                     icon: AppAssets.location, | ||||
|                     onPressed: () { | ||||
|                       context.read<EmergencyServicesViewModel>().openDirections(destLat:  double.parse(nearestERItem.latitude??"0.0"), destLng: double.parse(nearestERItem.longitude??"0.0") ); | ||||
|                     }, | ||||
|                     backgroundColor: AppColors.secondaryLightRedColor, | ||||
|                     borderColor: AppColors.secondaryLightRedColor, | ||||
|                     textColor: AppColors.primaryRedColor, | ||||
|                     iconColor: AppColors.primaryRedColor, | ||||
|                     height: 40.h, | ||||
|                     fontSize: 14, | ||||
|                     fontWeight: FontWeight.w500, | ||||
|                   ).toShimmer2(isShow: isLoading), | ||||
|                 ), | ||||
|                 SizedBox(width: 8.h), | ||||
|                 SizedBox( | ||||
|                   height: 40.h, | ||||
|                   width: 40.h, | ||||
|                   child: CustomButton( | ||||
|                     text: '', | ||||
|                     iconSize: 18.h, | ||||
|                     icon: AppAssets.call_fill, | ||||
|                     onPressed: () { | ||||
|                       context.read<EmergencyServicesViewModel>().openDialer( nearestERItem.phonenumber??""); | ||||
| 
 | ||||
|                     }, | ||||
|                     backgroundColor: AppColors.greyColor, | ||||
|                     iconColor: AppColors.textColor, | ||||
|                     borderColor: AppColors.greyColor, | ||||
|                     height: 40.h, | ||||
|                   ).toShimmer2(isShow: isLoading), | ||||
|                 ), | ||||
|               ], | ||||
|             ), | ||||
|           ], | ||||
|         ), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,49 @@ | ||||
| import 'package:flutter/material.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/theme/colors.dart'; | ||||
| 
 | ||||
| class CustomRadioOption<T> extends StatelessWidget { | ||||
|   final T value; | ||||
|   final T? groupValue; | ||||
|   final ValueChanged<T?> onChanged; | ||||
|   final String text; | ||||
| 
 | ||||
|   // final Widget child; // The content of your radio option (e.g., Text, Image) | ||||
| 
 | ||||
|   const CustomRadioOption({ | ||||
|     super.key, | ||||
|     required this.value, | ||||
|     required this.groupValue, | ||||
|     required this.onChanged, | ||||
|     // required this.child, | ||||
|     required this.text, | ||||
|   }); | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     // bool isSelected = value == groupValue; | ||||
|     bool isSelected = false; | ||||
|     return InkWell( | ||||
|       onTap: () => onChanged(value), | ||||
|       child: Container( | ||||
|         padding: EdgeInsets.all(8.h), | ||||
|         child: Row( | ||||
|           children: [ | ||||
|             Container( | ||||
|               width: 20.h, | ||||
|               height: 20.h, | ||||
|               decoration: BoxDecoration( | ||||
|                 shape: BoxShape.circle, | ||||
|                 color: isSelected ? AppColors.primaryRedColor : AppColors.whiteColor, | ||||
|                 border: Border.all(color: isSelected ? AppColors.primaryRedColor : AppColors.bottomNAVBorder, width: 2.h), | ||||
|               ), | ||||
|             ), | ||||
|             SizedBox(width: 8.h), | ||||
|             text.toText16(weight: FontWeight.w500), // The provided content | ||||
|           ], | ||||
|         ), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
					Loading…
					
					
				
		Reference in New Issue