Merge pull request 'haroon_dev' (#213) from haroon_dev into master

Reviewed-on: https://34.17.182.140/Haroon6138/HMG_Patient_App_New/pulls/213
pull/214/head
Haroon6138 5 days ago
commit 6e2d87d172

@ -400,9 +400,13 @@ class BookAppointmentsViewModel extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
refreshDoctorsList() {
setIsDoctorsListLoading(true);
getDoctorsList(isNearest: isNearestAppointmentSelected);
}
setIsNearestAppointmentSelected(bool isNearestAppointmentSelected) { setIsNearestAppointmentSelected(bool isNearestAppointmentSelected) {
this.isNearestAppointmentSelected = isNearestAppointmentSelected; this.isNearestAppointmentSelected = isNearestAppointmentSelected;
if (isNearestAppointmentSelected) { if (isNearestAppointmentSelected) {
for (var group in doctorsListGrouped) { for (var group in doctorsListGrouped) {
group.sort((a, b) { group.sort((a, b) {
@ -646,7 +650,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
} }
//TODO: Make the API dynamic with parameters for ProjectID, isNearest, languageID, doctorId, doctorName //TODO: Make the API dynamic with parameters for ProjectID, isNearest, languageID, doctorId, doctorName
Future<void> getDoctorsList({int projectID = 0, bool isNearest = true, int doctorId = 0, String doctorName = "", Function(dynamic)? onSuccess, Function(String)? onError}) async { Future<void> getDoctorsList({int projectID = 0, bool isNearest = false, int doctorId = 0, String doctorName = "", Function(dynamic)? onSuccess, Function(String)? onError}) async {
doctorsList.clear(); doctorsList.clear();
filteredDoctorList.clear(); filteredDoctorList.clear();
doctorsListGrouped.clear(); doctorsListGrouped.clear();
@ -674,7 +678,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
clearSearchFilters(); clearSearchFilters();
getFiltersFromDoctorList(); getFiltersFromDoctorList();
_groupDoctorsList(); _groupDoctorsList();
setIsNearestAppointmentSelected(true); setIsNearestAppointmentSelected(isNearest);
notifyListeners(); notifyListeners();
if (onSuccess != null) { if (onSuccess != null) {
onSuccess(apiResponse); onSuccess(apiResponse);

@ -51,6 +51,7 @@ class PatientAppointmentHistoryResponseModel {
bool? isExecludeDoctor; bool? isExecludeDoctor;
dynamic isFollowup; dynamic isFollowup;
bool? isLiveCareAppointment; bool? isLiveCareAppointment;
bool? isLiveCareClinic;
bool? isInOutPatient; bool? isInOutPatient;
bool? isMedicalReportRequested; bool? isMedicalReportRequested;
bool? isOnlineCheckedIN; bool? isOnlineCheckedIN;
@ -128,6 +129,7 @@ class PatientAppointmentHistoryResponseModel {
this.isExecludeDoctor, this.isExecludeDoctor,
this.isFollowup, this.isFollowup,
this.isLiveCareAppointment, this.isLiveCareAppointment,
this.isLiveCareClinic,
this.isMedicalReportRequested, this.isMedicalReportRequested,
this.isOnlineCheckedIN, this.isOnlineCheckedIN,
this.latitude, this.latitude,
@ -205,6 +207,7 @@ class PatientAppointmentHistoryResponseModel {
isExecludeDoctor = json['IsExecludeDoctor']; isExecludeDoctor = json['IsExecludeDoctor'];
isFollowup = json['IsFollowup']; isFollowup = json['IsFollowup'];
isLiveCareAppointment = json['IsLiveCareAppointment']; isLiveCareAppointment = json['IsLiveCareAppointment'];
isLiveCareClinic = json['IsLiveCareClinic'];
isInOutPatient = json['IsInOutPatient']; isInOutPatient = json['IsInOutPatient'];
isMedicalReportRequested = json['IsMedicalReportRequested']; isMedicalReportRequested = json['IsMedicalReportRequested'];
isOnlineCheckedIN = json['IsOnlineCheckedIN']; isOnlineCheckedIN = json['IsOnlineCheckedIN'];

@ -930,6 +930,7 @@ class MyAppointmentsViewModel extends ChangeNotifier {
isPatientHasQueueAppointment = false; isPatientHasQueueAppointment = false;
isAppointmentQueueDetailsLoading = true; isAppointmentQueueDetailsLoading = true;
notifyListeners(); notifyListeners();
final result = await myAppointmentsRepo.getPatientAppointmentQueueDetails( final result = await myAppointmentsRepo.getPatientAppointmentQueueDetails(
appointmentNo: patientArrivedAppointmentsHistoryList.first.appointmentNo, patientID: patientArrivedAppointmentsHistoryList.first.patientID); appointmentNo: patientArrivedAppointmentsHistoryList.first.appointmentNo, patientID: patientArrivedAppointmentsHistoryList.first.patientID);

@ -33,6 +33,11 @@ class AppointmentQueuePage extends StatelessWidget {
Expanded( Expanded(
child: CollapsingListView( child: CollapsingListView(
title: LocaleKeys.queueing.tr(context: context), title: LocaleKeys.queueing.tr(context: context),
child: RefreshIndicator(
color: AppColors.primaryRedColor,
onRefresh: () async {
await myAppointmentsVM.getPatientAppointmentQueueDetails();
},
child: SingleChildScrollView( child: SingleChildScrollView(
child: Padding( child: Padding(
padding: EdgeInsets.all(24.0), padding: EdgeInsets.all(24.0),
@ -45,10 +50,7 @@ class AppointmentQueuePage extends StatelessWidget {
borderRadius: 20.h, borderRadius: 20.h,
hasShadow: false, hasShadow: false,
side: BorderSide( side: BorderSide(
color: myAppointmentsVM.isAppointmentQueueDetailsLoading color: myAppointmentsVM.isAppointmentQueueDetailsLoading ? AppColors.whiteColor : Utils.getCardBorderColor(myAppointmentsVM.currentQueueStatus), width: 2.w),
? AppColors.whiteColor
: Utils.getCardBorderColor(myAppointmentsVM.currentQueueStatus),
width: 2.w),
), ),
child: Padding( child: Padding(
padding: EdgeInsets.all(16.h), padding: EdgeInsets.all(16.h),
@ -67,21 +69,17 @@ class AppointmentQueuePage extends StatelessWidget {
], ],
).toShimmer2(isShow: myAppointmentsVM.isAppointmentQueueDetailsLoading), ).toShimmer2(isShow: myAppointmentsVM.isAppointmentQueueDetailsLoading),
SizedBox(height: 10.h), SizedBox(height: 10.h),
"Hala ${appState!.getAuthenticatedUser()!.firstName}!!!" "Hala ${appState!.getAuthenticatedUser()!.firstName}!!!".toText16(isBold: true).toShimmer2(isShow: myAppointmentsVM.isAppointmentQueueDetailsLoading),
.toText16(isBold: true)
.toShimmer2(isShow: myAppointmentsVM.isAppointmentQueueDetailsLoading),
SizedBox(height: 8.h), SizedBox(height: 8.h),
LocaleKeys.thankYouForPatience.tr(context: context) LocaleKeys.thankYouForPatience
.tr(context: context)
.toText12(isBold: true, color: AppColors.textColorLight) .toText12(isBold: true, color: AppColors.textColorLight)
.toShimmer2(isShow: myAppointmentsVM.isAppointmentQueueDetailsLoading), .toShimmer2(isShow: myAppointmentsVM.isAppointmentQueueDetailsLoading),
SizedBox(height: 8.h), SizedBox(height: 8.h),
myAppointmentsVM.currentPatientQueueDetails.queueNo! myAppointmentsVM.currentPatientQueueDetails.queueNo!.toText32(isBold: true).toShimmer2(isShow: myAppointmentsVM.isAppointmentQueueDetailsLoading),
.toText32(isBold: true)
.toShimmer2(isShow: myAppointmentsVM.isAppointmentQueueDetailsLoading),
SizedBox(height: 8.h), SizedBox(height: 8.h),
CustomButton( CustomButton(
text: Utils.getCardButtonText( text: Utils.getCardButtonText(myAppointmentsVM.currentQueueStatus, myAppointmentsVM.currentPatientQueueDetails.roomNo ?? ""),
myAppointmentsVM.currentQueueStatus, myAppointmentsVM.currentPatientQueueDetails.roomNo ?? ""),
onPressed: () {}, onPressed: () {},
backgroundColor: Utils.getCardButtonColor(myAppointmentsVM.currentQueueStatus), backgroundColor: Utils.getCardButtonColor(myAppointmentsVM.currentQueueStatus),
borderColor: Utils.getCardButtonColor(myAppointmentsVM.currentQueueStatus).withValues(alpha: 0.01), borderColor: Utils.getCardButtonColor(myAppointmentsVM.currentQueueStatus).withValues(alpha: 0.01),
@ -111,9 +109,7 @@ class AppointmentQueuePage extends StatelessWidget {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
LocaleKeys.servingNow.tr(context: context) LocaleKeys.servingNow.tr(context: context).toText16(isBold: true).toShimmer2(isShow: myAppointmentsVM.isAppointmentQueueDetailsLoading),
.toText16(isBold: true)
.toShimmer2(isShow: myAppointmentsVM.isAppointmentQueueDetailsLoading),
SizedBox(height: 18.h), SizedBox(height: 18.h),
ListView.separated( ListView.separated(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
@ -129,22 +125,15 @@ class AppointmentQueuePage extends StatelessWidget {
Row( Row(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
"Room: ${myAppointmentsVM.patientQueueDetailsList[index].roomNo}" "Room: ${myAppointmentsVM.patientQueueDetailsList[index].roomNo}".toText12(isBold: true),
.toText12(isBold: true),
SizedBox(width: 8.w), SizedBox(width: 8.w),
AppCustomChipWidget( AppCustomChipWidget(
deleteIcon: myAppointmentsVM.patientQueueDetailsList[index].callType == 1 deleteIcon: myAppointmentsVM.patientQueueDetailsList[index].callType == 1 ? AppAssets.call_for_vitals : AppAssets.call_for_doctor,
? AppAssets.call_for_vitals
: AppAssets.call_for_doctor,
labelText: myAppointmentsVM.patientQueueDetailsList[index].callType == 1 labelText: myAppointmentsVM.patientQueueDetailsList[index].callType == 1
? LocaleKeys.callForVitalSigns.tr(context: context) ? LocaleKeys.callForVitalSigns.tr(context: context)
: LocaleKeys.callForDoctor.tr(context: context), : LocaleKeys.callForDoctor.tr(context: context),
iconColor: myAppointmentsVM.patientQueueDetailsList[index].callType == 1 iconColor: myAppointmentsVM.patientQueueDetailsList[index].callType == 1 ? AppColors.primaryRedColor : AppColors.successColor,
? AppColors.primaryRedColor textColor: myAppointmentsVM.patientQueueDetailsList[index].callType == 1 ? AppColors.primaryRedColor : AppColors.successColor,
: AppColors.successColor,
textColor: myAppointmentsVM.patientQueueDetailsList[index].callType == 1
? AppColors.primaryRedColor
: AppColors.successColor,
iconSize: 14.w, iconSize: 14.w,
backgroundColor: myAppointmentsVM.patientQueueDetailsList[index].callType == 1 backgroundColor: myAppointmentsVM.patientQueueDetailsList[index].callType == 1
? AppColors.primaryRedColor.withValues(alpha: 0.1) ? AppColors.primaryRedColor.withValues(alpha: 0.1)
@ -183,21 +172,15 @@ class AppointmentQueuePage extends StatelessWidget {
], ],
), ),
SizedBox(height: 8.h), SizedBox(height: 8.h),
"${LocaleKeys.improveOverallHealth.tr(context: context)}" "${LocaleKeys.improveOverallHealth.tr(context: context)}".toText12(isBold: true, color: AppColors.textColorLight),
.toText12(isBold: true, color: AppColors.textColorLight),
SizedBox(height: 4.h), SizedBox(height: 4.h),
"${LocaleKeys.routineScreenings.tr(context: context)}" "${LocaleKeys.routineScreenings.tr(context: context)}".toText12(isBold: true, color: AppColors.textColorLight),
.toText12(isBold: true, color: AppColors.textColorLight),
SizedBox(height: 4.h), SizedBox(height: 4.h),
"${LocaleKeys.whatIsThisMedicationFor.tr(context: context)}" "${LocaleKeys.whatIsThisMedicationFor.tr(context: context)}".toText12(isBold: true, color: AppColors.textColorLight),
.toText12(isBold: true, color: AppColors.textColorLight),
SizedBox(height: 4.h), SizedBox(height: 4.h),
"${LocaleKeys.sideEffectsToKnow.tr(context: context)}" "${LocaleKeys.sideEffectsToKnow.tr(context: context)}".toText12(isBold: true, color: AppColors.textColorLight),
.toText12(isBold: true, color: AppColors.textColorLight),
SizedBox(height: 4.h), SizedBox(height: 4.h),
"${LocaleKeys.whenFollowUp.tr(context: context)}" "${LocaleKeys.whenFollowUp.tr(context: context)}".toText12(isBold: true, color: AppColors.textColorLight),
.toText12(isBold: true, color: AppColors.textColorLight),
SizedBox(height: 16.h), SizedBox(height: 16.h),
], ],
).toShimmer2(isShow: myAppointmentsVM.isAppointmentQueueDetailsLoading), ).toShimmer2(isShow: myAppointmentsVM.isAppointmentQueueDetailsLoading),
@ -209,6 +192,7 @@ class AppointmentQueuePage extends StatelessWidget {
), ),
), ),
), ),
),
Container( Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration( decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor, color: AppColors.whiteColor,

@ -318,7 +318,7 @@ class _MyDoctorsPageState extends State<MyDoctorsPage> {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
Navigator.of(context).push( Navigator.of(context).push(
CustomPageRoute( CustomPageRoute(
page: DoctorProfilePage(), page: DoctorProfilePage(isDoctorAllowedToBook: !doctor?.isLiveCareClinic),
), ),
); );
}, onError: (err) { }, onError: (err) {

@ -161,7 +161,9 @@ class AppointmentDoctorCard extends StatelessWidget {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
Navigator.of(context).push( Navigator.of(context).push(
CustomPageRoute( CustomPageRoute(
page: DoctorProfilePage(), page: DoctorProfilePage(
isDoctorAllowedToBook: !(patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false),
),
), ),
); );
}, onError: (err) { }, onError: (err) {

@ -217,7 +217,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
Navigator.of(context).push( Navigator.of(context).push(
CustomPageRoute( CustomPageRoute(
page: DoctorProfilePage(), page: DoctorProfilePage(isDoctorAllowedToBook: !(myAppointmentsVM.patientMyDoctorsList[index].isLiveCareClinic ?? false)),
), ),
); );
}, onError: (err) { }, onError: (err) {
@ -406,7 +406,7 @@ class _BookAppointmentPageState extends State<BookAppointmentPage> {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
Navigator.of(context).push( Navigator.of(context).push(
CustomPageRoute( CustomPageRoute(
page: DoctorProfilePage(), page: DoctorProfilePage(isDoctorAllowedToBook: true),
), ),
); );
}, onError: (err) { }, onError: (err) {

@ -22,7 +22,9 @@ import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
class DoctorProfilePage extends StatelessWidget { class DoctorProfilePage extends StatelessWidget {
const DoctorProfilePage({super.key}); const DoctorProfilePage({super.key, required this.isDoctorAllowedToBook});
final bool isDoctorAllowedToBook;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -187,7 +189,7 @@ class DoctorProfilePage extends StatelessWidget {
), ),
), ),
), ),
Container( isDoctorAllowedToBook ? Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration( decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor, color: AppColors.whiteColor,
borderRadius: 24.h, borderRadius: 24.h,
@ -265,7 +267,7 @@ class DoctorProfilePage extends StatelessWidget {
iconColor: Colors.white, iconColor: Colors.white,
iconSize: 20.h, iconSize: 20.h,
).paddingSymmetrical(24.h, 24.h), ).paddingSymmetrical(24.h, 24.h),
), ) : SizedBox.shrink(),
], ],
), ),
); );

@ -214,7 +214,7 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
LocaleKeys.amountBeforeTax.tr(context: context).toText14(isBold: true), LocaleKeys.amountBeforeTax.tr(context: context).toText14(isBold: true),
Utils.getPaymentAmountWithSymbol(immediateLiveCareVM.liveCareImmediateAppointmentFeesList.amount!.toText16(isBold: true, isEnglishOnly: true), AppColors.blackColor, 13, Utils.getPaymentAmountWithSymbol((immediateLiveCareVM.liveCareImmediateAppointmentFeesList.amount ?? "").toText16(isBold: true, isEnglishOnly: true), AppColors.blackColor, 13,
isSaudiCurrency: immediateLiveCareVM.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "sar" || isSaudiCurrency: immediateLiveCareVM.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "sar" ||
immediateLiveCareVM.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "ريال"), immediateLiveCareVM.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "ريال"),
], ],

@ -218,7 +218,7 @@ class _SearchDoctorByNameState extends State<SearchDoctorByName> {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
Navigator.of(context).push( Navigator.of(context).push(
CustomPageRoute( CustomPageRoute(
page: DoctorProfilePage(), page: DoctorProfilePage(isDoctorAllowedToBook: true),
), ),
); );
}, },

@ -239,6 +239,7 @@ class _SelectDoctorPageState extends State<SelectDoctorPage> {
value: bookAppointmentsVM.isNearestAppointmentSelected, value: bookAppointmentsVM.isNearestAppointmentSelected,
onChanged: (newValue) async { onChanged: (newValue) async {
bookAppointmentsVM.setIsNearestAppointmentSelected(newValue); bookAppointmentsVM.setIsNearestAppointmentSelected(newValue);
bookAppointmentsVM.refreshDoctorsList();
}, },
), ),
], ],
@ -346,7 +347,7 @@ class _SelectDoctorPageState extends State<SelectDoctorPage> {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
Navigator.of(context).push( Navigator.of(context).push(
CustomPageRoute( CustomPageRoute(
page: DoctorProfilePage(), page: DoctorProfilePage(isDoctorAllowedToBook: true,),
), ),
); );
}, onError: (err) { }, onError: (err) {

@ -1,3 +1,5 @@
import 'dart:io';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart';
@ -67,7 +69,7 @@ class CallAmbulancePage extends StatelessWidget {
myLocationEnabled: true, myLocationEnabled: true,
inputController: context.read<EmergencyServicesViewModel>().gmsController, inputController: context.read<EmergencyServicesViewModel>().gmsController,
showCenterMarker: true, showCenterMarker: true,
bottomPaddingHeight: MediaQuery.of(context).size.height * 0.42, bottomPaddingHeight: 400.h,
) )
else else
HMSMap( HMSMap(

@ -270,7 +270,7 @@ class _RechargeWalletPageState extends State<RechargeWalletPage> {
isCloseButtonVisible: true, isCloseButtonVisible: true,
); );
} else { } else {
habibWalletVM.setWalletRechargeAmount(num.parse(amountTextController.text)); habibWalletVM.setWalletRechargeAmount(num.parse(amountTextController.text.replaceAll(',', '')));
habibWalletVM.setNotesText(notesTextController.text); habibWalletVM.setNotesText(notesTextController.text);
// habibWalletVM.setDepositorDetails(appState.getAuthenticatedUser()!.patientId.toString(), "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}", // habibWalletVM.setDepositorDetails(appState.getAuthenticatedUser()!.patientId.toString(), "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}",
// appState.getAuthenticatedUser()!.mobileNumber!); // appState.getAuthenticatedUser()!.mobileNumber!);

@ -180,7 +180,29 @@ class _LandingPageState extends State<LandingPage> {
body: Consumer<InsuranceViewModel>(builder: (context, insuranceVM, child) { body: Consumer<InsuranceViewModel>(builder: (context, insuranceVM, child) {
return Stack( return Stack(
children: [ children: [
SingleChildScrollView( RefreshIndicator(
color: AppColors.primaryRedColor,
onRefresh: () async {
if (appState.isAuthenticated) {
// Refresh Appointments Data
myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true);
myAppointmentsViewModel.initAppointmentsViewModel();
myAppointmentsViewModel.getPatientAppointments(true, false);
// Refresh Appointments Data
habibWalletVM.initHabibWalletProvider();
habibWalletVM.getPatientBalanceAmount();
// Refresh Ancillary Orders
todoSectionViewModel.initializeTodoSectionViewModel();
// Refresh Immediate LiveCare Data
immediateLiveCareViewModel.initImmediateLiveCare();
immediateLiveCareViewModel.getPatientLiveCareHistory();
}
},
child: SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
padding: EdgeInsets.only( padding: EdgeInsets.only(
top: (appState.isAuthenticated && !insuranceVM.isInsuranceLoading && insuranceVM.isInsuranceExpired && insuranceVM.isInsuranceExpiryBannerShown) top: (appState.isAuthenticated && !insuranceVM.isInsuranceLoading && insuranceVM.isInsuranceExpired && insuranceVM.isInsuranceExpiryBannerShown)
? (MediaQuery.paddingOf(context).top + 70.h) ? (MediaQuery.paddingOf(context).top + 70.h)
@ -215,9 +237,15 @@ class _LandingPageState extends State<LandingPage> {
}, },
name: ('${appState.getAuthenticatedUser()!.firstName!} ${appState.getAuthenticatedUser()!.lastName!}'), name: ('${appState.getAuthenticatedUser()!.firstName!} ${appState.getAuthenticatedUser()!.lastName!}'),
// imageUrl: appState.getAuthenticatedUser()?.gender == 1 ? AppAssets.maleImg : AppAssets.femaleImg, // imageUrl: appState.getAuthenticatedUser()?.gender == 1 ? AppAssets.maleImg : AppAssets.femaleImg,
imageUrl: appState.getAuthenticatedUser()?.gender == 1 imageUrl: appState
? ((appState.getAuthenticatedUser()?.age ?? 0) < 7 ? AppAssets.babyBoyImg : AppAssets.maleImg) .getAuthenticatedUser()
: ((appState.getAuthenticatedUser()?.age ?? 0) < 7 ? AppAssets.babyGirlImg : AppAssets.femaleImg), ?.gender == 1
? ((appState
.getAuthenticatedUser()
?.age ?? 0) < 7 ? AppAssets.babyBoyImg : AppAssets.maleImg)
: ((appState
.getAuthenticatedUser()
?.age ?? 0) < 7 ? AppAssets.babyGirlImg : AppAssets.femaleImg),
).expanded ).expanded
: CustomButton( : CustomButton(
text: LocaleKeys.loginOrRegister.tr(context: context), text: LocaleKeys.loginOrRegister.tr(context: context),
@ -279,7 +307,11 @@ class _LandingPageState extends State<LandingPage> {
child: Text( child: Text(
todoSectionVM.notificationsCount.toString(), todoSectionVM.notificationsCount.toString(),
style: TextStyle( style: TextStyle(
color: Colors.white, fontFamily: "Poppins", fontSize: 10.f, fontWeight: FontWeight.w600,), color: Colors.white,
fontFamily: "Poppins",
fontSize: 10.f,
fontWeight: FontWeight.w600,
),
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
), ),
@ -443,7 +475,8 @@ class _LandingPageState extends State<LandingPage> {
// ), // ),
// ); // );
}, },
separatorBuilder: (BuildContext cxt, int index) => SizedBox( separatorBuilder: (BuildContext cxt, int index) =>
SizedBox(
width: 10.w, width: 10.w,
), ),
), ),
@ -589,12 +622,13 @@ class _LandingPageState extends State<LandingPage> {
Navigator.of(context).push(CustomPageRoute(page: MedicalFilePage())); Navigator.of(context).push(CustomPageRoute(page: MedicalFilePage()));
}), }),
SizedBox(height: 16.h), SizedBox(height: 16.h),
Container( Consumer(builder: (BuildContext context, TodoSectionViewModel todoSectionVM, Widget? child) {
return Container(
// height: 121.h, // height: 121.h,
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r), decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r),
child: Column( child: Column(
children: [ children: [
todoSectionViewModel.patientAncillaryOrdersList.isNotEmpty todoSectionVM.patientAncillaryOrdersList.isNotEmpty
? Container( ? Container(
height: 50.h, height: 50.h,
decoration: ShapeDecoration( decoration: ShapeDecoration(
@ -607,14 +641,11 @@ class _LandingPageState extends State<LandingPage> {
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
LocaleKeys.pendingAncillaryOrders LocaleKeys.pendingAncillaryOrders.tr(context: context).toText14(color: AppColors.eReferralCardColor, isBold: true).paddingSymmetrical(24.h, 0.h),
.tr(context: context)
.toText14(color: AppColors.eReferralCardColor, isBold: true)
.paddingSymmetrical(24.h, 0.h),
CustomButton( CustomButton(
text: LocaleKeys.view.tr(context: context), text: LocaleKeys.view.tr(context: context),
onPressed: () { onPressed: () {
getIt.get<TodoSectionViewModel>().setIsAncillaryOrdersNeedReloading(true); todoSectionVM.setIsAncillaryOrdersNeedReloading(true);
Navigator.of(context).push( Navigator.of(context).push(
CustomPageRoute( CustomPageRoute(
page: ToDoPage(), page: ToDoPage(),
@ -645,7 +676,11 @@ class _LandingPageState extends State<LandingPage> {
trackColor: Color(0xffD9D9D9), trackColor: Color(0xffD9D9D9),
trackBorderColor: Colors.transparent, trackBorderColor: Colors.transparent,
trackRadius: Radius.circular(10.0), trackRadius: Radius.circular(10.0),
padding: EdgeInsets.only(top: 92.h + 32.h, left: MediaQuery.sizeOf(context).width / 2.5 - 10, right: MediaQuery.sizeOf(context).width / 2.5 - 10), padding: EdgeInsets.only(top: 92.h + 32.h, left: MediaQuery
.sizeOf(context)
.width / 2.5 - 10, right: MediaQuery
.sizeOf(context)
.width / 2.5 - 10),
child: ListView.separated( child: ListView.separated(
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
itemCount: LandingPageData.getLoggedInServiceCardsList.length, itemCount: LandingPageData.getLoggedInServiceCardsList.length,
@ -680,7 +715,8 @@ class _LandingPageState extends State<LandingPage> {
SizedBox(height: 16.h), SizedBox(height: 16.h),
], ],
), ),
).paddingSymmetrical(24.h, 0.h), ).paddingSymmetrical(24.h, 0.h);
}),
], ],
) )
: Container( : Container(
@ -698,7 +734,11 @@ class _LandingPageState extends State<LandingPage> {
trackColor: Color(0xffD9D9D9), trackColor: Color(0xffD9D9D9),
trackBorderColor: Colors.transparent, trackBorderColor: Colors.transparent,
trackRadius: Radius.circular(10.0), trackRadius: Radius.circular(10.0),
padding: EdgeInsets.only(top: 92.h + 32.h, left: MediaQuery.sizeOf(context).width / 2.5 - 10, right: MediaQuery.sizeOf(context).width / 2.5 - 10), padding: EdgeInsets.only(top: 92.h + 32.h, left: MediaQuery
.sizeOf(context)
.width / 2.5 - 10, right: MediaQuery
.sizeOf(context)
.width / 2.5 - 10),
child: ListView.separated( child: ListView.separated(
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
itemCount: LandingPageData.getNotLoggedInServiceCardsList.length, itemCount: LandingPageData.getNotLoggedInServiceCardsList.length,
@ -781,6 +821,7 @@ class _LandingPageState extends State<LandingPage> {
], ],
), ),
), ),
),
(appState.isAuthenticated && !insuranceVM.isInsuranceLoading && insuranceVM.isInsuranceExpired && insuranceVM.isInsuranceExpiryBannerShown) (appState.isAuthenticated && !insuranceVM.isInsuranceLoading && insuranceVM.isInsuranceExpired && insuranceVM.isInsuranceExpiryBannerShown)
? Container( ? Container(
height: MediaQuery.paddingOf(context).top + 50.h, height: MediaQuery.paddingOf(context).top + 50.h,

@ -1019,7 +1019,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
Navigator.of(context).push( Navigator.of(context).push(
CustomPageRoute( CustomPageRoute(
page: DoctorProfilePage(), page: DoctorProfilePage(isDoctorAllowedToBook: !(myAppointmentsVM.patientMyDoctorsList[index].isLiveCareClinic ?? false)),
), ),
); );
}, onError: (err) { }, onError: (err) {

@ -304,7 +304,7 @@ class TextInputWidget extends StatelessWidget {
hintLocales: const [Locale('en', 'US')], hintLocales: const [Locale('en', 'US')],
enabled: isEnable, enabled: isEnable,
scrollPadding: EdgeInsets.zero, scrollPadding: EdgeInsets.zero,
keyboardType: isMultiline ? TextInputType.multiline : keyboardType, keyboardType: isMultiline ? TextInputType.multiline : (isWalletAmountInput! ? const TextInputType.numberWithOptions(decimal: true) : keyboardType),
controller: controller, controller: controller,
readOnly: isReadOnly, readOnly: isReadOnly,
textAlignVertical: TextAlignVertical.top, textAlignVertical: TextAlignVertical.top,
@ -315,7 +315,12 @@ class TextInputWidget extends StatelessWidget {
autofocus: autoFocus, autofocus: autoFocus,
textInputAction: TextInputAction.done, textInputAction: TextInputAction.done,
cursorHeight: isWalletAmountInput! ? 40.h : 20.h, cursorHeight: isWalletAmountInput! ? 40.h : 20.h,
maxLength: isWalletAmountInput! ? 6 : 100, maxLength: isWalletAmountInput! ? 7 : 100,
inputFormatters: isWalletAmountInput!
? [
_ThousandSeparatorInputFormatter(),
]
: null,
onTapOutside: (event) { onTapOutside: (event) {
FocusManager.instance.primaryFocus?.unfocus(); FocusManager.instance.primaryFocus?.unfocus();
}, },
@ -407,3 +412,63 @@ class TextInputWidget extends StatelessWidget {
); );
} }
} }
class _ThousandSeparatorInputFormatter extends TextInputFormatter {
@override
TextEditingValue formatEditUpdate(
TextEditingValue oldValue,
TextEditingValue newValue,
) {
// Remove all commas to get the raw number
String newText = newValue.text.replaceAll(',', '');
// Allow only digits and one decimal point
if (newText.isNotEmpty && !RegExp(r'^\d*\.?\d{0,2}$').hasMatch(newText)) {
return oldValue;
}
// Split into integer and decimal parts
String integerPart;
String decimalPart = '';
if (newText.contains('.')) {
final parts = newText.split('.');
integerPart = parts[0];
decimalPart = '.${parts[1]}';
} else {
integerPart = newText;
}
// Add thousand separators to the integer part
if (integerPart.isNotEmpty) {
final buffer = StringBuffer();
int count = 0;
for (int i = integerPart.length - 1; i >= 0; i--) {
buffer.write(integerPart[i]);
count++;
if (count == 3 && i > 0) {
buffer.write(',');
count = 0;
}
}
integerPart = buffer.toString().split('').reversed.join();
}
final formatted = '$integerPart$decimalPart';
// Calculate new cursor position
int cursorOffset = newValue.selection.baseOffset;
// Count commas before cursor in the new formatted string
int commasInNew = ','.allMatches(formatted.substring(0, cursorOffset.clamp(0, formatted.length))).length;
// Count commas before cursor in the old value
int commasInOld = ','.allMatches(oldValue.text.substring(0, oldValue.selection.baseOffset.clamp(0, oldValue.text.length))).length;
int newCursorPos = cursorOffset + (commasInNew - commasInOld);
newCursorPos = newCursorPos.clamp(0, formatted.length);
return TextEditingValue(
text: formatted,
selection: TextSelection.collapsed(offset: newCursorPos),
);
}
}

@ -54,10 +54,16 @@
// } // }
import 'dart:async'; import 'dart:async';
import 'dart:io';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.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/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/location_util.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.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/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
@ -72,7 +78,7 @@ class GMSMap extends StatefulWidget {
final bool myLocationEnabled; final bool myLocationEnabled;
final bool showCenterMarker; final bool showCenterMarker;
final Completer<GoogleMapController>? inputController; final Completer<GoogleMapController>? inputController;
final num bottomPaddingHeight; final double bottomPaddingHeight;
const GMSMap({ const GMSMap({
super.key, super.key,
@ -93,6 +99,7 @@ class GMSMap extends StatefulWidget {
class _GMSMapState extends State<GMSMap> { class _GMSMapState extends State<GMSMap> {
late Completer<GoogleMapController> _controller; late Completer<GoogleMapController> _controller;
GoogleMapController? _activeController;
late MapType _selectedMapType; late MapType _selectedMapType;
bool _showMapTypeSelector = false; bool _showMapTypeSelector = false;
num bottomPaddingHeight = 0; num bottomPaddingHeight = 0;
@ -139,6 +146,37 @@ class _GMSMapState extends State<GMSMap> {
setState(() => _showMapTypeSelector = !_showMapTypeSelector); setState(() => _showMapTypeSelector = !_showMapTypeSelector);
} }
Future<void> _animateToMyLocation() async {
final appState = getIt.get<AppState>();
final locationUtils = getIt.get<LocationUtils>();
void _moveToLocation() {
if (appState.userLat != 0.0 && appState.userLong != 0.0 && _activeController != null) {
_activeController!.animateCamera(
CameraUpdate.newCameraPosition(
CameraPosition(
target: LatLng(appState.userLat, appState.userLong),
zoom: 16,
),
),
);
}
}
if (appState.userLat != 0.0 && appState.userLong != 0.0) {
_moveToLocation();
} else {
locationUtils.getLocation(
isShowConfirmDialog: true,
onSuccess: (latLng) {
_moveToLocation();
},
onFailure: () {},
onLocationDeniedForever: () {},
);
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Stack( return Stack(
@ -146,16 +184,21 @@ class _GMSMapState extends State<GMSMap> {
// Google Map // Google Map
GoogleMap( GoogleMap(
mapType: _selectedMapType, mapType: _selectedMapType,
zoomControlsEnabled: true, zoomControlsEnabled: false,
myLocationEnabled: widget.myLocationEnabled, // myLocationEnabled: widget.myLocationEnabled,
myLocationButtonEnabled: true, myLocationEnabled: true,
padding: EdgeInsets.only(bottom: double.parse(widget.bottomPaddingHeight.toString())), myLocationButtonEnabled: false,
// padding: EdgeInsets.only(bottom: double.parse(widget.bottomPaddingHeight.toString())),
// padding: EdgeInsets.only(top: Platform.isAndroid ? double.parse(widget.bottomPaddingHeight.toString()) : 0, bottom: Platform.isIOS ? double.parse(widget.bottomPaddingHeight.toString()) : 0),
compassEnabled: widget.compassEnabled, compassEnabled: widget.compassEnabled,
initialCameraPosition: widget.currentLocation, initialCameraPosition: widget.currentLocation,
onCameraMove: widget.onCameraMoved, onCameraMove: widget.onCameraMoved,
onCameraIdle: widget.onCameraIdle, onCameraIdle: widget.onCameraIdle,
onMapCreated: (GoogleMapController controller) { onMapCreated: (GoogleMapController controller) {
_activeController = controller;
if (!_controller.isCompleted) {
_controller.complete(controller); _controller.complete(controller);
}
}, },
), ),
@ -167,7 +210,31 @@ class _GMSMapState extends State<GMSMap> {
Icons.location_pin, Icons.location_pin,
size: 36.h, size: 36.h,
color: AppColors.primaryRedColor, color: AppColors.primaryRedColor,
).paddingOnly(bottom: double.parse((widget.bottomPaddingHeight + 25.h).toString())), ).paddingOnly(bottom: Platform.isAndroid ? 30.h : double.parse((widget.bottomPaddingHeight + 25.h).toString())),
),
// My Location button
PositionedDirectional(
// bottom: 300.h,
// bottom: 400.h,
bottom: widget.bottomPaddingHeight,
start: 16.w,
child: GestureDetector(
onTap: _animateToMyLocation,
child: Container(
width: 42.w,
height: 42.h,
decoration: BoxDecoration(
color: AppColors.whiteColor,
borderRadius: BorderRadius.circular(8.r),
),
child: Icon(
Icons.my_location,
size: 22.h,
color: AppColors.blackBgColor,
),
),
),
), ),
// Map-type toggle button // Map-type toggle button

@ -68,7 +68,7 @@ class MapUtilityScreen extends StatelessWidget {
myLocationEnabled: true, myLocationEnabled: true,
inputController: context.read<LocationViewModel>().gmsController, inputController: context.read<LocationViewModel>().gmsController,
showCenterMarker: true, showCenterMarker: true,
bottomPaddingHeight: MediaQuery.of(context).size.height * 0.2, bottomPaddingHeight: 300.h,
) )
else else
HMSMap( HMSMap(

Loading…
Cancel
Save