Ambulance order screens and geocoding request added

pull/95/head
tahaalam 4 months ago
parent 5aef8d67de
commit 1ca39e1332

@ -0,0 +1,4 @@
<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"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

@ -25,6 +25,7 @@ class AppAssets {
static const String download = '$svgBasePath/download.svg';
static const String language = '$svgBasePath/language.svg';
static const String location = '$svgBasePath/location.svg';
static const String pin_location = '$svgBasePath/pin_location.svg';
static const String whatsapp = '$svgBasePath/whatsapp.svg';
static const String card_user = '$svgBasePath/card_user.svg';
static const String habiblogo = '$svgBasePath/habiblogo.svg';

@ -19,6 +19,8 @@ import 'package:hmg_patient_app_new/features/insurance/insurance_repo.dart';
import 'package:hmg_patient_app_new/features/insurance/insurance_view_model.dart';
import 'package:hmg_patient_app_new/features/lab/lab_repo.dart';
import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart';
import 'package:hmg_patient_app_new/features/location/location_repo.dart';
import 'package:hmg_patient_app_new/features/location/location_view_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/medical_file_repo.dart';
import 'package:hmg_patient_app_new/features/medical_file/medical_file_view_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/appointment_via_region_viewmodel.dart';
@ -103,6 +105,8 @@ class AppDependencies {
getIt.registerLazySingleton<MedicalFileRepo>(() => MedicalFileRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<ImmediateLiveCareRepo>(() => ImmediateLiveCareRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<EmergencyServicesRepo>(() => EmergencyServicesRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<LocationRepo>(
() => LocationRepoImpl(apiClient: getIt()));
// ViewModels
// Global/shared VMs LazySingleton
@ -199,6 +203,15 @@ class AppDependencies {
emergencyServicesRepo: getIt(),
appState: getIt(),
errorHandlerService: getIt(),
appointmentRepo: getIt(),
dialogService: getIt()
),
);
getIt.registerLazySingleton<LocationViewModel>(
() => LocationViewModel(
locationRepo: getIt(),
errorHandlerService: getIt(),
),
);

@ -18,6 +18,8 @@ import 'package:hmg_patient_app_new/core/dependencies.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/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/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
@ -742,10 +744,14 @@ class Utils {
static Widget getPaymentAmountWithSymbol2(num habibWalletAmount,
{double iconSize = 14,
Color iconColor = AppColors.textColor,
double? fontSize,
double? letterSpacing,
FontWeight? fontWeight,
Color iconColor = AppColors.textColor,
Color textColor = AppColors.blackColor,
bool isSaudiCurrency = true,
bool isExpanded = true}) {
bool isExpanded = true,
}) {
return RichText(
maxLines: 1,
text: TextSpan(
@ -756,8 +762,13 @@ class Utils {
child: Utils.buildSvgWithAssets(icon: AppAssets.saudi_riyal_icon, width: iconSize.h, height: iconSize.h, iconColor: iconColor),
),
TextSpan(
text: " $habibWalletAmount",
style: TextStyle(color: textColor, fontSize: 32.f, letterSpacing: -4, fontWeight: FontWeight.w600, height: 1),
text: NumberFormat.currency(locale: 'en_US', symbol: " ", decimalDigits: 0).format(habibWalletAmount),
style: TextStyle(
color: textColor,
fontSize: fontSize ?? 32.f,
letterSpacing: letterSpacing??-4,
fontWeight: fontWeight ?? FontWeight.w600,
height: 1),
),
],
),
@ -815,4 +826,34 @@ class Utils {
}
return isHavePrivilege;
}
///method to be used to get the text as per the langauge of the application
static String getTextWRTCurrentLanguage(
String? englishText, String? arabicText) {
String? text = appState.isArabic() ? arabicText : englishText;
return text ?? '';
}
static String formatNumberToInternationalFormat(num number, {String? currencySymbol, int decimalDigit = 0}){
return NumberFormat.currency(
locale: 'en_US',
symbol: currencySymbol??"",
decimalDigits: decimalDigit)
.format(number);
}
static PatientDoctorAppointmentList? convertToPatientDoctorAppointmentList(
HospitalsModel? hospital) {
if (hospital == null) return null;
return PatientDoctorAppointmentList(
filterName: hospital.name,
distanceInKMs: hospital.distanceInKilometers?.toString(),
projectTopName: hospital.name,
projectBottomName: hospital.name,
model: hospital,
isHMC: hospital.isHMC);
}
}

@ -279,11 +279,11 @@ extension EmailValidator on String {
height: 1, color: color ?? AppColors.blackColor, fontSize: 22.f, letterSpacing: -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
);
Widget toText24({Color? color, bool isBold = false, bool isCenter = false, FontWeight? fontWeight}) => Text(
Widget toText24({Color? color, bool isBold = false, bool isCenter = false, FontWeight? fontWeight, double? letterSpacing}) => Text(
this,
textAlign: isCenter ? TextAlign.center : null,
style: TextStyle(
height: 23 / 24, color: color ?? AppColors.blackColor, fontSize: 24.f, letterSpacing: -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
height: 23 / 24, color: color ?? AppColors.blackColor, fontSize: 24.f, letterSpacing: letterSpacing??-1, fontWeight: isBold ? FontWeight.bold : fontWeight??FontWeight.normal),
);
Widget toText26({Color? color, bool isBold = false, double? height, bool isCenter = false, FontWeight? weight, double? letterSpacing}) => Text(

@ -3,14 +3,22 @@ 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/features/emergency_services/models/resp_model/ProjectAvgERWaitingTime.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/rrt_procedures_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
import 'models/resp_model/PatientERTransportationMethod.dart';
abstract class EmergencyServicesRepo {
Future<Either<Failure, GenericApiModel<List<RRTProceduresResponseModel>>>> getRRTProcedures();
Future<Either<Failure, GenericApiModel<List<ProjectAvgERWaitingTime>>>> getNearestEr({int? id, int? projectID});
Future<Either<Failure, GenericApiModel<List<PatientERTransportationMethod>>>> getTransportationMethods({int? id});
Future<Either<Failure, GenericApiModel<List<HospitalsModel>>>> getProjectList();
}
class EmergencyServicesRepoImp implements EmergencyServicesRepo {
@ -91,4 +99,79 @@ class EmergencyServicesRepoImp implements EmergencyServicesRepo {
return Left(UnknownFailure(e.toString()));
}
}
@override
Future<Either<Failure, GenericApiModel<List<PatientERTransportationMethod>>>> getTransportationMethods({int? id}) async {
Map<String, dynamic> mapDevice = {};
try {
GenericApiModel<List<PatientERTransportationMethod>>? apiResponse;
Failure? failure;
await apiClient.get(
"$GET_ALL_TRANSPORTATIONS_RC?patientID=$id",
isRCService: true,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['response']['transportationservices'];
final proceduresList = list.map((item) => PatientERTransportationMethod.fromJson(item as Map<String, dynamic>)).toList().cast<PatientERTransportationMethod>();
apiResponse = GenericApiModel<List<PatientERTransportationMethod>>(
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()));
}
}
@override
Future<Either<Failure, GenericApiModel<List<HospitalsModel>>>> getProjectList() async {
Map<String, dynamic> request = {};
try {
GenericApiModel<List<HospitalsModel>>? apiResponse;
Failure? failure;
await apiClient.post(
GET_PROJECT_LIST,
body: request,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['ListProject'];
final appointmentsList = list.map((item) => HospitalsModel.fromJson(item as Map<String, dynamic>)).toList().cast<HospitalsModel>();
apiResponse = GenericApiModel<List<HospitalsModel>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: appointmentsList,
);
} 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()));
}
}
}

@ -5,31 +5,73 @@ import 'package:google_maps_flutter/google_maps_flutter.dart' as GMSMapServices;
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/core/utils/doctor_response_mapper.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.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/features/emergency_services/models/AmbulanceCallingPlace.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/PatientERTransportationMethod.dart'
show PatientERTransportationMethod;
import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/ProjectAvgERWaitingTime.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/rrt_procedures_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/facility_selection.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/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_repo.dart';
import 'package:hmg_patient_app_new/presentation/authentication/login.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/call_ambulance_page.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/nearest_er_page.dart';
import 'package:hmg_patient_app_new/routes/app_routes.dart' show AppRoutes;
import 'package:hmg_patient_app_new/services/dialog_service.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/expandable_bottom_sheet/model/BottomSheetType.dart';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:huawei_map/huawei_map.dart' as HMSCameraServices;
import 'package:url_launcher/url_launcher.dart';
import '../location/GeocodeResponse.dart';
import 'models/ambulance_direction.dart';
class EmergencyServicesViewModel extends ChangeNotifier {
EmergencyServicesRepo emergencyServicesRepo;
MyAppointmentsRepo appointmentRepo;
ErrorHandlerService errorHandlerService;
DialogService dialogService;
Completer<GMSMapServices.GoogleMapController>? gmsController;
Completer<HMSCameraServices.HuaweiMapController>? hmsController;
final NavigationService navServices;
final LocationUtils? locationUtils;
final AppState appState;
//loading variables
bool isERListLoading = false;
bool isTransportationOptionsLoading = false;
List<ProjectAvgERWaitingTime> nearestERList = [];
List<ProjectAvgERWaitingTime> nearestERFilteredList = [];
List<RRTProceduresResponseModel> RRTProceduresList = [];
List<HospitalsModel>? hospitalList;
List<HospitalsModel>? hmgHospitalList;
List<HospitalsModel>? hmcHospitalList;
List<HospitalsModel>? displayList;
HospitalsModel? selectedHospital;
FacilitySelection selectedFacility = FacilitySelection.ALL;
int hmgCount = 0;
int hmcCount = 0;
bool pickupFromInsideTheLocation = true;
//ambulance selection data section
List<PatientERTransportationMethod> transportationOptions = [];
PatientERTransportationMethod? selectedTransportOption;
AmbulanceCallingPlace callingPlace = AmbulanceCallingPlace.FROM_HOSPITAL;
AmbulanceDirection ambulanceDirection = AmbulanceDirection.ONE_WAY;
late RRTProceduresResponseModel selectedRRTProcedure;
BottomSheetType bottomSheetType = BottomSheetType.FIXED;
@ -45,6 +87,8 @@ class EmergencyServicesViewModel extends ChangeNotifier {
required this.navServices,
required this.locationUtils,
required this.appState,
required this.appointmentRepo,
required this.dialogService,
});
get isGMSAvailable
@ -52,6 +96,13 @@ class EmergencyServicesViewModel extends ChangeNotifier {
return appState.isGMSAvailable;
}
bool get isArabic => appState.isArabic();
bool haveAnAppointment = false;
PatientAppointmentHistoryResponseModel? appointment;
bool isMyAppointmentsLoading = false;
Future<void> getRRTProcedures({Function(dynamic)? onSuccess, Function(String)? onError}) async {
RRTProceduresList.clear();
@ -168,17 +219,32 @@ class EmergencyServicesViewModel extends ChangeNotifier {
}
void navigateTOAmbulancePage() {
locationUtils!.getLocation(
isShowConfirmDialog: true,
onSuccess: (position) {
updateBottomSheetState(BottomSheetType.FIXED);
navServices.push(
CustomPageRoute(
page: CallAmbulancePage(), direction: AxisDirection.down
),
);
});
placeValueInController();
getProjects();
flushData();
selectedFacility = FacilitySelection.ALL;
print("the app state is ${appState.isAuthenticated}");
if (appState.isAuthenticated) {
locationUtils!.getLocation(
isShowConfirmDialog: true,
onSuccess: (position) {
updateBottomSheetState(BottomSheetType.FIXED);
navServices.push(
CustomPageRoute(
page: CallAmbulancePage(), direction: AxisDirection.down),
);
});
} else {
dialogService.showErrorBottomSheet(
message: "You Need To Login First To Continue".needTranslation,
onOkPressed: () {
navServices.pop();
navServices.pushAndReplace(
AppRoutes.loginScreen
);
});
}
}
void updateBottomSheetState(BottomSheetType sheetType) {
@ -187,8 +253,229 @@ class EmergencyServicesViewModel extends ChangeNotifier {
}
void setIsGMSAvailable(bool value) {
notifyListeners();
}
Future<void> getTransportationOption() async {
//handle the cache if the data is present then dont fetch it in the authenticated lifecycle
print("the app state is ${appState.isAuthenticated}");
if (appState.isAuthenticated == false) {
dialogService.showErrorBottomSheet(
message: "You Need To Login First To Continue".needTranslation,
onOkPressed: () {
navServices.pop();
print("inside the ok button");
navServices.pushAndReplace(
AppRoutes.loginScreen
);
});
return;
}
if (transportationOptions.isNotEmpty) return;
int? id = appState.getAuthenticatedUser()?.patientId;
LoaderBottomSheet.showLoader(
loadingText: "Getting Ambulance Transport Option".needTranslation);
notifyListeners();
var response = await emergencyServicesRepo.getTransportationMethods(id: id);
response.fold(
(failure) async {
LoaderBottomSheet.hideLoader();
},
(apiResponse) {
transportationOptions = apiResponse.data!;
LoaderBottomSheet.hideLoader();
notifyListeners();
},
);
}
Future<void> getTransportationMethods() async {
int? id = appState.getAuthenticatedUser()?.patientId;
LoaderBottomSheet.showLoader(
loadingText: "Getting Ambulance Transport Option".needTranslation);
notifyListeners();
var response =
await emergencyServicesRepo.getTransportationMethods(id: 4767477);
response.fold(
(failure) async {
LoaderBottomSheet.hideLoader();
},
(apiResponse) {
transportationOptions = apiResponse.data!;
LoaderBottomSheet.hideLoader();
notifyListeners();
},
);
}
void setTransportationOption(PatientERTransportationMethod item) {
selectedTransportOption = item;
}
void updateCallingPlace(AmbulanceCallingPlace? value) {
callingPlace = value!;
notifyListeners();
}
void updateDirection(AmbulanceDirection? value) {
ambulanceDirection = value!;
notifyListeners();
}
void placeValueInController() {
if (isGMSAvailable) {
gmsController = Completer<GMSMapServices.GoogleMapController>();
} else {
hmsController = Completer<HMSCameraServices.HuaweiMapController>();
}
}
void moveController(Location location) {
if (isGMSAvailable) {
gmsController?.future.then((controller) {
controller.animateCamera(
GMSMapServices.CameraUpdate.newCameraPosition(
GMSMapServices.CameraPosition(
target: GMSMapServices.LatLng(location.lat, location.lng),
zoom: 18,
),
),
);
});
} else {
hmsController?.future.then((controller) {
controller.animateCamera(
HMSCameraServices.CameraUpdate.newCameraPosition(
HMSCameraServices.CameraPosition(
target: HMSCameraServices.LatLng(location.lat, location.lng),
zoom: 18,
),
),
);
});
}
}
void moveToCurrentLocation() {
moveController(Location(lat: appState.userLat, lng: appState.userLong));
}
FutureOr<void> getProjects() async {
// if (hospitalList.isNotEmpty) return;
var response = await emergencyServicesRepo.getProjectList();
response.fold(
(failure) async {},
(apiResponse) async {
List<HospitalsModel>? data = apiResponse.data;
if (data == null) return;
hospitalList = data;
hmgHospitalList = data.where((e) => e.isHMC == false).toList();
hmcHospitalList = data.where((e) => e.isHMC == true).toList();
hmgCount = hmgHospitalList?.length ?? 0;
hmcCount = hmcHospitalList?.length ?? 0;
notifyListeners();
},
);
}
setSelectedFacility(FacilitySelection selection) {
selectedFacility = selection;
notifyListeners();
}
searchHospitals(String query) {
if (query.isEmpty) {
getDisplayList();
return;
}
List<HospitalsModel>? sourceList;
switch (selectedFacility) {
case FacilitySelection.ALL:
sourceList = hospitalList;
break;
case FacilitySelection.HMG:
sourceList = hmgHospitalList;
break;
case FacilitySelection.HMC:
sourceList = hmcHospitalList;
break;
}
displayList = sourceList
?.where((hospital) =>
hospital.name != null &&
hospital.name!.toLowerCase().contains(query.toLowerCase()))
.toList();
notifyListeners();
}
getDisplayList() {
switch (selectedFacility) {
case FacilitySelection.ALL:
displayList = hospitalList;
break;
case FacilitySelection.HMG:
displayList = hmgHospitalList;
break;
case FacilitySelection.HMC:
displayList = hmcHospitalList;
break;
}
notifyListeners();
}
void setSelectedHospital(HospitalsModel? hospital) {
selectedHospital = hospital;
notifyListeners();
}
String? getSelectedHospitalName() {
return selectedHospital?.getName(isArabic);
}
void updateThePickupPlaceFromLocation(bool value) {
pickupFromInsideTheLocation = value;
notifyListeners();
}
void flushData() {
selectedHospital = null;
displayList = hospitalList;
selectedFacility = FacilitySelection.ALL;
pickupFromInsideTheLocation = false;
notifyListeners();
}
void flushPickupInformation() {
ambulanceDirection = AmbulanceDirection.ONE_WAY;
callingPlace = AmbulanceCallingPlace.FROM_HOSPITAL;
notifyListeners();
}
num getTotalPrice() {
print("the ambulance direction is $ambulanceDirection");
switch (ambulanceDirection) {
case AmbulanceDirection.ONE_WAY:
return selectedTransportOption?.priceTotal ?? 0;
case AmbulanceDirection.TWO_WAY:
return (selectedTransportOption?.priceTotal ?? 0) * 2;
}
}
Future<void> updateAppointment(bool value) async {
haveAnAppointment = value;
if (value) {
await appointmentRepo.getPatientAppointments(
isActiveAppointment: true, isArrivedAppointments: false);
}
notifyListeners();
}
}

@ -0,0 +1,4 @@
enum AmbulanceCallingPlace{
FROM_HOSPITAL,
TO_HOSPITAL
}

@ -0,0 +1,3 @@
enum AmbulanceDirection{
ONE_WAY, TWO_WAY
}

@ -0,0 +1,205 @@
import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/PatientERTransportationMethod.dart' show PatientERTransportationMethod;
class PatientER_RC {
double? versionID;
int? channel;
int? languageID;
String? iPAdress;
String? generalid;
bool? patientOutSA;
String? sessionID;
bool? isDentalAllowedBackend;
int? deviceTypeID;
int? patientID;
String? tokenID;
int? patientTypeID;
int? patientType;
int? orderServiceID;
String? patientIdentificationID;
dynamic patientOutSa;
int? projectID;
int? lineItemNo;
TransportationDetails? transportationDetails;
PatientERTransportationMethod? patientERTransportationMethod;
PatientER_RC(
{this.versionID,
this.channel,
this.languageID,
this.iPAdress,
this.generalid,
this.patientOutSA,
this.sessionID,
this.isDentalAllowedBackend,
this.deviceTypeID,
this.patientID,
this.tokenID,
this.patientTypeID,
this.patientType,
this.orderServiceID,
this.patientIdentificationID,
this.patientOutSa,
this.projectID,
this.lineItemNo,
this.transportationDetails});
PatientER_RC.fromJson(Map<String, dynamic> json) {
versionID = json['VersionID'];
channel = json['Channel'];
languageID = json['LanguageID'];
iPAdress = json['IPAdress'];
generalid = json['generalid'];
patientOutSA = json['PatientOutSA'];
sessionID = json['SessionID'];
isDentalAllowedBackend = json['isDentalAllowedBackend'];
deviceTypeID = json['DeviceTypeID'];
patientID = json['PatientID'];
tokenID = json['TokenID'];
patientTypeID = json['PatientTypeID'];
patientType = json['PatientType'];
orderServiceID = json['OrderServiceID'];
patientIdentificationID = json['PatientIdentificationID'];
patientOutSa = json['patientOutSa'];
projectID = json['projectID'];
lineItemNo = json['lineItemNo'];
transportationDetails = json['transportationDetails'] != null
? new TransportationDetails.fromJson(json['transportationDetails'])
: null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['VersionID'] = this.versionID;
data['Channel'] = this.channel;
data['LanguageID'] = this.languageID;
data['IPAdress'] = this.iPAdress;
data['generalid'] = this.generalid;
data['PatientOutSA'] = this.patientOutSA;
data['SessionID'] = this.sessionID;
data['isDentalAllowedBackend'] = this.isDentalAllowedBackend;
data['DeviceTypeID'] = this.deviceTypeID;
data['PatientID'] = this.patientID;
data['TokenID'] = this.tokenID;
data['PatientTypeID'] = this.patientTypeID;
data['PatientType'] = this.patientType;
data['OrderServiceID'] = this.orderServiceID;
data['PatientIdentificationID'] = this.patientIdentificationID;
data['patientOutSa'] = this.patientOutSa;
data['projectID'] = this.projectID;
data['lineItemNo'] = this.lineItemNo;
if (this.transportationDetails != null) {
data['transportationDetails'] = this.transportationDetails!.toJson();
}
return data;
}
}
class TransportationDetails {
int? direction;
int? haveAppointment;
int? tripType;
int? pickupUrgency;
int? pickupSpot;
String? pickupDateTime;
String? transportationType;
int? ambulate;
String? ambulateTitle;
String? notes;
int? requesterFileNo;
String? requesterMobileNo;
bool? requesterIsOutSA;
String? pickupLocationName;
String? dropoffLocationName;
String? pickupLatitude;
String? pickupLongitude;
String? dropoffLatitude;
String? dropoffLongitude;
String? appointmentNo;
String? appointmentClinicName;
String? appointmentDoctorName;
String? appointmentBranch;
String? appointmentTime;
TransportationDetails(
{this.direction,
this.haveAppointment,
this.tripType,
this.pickupUrgency,
this.pickupSpot,
this.pickupDateTime,
this.transportationType,
this.ambulate,
this.ambulateTitle,
this.notes,
this.requesterFileNo,
this.requesterMobileNo,
this.requesterIsOutSA,
this.pickupLocationName,
this.dropoffLocationName,
this.pickupLatitude,
this.pickupLongitude,
this.dropoffLatitude,
this.dropoffLongitude,
this.appointmentNo,
this.appointmentClinicName,
this.appointmentDoctorName,
this.appointmentBranch,
this.appointmentTime});
TransportationDetails.fromJson(Map<String, dynamic> json) {
direction = json['direction'];
haveAppointment = json['haveAppointment'];
tripType = json['tripType'];
pickupUrgency = json['pickupUrgency'];
pickupSpot = json['pickupSpot'];
pickupDateTime = json['pickupDateTime'];
transportationType = json['transportationType'];
ambulate = json['ambulate'];
ambulateTitle = "";
notes = json['notes'];
requesterFileNo = json['requesterFileNo'];
requesterMobileNo = json['requesterMobileNo'];
requesterIsOutSA = json['requesterIsOutSA'];
pickupLocationName = json['pickupLocationName'];
dropoffLocationName = json['dropoffLocationName'];
pickupLatitude = json['pickup_Latitude'];
pickupLongitude = json['pickup_Longitude'];
dropoffLatitude = json['dropoff_Latitude'];
dropoffLongitude = json['dropoff_Longitude'];
appointmentNo = json['appointmentNo'];
appointmentClinicName = json['appointmentClinicName'];
appointmentDoctorName = json['appointmentDoctorName'];
appointmentBranch = json['appointmentBranch'];
appointmentTime = json['appointmentTime'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['direction'] = this.direction;
data['haveAppointment'] = this.haveAppointment;
data['tripType'] = this.tripType;
data['pickupUrgency'] = this.pickupUrgency;
data['pickupSpot'] = this.pickupSpot;
data['pickupDateTime'] = this.pickupDateTime;
data['transportationType'] = this.transportationType;
data['ambulate'] = this.ambulate;
data['ambulateTitle'] = this.ambulateTitle;
data['notes'] = this.notes;
data['requesterFileNo'] = this.requesterFileNo;
data['requesterMobileNo'] = this.requesterMobileNo;
data['requesterIsOutSA'] = this.requesterIsOutSA;
data['pickupLocationName'] = this.pickupLocationName;
data['dropoffLocationName'] = this.dropoffLocationName;
data['pickup_Latitude'] = this.pickupLatitude;
data['pickup_Longitude'] = this.pickupLongitude;
data['dropoff_Latitude'] = this.dropoffLatitude;
data['dropoff_Longitude'] = this.dropoffLongitude;
data['appointmentNo'] = this.appointmentNo;
data['appointmentClinicName'] = this.appointmentClinicName;
data['appointmentDoctorName'] = this.appointmentDoctorName;
data['appointmentBranch'] = this.appointmentBranch;
data['appointmentTime'] = this.appointmentTime;
return data;
}
}

@ -0,0 +1,56 @@
class PatientERTransportationMethod {
int? iD;
String? serviceID;
int? orderServiceID;
String? text;
String? textN;
dynamic price;
dynamic priceVAT;
dynamic priceTotal;
bool? isEnabled;
int? orderId;
int? quantity;
PatientERTransportationMethod(
{this.iD,
this.serviceID,
this.orderServiceID,
this.text,
this.textN,
this.price,
this.priceVAT,
this.priceTotal,
this.isEnabled,
this.orderId,
this.quantity});
PatientERTransportationMethod.fromJson(Map<String, dynamic> json) {
iD = json['ID'];
serviceID = json['ServiceID'];
orderServiceID = json['OrderServiceID'];
text = json['Text'];
textN = json['TextN'];
price = json['Price'];
priceVAT = json['PriceVAT'];
priceTotal = json['PriceTotal'];
isEnabled = json['IsEnabled'];
orderId = json['OrderId'];
quantity = json['Quantity'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['ID'] = this.iD;
data['ServiceID'] = this.serviceID;
data['OrderServiceID'] = this.orderServiceID;
data['Text'] = this.text;
data['TextN'] = this.textN;
data['Price'] = this.price;
data['PriceVAT'] = this.priceVAT;
data['PriceTotal'] = this.priceTotal;
data['IsEnabled'] = this.isEnabled;
data['OrderId'] = this.orderId;
data['Quantity'] = this.quantity;
return data;
}
}

@ -0,0 +1,80 @@
class GeocodeResponse {
final List<GeocodeResult> results;
final String status;
GeocodeResponse({
required this.results,
required this.status,
});
factory GeocodeResponse.fromJson(Map<String, dynamic> json) {
final resultsList = (json['results'] as List<dynamic>? ?? [])
.map((e) => GeocodeResult.fromJson(e as Map<String, dynamic>))
.toList();
return GeocodeResponse(
results: resultsList,
status: json['status'] ?? '',
);
}
@override
String toString() {
return 'GeocodeResponse(status: $status, results: [${results.map((r) => r.toString()).join(', ')}])';
}
}
class GeocodeResult {
final String formattedAddress;
final Geometry geometry;
final String placeId;
GeocodeResult({
required this.formattedAddress,
required this.geometry,
required this.placeId,
});
factory GeocodeResult.fromJson(Map<String, dynamic> json) {
return GeocodeResult(
formattedAddress: json['formatted_address'] ?? '',
geometry: Geometry.fromJson(json['geometry']),
placeId: json['place_id'] ?? '',
);
}
@override
String toString() {
return 'GeocodeResult(formattedAddress: $formattedAddress, placeId: $placeId, geometry: ${geometry.toString()})';
}
}
class Geometry {
final Location location;
Geometry({required this.location});
factory Geometry.fromJson(Map<String, dynamic> json) {
return Geometry(
location: Location.fromJson(json['location']),
);
}
@override
String toString() => 'Geometry(location: ${location.toString()})';
}
class Location {
final double lat;
final double lng;
Location({required this.lat, required this.lng});
factory Location.fromJson(Map<String, dynamic> json) {
return Location(
lat: (json['lat'] as num).toDouble(),
lng: (json['lng'] as num).toDouble(),
);
}
@override
String toString() => 'Location(lat: $lat, lng: $lng)';
}

@ -0,0 +1,14 @@
class PlaceDetails {
final double lat;
final double lng;
PlaceDetails({required this.lat, required this.lng});
factory PlaceDetails.fromJson(Map<String, dynamic> json) {
final loc = json['result']['geometry']['location'];
return PlaceDetails(
lat: (loc['lat'] as num).toDouble(),
lng: (loc['lng'] as num).toDouble(),
);
}
}

@ -0,0 +1,11 @@
class PlacePrediction {
final String description;
final String placeID;
PlacePrediction({required this.description, required this.placeID});
factory PlacePrediction.fromJson(Map<String, dynamic> json) {
return PlacePrediction(
description: json['description'] ?? '',
placeID: json['place_id'] ?? '',
);
}
}

@ -0,0 +1,153 @@
import 'package:dartz/dartz.dart';
import 'package:hmg_patient_app_new/core/api/api_client.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/location/GeocodeResponse.dart';
import 'package:hmg_patient_app_new/features/location/PlaceDetails.dart';
import '../../core/api_consts.dart';
import 'PlacePrediction.dart';
abstract class LocationRepo {
Future<Either<Failure, GenericApiModel<List<PlacePrediction>>>>
getPlacePredictionsAsInput(String input);
Future<Either<Failure, GenericApiModel<PlaceDetails>>>
getPlaceDetailsOfSelectedPrediction(String placeId);
Future<Either<Failure, GenericApiModel<GeocodeResponse>>>
getGeoCodeFromLatLng(double lat, double lng);
}
class LocationRepoImpl implements LocationRepo {
final ApiClient apiClient;
LocationRepoImpl({required this.apiClient});
@override
Future<Either<Failure, GenericApiModel<List<PlacePrediction>>>> getPlacePredictionsAsInput(
String input) async {
final url = Uri.parse(
'https://maps.googleapis.com/maps/api/place/autocomplete/json?input=$input&region=SA&key=$GOOGLE_API_KEY',
);
GenericApiModel<List<PlacePrediction>>? apiResponse;
Failure? failure;
try {
await apiClient.get(
url.toString(),
isExternal: true,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['predictions'];
final predictionsList = list
.map((item) =>
PlacePrediction.fromJson(item as Map<String, dynamic>))
.toList()
.cast<PlacePrediction>();
apiResponse = GenericApiModel<List<PlacePrediction>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: predictionsList,
);
} 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<GeocodeResponse>>> getGeoCodeFromLatLng(double lat, double lng) async {
final url = Uri.parse(
'https://maps.googleapis.com/maps/api/geocode/json?latlng=$lat,$lng&key=$GOOGLE_API_KEY',
);
GenericApiModel<GeocodeResponse>? apiResponse;
Failure? failure;
try {
await apiClient.get(
url.toString(),
isExternal: true,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final predictionsList = GeocodeResponse.fromJson(response);
apiResponse = GenericApiModel<GeocodeResponse>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: predictionsList,
);
} 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<PlaceDetails>>> getPlaceDetailsOfSelectedPrediction(String placeId) async {
final url = Uri.parse(
'https://maps.googleapis.com/maps/api/place/details/json'
'?place_id=$placeId&fields=geometry&key=$GOOGLE_API_KEY',
);
GenericApiModel<PlaceDetails>? apiResponse;
Failure? failure;
try {
await apiClient.get(
url.toString(),
isExternal: true,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final predictionsList = PlaceDetails.fromJson(response);
apiResponse = GenericApiModel<PlaceDetails>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: predictionsList,
);
} 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,120 @@
import 'dart:async';
import 'package:flutter/foundation.dart' show ChangeNotifier;
import 'package:flutter/material.dart';
import 'package:google_maps_flutter_platform_interface/src/types/camera.dart';
import 'package:hmg_patient_app_new/features/location/GeocodeResponse.dart';
import 'package:hmg_patient_app_new/features/location/PlaceDetails.dart';
import 'package:hmg_patient_app_new/features/location/location_repo.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
import 'package:huawei_map/huawei_map.dart' as HMSCameraServices;
import 'package:google_maps_flutter/google_maps_flutter.dart' as GMSMapServices;
import 'PlacePrediction.dart';
class LocationViewModel extends ChangeNotifier {
final LocationRepo locationRepo;
final ErrorHandlerService errorHandlerService;
LocationViewModel({required this.locationRepo, required this.errorHandlerService});
List<PlacePrediction> predictions = [];
PlacePrediction? selectedPrediction;
bool isPredictionLoading = false;
GeocodeResponse? geocodeResponse;
PlaceDetails? placeDetails;
Location? mapCapturedLocation;
FutureOr<void> getPlacesPrediction(String input) async {
predictions = [];
isPredictionLoading= true;
final result = await locationRepo.getPlacePredictionsAsInput(input);
result.fold(
(failure) {
errorHandlerService.handleError(failure: failure);
},
(apiModel) {
predictions = apiModel.data??[];
},
);
isPredictionLoading = false;
notifyListeners();
}
FutureOr<void> getPlaceEncodedData(double? lat, double? lng) async {
geocodeResponse = null;
final result = await locationRepo.getGeoCodeFromLatLng(lat!, lng!);
result.fold(
(failure) {
errorHandlerService.handleError(failure: failure);
},
(apiModel) {
print("Geocode Response: ${apiModel.data}");
geocodeResponse = apiModel.data;
},
);
notifyListeners();
}
FutureOr<void> getPlaceDetails(String placeID) async {
placeDetails = null;
final result = await locationRepo.getPlaceDetailsOfSelectedPrediction(placeID);
result.fold(
(failure) {
errorHandlerService.handleError(failure: failure);
},
(apiModel) {
placeDetails = apiModel.data;
},
);
notifyListeners();
}
handleGMSMapCameraMoved(GMSMapServices.CameraPosition value) {
mapCapturedLocation = Location(lat: value.target.latitude, lng: value.target.longitude);
}
handleHMSMapCameraMoved(HMSCameraServices.CameraPosition value) {
mapCapturedLocation = Location(lat: value.target.lat, lng: value.target.lng);
}
handleOnCameraIdle(){
if(mapCapturedLocation != null) {
getPlaceEncodedData(mapCapturedLocation!.lat, mapCapturedLocation!.lng);
}
}
void updateSearchQuery(String? value) {
if(value == null || value.isEmpty){
predictions = [];
return;
}
getPlacesPrediction(value);
}
void flushSearchPredictions() {
predictions = [];
mapCapturedLocation= null;
placeDetails= null;
geocodeResponse= null;
selectedPrediction= null;
notifyListeners();
}
FutureOr<void> selectPlacePrediction(PlacePrediction placePrediction) async{
selectedPrediction= placePrediction;
await getPlaceDetails(placePrediction.placeID);
}
}

@ -101,4 +101,6 @@ class HospitalsModel {
data['UsingInDoctorApp'] = this.usingInDoctorApp;
return data;
}
}

@ -17,6 +17,7 @@ import 'package:hmg_patient_app_new/features/immediate_livecare/immediate_liveca
import 'package:hmg_patient_app_new/features/insurance/insurance_view_model.dart';
import 'package:hmg_patient_app_new/features/lab/history/lab_history_viewmodel.dart';
import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart';
import 'package:hmg_patient_app_new/features/location/location_view_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/medical_file_view_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/appointment_via_region_viewmodel.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart';
@ -129,6 +130,8 @@ void main() async {
),
ChangeNotifierProvider<EmergencyServicesViewModel>(
create: (_) => getIt.get<EmergencyServicesViewModel>(),
),ChangeNotifierProvider<LocationViewModel>(
create: (_) => getIt.get<LocationViewModel>(),
)
], child: MyApp()),
),

@ -72,6 +72,7 @@ class HospitalListItem extends StatelessWidget {
);
Widget get distanceInfo => Row(
spacing: 4.w,
children: [
Visibility(
visible: (hospitalData?.distanceInKMs != "0"),
@ -91,9 +92,9 @@ class HospitalListItem extends StatelessWidget {
labelText: "Distance not available".needTranslation,
textColor: AppColors.blackColor,
),
SizedBox(
width: 8.h,
)
// SizedBox(
// width: 8.h,
// )
],
)),
Visibility(

@ -8,10 +8,14 @@ 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/models/AmbulanceCallingPlace.dart';
import 'package:hmg_patient_app_new/features/location/location_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_checkin_bottom_sheet.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/requesting_services_page.dart' show RequestingServicesPage;
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/tracking_screen.dart' show TrackingScreen;
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/widgets/HospitalBottomSheetBody.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/widgets/location_input_bottom_sheet.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/CustomSwitch.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
@ -30,13 +34,37 @@ class CallAmbulancePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
bottomSheet: ExpandableBottomSheet(
bottomSheetType:
context.watch<EmergencyServicesViewModel>().bottomSheetType,
children: {
BottomSheetType.EXPANDED: ExpanedBottomSheet(context),
BottomSheetType.FIXED: FixedBottomSheet(context),
},
floatingActionButton: Visibility(
visible: context.watch<EmergencyServicesViewModel>().bottomSheetType ==
BottomSheetType.FIXED,
child: Padding(
padding: EdgeInsetsDirectional.only(end: 8.h, bottom: 68.h),
child: DecoratedBox(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor, borderRadius: 12.h),
child: Utils.buildSvgWithAssets(
icon: AppAssets.locate_me, width: 24.h, height: 24.h)
.paddingAll(12.h)
.onPress(() {
context
.read<EmergencyServicesViewModel>()
.moveToCurrentLocation();
}),
),
),
),
bottomSheet: Column(
mainAxisSize: MainAxisSize.min,
children: [
ExpandableBottomSheet(
bottomSheetType:
context.watch<EmergencyServicesViewModel>().bottomSheetType,
children: {
BottomSheetType.EXPANDED: ExpanedBottomSheet(context),
BottomSheetType.FIXED: FixedBottomSheet(context),
},
),
],
),
body: Stack(
children: [
@ -46,22 +74,40 @@ class CallAmbulancePage extends StatelessWidget {
currentLocation:
context.read<EmergencyServicesViewModel>().getGMSLocation(),
onCameraMoved: (value) => context
.read<EmergencyServicesViewModel>()
.handleGMSMapCameraMoved(value))
.read<LocationViewModel>()
.handleGMSMapCameraMoved(value),
onCameraIdle:
context.read<LocationViewModel>().handleOnCameraIdle,
myLocationEnabled: true,
inputController:
context.read<EmergencyServicesViewModel>().gmsController,
showCenterMarker: true,
)
else
HMSMap(
currentLocation:
context.read<EmergencyServicesViewModel>().getHMSLocation(),
onCameraMoved: (value) => context
.read<EmergencyServicesViewModel>()
.handleHMSMapCameraMoved(value)),
.read<LocationViewModel>()
.handleHMSMapCameraMoved(value),
onCameraIdle:
context.read<LocationViewModel>().handleOnCameraIdle,
myLocationEnabled: false,
inputController:
context.read<EmergencyServicesViewModel>().hmsController,
showCenterMarker: true,
),
Align(
alignment: AlignmentDirectional.topStart,
child: Utils.buildSvgWithAssets(
icon: AppAssets.closeBottomNav, width: 32.h, height: 32.h),
).paddingOnly(top: 51.h, left: 24.h).onPress((){
Navigator.pop(context);
})
icon: AppAssets.closeBottomNav, width: 32.h, height: 32.h)
.onPress(() {
context
.read<EmergencyServicesViewModel>()
.flushPickupInformation();
Navigator.pop(context);
}),
).paddingOnly(top: 51.h, left: 24.h),
],
),
);
@ -70,7 +116,6 @@ class CallAmbulancePage extends StatelessWidget {
Widget FixedBottomSheet(BuildContext context) {
return GestureDetector(
onVerticalDragUpdate: (details){
print("the delta is ${details.delta.dy}");
if(details.delta.dy<0){
@ -81,22 +126,24 @@ class CallAmbulancePage extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Padding(
padding: EdgeInsetsDirectional.only(end:24.h, bottom: 24.h),
child: DecoratedBox(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor, borderRadius: 12.h),
child: Utils.buildSvgWithAssets(
icon: AppAssets.locate_me, width: 24.h, height: 24.h)
.paddingAll(12.h),
),
),
],
),
// Row(
// mainAxisAlignment: MainAxisAlignment.end,
// children: [
// Padding(
//
// padding: EdgeInsetsDirectional.only(end:24.h, bottom: 24.h),
// child: DecoratedBox(
// decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
// color: AppColors.whiteColor, borderRadius: 12.h),
// child: Utils.buildSvgWithAssets(
// icon: AppAssets.locate_me, width: 24.h, height: 24.h)
// .paddingAll(12.h).onPress((){
// context.read<EmergencyServicesViewModel>().moveToCurrentLocation();
// }),
// ),
// ),
// ],
// ),
// PositionedDirectional(
// end: 1,
// child: Padding(
@ -116,25 +163,7 @@ class CallAmbulancePage extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
spacing: 24.h,
children: [
TextInputWidget(
labelText: "Enter Pickup Location Manually".needTranslation,
hintText: "Enter Pickup Location".needTranslation,
leadingIcon: AppAssets.location_pickup,
isAllowLeadingIcon: true,
isEnable: false,
prefix: null,
autoFocus: false,
isBorderAllowed: false,
keyboardType: TextInputType.text,
padding: EdgeInsets.symmetric(
vertical: ResponsiveExtension(10).h,
horizontal: ResponsiveExtension(15).h,
),
).onPress(() {
context
.read<EmergencyServicesViewModel>()
.updateBottomSheetState(BottomSheetType.EXPANDED);
}).paddingOnly(right: 24.h, left: 24.h),
inputFields(context),
SizedBox(
height: 200.h,
child: DecoratedBox(
@ -152,11 +181,11 @@ class CallAmbulancePage extends StatelessWidget {
Column(
spacing: 4.h,
children: [
"Select Pickup Location".needTranslation.toText21(
"Select Pickup Details".needTranslation.toText21(
weight: FontWeight.w600,
color: AppColors.textColor,
),
" Please select the location of pickup"
" Please select the details of pickup"
.needTranslation
.toText12(
fontWeight: FontWeight.w500,
@ -165,7 +194,7 @@ class CallAmbulancePage extends StatelessWidget {
],
),
CustomButton(
text: "Select Location".needTranslation,
text: "Select Details".needTranslation,
onPressed: () {
context
.read<EmergencyServicesViewModel>()
@ -207,11 +236,11 @@ class CallAmbulancePage extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 16.h,
children: [
"Select Pickup Location".needTranslation.toText21(
weight: FontWeight.w600,
color: AppColors.textColor,
),
locationsSections(context),
// "Select Pickup Location".needTranslation.toText21(
// weight: FontWeight.w600,
// color: AppColors.textColor,
// ),
// locationsSections(context),
hospitalAndPickUpSection(context),
],
@ -281,44 +310,72 @@ class CallAmbulancePage extends StatelessWidget {
return DecoratedBox(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.h,
borderRadius: 24.r,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 16.h,
children: [
// Row(
// children: [
// hospitalAndPickUpItemContent(
// title: "Select Hospital".needTranslation,
// subTitle: "hospital".needTranslation,
// leadingIcon: AppAssets.hospital,
// ),
// Utils.buildSvgWithAssets(icon: AppAssets.down_cheveron,
// width: 24.h, height: 24.h)
// .paddingAll(16.h)
// ],
// ).onPress((){
// showHospitalBottomSheet(context);
// }),
// SizedBox(height: 16.h),
// Divider(
// color: AppColors.bottomNAVBorder,
// height: 1,
// thickness: 1,
// ),
// SizedBox(height: 16.h),
Row(
children: [
hospitalAndPickUpItemContent(
title: "Select Hospital".needTranslation,
subTitle: "hospital".needTranslation,
leadingIcon: AppAssets.hospital,
title: "Pick".needTranslation,
subTitle: "Inside the home".needTranslation,
leadingIcon: AppAssets.pickup_bed,
),
Utils.buildSvgWithAssets(icon: AppAssets.down_cheveron,
width: 24.h, height: 24.h)
.paddingAll(16.h)
CustomSwitch(
value: context
.watch<EmergencyServicesViewModel>()
.pickupFromInsideTheLocation,
onChanged: (value){
context
.read<EmergencyServicesViewModel>()
.updateThePickupPlaceFromLocation(value);
},
)
],
).onPress((){
showHospitalBottomSheet(context);
}),
SizedBox(height: 16.h),
Divider(
color: AppColors.bottomNAVBorder,
height: 1,
thickness: 1,
),
SizedBox(height: 16.h),
Row(
children: [
hospitalAndPickUpItemContent(
title: "Pick".needTranslation,
subTitle: "Inside the home".needTranslation,
leadingIcon: AppAssets.pickup_bed,
title: '',
subTitle: "Have any appointment".needTranslation,
leadingIcon: AppAssets.appointment_checkin_icon,
),
CustomSwitch(
value: context.watch<EmergencyServicesViewModel>().isGMSAvailable,
onChanged: (value){
context.read<EmergencyServicesViewModel>().setIsGMSAvailable( value);
value: context
.watch<EmergencyServicesViewModel>()
.haveAnAppointment,
onChanged: (value) {
if (value) {
openAppointmentList(context);
}
context
.read<EmergencyServicesViewModel>()
.updateAppointment(value);
},
)
],
@ -354,13 +411,22 @@ class CallAmbulancePage extends StatelessWidget {
this.leadingIcon(leadingIcon),
Expanded(
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
title.toText12(
color: AppColors.greyTextColor,
fontWeight: FontWeight.w500,
Visibility(
visible: title.isNotEmpty,
child: Column(
children: [
title.toText12(
color: AppColors.greyTextColor,
fontWeight: FontWeight.w500,
),
SizedBox(height: 2.h),
],
),
),
SizedBox(height: 2.h),
subTitle.toText14(
color: AppColors.textColor,
weight: FontWeight.w500,
@ -418,15 +484,24 @@ class CallAmbulancePage extends StatelessWidget {
],
),
),
"\$250".toText24(
fontWeight: FontWeight.w600,
color: AppColors.textColor,
)
],
),
CustomButton(
text: "Submit Request".needTranslation,
onPressed: () {
Utils.getPaymentAmountWithSymbol(
(Utils.formatNumberToInternationalFormat(context
.read<EmergencyServicesViewModel>()
.getTotalPrice() ??
0))
.toText24(
fontWeight: FontWeight.w600,
color: AppColors.textColor,
letterSpacing: -2),
AppColors.blackColor,
17.h)
// Utils.getPaymentAmountWithSymbol2(context.read<EmergencyServicesViewModel>().selectedTransportOption?.priceTotal??"0", letterSpacing: -2)
],
),
CustomButton(
text: "Submit Request".needTranslation,
onPressed: () {
Navigator.push(context, CustomPageRoute(page: RequestingServicesPage()));
})
],
@ -441,7 +516,26 @@ class CallAmbulancePage extends StatelessWidget {
title:
LocaleKeys.selectHospital.tr(),
context,
child: HospitalBottomSheetBody(),
child: Consumer<EmergencyServicesViewModel>(
builder:(_,vm,__)=> HospitalBottomSheetBody(
displayList: vm.displayList,
onFacilityClicked: (value) {
vm.setSelectedFacility(value);
vm.getDisplayList();
},
onHospitalClicked: (hospital) {
Navigator.pop(context);
vm.setSelectedHospital(hospital);
},
onHospitalSearch: (value) {
vm.searchHospitals(value ?? "");
},
selectedFacility:
vm.selectedFacility,
hmcCount: vm.hmcCount,
hmgCount: vm.hmgCount,
),
),
isFullScreen: false,
isCloseButtonVisible: true,
hasBottomPadding: false,
@ -449,4 +543,124 @@ class CallAmbulancePage extends StatelessWidget {
callBackFunc: () {},
);
}
///it will show the places field first and then hospital field
PlaceFirstThanHospitalField(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 16.h,
children: [
textPlaceInput(context),
hospitalField(context),
],
).paddingOnly(right: 24.h, left: 24.h);
}
HospitalFieldFirstThanPlaces(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 16.h,
children: [hospitalField(context), textPlaceInput(context)],
).paddingOnly(right: 24.h, left: 24.h);
}
textPlaceInput(context) {
return Consumer<LocationViewModel>(builder: (_, vm, __) {
print(
"the data is ${vm.geocodeResponse?.results.first.formattedAddress ?? vm.selectedPrediction?.description}");
return SizedBox(
width: MediaQuery.sizeOf(context).width,
child: TextInputWidget(
labelText: "Enter Pickup Location Manually".needTranslation,
hintText: "Enter Pickup Location".needTranslation,
controller: TextEditingController(
text: vm.geocodeResponse?.results.first.formattedAddress ??
vm.selectedPrediction?.description,
),
leadingIcon: AppAssets.location_pickup,
isAllowLeadingIcon: true,
isEnable: false,
prefix: null,
autoFocus: false,
isBorderAllowed: false,
keyboardType: TextInputType.text,
padding: EdgeInsets.symmetric(
vertical: ResponsiveExtension(10).h,
horizontal: ResponsiveExtension(15).h,
),
).onPress(() {
openLocationInputBottomSheet(context);
}),
);
});
}
///decide which field to show first based on the selected calling place
inputFields(BuildContext context) {
return context.read<EmergencyServicesViewModel>().callingPlace ==
AmbulanceCallingPlace.FROM_HOSPITAL
? HospitalFieldFirstThanPlaces(context)
: PlaceFirstThanHospitalField(context);
}
openLocationInputBottomSheet(BuildContext context) {
context.read<LocationViewModel>().flushSearchPredictions();
showCommonBottomSheetWithoutHeight(
title: "".needTranslation,
context,
child: SizedBox(
height: MediaQuery.sizeOf(context).height * .8,
child: LocationInputBottomSheet(),
),
isFullScreen: false,
isCloseButtonVisible: true,
hasBottomPadding: false,
backgroundColor: AppColors.bottomSheetBgColor,
callBackFunc: () {},
);
}
hospitalField(BuildContext context) {
return DecoratedBox(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor, borderRadius: 12.h),
child: Row(
children: [
hospitalAndPickUpItemContent(
title: "Select Hospital".needTranslation,
subTitle: context
.read<EmergencyServicesViewModel>()
.getSelectedHospitalName() ??
"hospital".needTranslation,
leadingIcon: AppAssets.hospital,
),
Utils.buildSvgWithAssets(
icon: AppAssets.down_cheveron, width: 24.h, height: 24.h)
.paddingAll(16.h)
],
).onPress(() {
print("the item is clicked");
showHospitalBottomSheet(context);
}).paddingSymmetrical(
10.w,
12.h,
),
);
}
void openAppointmentList(BuildContext context) {
// showCommonBottomSheetWithoutHeight(
// title: "".needTranslation,
// context,
// child: SizedBox(
// height: MediaQuery.sizeOf(context).height * .6,
// child: AppointmentBottomSheet(),
// ),
// isFullScreen: false,
// isCloseButtonVisible: true,
// hasBottomPadding: false,
// backgroundColor: AppColors.bottomSheetBgColor,
// callBackFunc: () {},
// );
}
}

@ -203,11 +203,17 @@ class TrackingScreen extends StatelessWidget {
if (context.read<EmergencyServicesViewModel>().isGMSAvailable || Platform.isIOS) {
return GMSMap(
myLocationEnabled: false,
onCameraIdle: (){
},
currentLocation: context.read<EmergencyServicesViewModel>().getGMSLocation(),
onCameraMoved: (value) => context.read<EmergencyServicesViewModel>().handleGMSMapCameraMoved(value));
} else {
return HMSMap(
myLocationEnabled: false,
onCameraIdle: (){
},
currentLocation: context.read<EmergencyServicesViewModel>().getHMSLocation(),
onCameraMoved: (value) => context.read<EmergencyServicesViewModel>().handleHMSMapCameraMoved(value));
}

@ -2,12 +2,17 @@ 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/debouncer.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/emergency_services/emergency_services_view_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/appointment_via_region_viewmodel.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/facility_selection.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/doctor_list_api_response.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart' show HospitalsModel;
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';
@ -20,8 +25,20 @@ import 'package:provider/provider.dart';
class HospitalBottomSheetBody extends StatelessWidget {
final TextEditingController searchText = TextEditingController();
final Debouncer debouncer = Debouncer(milliseconds: 500);
HospitalBottomSheetBody({super.key});
final int hmcCount;
final int hmgCount;
final List<HospitalsModel>? displayList;
final FacilitySelection selectedFacility;
final Function(FacilitySelection) onFacilityClicked;
final Function(HospitalsModel) onHospitalClicked;
final Function(String) onHospitalSearch;
HospitalBottomSheetBody({super.key, required this.hmcCount, required this.hmgCount, this.displayList, required this.selectedFacility, required this.onFacilityClicked, required this.onHospitalClicked, required this.onHospitalSearch});
@override
Widget build(BuildContext context) {
@ -29,13 +46,14 @@ class HospitalBottomSheetBody extends StatelessWidget {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextInputWidget(
labelText: LocaleKeys.search.tr(),
hintText: LocaleKeys.searchHospital.tr(),
controller: searchText,
onChange: (value) {
debouncer.run((){
onHospitalSearch(value??"");
});
},
isEnable: true,
prefix: null,
@ -51,10 +69,11 @@ class HospitalBottomSheetBody extends StatelessWidget {
),
SizedBox(height: 24.h),
TypeSelectionWidget(
hmcCount: "0",
hmgCount: "0",
selectedFacility:selectedFacility ,
hmcCount: hmcCount.toString(),
hmgCount: hmgCount.toString(),
onitemClicked: (selectedValue){
onFacilityClicked(selectedValue);
},
),
SizedBox(height: 21.h),
@ -63,17 +82,17 @@ class HospitalBottomSheetBody extends StatelessWidget {
child: ListView.separated(
itemBuilder: (_, index)
{
var hospital = null;
var hospital = displayList?[index];
return HospitalListItem(
hospitalData: hospital,
isLocationEnabled: false,
hospitalData: Utils.convertToPatientDoctorAppointmentList(hospital),
isLocationEnabled: true,
).onPress(() {
onHospitalClicked(hospital!);
});},
separatorBuilder: (_, __) => SizedBox(
height: 16.h,
),
itemCount: 0,
itemCount: displayList?.length ?? 0,
))
],
);

@ -1,10 +1,14 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart' show AppAssets;
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/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/models/resp_model/PatientERTransportationMethod.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/widgets/transport_option_Item.dart' show TransportOptionItem;
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:provider/provider.dart';
class AmbulanceOptionSelectionBottomSheet extends StatelessWidget {
final Function onTap;
@ -12,40 +16,36 @@ class AmbulanceOptionSelectionBottomSheet extends StatelessWidget {
const AmbulanceOptionSelectionBottomSheet({super.key, required this.onTap});
@override
Widget build(BuildContext context) {
return Column(
spacing: 16.h,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
return Selector<EmergencyServicesViewModel,
List<PatientERTransportationMethod>>(
selector: (_, model) => model.transportationOptions,
builder: (_, data, __) => Column(
spacing: 16.h,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: ListView.separated(
separatorBuilder: (_,__)=> SizedBox(
height: 16.h,
),
itemCount: data.length??0,
itemBuilder: (_, index) => TransportOptionItem(
title: Utils.getTextWRTCurrentLanguage(data[index].text, data[index].textN),
subTitle: "",
firstIcon: AppAssets.location_pickup,
middleIcon: AppAssets.to_arrow,
lastIcon: AppAssets.hospital,
price: data[index].priceTotal.toString(),
onTap: () {
onTap();
context.read<EmergencyServicesViewModel>().setTransportationOption(data[index]);
},
),
),
),
TransportOptionItem(
title: "Home to Hospital (One Way)",
subTitle: "Pickup from home location to hospital",
firstIcon: AppAssets.location_pickup,
middleIcon:AppAssets.to_arrow,
lastIcon: AppAssets.hospital,
price: "150 AED",
onTap: (){onTap();},
),
TransportOptionItem(
title: "Hospital to Home (One Way)",
subTitle: "Pickup from hospital to home",
lastIcon: AppAssets.location_pickup,
middleIcon:AppAssets.to_arrow,
firstIcon: AppAssets.hospital,
price: "150 AED",
onTap: (){onTap();},
),
TransportOptionItem(
title: "Home to Hospital (Two Way)",
subTitle: "Pick from home to hospital then drop off to home",
firstIcon: AppAssets.location_pickup,
middleIcon:AppAssets.dual_arrow,
lastIcon: AppAssets.hospital,
price: "150 AED",
onTap: (){onTap();},
),
SizedBox(height: 16.h,)
],
],
),
);
}
}

@ -0,0 +1,92 @@
// import 'package:flutter/cupertino.dart';
// import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
// import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
// import 'package:hmg_patient_app_new/features/emergency_services/emergency_services_view_model.dart';
// import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
// import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_card.dart';
// import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/doctor_card.dart';
// import 'package:hmg_patient_app_new/theme/colors.dart';
// import 'package:provider/provider.dart';
//
// class AppointmentBottomSheet extends StatelessWidget{
// @override
// Widget build(BuildContext context) {
// // TODO: implement build
// throw UnimplementedError();
// }
//
// Widget getAppointList(EmergencyServicesViewModel viewmodel, List<PatientAppointmentHistoryResponseModel> filteredAppointmentList) {
// return Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// ListView.separated(
// padding: EdgeInsets.only(top: 24.h),
// shrinkWrap: true,
// physics: NeverScrollableScrollPhysics(),
// itemCount: viewmodel.isMyAppointmentsLoading
// ? 5
// : filteredAppointmentList.isNotEmpty
// ? filteredAppointmentList.length
// : 1,
// itemBuilder: (context, index) {
// return viewmodel.isMyAppointmentsLoading
// ? Container(
// decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true),
// child: DoctorCard(doctorsListResponseModel: doctorsListResponseModel, isLoading: viewmodel.isMyAppointmentsLoading, bookAppointmentsViewModel: bookAppointmentsViewModel),
// ).paddingSymmetrical(24.h, 0.h)
// : filteredAppointmentList.isNotEmpty
// ? AnimationConfiguration.staggeredList(
// position: index,
// duration: const Duration(milliseconds: 500),
// child: SlideAnimation(
// verticalOffset: 100.0,
// child: FadeInAnimation(
// child: AnimatedContainer(
// duration: Duration(milliseconds: 300),
// curve: Curves.easeInOut,
// decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true),
// child: AppointmentCard(
// patientAppointmentHistoryResponseModel: filteredAppointmentList[index],
// myAppointmentsViewModel: myAppointmentsViewModel,
// bookAppointmentsViewModel: bookAppointmentsViewModel,
// isLoading: false,
// isFromHomePage: false,
// ),
// ).paddingSymmetrical(24.h, 0.h),
// ),
// ),
// )
// : Utils.getNoDataWidget(
// context,
// noDataText: "You don't have any appointments yet.".needTranslation,
// callToActionButton: CustomButton(
// text: LocaleKeys.bookAppo.tr(context: context),
// onPressed: () {
// Navigator.of(context).push(
// CustomPageRoute(
// page: BookAppointmentPage(),
// ),
// );
// },
// backgroundColor: Color(0xffFEE9EA),
// borderColor: Color(0xffFEE9EA),
// textColor: Color(0xffED1C2B),
// fontSize: 14.f,
// fontWeight: FontWeight.w500,
// borderRadius: 12.r,
// padding: EdgeInsets.fromLTRB(10.w, 0, 10.w, 0),
// height: 40.h,
// icon: AppAssets.add_icon,
// iconColor: AppColors.primaryRedColor,
// ).paddingSymmetrical(48.h, 0.h),
// );
// },
// separatorBuilder: (BuildContext cxt, int index) => SizedBox(height: 16.h),
// ),
// SizedBox(height: 24.h),
// ],
// );
// }
//
//
// }

@ -0,0 +1,172 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_export.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/models/AmbulanceCallingPlace.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/ambulance_direction.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:provider/provider.dart';
import '../../../../generated/locale_keys.g.dart' show LocaleKeys;
class PickupLocation extends StatelessWidget {
final VoidCallback onTap;
const PickupLocation({super.key, required this.onTap});
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Select Pickup Direction"
.needTranslation
.toText24(color: AppColors.textColor,isBold: true),
SizedBox(
height: 16.h,
),
"Select Direction"
.needTranslation
.toText14(color: AppColors.textColor, weight: FontWeight.w600),
SizedBox(
height: 12.h,
),
Selector<EmergencyServicesViewModel, AmbulanceCallingPlace>(
selector: (context, viewModel) => viewModel.callingPlace,
builder: (context, value, _) {
return Column(
spacing: 12.h,
children: [
RadioGroup<AmbulanceCallingPlace>(
groupValue: value,
onChanged: (value) {
context
.read<EmergencyServicesViewModel>()
.updateCallingPlace(value);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
spacing: 24.h,
children: [
Row(
children: [
Radio(
value: AmbulanceCallingPlace.TO_HOSPITAL,
groupValue: value,
activeColor: AppColors.primaryRedColor,
fillColor: MaterialStateProperty.all(AppColors.primaryRedColor),
),
"To Hospital"
.needTranslation
.toText12(color: AppColors.textColor)
],
).onPress((){
context
.read<EmergencyServicesViewModel>()
.updateCallingPlace(AmbulanceCallingPlace.TO_HOSPITAL);
}),
Row(
children: [
Radio(
value: AmbulanceCallingPlace.FROM_HOSPITAL,
activeColor: AppColors.primaryRedColor,
fillColor: MaterialStateProperty.all(AppColors.primaryRedColor),
),
"From Hospital"
.needTranslation
.toText12(color: AppColors.textColor)
],
).onPress((){
context
.read<EmergencyServicesViewModel>()
.updateCallingPlace(AmbulanceCallingPlace.FROM_HOSPITAL);
}),
],
),
),
Visibility(
visible: value == AmbulanceCallingPlace.TO_HOSPITAL,
child: Selector<EmergencyServicesViewModel, AmbulanceDirection>(
selector: (context, viewModel) =>
viewModel.ambulanceDirection,
builder: (context, directionValue, _) {
return Column(
spacing: 12.h,
children: [
"Select Way"
.needTranslation
.toText14(color: AppColors.textColor, weight: FontWeight.w600),
RadioGroup<AmbulanceDirection>(
groupValue: directionValue,
onChanged: (value) {
context
.read<EmergencyServicesViewModel>()
.updateDirection(value);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
spacing: 24.h,
children: [
Row(
children: [
Radio(
value: AmbulanceDirection.ONE_WAY,
activeColor: AppColors.primaryRedColor,
fillColor: MaterialStateProperty.all(AppColors.primaryRedColor),
),
"One Way"
.needTranslation
.toText12(color: AppColors.textColor)
],
).onPress((){
context
.read<EmergencyServicesViewModel>()
.updateDirection(AmbulanceDirection.ONE_WAY);
}),
Row(
children: [
Radio(
value: AmbulanceDirection.TWO_WAY,
// activeColor: AppColors.primaryRedColor,
fillColor: MaterialStateProperty.all(AppColors.primaryRedColor),
),
"Two Way"
.needTranslation
.toText12(color: AppColors.textColor)
],
).onPress((){
context
.read<EmergencyServicesViewModel>()
.updateDirection(AmbulanceDirection.TWO_WAY);
}),
],
),
),
],
);
}),
)
],
);
}),
SizedBox(
height: 16.h,
),
CustomButton(
text: LocaleKeys.confirm.tr(context: context),
onPressed: onTap,
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
textColor: AppColors.whiteColor,
iconColor: AppColors.whiteColor,
),
],
);
}
}

@ -48,7 +48,6 @@ class TransportOptionItem extends StatelessWidget {
titleSection() {
return Row(
children: [
Expanded(
child: Column(
@ -56,8 +55,8 @@ class TransportOptionItem extends StatelessWidget {
children: [
title.toText16(
color: AppColors.textColor, weight: FontWeight.w600),
subTitle.toText12(
color: AppColors.greyTextColor, fontWeight: FontWeight.w500),
// subTitle.toText12(
// color: AppColors.greyTextColor, fontWeight: FontWeight.w500),
],
),
),
@ -69,18 +68,23 @@ class TransportOptionItem extends StatelessWidget {
headerSection() {
return Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Expanded(
child: Row(
children: [
buildIcon(firstIcon),
Utils.buildSvgWithAssets(
icon: middleIcon, width: 24.h, height: 24.h).paddingAll(8.h),
buildIcon(lastIcon)
],
),
// Expanded(
// child: Row(
// children: [
// buildIcon(firstIcon),
// Utils.buildSvgWithAssets(
// icon: middleIcon, width: 24.h, height: 24.h).paddingAll(8.h),
// buildIcon(lastIcon)
// ],
// ),
// ),
Utils.getPaymentAmountWithSymbol2(
num.tryParse(price) ?? 0.0,
fontSize: 18.f,
letterSpacing:-2
),
price.toText18(color: AppColors.textColor, weight: FontWeight.w600)
],
);
}

@ -12,10 +12,15 @@ import 'package:provider/provider.dart' show Consumer;
class TypeSelectionWidget extends StatelessWidget {
final String hmcCount;
final String hmgCount;
final Function(String) onitemClicked;
final FacilitySelection selectedFacility;
final Function(FacilitySelection) onitemClicked;
const TypeSelectionWidget(
{super.key, required this.hmcCount, required this.hmgCount, required this.onitemClicked});
{super.key,
required this.hmcCount,
required this.hmgCount,
required this.onitemClicked,
required this.selectedFacility});
@override
Widget build(BuildContext context) {
@ -28,51 +33,69 @@ class TypeSelectionWidget extends StatelessWidget {
labelText: "All Facilities".needTranslation,
shape: RoundedRectangleBorder(
side: BorderSide(
color: AppColors.errorColor
,
color: selectedFacility == FacilitySelection.ALL
? AppColors.errorColor
: AppColors.chipBorderColorOpacity20,
width: 1,
),
borderRadius: BorderRadius.circular(10)),
backgroundColor:
AppColors.secondaryLightRedColor
,
textColor: AppColors.errorColor
selectedFacility == FacilitySelection.ALL
?AppColors.secondaryLightRedColor: AppColors.whiteColor,
textColor: selectedFacility == FacilitySelection.ALL
? AppColors.errorColor:AppColors.blackColor
,
).onPress((){
onitemClicked(FacilitySelection.ALL.name);
}),
AppCustomChipWidget(
icon: AppAssets.hmg,
iconHasColor: false,
labelText: "Hospitals".needTranslation,
shape: RoundedRectangleBorder(
side: BorderSide(
color: AppColors.chipBorderColorOpacity20,
width: 1,
),
borderRadius: BorderRadius.circular(10)),
backgroundColor:
AppColors.whiteColor,
textColor: AppColors.blackColor,
).onPress((){
onitemClicked(FacilitySelection.HMG.name);
}),
AppCustomChipWidget(
icon: AppAssets.hmc,
iconHasColor: false,
labelText: "Medical Centers".needTranslation,
shape: RoundedRectangleBorder(
side: BorderSide(
color:AppColors.chipBorderColorOpacity20,
width: 1,
),
borderRadius: BorderRadius.circular(10)),
backgroundColor:
AppColors.whiteColor,
textColor: AppColors.blackColor,
).onPress((){
onitemClicked(FacilitySelection.HMC.name);
onitemClicked(FacilitySelection.ALL);
}),
Visibility(
visible: hmgCount != "0",
child: AppCustomChipWidget(
icon: AppAssets.hmg,
iconHasColor: false,
labelText: "Hospitals".needTranslation,
shape: RoundedRectangleBorder(
side: BorderSide(
color: selectedFacility == FacilitySelection.HMG
? AppColors.errorColor
: AppColors.chipBorderColorOpacity20,
width: 1,
),
borderRadius: BorderRadius.circular(10)),
backgroundColor:
selectedFacility == FacilitySelection.HMG
?AppColors.secondaryLightRedColor: AppColors.whiteColor,
textColor: selectedFacility == FacilitySelection.HMG
? AppColors.errorColor
: AppColors.blackColor,
).onPress((){
onitemClicked(FacilitySelection.HMG);
}),
),
Visibility(
visible: hmcCount != "0",
child: AppCustomChipWidget(
icon: AppAssets.hmc,
iconHasColor: false,
labelText: "Medical Centers".needTranslation,
shape: RoundedRectangleBorder(
side: BorderSide(
color: selectedFacility == FacilitySelection.HMC
? AppColors.errorColor
: AppColors.chipBorderColorOpacity20,
width: 1,
),
borderRadius: BorderRadius.circular(10)),
backgroundColor:
selectedFacility == FacilitySelection.HMC
?AppColors.secondaryLightRedColor: AppColors.whiteColor,
textColor: selectedFacility == FacilitySelection.HMC
? AppColors.errorColor
: AppColors.blackColor,
).onPress((){
onitemClicked(FacilitySelection.HMC);
}),
),
],
);
}

@ -8,10 +8,12 @@ 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/location/location_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/RRT/rrt_request_type_select.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/call_ambulance_page.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/widgets/ambulance_option_selection_bottomsheet.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/widgets/pickup_location.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/nearest_er_page.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
@ -114,23 +116,8 @@ class EmergencyServicesPage extends StatelessWidget {
onPressed: () async {
//
Navigator.of(context).pop();
showCommonBottomSheetWithoutHeight(
title:
"Transport Options".needTranslation,
context,
child: AmbulanceOptionSelectionBottomSheet(
onTap: () {
Navigator.of(context).pop();
context
.read<EmergencyServicesViewModel>()
.navigateTOAmbulancePage();
}),
isFullScreen: false,
isCloseButtonVisible: true,
hasBottomPadding: false,
backgroundColor: AppColors.bottomSheetBgColor,
callBackFunc: () {},
);
await emergencyServicesViewModel.getTransportationOption();
openTranportationSelectionBottomSheet(context);
},
backgroundColor: AppColors.whiteColor,
borderColor: AppColors.whiteColor,
@ -276,4 +263,68 @@ class EmergencyServicesPage extends StatelessWidget {
),
);
}
openPickupDetailsBottomSheet(BuildContext context){
showCommonBottomSheetWithoutHeight(
onCloseClicked: (){
context
.read<EmergencyServicesViewModel>()
.flushPickupInformation();
},
titleWidget: Transform.flip(
flipX: emergencyServicesViewModel.isArabic ? true : false,
child: Utils.buildSvgWithAssets(
icon: AppAssets.arrow_back,
iconColor: Color(0xff2B353E),
fit: BoxFit.contain,
),
).onPress(() {
context
.read<EmergencyServicesViewModel>()
.flushPickupInformation();
Navigator.pop(context);
openTranportationSelectionBottomSheet(context);
}),
context,
child: PickupLocation(
onTap: () {
Navigator.of(context).pop();
context.read<LocationViewModel>().flushSearchPredictions();
context
.read<EmergencyServicesViewModel>()
.navigateTOAmbulancePage();
}),
isFullScreen: false,
isCloseButtonVisible: true,
hasBottomPadding: false,
backgroundColor: AppColors.bottomSheetBgColor,
callBackFunc: () {},
);
}
void openTranportationSelectionBottomSheet(BuildContext context) {
if(emergencyServicesViewModel.transportationOptions.isNotEmpty) {
showCommonBottomSheetWithoutHeight(
title: "Transport Options".needTranslation,
context,
child: SizedBox(
height: 400.h,
child: AmbulanceOptionSelectionBottomSheet(
onTap: () {
Navigator.of(context).pop();
openPickupDetailsBottomSheet(context);
// context
// .read<EmergencyServicesViewModel>()
// .navigateTOAmbulancePage();
}),
),
isFullScreen: false,
isCloseButtonVisible: true,
hasBottomPadding: false,
backgroundColor: AppColors.bottomSheetBgColor,
callBackFunc: () {},
);
}
}
}

@ -7,7 +7,7 @@ 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/features/emergency_services/models/resp_model/ProjectAvgERWaitingTime.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/widgets/nearestERItem.dart' show NearestERItem;
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';

@ -0,0 +1,118 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'
show AnimationConfiguration, SlideAnimation, FadeInAnimation;
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/enums.dart';
import 'package:hmg_patient_app_new/core/utils/debouncer.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/location/GeocodeResponse.dart';
import 'package:hmg_patient_app_new/features/location/PlacePrediction.dart';
import 'package:hmg_patient_app_new/features/location/location_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/widgets/input_widget.dart';
import 'package:provider/provider.dart';
import '../../../theme/colors.dart';
import '../../appointments/widgets/hospital_bottom_sheet/type_selection_widget.dart';
class LocationInputBottomSheet extends StatelessWidget {
final Debouncer debouncer = Debouncer(milliseconds: 500);
LocationInputBottomSheet({super.key});
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextInputWidget(
labelText: LocaleKeys.search.tr(),
hintText: "Search Location".needTranslation,
controller: TextEditingController(),
onChange: (value){
debouncer.run(() {
context.read<LocationViewModel>().updateSearchQuery(value);
});
},
isEnable: true,
prefix: null,
autoFocus: false,
isBorderAllowed: false,
keyboardType: TextInputType.text,
isAllowLeadingIcon: true,
selectionType: SelectionTypeEnum.search,
padding: EdgeInsets.symmetric(
vertical: 10.h,
horizontal: 15.h,
),
),
SizedBox(height: 24.h),
Selector<LocationViewModel, List<PlacePrediction>>(
selector: (_, vm) => vm.predictions ?? <PlacePrediction>[],
builder: (context, predictions, _) {
if (predictions.isEmpty) return SizedBox.shrink();
return Expanded(
child: ListView.separated(
separatorBuilder: (_,__)=>SizedBox(height: 16.h,),
itemCount: predictions.length,
itemBuilder: (_, index) {
final prediction = predictions[index];
return AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 500),
child: SlideAnimation(
verticalOffset: 100.0,
child: FadeInAnimation(
child: AnimatedContainer(
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
decoration: RoundedRectangleBorder()
.toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.h,
hasShadow: true),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: prediction.description.toText14(
color: AppColors.textColor,
weight: FontWeight.w500),
),
Utils.buildSvgWithAssets(
icon: AppAssets.forward_arrow_icon_small,
iconColor: AppColors.blackColor,
width: 20.h,
height: 15.h,
fit: BoxFit.contain,
),
],
).paddingAll(24.h),),
),
),
).onPress(() async {
await context.read<LocationViewModel>().selectPlacePrediction(prediction);
Navigator.of(context).pop();
var location = context.read<LocationViewModel>().placeDetails;
if(location != null) {
context.read<EmergencyServicesViewModel>().moveController(
Location(lat: location.lat, lng: location.lng));
}
});
},
),
);
},
)
],
);
}
}

@ -5,7 +5,7 @@ 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/features/emergency_services/models/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';

@ -62,16 +62,20 @@ class DialogServiceImp implements DialogService {
message: message,
showCancel: onCancelPressed != null ? true : false,
onOkPressed: () {
print('ok button is pressed');
if (onOkPressed != null) {
print('onOkPressed is not null');
onOkPressed();
}else {
Navigator.pop(context);
}
context.pop();
},
onCancelPressed: () {
if (onCancelPressed != null) {
onCancelPressed();
}else {
Navigator.pop(context);
}
context.pop();
},
),
);

@ -63,6 +63,8 @@ static const Color alertLightColor = Color(0xFFD48D05);
static const Color infoLightColor = Color(0xFF0B85F7);
static const Color warningLightColor = Color(0xFFFFCC00);
static const Color greyLightColor = Color(0xFFEFEFF0);
static const Color thumbColor = Color(0xFF18C273);
static const Color switchBackgroundColor = Color(0x2618C273);
static const Color bottomNAVBorder = Color(0xFFEEEEEE);

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
class CustomSwitch extends StatefulWidget {
final bool value;
@ -17,21 +18,21 @@ class _CustomSwitchState extends State<CustomSwitch> {
return GestureDetector(
onTap: () => widget.onChanged(!widget.value),
child: Container(
width: 48.h,
width: 48.w,
height: 30.h,
decoration: BoxDecoration(
color: widget.value ? Color(0xFFE6F7F0) : Color(0xFFE6F7F0),
color: AppColors.switchBackgroundColor ,
borderRadius: BorderRadius.circular(18),
),
child: AnimatedAlign(
duration: Duration(milliseconds: 200),
duration: Duration(milliseconds: 300),
alignment: widget.value ? Alignment.centerRight : Alignment.centerLeft,
child: Container(
margin: EdgeInsets.all(4),
width: 28,
height: 28,
margin: EdgeInsets.all(2.h),
width: 28.w,
height: 28.h,
decoration: BoxDecoration(
color: Color(0xFF5FCB89),
color: AppColors.thumbColor,
shape: BoxShape.circle,
),
),

@ -116,6 +116,7 @@ void showCommonBottomSheetWithoutHeight(
bool useSafeArea = false,
bool hasBottomPadding = true,
Color backgroundColor = AppColors.bottomSheetBgColor,
VoidCallback? onCloseClicked
}) {
showModalBottomSheet<String>(
sheetAnimationStyle: AnimationStyle(
@ -170,6 +171,7 @@ void showCommonBottomSheetWithoutHeight(
icon: AppAssets.close_bottom_sheet_icon,
iconColor: Color(0xff2B353E),
).onPress(() {
onCloseClicked?.call();
Navigator.of(context).pop();
}),
],

@ -113,7 +113,7 @@ class TextInputWidget extends StatelessWidget {
children: [
Container(
padding: padding,
height: 58.h,
height: 64.h,
alignment: Alignment.center,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: Colors.white,

@ -1,41 +1,63 @@
import 'dart:async';
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:huawei_map/huawei_map.dart' ;
class HMSMap extends StatefulWidget{
final CameraPosition currentLocation;
final Function(CameraPosition) onCameraMoved;
final VoidCallback onCameraIdle;
final MapType mapType;
final bool compassEnabled;
final bool myLocationEnabled;
final bool showCenterMarker;
final Completer<HuaweiMapController>? inputController;
HMSMap({super.key, required this.currentLocation ,required this.onCameraMoved, this.mapType = MapType.normal,this.compassEnabled = false, this.myLocationEnabled = true});
HMSMap({super.key, required this.currentLocation ,required this.onCameraMoved,required this.onCameraIdle,
this.mapType = MapType.normal,this.compassEnabled = false,this.showCenterMarker = false,
this.myLocationEnabled = true, this.inputController});
@override
State<HMSMap> createState() => _HMSMapState();
}
class _HMSMapState extends State<HMSMap> {
final Completer<HuaweiMapController> _controller = Completer<HuaweiMapController>();
Completer<HuaweiMapController>? controller;
@override
void initState() {
HuaweiMapInitializer.initializeMap();
controller = widget.inputController ?? Completer<HuaweiMapController>();
super.initState();
}
// @override
@override
Widget build(BuildContext context) =>
HuaweiMap(
mapType: widget.mapType,
zoomControlsEnabled: false,
myLocationEnabled: widget.myLocationEnabled,
compassEnabled: widget.compassEnabled,
initialCameraPosition: widget.currentLocation,
onCameraMove: (value) => widget.onCameraMoved(value),
onMapCreated: (HuaweiMapController controller) {
_controller.complete(controller);
},
);
Stack(
children: [
HuaweiMap(
mapType: widget.mapType,
zoomControlsEnabled: false,
myLocationEnabled: widget.myLocationEnabled,
myLocationButtonEnabled: false,
compassEnabled: widget.compassEnabled,
onCameraIdle:()=> widget.onCameraIdle(),
initialCameraPosition: widget.currentLocation,
onCameraMove: (value) => widget.onCameraMoved(value),
onMapCreated: (HuaweiMapController controller) {
this.controller?.complete(controller);
},
),
Visibility(
visible: widget.showCenterMarker,
child: Align(
alignment: Alignment.center,
child: Utils.buildSvgWithAssets(icon: AppAssets.pin_location, width: 24.w, height: 36.h),
),
)
],
);
}

@ -2,31 +2,52 @@ import 'dart:async';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.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';
class GMSMap extends StatelessWidget{
final Completer<GoogleMapController> _controller = Completer<GoogleMapController>();
Completer<GoogleMapController>? controller;
final CameraPosition currentLocation;
final Function(CameraPosition) onCameraMoved;
final VoidCallback onCameraIdle;
final MapType mapType;
final bool compassEnabled;
final bool myLocationEnabled;
final bool showCenterMarker;
GMSMap({super.key, required this.currentLocation ,required this.onCameraMoved, this.mapType = MapType.normal,this.compassEnabled = false, this.myLocationEnabled = true});
GMSMap({super.key, required this.currentLocation ,required this.onCameraMoved,required this.onCameraIdle,
this.mapType = MapType.normal,this.compassEnabled = false,this.showCenterMarker = false,
this.myLocationEnabled = true,Completer<GoogleMapController>? inputController}){
controller = inputController ?? Completer<GoogleMapController>();
}
@override
Widget build(BuildContext context) {
return GoogleMap(
mapType: mapType,
zoomControlsEnabled: false,
myLocationEnabled: myLocationEnabled,
compassEnabled: compassEnabled,
initialCameraPosition: currentLocation,
onCameraMove: (value) => onCameraMoved(value),
onMapCreated: (GoogleMapController controller) {
_controller.complete(controller);
},
return Stack(
children: [
GoogleMap(
mapType: mapType,
zoomControlsEnabled: false,
myLocationEnabled: myLocationEnabled,
myLocationButtonEnabled: false,
compassEnabled: compassEnabled,
initialCameraPosition: currentLocation,
onCameraMove: (value) => onCameraMoved(value),
onCameraIdle: ()=>onCameraIdle(),
onMapCreated: (GoogleMapController controller) {
this.controller?.complete(controller);
},
),
Visibility(
visible: showCenterMarker,
child: Align(
alignment: Alignment.center,
child: Utils.buildSvgWithAssets(icon: AppAssets.pin_location, width: 24.w, height: 36.h),
),
)
],
);
}
}
Loading…
Cancel
Save