From 5e81ba1ed8f5dd7738818d0750526f8b52de572e Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Thu, 18 Sep 2025 10:24:13 +0300 Subject: [PATCH 01/12] updates --- .../appointments/my_appointments_page.dart | 1 - .../widgets/appointment_card.dart | 3 +- lib/presentation/home/landing_page.dart | 377 ++++++++++-------- 3 files changed, 210 insertions(+), 171 deletions(-) diff --git a/lib/presentation/appointments/my_appointments_page.dart b/lib/presentation/appointments/my_appointments_page.dart index 5a3205d..4c16a17 100644 --- a/lib/presentation/appointments/my_appointments_page.dart +++ b/lib/presentation/appointments/my_appointments_page.dart @@ -53,7 +53,6 @@ class _MyAppointmentsPageState extends State { CustomTabBarModel(null, "Completed".needTranslation), ], onTabChange: (index) { - print(index); myAppointmentsViewModel.onTabChange(index); }, ).paddingSymmetrical(24.h, 0.h), diff --git a/lib/presentation/appointments/widgets/appointment_card.dart b/lib/presentation/appointments/widgets/appointment_card.dart index 815443e..29694ed 100644 --- a/lib/presentation/appointments/widgets/appointment_card.dart +++ b/lib/presentation/appointments/widgets/appointment_card.dart @@ -20,10 +20,11 @@ import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart'; import 'package:smooth_corner/smooth_corner.dart'; class AppointmentCard extends StatefulWidget { - AppointmentCard({super.key, required this.patientAppointmentHistoryResponseModel, required this.myAppointmentsViewModel}); + AppointmentCard({super.key, required this.patientAppointmentHistoryResponseModel, required this.myAppointmentsViewModel, this.isLoading = false}); PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel; MyAppointmentsViewModel myAppointmentsViewModel; + bool isLoading; @override State createState() => _AppointmentCardState(); diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart index 9f8ae79..0a5ec2c 100644 --- a/lib/presentation/home/landing_page.dart +++ b/lib/presentation/home/landing_page.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; +import 'package:flutter_swiper_view/flutter_swiper_view.dart'; import 'package:get_it/get_it.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; @@ -18,6 +19,7 @@ import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_view_mode import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart'; import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/presentation/appointments/my_appointments_page.dart'; import 'package:hmg_patient_app_new/presentation/authentication/quick_login.dart'; import 'package:hmg_patient_app_new/presentation/book_appointment/book_appointment_page.dart'; import 'package:hmg_patient_app_new/presentation/home/data/landing_page_data.dart'; @@ -54,6 +56,8 @@ class _LandingPageState extends State { late PrescriptionsViewModel prescriptionsViewModel; final CacheService cacheService = GetIt.instance(); + final SwiperController _controller = SwiperController(); + @override void initState() { authVM = context.read(); @@ -93,35 +97,32 @@ class _LandingPageState extends State { child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - appState.isAuthenticated ? WelcomeWidget( - onTap: () { - Navigator.of(context).push( - FadePage( - page: ProfileSettings(), - ), - ); - }, - name: ('${appState.getAuthenticatedUser()!.firstName!} ${appState.getAuthenticatedUser()!.lastName!}'), - imageUrl: appState - .getAuthenticatedUser() - ?.gender == 1 ? AppAssets.male_img : AppAssets.femaleImg, - ) + onTap: () { + Navigator.of(context).push( + FadePage( + page: ProfileSettings(), + ), + ); + }, + name: ('${appState.getAuthenticatedUser()!.firstName!} ${appState.getAuthenticatedUser()!.lastName!}'), + imageUrl: appState.getAuthenticatedUser()?.gender == 1 ? AppAssets.male_img : AppAssets.femaleImg, + ) : CustomButton( - text: LocaleKeys.loginOrRegister.tr(context: context), - onPressed: () async { - await authVM.onLoginPressed(); - }, - backgroundColor: Color(0xffFEE9EA), - borderColor: Color(0xffFEE9EA), - textColor: Color(0xffED1C2B), - fontSize: 16, - fontWeight: FontWeight.w500, - borderRadius: 12, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 50, - ), + text: LocaleKeys.loginOrRegister.tr(context: context), + onPressed: () async { + await authVM.onLoginPressed(); + }, + backgroundColor: Color(0xffFEE9EA), + borderColor: Color(0xffFEE9EA), + textColor: Color(0xffED1C2B), + fontSize: 16, + fontWeight: FontWeight.w500, + borderRadius: 12, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 50, + ), Row( children: [ Utils.buildSvgWithAssets(icon: AppAssets.bell, height: 20, width: 20).onPress(() { @@ -156,156 +157,194 @@ class _LandingPageState extends State { SizedBox(height: 16.h), appState.isAuthenticated ? Column( - children: [ - Container( - width: double.infinity, - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - borderRadius: 24, - ), - child: Padding( - padding: EdgeInsets.all(12.h), - child: Column( - children: [ - Utils.buildSvgWithAssets(icon: AppAssets.home_calendar_icon, width: 32.h, height: 32.h), - SizedBox(height: 12.h), - "You do not have any upcoming appointment. Please book an appointment".toText12(isCenter: true), - SizedBox(height: 12.h), - CustomButton( - text: LocaleKeys.bookAppo.tr(context: context), - onPressed: () { - Navigator.of(context) - .push( - FadePage( - page: BookAppointmentPage(), - ), - ); - }, - backgroundColor: Color(0xffFEE9EA), - borderColor: Color(0xffFEE9EA), - textColor: Color(0xffED1C2B), - fontSize: 14, - fontWeight: FontWeight.w500, - borderRadius: 12, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 40, - icon: AppAssets.add_icon, - iconColor: AppColors.primaryRedColor, + children: [ + SizedBox(height: 12.h), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + "Appointments & Visits".toText16(isBold: true), + Row( + children: [ + LocaleKeys.viewAll.tr(context: context).toText12(color: AppColors.primaryRedColor), + SizedBox(width: 2.h), + Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 10.h), + ], + ), + ], + ).paddingSymmetrical(24.h, 0.h).onPress(() { + Navigator.of(context).push( + FadePage( + page: MyAppointmentsPage(), + ), + ); + }), + SizedBox(height: 12.h), + Swiper( + itemCount: 3, + layout: SwiperLayout.STACK, + loop: true, + itemWidth: MediaQuery.of(context).size.width - 42, + indicatorLayout: PageIndicatorLayout.COLOR, + axisDirection: AxisDirection.right, + controller: _controller, + itemHeight: 210 + 16, + pagination: const SwiperPagination( + alignment: Alignment.bottomCenter, + margin: EdgeInsets.only(top: 210 + 8 + 24), + builder: DotSwiperPaginationBuilder(color: Color(0xffD9D9D9), activeColor: AppColors.blackBgColor), ), - ], - ), - ), - ).paddingSymmetrical(24.h, 0.h), - SizedBox(height: 12.h), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - "Quick Links".toText16(isBold: true), - Row( - children: [ - "View medical file".toText12(color: AppColors.primaryRedColor), - SizedBox(width: 2.h), - Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 10.h), - ], - ), - ], - ).paddingSymmetrical(24.h, 0.h).onPress(() { - Navigator.of(context).push( - FadePage( - page: MedicalFilePage(), - ), - ); - }), - SizedBox(height: 12.h), - Container( - height: 127.h, - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - borderRadius: 24, - ), - child: Padding( - padding: EdgeInsets.all(16.h), - child: Column( - children: [ - Expanded( - child: ListView.separated( - scrollDirection: Axis.horizontal, - itemCount: LandingPageData.getLoggedInServiceCardsList.length, - shrinkWrap: true, - padding: const EdgeInsets.only(left: 0, right: 8), - itemBuilder: (context, index) { - return AnimationConfiguration.staggeredList( - position: index, - duration: const Duration(milliseconds: 1000), - child: SlideAnimation( - horizontalOffset: 100.0, - child: FadeInAnimation( - child: SmallServiceCard( - icon: LandingPageData.getLoggedInServiceCardsList[index].icon, - title: LandingPageData.getLoggedInServiceCardsList[index].title, - subtitle: LandingPageData.getLoggedInServiceCardsList[index].subtitle, - iconColor: LandingPageData.getLoggedInServiceCardsList[index].iconColor, - textColor: LandingPageData.getLoggedInServiceCardsList[index].textColor, - backgroundColor: LandingPageData.getLoggedInServiceCardsList[index].backgroundColor, - isBold: LandingPageData.getLoggedInServiceCardsList[index].isBold, - serviceName: LandingPageData.getLoggedInServiceCardsList[index].serviceName, - ), - ), - ), - ); - }, - separatorBuilder: (BuildContext cxt, int index) => 0.width, + itemBuilder: (BuildContext context, int index) { + return FamilyCardWidget().paddingOnly(right: 16); + }, + ), + // Container( + // width: double.infinity, + // decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + // color: AppColors.whiteColor, + // borderRadius: 24, + // ), + // child: Padding( + // padding: EdgeInsets.all(12.h), + // child: Column( + // children: [ + // Utils.buildSvgWithAssets(icon: AppAssets.home_calendar_icon, width: 32.h, height: 32.h), + // SizedBox(height: 12.h), + // "You do not have any upcoming appointment. Please book an appointment".toText12(isCenter: true), + // SizedBox(height: 12.h), + // CustomButton( + // text: LocaleKeys.bookAppo.tr(context: context), + // onPressed: () { + // Navigator.of(context).push( + // FadePage( + // page: BookAppointmentPage(), + // ), + // ); + // }, + // backgroundColor: Color(0xffFEE9EA), + // borderColor: Color(0xffFEE9EA), + // textColor: Color(0xffED1C2B), + // fontSize: 14, + // fontWeight: FontWeight.w500, + // borderRadius: 12, + // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + // height: 40, + // icon: AppAssets.add_icon, + // iconColor: AppColors.primaryRedColor, + // ), + // ], + // ), + // ), + // ).paddingSymmetrical(24.h, 0.h), + SizedBox(height: 12.h), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + "Quick Links".toText16(isBold: true), + Row( + children: [ + "View medical file".toText12(color: AppColors.primaryRedColor), + SizedBox(width: 2.h), + Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 10.h), + ], ), + ], + ).paddingSymmetrical(24.h, 0.h).onPress(() { + Navigator.of(context).push( + FadePage( + page: MedicalFilePage(), + ), + ); + }), + SizedBox(height: 12.h), + Container( + height: 127.h, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24, ), - ], - ), - ), - ).paddingSymmetrical(24.h, 0.h), - ], - ) - : Container( - height: 127.h, - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - borderRadius: 24, - ), - child: Padding( - padding: EdgeInsets.all(16.h), - child: Column( - children: [ - Expanded( - child: ListView.separated( - scrollDirection: Axis.horizontal, - itemCount: LandingPageData.getNotLoggedInServiceCardsList.length, - shrinkWrap: true, - padding: const EdgeInsets.only(left: 0, right: 8), - itemBuilder: (context, index) { - return AnimationConfiguration.staggeredList( - position: index, - duration: const Duration(milliseconds: 1000), - child: SlideAnimation( - horizontalOffset: 100.0, - child: FadeInAnimation( - child: SmallServiceCard( - icon: LandingPageData.getNotLoggedInServiceCardsList[index].icon, - title: LandingPageData.getNotLoggedInServiceCardsList[index].title, - subtitle: LandingPageData.getNotLoggedInServiceCardsList[index].subtitle, - iconColor: LandingPageData.getNotLoggedInServiceCardsList[index].iconColor, - textColor: LandingPageData.getNotLoggedInServiceCardsList[index].textColor, - backgroundColor: LandingPageData.getNotLoggedInServiceCardsList[index].backgroundColor, - isBold: LandingPageData.getNotLoggedInServiceCardsList[index].isBold, + child: Padding( + padding: EdgeInsets.all(16.h), + child: Column( + children: [ + Expanded( + child: ListView.separated( + scrollDirection: Axis.horizontal, + itemCount: LandingPageData.getLoggedInServiceCardsList.length, + shrinkWrap: true, + padding: const EdgeInsets.only(left: 0, right: 8), + itemBuilder: (context, index) { + return AnimationConfiguration.staggeredList( + position: index, + duration: const Duration(milliseconds: 1000), + child: SlideAnimation( + horizontalOffset: 100.0, + child: FadeInAnimation( + child: SmallServiceCard( + icon: LandingPageData.getLoggedInServiceCardsList[index].icon, + title: LandingPageData.getLoggedInServiceCardsList[index].title, + subtitle: LandingPageData.getLoggedInServiceCardsList[index].subtitle, + iconColor: LandingPageData.getLoggedInServiceCardsList[index].iconColor, + textColor: LandingPageData.getLoggedInServiceCardsList[index].textColor, + backgroundColor: LandingPageData.getLoggedInServiceCardsList[index].backgroundColor, + isBold: LandingPageData.getLoggedInServiceCardsList[index].isBold, + serviceName: LandingPageData.getLoggedInServiceCardsList[index].serviceName, + ), + ), + ), + ); + }, + separatorBuilder: (BuildContext cxt, int index) => 0.width, ), ), + ], + ), + ), + ).paddingSymmetrical(24.h, 0.h), + ], + ) + : Container( + height: 127.h, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24, + ), + child: Padding( + padding: EdgeInsets.all(16.h), + child: Column( + children: [ + Expanded( + child: ListView.separated( + scrollDirection: Axis.horizontal, + itemCount: LandingPageData.getNotLoggedInServiceCardsList.length, + shrinkWrap: true, + padding: const EdgeInsets.only(left: 0, right: 8), + itemBuilder: (context, index) { + return AnimationConfiguration.staggeredList( + position: index, + duration: const Duration(milliseconds: 1000), + child: SlideAnimation( + horizontalOffset: 100.0, + child: FadeInAnimation( + child: SmallServiceCard( + icon: LandingPageData.getNotLoggedInServiceCardsList[index].icon, + title: LandingPageData.getNotLoggedInServiceCardsList[index].title, + subtitle: LandingPageData.getNotLoggedInServiceCardsList[index].subtitle, + iconColor: LandingPageData.getNotLoggedInServiceCardsList[index].iconColor, + textColor: LandingPageData.getNotLoggedInServiceCardsList[index].textColor, + backgroundColor: LandingPageData.getNotLoggedInServiceCardsList[index].backgroundColor, + isBold: LandingPageData.getNotLoggedInServiceCardsList[index].isBold, + ), + ), + ), + ); + }, + separatorBuilder: (BuildContext cxt, int index) => 0.width, ), - ); - }, - separatorBuilder: (BuildContext cxt, int index) => 0.width, + ), + ], ), ), - ], - ), - ), - ).paddingSymmetrical(24.h, 0.h), + ).paddingSymmetrical(24.h, 0.h), SizedBox(height: 16.h), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -375,7 +414,7 @@ class _LandingPageState extends State { // sharedPref.setBool(HAS_ENABLED_QUICK_LOGIN, true); authVM.loginWithFingerPrintFace(() { isDone = true; - cacheService.saveBool(key: CacheConst.quickLoginEnabled,value: true); + cacheService.saveBool(key: CacheConst.quickLoginEnabled, value: true); setState(() {}); }); }, From 29615834147660be78a0727f06b95176c9f1f9e8 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Thu, 18 Sep 2025 10:49:27 +0300 Subject: [PATCH 02/12] update --- lib/presentation/authentication/register_step2.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/presentation/authentication/register_step2.dart b/lib/presentation/authentication/register_step2.dart index 8dbe8e8..d58c7b3 100644 --- a/lib/presentation/authentication/register_step2.dart +++ b/lib/presentation/authentication/register_step2.dart @@ -43,7 +43,9 @@ class _RegisterNew extends State { @override Widget build(BuildContext context) { AppState appState = getIt.get(); - var name = appState.getLanguageCode() == "en" + + // TODO: to be checked with yakeen data + var name = authVM!.isUserFromUAE() ? "" : appState.getLanguageCode() == "en" ? ("${appState.getNHICUserData.firstNameEn!.toUpperCase()} ${appState.getNHICUserData.lastNameEn!.toUpperCase()}") : ("${appState.getNHICUserData.firstNameAr!.toUpperCase()} ${appState.getNHICUserData.lastNameAr!.toUpperCase()}"); return Scaffold( From 17c47d093c844c6c38e56c5c153ab60b6f96d366 Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Thu, 18 Sep 2025 16:10:55 +0300 Subject: [PATCH 03/12] otp screen & register Uae & resend Activation Code. --- assets/langs/ar-SA.json | 5 +- assets/langs/en-US.json | 7 +- lib/extensions/widget_extensions.dart | 3 +- .../authentication_view_model.dart | 191 ++++--- .../widgets/otp_verification_screen.dart | 17 +- lib/generated/locale_keys.g.dart | 2 + .../authentication/register_step2.dart | 517 +++++++++--------- .../authentication/saved_login_screen.dart | 31 +- .../bottomsheet/generic_bottom_sheet.dart | 5 +- lib/widgets/buttons/custom_button.dart | 2 +- .../dropdown/country_dropdown_widget.dart | 25 +- lib/widgets/dropdown/dropdown_widget.dart | 2 + lib/widgets/input_widget.dart | 7 +- 13 files changed, 426 insertions(+), 388 deletions(-) diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index ea6ad94..19111f7 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -847,5 +847,8 @@ "pleaseSelectAMaritalStatus": "يرجى اختيار الحالة الاجتماعية", "pleaseSelectACountry": "يرجى اختيار الدولة", "pleaseEnterEmail": "يرجى إدخال البريد الإلكتروني", - "pleaseEnterAValidEmailFormat": "يرجى إدخال تنسيق بريد إلكتروني صالح" + "pleaseEnterAValidEmailFormat": "يرجى إدخال تنسيق بريد إلكتروني صالح", + "selectCountry": "اختر الدولة", + "forLoginVerification": "للتحقق من تسجيل الدخول" + } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index b90557e..27609c8 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -803,7 +803,6 @@ "loginByOTP": "Login By OTP", "guest": "Guest", "switchAccount": "Switch Account", - "lastloginBy": "Last login by", "allSet": "All Set! Now you can login with Face ID or Biometric", "enableQuickLogin": "Enable Quick Login", "enableMsg": "Enabling the quick login will verify through your existing device Face ID / Biometric", @@ -843,6 +842,8 @@ "pleaseSelectAMaritalStatus": "Please select a marital status", "pleaseSelectACountry": "Please select a country", "pleaseEnterEmail": "Please enter email", - "pleaseEnterAValidEmailFormat": "Please enter a valid email format" - + "pleaseEnterAValidEmailFormat": "Please enter a valid email format", + "selectCountry": "Select Country", + "forLoginVerification": "for login verification", + "lastLoginBy": "Last login by" } \ No newline at end of file diff --git a/lib/extensions/widget_extensions.dart b/lib/extensions/widget_extensions.dart index 1136c32..26a1442 100644 --- a/lib/extensions/widget_extensions.dart +++ b/lib/extensions/widget_extensions.dart @@ -150,13 +150,14 @@ extension SmoothContainerExtension on ShapeBorder { bool isDisabled = false, Color? backgroundColor, BorderSide? side, + BorderRadius? customBorder, bool hasShadow = false, }) { final bgColor = backgroundColor ?? color; return ShapeDecoration( color: isDisabled ? bgColor.withOpacity(0.5) : bgColor, shape: SmoothRectangleBorder( - borderRadius: BorderRadius.circular(borderRadius ?? 0), + borderRadius: customBorder ?? BorderRadius.circular(borderRadius ?? 0), smoothness: 1, side: side ?? BorderSide.none, ), diff --git a/lib/features/authentication/authentication_view_model.dart b/lib/features/authentication/authentication_view_model.dart index c0b20b5..11374b7 100644 --- a/lib/features/authentication/authentication_view_model.dart +++ b/lib/features/authentication/authentication_view_model.dart @@ -59,8 +59,7 @@ class AuthenticationViewModel extends ChangeNotifier { required NavigationService navigationService, required CacheService cacheService, required LocalAuthService localAuthService, - }) - : _navigationService = navigationService, + }) : _navigationService = navigationService, _dialogService = dialogService, _errorHandlerService = errorHandlerService, _appState = appState, @@ -205,13 +204,13 @@ class AuthenticationViewModel extends ChangeNotifier { final result = await _authenticationRepo.selectDeviceByImei(firebaseToken: firebaseToken); result.fold( - (failure) async { + (failure) async { // LoadingUtils.hideFullScreenLoader(); // await _errorHandlerService.handleError(failure: failure); LoaderBottomSheet.hideLoader(); _navigationService.pushPage(page: LoginScreen()); }, - (apiResponse) { + (apiResponse) { // LoadingUtils.hideFullScreenLoader(); log("apiResponse: ${apiResponse.data.toString()}"); log("messageStatus: ${apiResponse.messageStatus.toString()}"); @@ -301,8 +300,7 @@ class AuthenticationViewModel extends ChangeNotifier { final result = await _authenticationRepo.checkPatientAuthentication(checkPatientAuthenticationReq: checkPatientAuthenticationReq); result.fold( - (failure) async => - await _errorHandlerService.handleError( + (failure) async => await _errorHandlerService.handleError( failure: failure, onUnHandledFailure: (failure) async { LoaderBottomSheet.hideLoader(); @@ -316,7 +314,7 @@ class AuthenticationViewModel extends ChangeNotifier { _navigationService.pop(); }); }), - (apiResponse) async { + (apiResponse) async { if (apiResponse.messageStatus == 2) { LoaderBottomSheet.hideLoader(); await _dialogService.showErrorBottomSheet(message: apiResponse.errorMessage ?? "ErrorEmpty", onOkPressed: () {}); @@ -359,8 +357,8 @@ class AuthenticationViewModel extends ChangeNotifier { patientOutSA: isForRegister ? isPatientOutsideSA(request: payload) : selectedCountrySignup.countryCode == CountryEnum.saudiArabia - ? false - : true, + ? false + : true, payload: payload, ); @@ -374,8 +372,8 @@ class AuthenticationViewModel extends ChangeNotifier { final resultEither = await _authenticationRepo.sendActivationCodeRepo(sendActivationCodeReq: request, isRegister: checkIsUserComingForRegister(request: payload), languageID: 'er'); resultEither.fold( - (failure) async => await _errorHandlerService.handleError(failure: failure), - (apiResponse) async { + (failure) async => await _errorHandlerService.handleError(failure: failure), + (apiResponse) async { if (apiResponse.messageStatus == 2) { LoaderBottomSheet.hideLoader(); await _dialogService.showCommonBottomSheetWithoutH( @@ -409,27 +407,27 @@ class AuthenticationViewModel extends ChangeNotifier { bool isForRegister = (_appState.getUserRegistrationPayload.healthId != null || _appState.getUserRegistrationPayload.patientOutSa == true || _appState.getUserRegistrationPayload.patientOutSa == 1); final request = RequestUtils.getCommonRequestWelcome( - phoneNumber: phoneNumberController.text, - otpTypeEnum: otpTypeEnum, - deviceToken: _appState.deviceToken, - // patientOutSA: _appState.getUserRegistrationPayload.projectOutSa == 1 ? true : false, - patientOutSA: isForRegister - ? _appState.getUserRegistrationPayload.projectOutSa == true - ? true - : false - : _appState.getSelectDeviceByImeiRespModelElement != null - ? _appState.getSelectDeviceByImeiRespModelElement!.outSa! - : selectedCountrySignup == CountryEnum.saudiArabia - ? false - : true, - loginTokenID: _appState.appAuthToken, - registeredData: isForRegister ? _appState.getUserRegistrationPayload : null, - nationIdText: nationalIdController.text, - countryCode: _appState.getSelectDeviceByImeiRespModelElement != null && _appState.getSelectDeviceByImeiRespModelElement!.outSa == true - ? CountryEnum.unitedArabEmirates.countryCode - : selectedCountrySignup.countryCode, - //TODO: Error Here IN Zip Code. - loginType: loginTypeEnum.toInt) + phoneNumber: phoneNumberController.text, + otpTypeEnum: otpTypeEnum, + deviceToken: _appState.deviceToken, + // patientOutSA: _appState.getUserRegistrationPayload.projectOutSa == 1 ? true : false, + patientOutSA: isForRegister + ? _appState.getUserRegistrationPayload.projectOutSa == true + ? true + : false + : _appState.getSelectDeviceByImeiRespModelElement != null + ? _appState.getSelectDeviceByImeiRespModelElement!.outSa! + : selectedCountrySignup == CountryEnum.saudiArabia + ? false + : true, + loginTokenID: _appState.appAuthToken, + registeredData: isForRegister ? _appState.getUserRegistrationPayload : null, + nationIdText: nationalIdController.text, + countryCode: _appState.getSelectDeviceByImeiRespModelElement != null && _appState.getSelectDeviceByImeiRespModelElement!.outSa == true + ? CountryEnum.unitedArabEmirates.countryCode + : selectedCountrySignup.countryCode, + //TODO: Error Here IN Zip Code. + loginType: loginTypeEnum.toInt) .toJson(); LoaderBottomSheet.showLoader(); if (isForRegister) { @@ -445,8 +443,7 @@ class AuthenticationViewModel extends ChangeNotifier { LoaderBottomSheet.hideLoader(); resultEither.fold( - (failure) async => - await _errorHandlerService.handleError( + (failure) async => await _errorHandlerService.handleError( failure: failure, onUnHandledFailure: (failure) async { LoaderBottomSheet.hideLoader(); @@ -454,9 +451,6 @@ class AuthenticationViewModel extends ChangeNotifier { message: failure.message, label: LocaleKeys.notice.tr(), onOkPressed: () { - _navigationService.pushAndReplace(AppRoutes.register); - }, - onCancelPressed: () { _navigationService.pop(); }); }), (apiResponse) { @@ -473,8 +467,7 @@ class AuthenticationViewModel extends ChangeNotifier { final resultEither = await _authenticationRepo.checkActivationCodeRepo(newRequest: CheckActivationCodeRegisterReq.fromJson(request), activationCode: activationCode, isRegister: false); resultEither.fold( - (failure) async => - await _errorHandlerService.handleError( + (failure) async => await _errorHandlerService.handleError( failure: failure, onUnHandledFailure: (failure) async { LoaderBottomSheet.hideLoader(); @@ -658,15 +651,15 @@ class AuthenticationViewModel extends ChangeNotifier { bool isOutSidePatient = selectedCountrySignup.countryCode == CountryEnum.unitedArabEmirates.countryCode ? true : false; LoaderBottomSheet.showLoader(); final request = await RequestUtils.getPatientAuthenticationRequest( - phoneNumber: phoneNumberController.text, - nationId: nationalIdController.text, - patientOutSA: isOutSidePatient, - otpTypeEnum: otpTypeEnum, - isForRegister: true, - patientId: 0, - zipCode: selectedCountrySignup.countryCode, - calenderType: calenderType, - dob: dob) + phoneNumber: phoneNumberController.text, + nationId: nationalIdController.text, + patientOutSA: isOutSidePatient, + otpTypeEnum: otpTypeEnum, + isForRegister: true, + patientId: 0, + zipCode: selectedCountrySignup.countryCode, + calenderType: calenderType, + dob: dob) .toJson(); var nRequest = Map.from(request); @@ -802,22 +795,22 @@ class AuthenticationViewModel extends ChangeNotifier { Future insertPatientIMEIData(int loginType) async { final resultEither = await _authenticationRepo.insertPatientIMEIData( patientIMEIDataRequest: PatientInsertDeviceImei( - imei: _appState.deviceToken, - deviceTypeId: _appState.getDeviceTypeID(), - patientId: _appState.getAuthenticatedUser()!.patientId!, - patientIdentificationNo: _appState.getAuthenticatedUser()!.patientIdentificationNo!, - identificationNo: _appState.getAuthenticatedUser()!.patientIdentificationNo!, - firstName: _appState.getAuthenticatedUser()!.firstName!, - lastName: _appState.getAuthenticatedUser()!.lastName!, - patientTypeId: _appState.getAuthenticatedUser()!.patientType, - mobileNo: _appState.getAuthenticatedUser()!.mobileNumber!, - logInTypeId: loginType, - patientOutSa: _appState.getAuthenticatedUser()!.outSa!, - outSa: _appState.getAuthenticatedUser()!.outSa == 1 ? true : false, - biometricEnabled: loginType == 1 || loginType == 2 ? false : true, - firstNameN: _appState.getAuthenticatedUser()!.firstNameN, - lastNameN: _appState.getAuthenticatedUser()!.lastNameN, - ).toJson()); + imei: _appState.deviceToken, + deviceTypeId: _appState.getDeviceTypeID(), + patientId: _appState.getAuthenticatedUser()!.patientId!, + patientIdentificationNo: _appState.getAuthenticatedUser()!.patientIdentificationNo!, + identificationNo: _appState.getAuthenticatedUser()!.patientIdentificationNo!, + firstName: _appState.getAuthenticatedUser()!.firstName!, + lastName: _appState.getAuthenticatedUser()!.lastName!, + patientTypeId: _appState.getAuthenticatedUser()!.patientType, + mobileNo: _appState.getAuthenticatedUser()!.mobileNumber!, + logInTypeId: loginType, + patientOutSa: _appState.getAuthenticatedUser()!.outSa!, + outSa: _appState.getAuthenticatedUser()!.outSa == 1 ? true : false, + biometricEnabled: loginType == 1 || loginType == 2 ? false : true, + firstNameN: _appState.getAuthenticatedUser()!.firstNameN, + lastNameN: _appState.getAuthenticatedUser()!.lastNameN, + ).toJson()); resultEither.fold((failure) async => await _errorHandlerService.handleError(failure: failure), (apiResponse) async { if (apiResponse.messageStatus == 1) { log("Insert IMEI Success"); @@ -831,20 +824,20 @@ class AuthenticationViewModel extends ChangeNotifier { Future insertPatientDeviceData(int loginType) async { final resultEither = await _authenticationRepo.insertPatientDeviceData( patientDeviceDataRequest: InsertPatientMobileDeviceInfo( - deviceToken: _appState.deviceToken, - deviceTypeId: _appState.getDeviceTypeID(), - patientId: _appState.getAuthenticatedUser()!.patientId!, - patientTypeId: _appState.getAuthenticatedUser()!.patientType, - patientOutSa: _appState.getAuthenticatedUser()!.outSa!, - loginType: loginType, - languageId: _appState.getLanguageID(), - latitude: _appState.userLat, - longitude: _appState.userLong, - voipToken: "", - deviceType: _appState.deviceTypeID, - patientMobileNumber: _appState.getAuthenticatedUser()!.mobileNumber, - nationalId: _appState.getAuthenticatedUser()!.patientIdentificationNo, - gender: _appState.getAuthenticatedUser()!.gender) + deviceToken: _appState.deviceToken, + deviceTypeId: _appState.getDeviceTypeID(), + patientId: _appState.getAuthenticatedUser()!.patientId!, + patientTypeId: _appState.getAuthenticatedUser()!.patientType, + patientOutSa: _appState.getAuthenticatedUser()!.outSa!, + loginType: loginType, + languageId: _appState.getLanguageID(), + latitude: _appState.userLat, + longitude: _appState.userLong, + voipToken: "", + deviceType: _appState.deviceTypeID, + patientMobileNumber: _appState.getAuthenticatedUser()!.mobileNumber, + nationalId: _appState.getAuthenticatedUser()!.patientIdentificationNo, + gender: _appState.getAuthenticatedUser()!.gender) .toJson()); resultEither.fold((failure) async => await _errorHandlerService.handleError(failure: failure), (apiResponse) async { if (apiResponse.messageStatus == 1) { @@ -858,18 +851,18 @@ class AuthenticationViewModel extends ChangeNotifier { Future getPatientDeviceData(int loginType) async { final resultEither = await _authenticationRepo.getPatientDeviceData( patientDeviceDataRequest: GetUserMobileDeviceData( - deviceToken: _appState.deviceToken, - deviceTypeId: _appState.getDeviceTypeID(), - patientId: _appState.getSelectDeviceByImeiRespModelElement!.patientId!, - patientType: _appState.getSelectDeviceByImeiRespModelElement!.patientType, - patientOutSa: _appState.getSelectDeviceByImeiRespModelElement!.outSa == true ? 1 : 0, - loginType: loginType, - languageId: _appState.getLanguageID(), - latitude: _appState.userLat, - longitude: _appState.userLong, - mobileNo: _appState.getSelectDeviceByImeiRespModelElement!.mobile!, - patientMobileNumber: int.parse(_appState.getSelectDeviceByImeiRespModelElement!.mobile!), - nationalId: _appState.getSelectDeviceByImeiRespModelElement!.identificationNo) + deviceToken: _appState.deviceToken, + deviceTypeId: _appState.getDeviceTypeID(), + patientId: _appState.getSelectDeviceByImeiRespModelElement!.patientId!, + patientType: _appState.getSelectDeviceByImeiRespModelElement!.patientType, + patientOutSa: _appState.getSelectDeviceByImeiRespModelElement!.outSa == true ? 1 : 0, + loginType: loginType, + languageId: _appState.getLanguageID(), + latitude: _appState.userLat, + longitude: _appState.userLong, + mobileNo: _appState.getSelectDeviceByImeiRespModelElement!.mobile!, + patientMobileNumber: int.parse(_appState.getSelectDeviceByImeiRespModelElement!.mobile!), + nationalId: _appState.getSelectDeviceByImeiRespModelElement!.identificationNo) .toJson()); resultEither.fold((failure) async => await _errorHandlerService.handleError(failure: failure), (apiResponse) async { if (apiResponse.messageStatus == 1) { @@ -885,11 +878,15 @@ class AuthenticationViewModel extends ChangeNotifier { message: apiResponse.errorMessage ?? "", label: LocaleKeys.notice.tr(), onOkPressed: () { - _dialogService.showPhoneNumberPickerSheet(label:"Where would you like to receive OTP?", message:"Please select from the below options to receive OTP.", onSMSPress: () { - checkUserAuthentication(otpTypeEnum: OTPTypeEnum.sms); - }, onWhatsappPress: () { - checkUserAuthentication(otpTypeEnum: OTPTypeEnum.whatsapp); - }); + _dialogService.showPhoneNumberPickerSheet( + label: "Where would you like to receive OTP?", + message: "Please select from the below options to receive OTP.", + onSMSPress: () { + checkUserAuthentication(otpTypeEnum: OTPTypeEnum.sms); + }, + onWhatsappPress: () { + checkUserAuthentication(otpTypeEnum: OTPTypeEnum.whatsapp); + }); }, onCancelPressed: () { _navigationService.pop(); @@ -914,8 +911,8 @@ class AuthenticationViewModel extends ChangeNotifier { List projectDetailListModel = []; resultEither.fold( - (failure) async => await _errorHandlerService.handleError(failure: failure), - (apiResponse) async { + (failure) async => await _errorHandlerService.handleError(failure: failure), + (apiResponse) async { if (apiResponse.messageStatus == 2) { await _dialogService.showErrorBottomSheet(message: apiResponse.errorMessage ?? "ErrorEmpty"); } else { diff --git a/lib/features/authentication/widgets/otp_verification_screen.dart b/lib/features/authentication/widgets/otp_verification_screen.dart index 5f8cdf0..e7f8d72 100644 --- a/lib/features/authentication/widgets/otp_verification_screen.dart +++ b/lib/features/authentication/widgets/otp_verification_screen.dart @@ -533,6 +533,7 @@ class _OTPVerificationScreenState extends State { @override Widget build(BuildContext context) { AuthenticationViewModel authVM = context.read(); + AppState appState = getIt(); return Scaffold( backgroundColor: AppColors.scaffoldBgColor, appBar: CustomAppBar( @@ -552,14 +553,16 @@ class _OTPVerificationScreenState extends State { LocaleKeys.otpVerification.tr().toText24(isBold: true), SizedBox(height: 20.h), Wrap( - spacing: 4.h, - runSpacing: 8.0, + spacing: 2.h, + runSpacing: 2.h, children: [ - LocaleKeys.weHaveSendOTP.tr().toText16(color: AppColors.inputLabelTextColor), - _getMaskedPhoneNumber().toText16(color: AppColors.inputLabelTextColor, isBold: true), - LocaleKeys.via.tr().toText16(color: AppColors.inputLabelTextColor), - authVM.loginTypeEnum.displayName.toText16(color: AppColors.inputLabelTextColor), - LocaleKeys.forRegistrationVerification.tr().toText16(color: AppColors.inputLabelTextColor), + LocaleKeys.weHaveSendOTP.tr().toText15(color: AppColors.inputLabelTextColor, letterSpacing: -0.4), + _getMaskedPhoneNumber().toText15(color: AppColors.inputLabelTextColor, isBold: true), + LocaleKeys.via.tr().toText15(color: AppColors.inputLabelTextColor, letterSpacing: -0.4), + authVM.loginTypeEnum.displayName.toText15(color: AppColors.inputLabelTextColor, isBold: true, letterSpacing: -0.4), + appState.getUserRegistrationPayload.isRegister != null && appState.getUserRegistrationPayload.isRegister == true + ? LocaleKeys.forRegistrationVerification.tr().toText15(color: AppColors.inputLabelTextColor, letterSpacing: -0.4) + : LocaleKeys.forLoginVerification.tr().toText15(color: AppColors.inputLabelTextColor, letterSpacing: -0.4), ], ), diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 6445de8..a452959 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -846,5 +846,7 @@ abstract class LocaleKeys { static const pleaseSelectACountry = 'pleaseSelectACountry'; static const pleaseEnterEmail = 'pleaseEnterEmail'; static const pleaseEnterAValidEmailFormat = 'pleaseEnterAValidEmailFormat'; + static const selectCountry = 'selectCountry'; + static const forLoginVerification = 'forLoginVerification'; } diff --git a/lib/presentation/authentication/register_step2.dart b/lib/presentation/authentication/register_step2.dart index 8dbe8e8..3466497 100644 --- a/lib/presentation/authentication/register_step2.dart +++ b/lib/presentation/authentication/register_step2.dart @@ -43,9 +43,11 @@ class _RegisterNew extends State { @override Widget build(BuildContext context) { AppState appState = getIt.get(); - var name = appState.getLanguageCode() == "en" - ? ("${appState.getNHICUserData.firstNameEn!.toUpperCase()} ${appState.getNHICUserData.lastNameEn!.toUpperCase()}") - : ("${appState.getNHICUserData.firstNameAr!.toUpperCase()} ${appState.getNHICUserData.lastNameAr!.toUpperCase()}"); + var name = authVM!.isUserFromUAE() + ? "" + : appState.getLanguageCode() == "en" + ? ("${appState.getNHICUserData.firstNameEn!.toUpperCase()} ${appState.getNHICUserData.lastNameEn!.toUpperCase()}") + : ("${appState.getNHICUserData.firstNameAr!.toUpperCase()} ${appState.getNHICUserData.lastNameAr!.toUpperCase()}"); return Scaffold( backgroundColor: AppColors.bgScaffoldColor, appBar: CustomAppBar( @@ -57,262 +59,273 @@ class _RegisterNew extends State { onLanguageChanged: (lang) {}, hideLogoAndLang: true, ), - body: SingleChildScrollView( - reverse: false, - padding: EdgeInsets.only(left: 24.h, right: 24.h, top: 0.h), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - LocaleKeys.personalDetailsVerification.tr().toText26(color: AppColors.textColor, weight: FontWeight.w600, letterSpacing: -2), - SizedBox(height: 24.h), - Directionality( - textDirection: Directionality.of(context), - child: Container( - decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(24)), - padding: EdgeInsets.only(left: 16.h, right: 16.h), - child: Column( + body: GestureDetector( + onTap: () { + FocusScope.of(context).unfocus(); + }, + behavior: HitTestBehavior.translucent, // Ensures taps on empty space are detected + child: SizedBox( + width: double.infinity, + height: double.infinity, + child: SingleChildScrollView( + reverse: false, + padding: EdgeInsets.only(left: 24.h, right: 24.h, top: 0.h), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.personalDetailsVerification.tr().toText26(color: AppColors.textColor, weight: FontWeight.w600, letterSpacing: -2), + SizedBox(height: 24.h), + Container( + decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(24)), + padding: EdgeInsets.only(left: 16.h, right: 16.h), + child: Column( + children: [ + TextInputWidget( + labelText: authVM!.isUserFromUAE() ? LocaleKeys.fullName.tr() : LocaleKeys.name.tr(), + hintText: authVM!.isUserFromUAE() ? LocaleKeys.enterNameHere.tr() : (name), + controller: authVM!.isUserFromUAE() ? authVM!.nameController : null, + isEnable: true, + prefix: null, + isAllowRadius: false, + isBorderAllowed: false, + keyboardType: TextInputType.text, + // textInputAction: TextInputAction.done, + onSubmitted: (value) { + FocusScope.of(context).unfocus(); + }, + isAllowLeadingIcon: true, + isReadOnly: authVM!.isUserFromUAE() ? false : true, + leadingIcon: AppAssets.user_circle, + labelColor: AppColors.textColor, + ).paddingSymmetrical(0.h, 16.h), + Divider(height: 1, color: AppColors.greyColor), + TextInputWidget( + labelText: LocaleKeys.nationalIdNumber.tr(), + hintText: authVM!.isUserFromUAE() ? appState.getUserRegistrationPayload.patientIdentificationId.toString() : (appState.getNHICUserData.idNumber ?? ""), + controller: null, + isEnable: true, + prefix: null, + isAllowRadius: false, + isBorderAllowed: false, + isAllowLeadingIcon: true, + isReadOnly: true, + labelColor: AppColors.textColor, + leadingIcon: AppAssets.student_card) + .paddingSymmetrical(0.h, 16.h), + Divider(height: 1, color: AppColors.greyColor), + authVM!.isUserFromUAE() + ? Selector( + selector: (_, authViewModel) => authViewModel.genderType, + shouldRebuild: (previous, next) => previous != next, + builder: (context, genderType, child) { + final authVM = context.read(); + return DropdownWidget( + labelText: LocaleKeys.gender.tr(), + hintText: LocaleKeys.malE.tr(), + isEnable: true, + dropdownItems: GenderTypeEnum.values.map((e) => appState.isArabic() ? e.typeAr : e.type).toList(), + selectedValue: genderType != null ? (appState.isArabic() ? genderType.typeAr : genderType.type) : "", + onChange: authVM.onGenderChange, + isBorderAllowed: false, + hasSelectionCustomIcon: true, + isAllowRadius: false, + labelColor: AppColors.textColor, + padding: const EdgeInsets.only(top: 8, bottom: 8, left: 0, right: 0), + selectionCustomIcon: AppAssets.arrow_down, + leadingIcon: AppAssets.user_full, + ).withVerticalPadding(8); + }) + : TextInputWidget( + labelText: LocaleKeys.gender.tr(), + hintText: (appState.getNHICUserData.gender ?? ""), + controller: null, + isEnable: true, + prefix: null, + isAllowRadius: false, + isBorderAllowed: false, + isAllowLeadingIcon: true, + isReadOnly: authVM!.isUserFromUAE() ? false : true, + leadingIcon: AppAssets.user_full, + labelColor: AppColors.textColor, + onChange: (value) {}) + .paddingSymmetrical(0.h, 16.h), + Divider(height: 1, color: AppColors.greyColor), + authVM!.isUserFromUAE() + ? Selector( + selector: (_, authViewModel) => authViewModel.maritalStatus, + shouldRebuild: (previous, next) => previous != next, + builder: (context, maritalStatus, child) { + final authVM = context.read(); // For onChange + return DropdownWidget( + labelText: LocaleKeys.maritalStatus.tr(), + hintText: LocaleKeys.married.tr(), + isEnable: true, + dropdownItems: MaritalStatusTypeEnum.values.map((e) => appState.isArabic() ? e.typeAr : e.type).toList(), + selectedValue: maritalStatus != null ? (appState.isArabic() ? maritalStatus.typeAr : maritalStatus.type) : "", + onChange: authVM.onMaritalStatusChange, + isBorderAllowed: false, + hasSelectionCustomIcon: true, + isAllowRadius: false, + labelColor: AppColors.textColor, + padding: const EdgeInsets.only(top: 8, bottom: 8, left: 0, right: 0), + selectionCustomIcon: AppAssets.arrow_down, + leadingIcon: AppAssets.smart_phone, + ).withVerticalPadding(8); + }, + ) + : TextInputWidget( + labelText: LocaleKeys.maritalStatus.tr(), + hintText: appState.isArabic() + ? (MaritalStatusTypeExtension.fromValue(appState.getNHICUserData.maritalStatusCode)!.typeAr) + : (MaritalStatusTypeExtension.fromValue(appState.getNHICUserData.maritalStatusCode)!.type), + isEnable: true, + prefix: null, + isAllowRadius: false, + isBorderAllowed: false, + isAllowLeadingIcon: true, + isReadOnly: true, + labelColor: AppColors.textColor, + leadingIcon: AppAssets.smart_phone, + onChange: (value) {}) + .paddingSymmetrical(0.h, 16.h), + Divider(height: 1, color: AppColors.greyColor), + authVM!.isUserFromUAE() + ? Selector? countriesList, NationalityCountries? selectedCountry, bool isArabic})>( + selector: (context, authViewModel) { + final appState = getIt.get(); + return ( + countriesList: authViewModel.countriesList, + selectedCountry: authViewModel.pickedCountryByUAEUser, + isArabic: appState.isArabic(), + ); + }, + shouldRebuild: (previous, next) => previous.countriesList != next.countriesList || previous.selectedCountry != next.selectedCountry || previous.isArabic != next.isArabic, + builder: (context, data, child) { + final authVM = context.read(); + return DropdownWidget( + labelText: LocaleKeys.country.tr(), + hintText: LocaleKeys.uae.tr(), + isEnable: true, + dropdownItems: (data.countriesList ?? []).map((e) => data.isArabic ? e.nameN ?? "" : e.name ?? "").toList(), + selectedValue: data.selectedCountry != null + ? data.isArabic + ? data.selectedCountry!.nameN ?? "" + : data.selectedCountry!.name ?? "" + : "", + onChange: authVM.onUAEUserCountrySelection, + isBorderAllowed: false, + hasSelectionCustomIcon: true, + labelColor: AppColors.textColor, + isAllowRadius: false, + padding: const EdgeInsets.only(top: 8, bottom: 8, left: 0, right: 0), + selectionCustomIcon: AppAssets.arrow_down, + leadingIcon: AppAssets.globe, + ).withVerticalPadding(8); + }, + ) + : TextInputWidget( + labelText: LocaleKeys.nationality.tr(), + hintText: appState.isArabic() + ? (authVM!.countriesList!.firstWhere((e) => e.id == (appState.getNHICUserData.nationalityCode ?? ""), orElse: () => NationalityCountries()).nameN ?? "") + : (authVM!.countriesList!.firstWhere((e) => e.id == (appState.getNHICUserData.nationalityCode ?? ""), orElse: () => NationalityCountries()).name ?? ""), + isEnable: true, + prefix: null, + isAllowRadius: false, + isBorderAllowed: false, + isAllowLeadingIcon: true, + isReadOnly: true, + labelColor: AppColors.textColor, + leadingIcon: AppAssets.globe, + onChange: (value) {}) + .paddingSymmetrical(0.h, 16.h), + Divider( + height: 1, + color: AppColors.greyColor, + ), + TextInputWidget( + labelText: LocaleKeys.mobileNumber.tr(), + hintText: (appState.getUserRegistrationPayload.patientMobileNumber.toString() ?? ""), + controller: null, + isEnable: false, + prefix: null, + isAllowRadius: false, + isBorderAllowed: false, + isAllowLeadingIcon: true, + labelColor: AppColors.textColor, + isReadOnly: true, + leadingIcon: AppAssets.call) + .paddingSymmetrical(0.h, 16.h), + Divider( + height: 1, + color: AppColors.greyColor, + ), + TextInputWidget( + labelText: LocaleKeys.dob.tr(), + hintText: authVM!.isUserFromUAE() ? appState.getUserRegistrationPayload.dob! : appState.getNHICUserData.dateOfBirth ?? "", + controller: authVM!.isUserFromUAE() ? authVM!.dobController : null, + isEnable: false, + prefix: null, + isBorderAllowed: false, + isAllowLeadingIcon: true, + isReadOnly: true, + labelColor: AppColors.textColor, + leadingIcon: AppAssets.birthday_cake, + selectionType: null, + ).paddingSymmetrical(0.h, 16.h), + ], + ), + ), + SizedBox(height: 50.h), + Row( children: [ - TextInputWidget( - labelText: authVM!.isUserFromUAE() ? LocaleKeys.fullName.tr() : LocaleKeys.name.tr(), - hintText: authVM!.isUserFromUAE() ? LocaleKeys.enterNameHere.tr() : (name), - controller: authVM!.isUserFromUAE() ? authVM!.nameController : null, - isEnable: true, - prefix: null, - isAllowRadius: false, - isBorderAllowed: false, - keyboardType: TextInputType.text, - isAllowLeadingIcon: true, - isReadOnly: authVM!.isUserFromUAE() ? false : true, - leadingIcon: AppAssets.user_circle, - labelColor: AppColors.textColor, - ).paddingSymmetrical(0.h, 16.h), - Divider(height: 1, color: AppColors.greyColor), - TextInputWidget( - labelText: LocaleKeys.nationalIdNumber.tr(), - hintText: authVM!.isUserFromUAE() ? appState.getUserRegistrationPayload.patientIdentificationId.toString() : (appState.getNHICUserData.idNumber ?? ""), - controller: null, - isEnable: true, - prefix: null, - isAllowRadius: false, - isBorderAllowed: false, - isAllowLeadingIcon: true, - isReadOnly: true, - labelColor: AppColors.textColor, - leadingIcon: AppAssets.student_card) - .paddingSymmetrical(0.h, 16.h), - Divider(height: 1, color: AppColors.greyColor), - authVM!.isUserFromUAE() - ? Selector( - selector: (_, authViewModel) => authViewModel.genderType, - shouldRebuild: (previous, next) => previous != next, - builder: (context, genderType, child) { - final authVM = context.read(); - return DropdownWidget( - labelText: LocaleKeys.gender.tr(), - hintText: LocaleKeys.malE.tr(), - isEnable: true, - dropdownItems: GenderTypeEnum.values.map((e) => appState.isArabic() ? e.typeAr : e.type).toList(), - selectedValue: genderType != null ? (appState.isArabic() ? genderType.typeAr : genderType.type) : "", - onChange: authVM.onGenderChange, - isBorderAllowed: false, - hasSelectionCustomIcon: true, - isAllowRadius: false, - labelColor: AppColors.textColor, - padding: const EdgeInsets.only(top: 8, bottom: 8, left: 0, right: 0), - selectionCustomIcon: AppAssets.arrow_down, - leadingIcon: AppAssets.user_full, - ).withVerticalPadding(8); - }) - : TextInputWidget( - labelText: LocaleKeys.gender.tr(), - hintText: (appState.getNHICUserData.gender ?? ""), - controller: null, - isEnable: true, - prefix: null, - isAllowRadius: false, - isBorderAllowed: false, - isAllowLeadingIcon: true, - isReadOnly: authVM!.isUserFromUAE() ? false : true, - leadingIcon: AppAssets.user_full, - labelColor: AppColors.textColor, - onChange: (value) {}) - .paddingSymmetrical(0.h, 16.h), - Divider(height: 1, color: AppColors.greyColor), - authVM!.isUserFromUAE() - ? Selector( - selector: (_, authViewModel) => authViewModel.maritalStatus, - shouldRebuild: (previous, next) => previous != next, - builder: (context, maritalStatus, child) { - final authVM = context.read(); // For onChange - return DropdownWidget( - labelText: LocaleKeys.maritalStatus.tr(), - hintText: LocaleKeys.married.tr(), - isEnable: true, - dropdownItems: MaritalStatusTypeEnum.values.map((e) => appState.isArabic() ? e.typeAr : e.type).toList(), - selectedValue: maritalStatus != null ? (appState.isArabic() ? maritalStatus.typeAr : maritalStatus.type) : "", - onChange: authVM.onMaritalStatusChange, - isBorderAllowed: false, - hasSelectionCustomIcon: true, - isAllowRadius: false, - labelColor: AppColors.textColor, - padding: const EdgeInsets.only(top: 8, bottom: 8, left: 0, right: 0), - selectionCustomIcon: AppAssets.arrow_down, - leadingIcon: AppAssets.smart_phone, - ).withVerticalPadding(8); - }, - ) - : TextInputWidget( - labelText: LocaleKeys.maritalStatus.tr(), - hintText: appState.isArabic() - ? (MaritalStatusTypeExtension.fromValue(appState.getNHICUserData.maritalStatusCode)!.typeAr) - : (MaritalStatusTypeExtension.fromValue(appState.getNHICUserData.maritalStatusCode)!.type), - isEnable: true, - prefix: null, - isAllowRadius: false, - isBorderAllowed: false, - isAllowLeadingIcon: true, - isReadOnly: true, - labelColor: AppColors.textColor, - leadingIcon: AppAssets.smart_phone, - onChange: (value) {}) - .paddingSymmetrical(0.h, 16.h), - Divider(height: 1, color: AppColors.greyColor), - authVM!.isUserFromUAE() - ? Selector? countriesList, NationalityCountries? selectedCountry, bool isArabic})>( - selector: (context, authViewModel) { - final appState = getIt.get(); - return ( - countriesList: authViewModel.countriesList, - selectedCountry: authViewModel.pickedCountryByUAEUser, - isArabic: appState.isArabic(), - ); - }, - shouldRebuild: (previous, next) => previous.countriesList != next.countriesList || previous.selectedCountry != next.selectedCountry || previous.isArabic != next.isArabic, - builder: (context, data, child) { - final authVM = context.read(); - return DropdownWidget( - labelText: LocaleKeys.country.tr(), - hintText: LocaleKeys.uae.tr(), - isEnable: true, - dropdownItems: (data.countriesList ?? []).map((e) => data.isArabic ? e.nameN ?? "" : e.name ?? "").toList(), - selectedValue: data.selectedCountry != null - ? data.isArabic - ? data.selectedCountry!.nameN ?? "" - : data.selectedCountry!.name ?? "" - : "", - onChange: authVM.onUAEUserCountrySelection, - isBorderAllowed: false, - hasSelectionCustomIcon: true, - labelColor: AppColors.textColor, - isAllowRadius: false, - padding: const EdgeInsets.only(top: 8, bottom: 8, left: 0, right: 0), - selectionCustomIcon: AppAssets.arrow_down, - leadingIcon: AppAssets.globe, - ).withVerticalPadding(8); - }, - ) - : TextInputWidget( - labelText: LocaleKeys.nationality.tr(), - hintText: appState.isArabic() - ? (authVM!.countriesList!.firstWhere((e) => e.id == (appState.getNHICUserData.nationalityCode ?? ""), orElse: () => NationalityCountries()).nameN ?? "") - : (authVM!.countriesList!.firstWhere((e) => e.id == (appState.getNHICUserData.nationalityCode ?? ""), orElse: () => NationalityCountries()).name ?? ""), - isEnable: true, - prefix: null, - isAllowRadius: false, - isBorderAllowed: false, - isAllowLeadingIcon: true, - isReadOnly: true, - labelColor: AppColors.textColor, - leadingIcon: AppAssets.globe, - onChange: (value) {}) - .paddingSymmetrical(0.h, 16.h), - Divider( - height: 1, - color: AppColors.greyColor, + Expanded( + child: CustomButton( + text: LocaleKeys.cancel.tr(), + icon: AppAssets.cancel, + onPressed: () { + Navigator.of(context).pop(); + // authVM!.clearDefaultInputValues(); + }, + backgroundColor: AppColors.secondaryLightRedColor, + borderColor: AppColors.secondaryLightRedColor, + textColor: AppColors.primaryRedColor, + iconColor: AppColors.primaryRedColor, + ), ), - TextInputWidget( - labelText: LocaleKeys.mobileNumber.tr(), - hintText: (appState.getUserRegistrationPayload.patientMobileNumber.toString() ?? ""), - controller: null, - isEnable: false, - prefix: null, - isAllowRadius: false, - isBorderAllowed: false, - isAllowLeadingIcon: true, - labelColor: AppColors.textColor, - isReadOnly: true, - leadingIcon: AppAssets.call) - .paddingSymmetrical(0.h, 16.h), - Divider( - height: 1, - color: AppColors.greyColor, + SizedBox( + width: 16, ), - TextInputWidget( - labelText: LocaleKeys.dob.tr(), - hintText: authVM!.isUserFromUAE() ? appState.getUserRegistrationPayload.dob! : appState.getNHICUserData.dateOfBirth ?? "", - controller: authVM!.isUserFromUAE() ? authVM!.dobController : null, - isEnable: false, - prefix: null, - isBorderAllowed: false, - isAllowLeadingIcon: true, - isReadOnly: true, - labelColor: AppColors.textColor, - leadingIcon: AppAssets.birthday_cake, - selectionType: null, - ).paddingSymmetrical(0.h, 16.h), + Expanded( + child: CustomButton( + backgroundColor: AppColors.primaryRedColor, + borderColor: AppColors.primaryRedColor, + textColor: AppColors.whiteColor, + text: LocaleKeys.confirm.tr(), + icon: AppAssets.confirm, + iconColor: AppColors.whiteColor, + onPressed: () { + if (appState.getUserRegistrationPayload.zipCode != CountryEnum.saudiArabia.countryCode) { + if (ValidationUtils.validateUaeRegistration( + name: authVM!.nameController.text, + gender: authVM!.genderType, + country: authVM!.pickedCountryByUAEUser, + maritalStatus: authVM!.maritalStatus, + onOkPress: () { + Navigator.of(context).pop(); + })) { + showModel(context: context); + } + } else { + showModel(context: context); + } + }, + ), + ) ], ), - ), - ), - SizedBox(height: 50.h), - Row( - children: [ - Expanded( - child: CustomButton( - text: LocaleKeys.cancel.tr(), - icon: AppAssets.cancel, - onPressed: () { - Navigator.of(context).pop(); - // authVM!.clearDefaultInputValues(); - }, - backgroundColor: AppColors.secondaryLightRedColor, - borderColor: AppColors.secondaryLightRedColor, - textColor: AppColors.primaryRedColor, - iconColor: AppColors.primaryRedColor, - ), - ), - SizedBox( - width: 16, - ), - Expanded( - child: CustomButton( - backgroundColor: AppColors.primaryRedColor, - borderColor: AppColors.primaryRedColor, - textColor: AppColors.whiteColor, - text: LocaleKeys.confirm.tr(), - icon: AppAssets.confirm, - iconColor: AppColors.whiteColor, - onPressed: () { - if (appState.getUserRegistrationPayload.zipCode != CountryEnum.saudiArabia.countryCode) { - if (ValidationUtils.validateUaeRegistration( - name: authVM!.nameController.text, - gender: authVM!.genderType, - country: authVM!.pickedCountryByUAEUser, - maritalStatus: authVM!.maritalStatus, - onOkPress: () { - Navigator.of(context).pop(); - })) { - showModel(context: context); - } - } else { - showModel(context: context); - } - }, - ), - ) ], ), - ], + ), ), ), ); diff --git a/lib/presentation/authentication/saved_login_screen.dart b/lib/presentation/authentication/saved_login_screen.dart index 073ff8b..65b1828 100644 --- a/lib/presentation/authentication/saved_login_screen.dart +++ b/lib/presentation/authentication/saved_login_screen.dart @@ -72,7 +72,9 @@ class _SavedLogin extends State { // Welcome back text LocaleKeys.welcomeBack.tr().toText16(color: AppColors.inputLabelTextColor), SizedBox(height: 16.h), - appState.getSelectDeviceByImeiRespModelElement!.name!.toCamelCase.toText26(isBold: true, height: 26 / 36, color: AppColors.textColor), + appState.getSelectDeviceByImeiRespModelElement != null + ? appState.getSelectDeviceByImeiRespModelElement!.name!.toCamelCase.toText26(isBold: true, height: 26 / 36, color: AppColors.textColor) + : SizedBox(), SizedBox(height: 24.h), Container( padding: EdgeInsets.all(16.h), @@ -89,15 +91,22 @@ class _SavedLogin extends State { // Last login info ("${LocaleKeys.lastLoginBy.tr()} ${loginType.displayName}").toText14(isBold: true, color: AppColors.greyTextColor, letterSpacing: -1), - (appState.getSelectDeviceByImeiRespModelElement!.createdOn != null - ? DateUtil.getFormattedDate(DateUtil.convertStringToDate(appState.getSelectDeviceByImeiRespModelElement!.createdOn!), "d MMMM, y 'at' HH:mm") - : '--') - .toText16(isBold: true, color: AppColors.textColor), + appState.getSelectDeviceByImeiRespModelElement != null + ? (appState.getSelectDeviceByImeiRespModelElement!.createdOn != null + ? DateUtil.getFormattedDate(DateUtil.convertStringToDate(appState.getSelectDeviceByImeiRespModelElement!.createdOn!), "d MMMM, y 'at' HH:mm") + : '--') + .toText16(isBold: true, color: AppColors.textColor) + : SizedBox(), - Container( - margin: EdgeInsets.all(16.h), - child: Utils.buildSvgWithAssets( - icon: getTypeIcons(appState.getSelectDeviceByImeiRespModelElement!.logInType!), height: 54, width: 54, iconColor: loginType.toInt == 4 ? null : AppColors.primaryRedColor)), + appState.getSelectDeviceByImeiRespModelElement != null + ? Container( + margin: EdgeInsets.all(16.h), + child: Utils.buildSvgWithAssets( + icon: getTypeIcons(appState.getSelectDeviceByImeiRespModelElement!.logInType!), + height: 54, + width: 54, + iconColor: loginType.toInt == 4 ? null : AppColors.primaryRedColor)) + : SizedBox(), // Face ID login button SizedBox( height: 45, @@ -110,8 +119,8 @@ class _SavedLogin extends State { authVm.checkUserAuthentication(otpTypeEnum: loginType == LoginTypeEnum.sms ? OTPTypeEnum.sms : OTPTypeEnum.whatsapp); } }, - backgroundColor: Color(0xffED1C2B), - borderColor: Color(0xffFEE9EA), + backgroundColor: AppColors.primaryRedColor, + borderColor: AppColors.primaryRedColor, textColor: Colors.white, fontSize: 12, fontWeight: FontWeight.w500, diff --git a/lib/widgets/bottomsheet/generic_bottom_sheet.dart b/lib/widgets/bottomsheet/generic_bottom_sheet.dart index 05275fa..cf7697d 100644 --- a/lib/widgets/bottomsheet/generic_bottom_sheet.dart +++ b/lib/widgets/bottomsheet/generic_bottom_sheet.dart @@ -85,7 +85,8 @@ class _GenericBottomSheetState extends State { textDirection: Directionality.of(context), child: Container( padding: EdgeInsets.all(24.h), - decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.bgScaffoldColor, borderRadius: 16), + decoration: RoundedRectangleBorder() + .toSmoothCornerDecoration(color: AppColors.bgScaffoldColor, borderRadius: 16, customBorder: BorderRadius.only(topLeft: Radius.circular(16), topRight: Radius.circular(16))), child: Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.start, @@ -151,7 +152,7 @@ class _GenericBottomSheetState extends State { prefix: widget.isForEmail ? null : widget.countryCode, isBorderAllowed: false, isAllowLeadingIcon: true, - fontSize: 12.h, + fontSize: 13.h, isCountryDropDown: widget.isEnableCountryDropdown, leadingIcon: widget.isForEmail ? AppAssets.email : AppAssets.smart_phone, ) diff --git a/lib/widgets/buttons/custom_button.dart b/lib/widgets/buttons/custom_button.dart index 30e4e5d..7df7dfb 100644 --- a/lib/widgets/buttons/custom_button.dart +++ b/lib/widgets/buttons/custom_button.dart @@ -53,7 +53,7 @@ class CustomButton extends StatelessWidget { color: isDisabled ? Colors.transparent : backgroundColor, borderRadius: borderRadius, side: BorderSide( - width: borderWidth, + width: borderWidth.h, color: isDisabled ? borderColor.withOpacity(0.5) : borderColor, )), child: Row( diff --git a/lib/widgets/dropdown/country_dropdown_widget.dart b/lib/widgets/dropdown/country_dropdown_widget.dart index 772bf39..f002f24 100644 --- a/lib/widgets/dropdown/country_dropdown_widget.dart +++ b/lib/widgets/dropdown/country_dropdown_widget.dart @@ -98,30 +98,33 @@ class _CustomCountryDropdownState extends State { children: [ Text( LocaleKeys.phoneNumber.tr(), - style: TextStyle(fontSize: 12.fSize, height: 21 / 12, fontWeight: FontWeight.w500, letterSpacing: -1), + style: TextStyle(fontSize: 12.fSize, height: 1.2.h, fontWeight: FontWeight.w500, letterSpacing: -1), ), ], ), Row( crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, children: [ Text( selectedCountry!.countryCode, - style: TextStyle(fontSize: 12.fSize, height: 23 / 18, fontWeight: FontWeight.w600, letterSpacing: -1), + style: TextStyle(fontSize: 12.fSize, fontWeight: FontWeight.w600, letterSpacing: -0.4, height: 1.5), ), SizedBox(width: 4.h), if (widget.isEnableTextField) SizedBox( - height: 20, - width: 200, - // color: Colors.red, - child: TextField( + height: 20.h, + width: 200.h, + child: Align( + alignment: Alignment.centerLeft, + child: TextField( focusNode: textFocusNode, - style: TextStyle(fontSize: 12.fSize, height: 23 / 18, fontWeight: FontWeight.w600, letterSpacing: -1), - decoration: InputDecoration(hintText: "", isDense: false, border: InputBorder.none), + style: TextStyle(fontSize: 12.fSize, fontWeight: FontWeight.w600, letterSpacing: -0.4, height: 1.5), + decoration: InputDecoration(hintText: "", isDense: true, border: InputBorder.none, contentPadding: EdgeInsets.zero), keyboardType: TextInputType.phone, - onChanged: widget.onPhoneNumberChanged), + onChanged: widget.onPhoneNumberChanged, + ), + ), ), ], ) @@ -134,7 +137,7 @@ class _CustomCountryDropdownState extends State { ? appState.getLanguageCode() == "ar" ? selectedCountry!.nameArabic : selectedCountry!.displayName - : "Select Country", + : LocaleKeys.selectCountry.tr(), style: TextStyle(fontSize: 14.fSize, height: 21 / 14, fontWeight: FontWeight.w500, letterSpacing: -0.2), ), ], diff --git a/lib/widgets/dropdown/dropdown_widget.dart b/lib/widgets/dropdown/dropdown_widget.dart index f093f0b..d4c1c5f 100644 --- a/lib/widgets/dropdown/dropdown_widget.dart +++ b/lib/widgets/dropdown/dropdown_widget.dart @@ -122,7 +122,9 @@ class DropdownWidget extends StatelessWidget { .toList(), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), + ), + color: AppColors.scaffoldBgColor ); if (selected != null && onChange != null) { diff --git a/lib/widgets/input_widget.dart b/lib/widgets/input_widget.dart index a527054..4a2322c 100644 --- a/lib/widgets/input_widget.dart +++ b/lib/widgets/input_widget.dart @@ -42,6 +42,7 @@ class TextInputWidget extends StatelessWidget { final bool? isWalletAmountInput; final Widget? suffix; final Color? labelColor; + final Function(String)? onSubmitted; // final List countryList; // final Function(Country)? onCountryChange; @@ -72,7 +73,8 @@ class TextInputWidget extends StatelessWidget { this.fontSize = 14, this.isWalletAmountInput = false, this.suffix, - this.labelColor + this.labelColor, + this.onSubmitted // this.countryList = const [], // this.onCountryChange, }); @@ -239,7 +241,8 @@ class TextInputWidget extends StatelessWidget { onTapOutside: (event) { FocusManager.instance.primaryFocus?.unfocus(); }, - style: TextStyle(fontSize: fontSize!.fSize, height: isWalletAmountInput! ? 1 / 4 : 21 / 14, fontWeight: FontWeight.w500, color: AppColors.textColor, letterSpacing: -0.2), + onSubmitted: onSubmitted, + style: TextStyle(fontSize: fontSize!.fSize, height: isWalletAmountInput! ? 1 / 4 : 0, fontWeight: FontWeight.w500, color: AppColors.textColor, letterSpacing: -1), decoration: InputDecoration( isDense: true, hintText: hintText, From 3fdd17ccaab2ef2ef430943703d2c358e3cf7ee8 Mon Sep 17 00:00:00 2001 From: "taha.alam" Date: Thu, 18 Sep 2025 16:17:36 +0300 Subject: [PATCH 04/12] code added to get the location for gms hms and iphone. fallback added if the last known location is null. --- lib/core/app_state.dart | 5 + lib/core/dependencies.dart | 3 +- lib/core/location_util.dart | 174 +++++++++++++----- .../book_appointments_view_model.dart | 39 ++-- lib/main.dart | 1 + .../appointment_checkin_bottom_sheet.dart | 2 +- .../hospital_bottom_sheet_body.dart | 2 +- .../book_appointment_page.dart | 1 + pubspec.yaml | 2 + 9 files changed, 169 insertions(+), 60 deletions(-) diff --git a/lib/core/app_state.dart b/lib/core/app_state.dart index f4c0fd8..e9abeaa 100644 --- a/lib/core/app_state.dart +++ b/lib/core/app_state.dart @@ -133,5 +133,10 @@ class AppState { _userRegistrationPayload = value; } + ///this will be called if there is any problem in getting the user location + void resetLocation(){ + userLong = 0.0; + userLong = 0.0; + } } diff --git a/lib/core/dependencies.dart b/lib/core/dependencies.dart index f5b3d05..4de7c5f 100644 --- a/lib/core/dependencies.dart +++ b/lib/core/dependencies.dart @@ -158,7 +158,8 @@ class AppDependencies { bookAppointmentsRepo: getIt(), errorHandlerService: getIt(), navigationService: getIt(), - myAppointmentsViewModel: getIt() + myAppointmentsViewModel: getIt(), + locationUtils: getIt() ), ); diff --git a/lib/core/location_util.dart b/lib/core/location_util.dart index d556034..2104078 100644 --- a/lib/core/location_util.dart +++ b/lib/core/location_util.dart @@ -1,12 +1,23 @@ import 'dart:io'; +import 'dart:ui'; import 'package:geolocator/geolocator.dart'; +import 'package:gms_check/gms_check.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/cache_consts.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/services/navigation_service.dart'; -import 'package:permission_handler/permission_handler.dart'; +import 'package:huawei_location/huawei_location.dart' as HmsLocation + show + FusedLocationProviderClient, + Location, + LocationSettingsRequest, + LocationRequest; +import 'package:location/location.dart' + show Location, PermissionStatus, LocationData; +import 'package:permission_handler/permission_handler.dart' + show Permission, PermissionListActions, PermissionStatusGetters; class LocationUtils { NavigationService navigationService; @@ -16,6 +27,7 @@ class LocationUtils { bool isShowLocationTimeoutDialog; bool isHuawei; final GeolocatorPlatform _geolocatorPlatform = GeolocatorPlatform.instance; + Future? isGMSDevice; LocationUtils({ required this.isShowConfirmDialog, @@ -23,49 +35,62 @@ class LocationUtils { required this.appState, this.isHuawei = false, this.isShowLocationTimeoutDialog = true, - }); - - void getCurrentLocation({Function(LatLng)? callBack}) async { - Geolocator.isLocationServiceEnabled().then((value) async { - if (value) { - await Geolocator.checkPermission().then((permission) async { - if (permission == LocationPermission.always || permission == LocationPermission.whileInUse) { - Geolocator.getLastKnownPosition().then((value) { - setLocation(value); - if (callBack != null) callBack(LatLng(value?.latitude ?? 24.7101433, value?.longitude ?? 46.6757709)); - }).catchError((err) { - if (isShowConfirmDialog && isShowLocationTimeoutDialog) {} - }); - } + }) { + isGMSDevice = GmsCheck().checkGmsAvailability(); + } - if (permission == LocationPermission.denied || permission == LocationPermission.deniedForever) { - if (Platform.isAndroid) { - // Utils.showPermissionConsentDialog(context, TranslationBase.of(context).locationPermissionDialog, () async { - final hasPermission = await _handlePermission(); - if (hasPermission) { - // Geolocator.getCurrentPosition(locationSettings: LocationSettings(accuracy: LocationAccuracy.medium, timeLimit: Duration(seconds: 5))).then((value) { - Geolocator.getLastKnownPosition().then((value) { - setLocation(value); - if (callBack != null) callBack(LatLng(value?.latitude ?? 24.7101433, value?.longitude ?? 46.6757709)); - }); - } else { - // if (isShowConfirmDialog) showErrorLocationDialog(false, failureCallBack: () {}); - } - // }); - } else { - if (await Permission.location.request().isGranted) { - getCurrentLocation(callBack: callBack); - } else { - setZeroLocation(); - if (isShowConfirmDialog) showErrorLocationDialog(false, failureCallBack: () {}); - } - } - } - }).catchError((err) {}); - } else { - if (isShowConfirmDialog) showErrorLocationDialog(false, failureCallBack: () {}); + void getLocation( + {Function(LatLng)? onSuccess, VoidCallback? onFailure}) async { + if (Platform.isIOS) { + getCurrentLocation(onFailure: onFailure, onSuccess: onSuccess); + return; + } + + if (await isGMSDevice ?? true) { + getCurrentLocation(onFailure: onFailure, onSuccess: onSuccess); + return; + } + + getHMSLocation(onFailure: onFailure, onSuccess: onSuccess); + } + + void getCurrentLocation( + {Function(LatLng)? onSuccess, VoidCallback? onFailure}) async { + var location = Location(); + + bool isLocationEnabled = await location.serviceEnabled(); + //if the location service is not enabled, ask the user to enable it + if (!isLocationEnabled) { + isLocationEnabled = await location.requestService(); + if (!isLocationEnabled) { + appState.resetLocation(); + onFailure?.call(); + return; + } + } + + LocationPermission permissionGranted = await Geolocator.checkPermission(); + if (permissionGranted == LocationPermission.denied) { + permissionGranted = await Geolocator.requestPermission(); + if (permissionGranted != LocationPermission.whileInUse && + permissionGranted != LocationPermission.always) { + appState.resetLocation(); + onFailure?.call(); + return; } - }).catchError((err) {}); + } + + Position? currentLocation = await Geolocator.getLastKnownPosition(); + + if(currentLocation?.latitude == null || currentLocation?.longitude == null){ + currentLocation = await Geolocator.getCurrentPosition( + desiredAccuracy: LocationAccuracy.low); + } + + LatLng locationData = LatLng( + currentLocation?.latitude ?? 0.0, currentLocation?.longitude ?? 0.0); + saveLatLngToAppState(locationData); + onSuccess?.call(locationData); } Future checkIfGPSIsEnabled() async { @@ -166,4 +191,69 @@ class LocationUtils { ].request(); return (result[Permission.location]!.isGranted || result[Permission.locationAlways]!.isGranted); } + + void saveLatLngToAppState(LatLng locationData) { + appState.userLat = locationData.latitude; + appState.userLong = locationData.longitude; + } + + void getHMSLocation( + {VoidCallback? onFailure, Function(LatLng p1)? onSuccess}) async { + try { + var location = Location(); + HmsLocation.FusedLocationProviderClient locationService = + HmsLocation.FusedLocationProviderClient()..initFusedLocationService(); + + bool isLocationEnabled = await Geolocator.isLocationServiceEnabled(); + //if the location service is not enabled, ask the user to enable it + if (!isLocationEnabled) { + HmsLocation.LocationRequest locationRequest = + HmsLocation.LocationRequest() + ..priority = HmsLocation.LocationRequest.PRIORITY_HIGH_ACCURACY; + + HmsLocation.LocationSettingsRequest request = + HmsLocation.LocationSettingsRequest( + alwaysShow: true, + needBle: false, + requests: [locationRequest], + ); + + await locationService.checkLocationSettings(request); + } + LocationPermission permissionGranted = await Geolocator.checkPermission(); + if (permissionGranted == LocationPermission.denied) { + permissionGranted = await Geolocator.requestPermission(); + if (permissionGranted != LocationPermission.whileInUse && + permissionGranted != LocationPermission.always) { + appState.resetLocation(); + onFailure?.call(); + return; + } + } + + HmsLocation.Location data = await locationService.getLastLocation(); + if (data.latitude == null || data.longitude == null) { + appState.resetLocation(); + HmsLocation.LocationRequest request = HmsLocation.LocationRequest() + ..priority = HmsLocation.LocationRequest.PRIORITY_HIGH_ACCURACY + ..interval = 1000 // 1 second + ..numUpdates = 1; + locationService.requestLocationUpdates(request); + locationService.onLocationData?.listen((location) { + data = location; + if (data.latitude == null || data.longitude == null) { + appState.resetLocation(); + onFailure?.call(); + return; + } + saveLatLngToAppState( + LatLng(data.latitude ?? 0.0, data.longitude ?? 0.0)); + }); + } + saveLatLngToAppState(LatLng(data.latitude ?? 0.0, data.longitude ?? 0.0)); + } catch (e) { + appState.resetLocation(); + onFailure?.call(); + } + } } diff --git a/lib/features/book_appointments/book_appointments_view_model.dart b/lib/features/book_appointments/book_appointments_view_model.dart index c74b176..7dc1e68 100644 --- a/lib/features/book_appointments/book_appointments_view_model.dart +++ b/lib/features/book_appointments/book_appointments_view_model.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/cache_consts.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/date_util.dart'; import 'package:hmg_patient_app_new/core/utils/doctor_response_mapper.dart'; import 'package:hmg_patient_app_new/core/utils/loading_utils.dart'; @@ -37,6 +38,8 @@ class BookAppointmentsViewModel extends ChangeNotifier { int initialSlotDuration = 0; + LocationUtils locationUtils; + List clinicsList = []; List _filteredClinicsList = []; @@ -74,7 +77,9 @@ class BookAppointmentsViewModel extends ChangeNotifier { bool shouldLoadSpecificClinic = false; String? currentlySelectedHospitalFromRegionFlow; - BookAppointmentsViewModel({required this.bookAppointmentsRepo, required this.errorHandlerService, required this.navigationService, required this.myAppointmentsViewModel}); + BookAppointmentsViewModel({required this.bookAppointmentsRepo, required this.errorHandlerService, required this.navigationService, required this.myAppointmentsViewModel, required this.locationUtils}) {; + initBookAppointmentViewModel(); + } void initializeFilteredList() { _filteredClinicsList = List.from(clinicsList); @@ -97,6 +102,7 @@ class BookAppointmentsViewModel extends ChangeNotifier { isDoctorProfileLoading = true; clinicsList.clear(); doctorsList.clear(); + // getLocation(); notifyListeners(); } @@ -408,10 +414,10 @@ class BookAppointmentsViewModel extends ChangeNotifier { Future getRegionMappedProjectList() async { //todo handle the case in the location is switch on - if(hospitalList != null && hospitalList!.registeredDoctorMap != null && hospitalList!.registeredDoctorMap!.isNotEmpty){ - filteredHospitalList = hospitalList; - return; - } + // if(hospitalList != null && hospitalList!.registeredDoctorMap != null && hospitalList!.registeredDoctorMap!.isNotEmpty){ + // filteredHospitalList = hospitalList; + // return; + // } isRegionListLoading = true; notifyListeners(); final result = await bookAppointmentsRepo.getProjectList(); @@ -429,10 +435,8 @@ class BookAppointmentsViewModel extends ChangeNotifier { lat: _appState.userLat, lng: _appState.userLong, ); - var lat = await Utils.getNumFromPrefs(CacheConst.userLat); - var lng = await Utils.getNumFromPrefs(CacheConst.userLong); - var isLocationEnabled = (lat != 0) && (lng != 0); + var isLocationEnabled = (_appState.userLat != 0) && (_appState.userLong != 0); hospitalList = await DoctorMapper.sortList(isLocationEnabled, hospitalList!); @@ -480,15 +484,15 @@ class BookAppointmentsViewModel extends ChangeNotifier { notifyListeners(); } - Future isLocationEnabled() async{ - return await Location().serviceEnabled(); + bool isLocationEnabled() { + return _appState.userLong != 0.0 && _appState.userLong != 0.0; } - bool getLocationStatus() { - bool isLocationAvaiable = false; - isLocationEnabled().then((value) => isLocationAvaiable = value); - return isLocationAvaiable; - } + // bool getLocationStatus() { + // bool isLocationAvaiable = false; + // isLocationEnabled().then((value) => isLocationAvaiable = value); + // return isLocationAvaiable; + // } void setLoadSpecificClinic(bool status) { shouldLoadSpecificClinic = status; @@ -518,4 +522,9 @@ class BookAppointmentsViewModel extends ChangeNotifier { void resetFilterList(){ filteredHospitalList = hospitalList; } + + + void getLocation(){ + locationUtils.getLocation(); + } } diff --git a/lib/main.dart b/lib/main.dart index c75cf91..6abde55 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -132,6 +132,7 @@ void main() async { errorHandlerService: getIt(), navigationService: getIt(), myAppointmentsViewModel: getIt(), + locationUtils: getIt(), ), ), ChangeNotifierProvider( diff --git a/lib/presentation/appointments/widgets/appointment_checkin_bottom_sheet.dart b/lib/presentation/appointments/widgets/appointment_checkin_bottom_sheet.dart index 77fec61..b701f69 100644 --- a/lib/presentation/appointments/widgets/appointment_checkin_bottom_sheet.dart +++ b/lib/presentation/appointments/widgets/appointment_checkin_bottom_sheet.dart @@ -51,7 +51,7 @@ class AppointmentCheckinBottomSheet extends StatelessWidget { // navigationService: myAppointmentsViewModel.navigationService, // appState: myAppointmentsViewModel.appState, // ); - locationUtils.getCurrentLocation(callBack: (value) { + locationUtils.getCurrentLocation(onSuccess: (value) { projectDetailListModel = Utils.getProjectDetailObj(_appState, patientAppointmentHistoryResponseModel.projectID); double dist = Utils.distance(value.latitude, value.longitude, double.parse(projectDetailListModel.latitude!), double.parse(projectDetailListModel.longitude!)).ceilToDouble() * 1000; print(dist); diff --git a/lib/presentation/appointments/widgets/hospital_bottom_sheet/hospital_bottom_sheet_body.dart b/lib/presentation/appointments/widgets/hospital_bottom_sheet/hospital_bottom_sheet_body.dart index 71cc07d..8159abd 100644 --- a/lib/presentation/appointments/widgets/hospital_bottom_sheet/hospital_bottom_sheet_body.dart +++ b/lib/presentation/appointments/widgets/hospital_bottom_sheet/hospital_bottom_sheet_body.dart @@ -93,7 +93,7 @@ class HospitalBottomSheetBody extends StatelessWidget { ?.hmcDoctorList?[index]; return HospitalListItem( hospitalData: hospital, - isLocationEnabled: appointmentsViewModel.getLocationStatus(), + isLocationEnabled: appointmentsViewModel.isLocationEnabled(), ).onPress(() { regionalViewModel.setHospitalModel(hospital); regionalViewModel.setBottomSheetState(AppointmentViaRegionState.CLINIC_SELECTION); diff --git a/lib/presentation/book_appointment/book_appointment_page.dart b/lib/presentation/book_appointment/book_appointment_page.dart index 482d864..f0dee1e 100644 --- a/lib/presentation/book_appointment/book_appointment_page.dart +++ b/lib/presentation/book_appointment/book_appointment_page.dart @@ -44,6 +44,7 @@ class _BookAppointmentPageState extends State { void initState() { scheduleMicrotask(() { bookAppointmentsViewModel.initBookAppointmentViewModel(); + bookAppointmentsViewModel.getLocation(); }); super.initState(); } diff --git a/pubspec.yaml b/pubspec.yaml index e55d241..5423904 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -83,6 +83,8 @@ dependencies: family_bottom_sheet: ^0.1.0 location: ^8.0.1 + gms_check: ^1.0.4 + huawei_location: ^6.14.2+301 dev_dependencies: flutter_test: From 4473145c0045ec8d4d6c0fe308482121c15e5472 Mon Sep 17 00:00:00 2001 From: "taha.alam" Date: Thu, 18 Sep 2025 16:25:25 +0300 Subject: [PATCH 05/12] on success block added to the hms location block --- lib/core/location_util.dart | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/core/location_util.dart b/lib/core/location_util.dart index 2104078..ecfab62 100644 --- a/lib/core/location_util.dart +++ b/lib/core/location_util.dart @@ -246,11 +246,17 @@ class LocationUtils { onFailure?.call(); return; } - saveLatLngToAppState( - LatLng(data.latitude ?? 0.0, data.longitude ?? 0.0)); + var locationData = + LatLng(data.latitude ?? 0.0, data.longitude ?? 0.0); + saveLatLngToAppState(locationData); + onSuccess?.call(locationData); }); + } else { + var locationData = LatLng(data.latitude ?? 0.0, data.longitude ?? 0.0); + + saveLatLngToAppState(locationData); + onSuccess?.call(locationData); } - saveLatLngToAppState(LatLng(data.latitude ?? 0.0, data.longitude ?? 0.0)); } catch (e) { appState.resetLocation(); onFailure?.call(); From 3b5d2d27a46051ff433d25344360c41aabd92abb Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Thu, 18 Sep 2025 17:40:49 +0300 Subject: [PATCH 06/12] Updates --- lib/core/api_consts.dart | 2 +- lib/core/utils/utils.dart | 13 +- lib/extensions/string_extensions.dart | 15 +- .../book_appointments_view_model.dart | 3 +- .../appointment_via_region_viewmodel.dart | 3 +- .../my_appointments_view_model.dart | 5 + lib/features/payfort/payfort_view_model.dart | 4 +- .../appointment_details_page.dart | 13 +- .../appointment_payment_page.dart | 379 +++++++++--------- .../appointments/my_appointments_page.dart | 13 +- .../widgets/appointment_card.dart | 63 +-- .../appointment_checkin_bottom_sheet.dart | 19 +- .../authentication/saved_login_screen.dart | 4 +- .../book_appointment_page.dart | 39 +- .../review_appointment_page.dart | 3 +- .../search_doctor_by_name.dart | 3 +- .../book_appointment/select_clinic_page.dart | 5 +- .../book_appointment/select_doctor_page.dart | 3 +- .../select_livecare_clinic_page.dart | 3 +- .../widgets/appointment_calendar.dart | 13 +- .../habib_wallet/habib_wallet_page.dart | 3 +- lib/presentation/home/landing_page.dart | 206 ++++++---- .../home/widgets/habib_wallet_card.dart | 3 +- .../home/widgets/small_service_card.dart | 13 +- .../medical_file/medical_file_page.dart | 17 +- .../medical_file_appointment_card.dart | 5 +- .../widgets/patient_sick_leave_card.dart | 3 +- .../prescriptions_list_page.dart | 3 +- .../profile_settings/profile_settings.dart | 2 +- .../radiology/radiology_orders_page.dart | 270 ++++++------- .../radiology/radiology_result_page.dart | 76 ++++ lib/splashPage.dart | 3 +- 32 files changed, 674 insertions(+), 535 deletions(-) create mode 100644 lib/presentation/radiology/radiology_result_page.dart diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index f802818..d31679c 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -723,7 +723,7 @@ const DEACTIVATE_ACCOUNT = 'Services/Patients.svc/REST/PatientAppleActivation_In class ApiConsts { static const maxSmallScreen = 660; - static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.uat; + static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.prod; // static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT diff --git a/lib/core/utils/utils.dart b/lib/core/utils/utils.dart index 152cd54..6b74a7b 100644 --- a/lib/core/utils/utils.dart +++ b/lib/core/utils/utils.dart @@ -346,9 +346,9 @@ class Utils { mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ - Lottie.asset(AppAnimations.warningAnimation, repeat: true, reverse: false, frameRate: FrameRate(60), width: 100.h, height: 100.h, fit: BoxFit.fill), + Lottie.asset(AppAnimations.warningAnimation, repeat: true, reverse: false, frameRate: FrameRate(60), width: 128.h, height: 128.h, fit: BoxFit.fill), SizedBox(height: 8.h), - (loadingText ?? LocaleKeys.loadingText.tr()).toText14(color: AppColors.blackColor), + (loadingText ?? LocaleKeys.loadingText.tr()).toText14(color: AppColors.blackColor, letterSpacing: 0), SizedBox(height: 16.h), isShowActionButtons ? Row( @@ -361,11 +361,11 @@ class Utils { onCancelTap(); } }, - backgroundColor: AppColors.secondaryLightRedColor, - borderColor: AppColors.secondaryLightRedColor, - textColor: AppColors.primaryRedColor, + backgroundColor: AppColors.primaryRedColor, + borderColor: AppColors.primaryRedColor, + textColor: AppColors.whiteColor, icon: AppAssets.cancel, - iconColor: AppColors.primaryRedColor, + iconColor: AppColors.whiteColor, ), ), SizedBox(width: 8.h), @@ -652,6 +652,7 @@ class Utils { static Widget getPaymentAmountWithSymbol2(num habibWalletAmount, Color iconColor, double iconSize, {bool isSaudiCurrency = true, bool isExpanded = true}) { return RichText( + maxLines: 1, text: TextSpan( children: [ WidgetSpan( diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index 7140c05..5465ce3 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -30,12 +30,11 @@ extension EmailValidator on String { fontStyle: fontStyle ?? FontStyle.normal, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, color: color ?? AppColors.blackColor, - letterSpacing: -1, + letterSpacing: 0, ), ); - Widget toText10({Color? color, FontWeight? weight, bool isBold = false, bool isUnderLine = false, int? maxlines, FontStyle? fontStyle, TextOverflow? textOverflow, double letterSpacing = -1}) => - Text( + Widget toText10({Color? color, FontWeight? weight, bool isBold = false, bool isUnderLine = false, int? maxlines, FontStyle? fontStyle, TextOverflow? textOverflow, double letterSpacing = 0}) => Text( this, maxLines: maxlines, overflow: textOverflow, @@ -49,7 +48,7 @@ extension EmailValidator on String { decorationColor: color ?? AppColors.blackColor), ); - Widget toText11({Color? color, FontWeight? weight, bool isUnderLine = false, bool isCenter = false, bool isBold = false, int maxLine = 0, double letterSpacing = -1}) => Text( + Widget toText11({Color? color, FontWeight? weight, bool isUnderLine = false, bool isCenter = false, bool isBold = false, int maxLine = 0, double letterSpacing = 0}) => Text( this, textAlign: isCenter ? TextAlign.center : null, maxLines: (maxLine > 0) ? maxLine : null, @@ -71,7 +70,7 @@ extension EmailValidator on String { fontSize: 12.fSize, fontWeight: fontWeight ?? (isBold ? FontWeight.bold : FontWeight.normal), color: color ?? AppColors.blackColor, - letterSpacing: -1, + letterSpacing: 0, height: height, decorationColor: isUnderLine ? AppColors.blackColor : null, decoration: isUnderLine ? TextDecoration.underline : null, @@ -87,7 +86,7 @@ extension EmailValidator on String { fontSize: 12.fSize, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, color: color ?? AppColors.blackColor, - letterSpacing: -1, + letterSpacing: 0, decoration: isUnderLine ? TextDecoration.underline : null, ), ); @@ -120,7 +119,7 @@ extension EmailValidator on String { ), ); - Widget toText13({Color? color, bool isUnderLine = false, bool isBold = false, bool isCenter = false, int maxLine = 0, FontWeight? weight, double? letterSpacing = -1}) => Text( + Widget toText13({Color? color, bool isUnderLine = false, bool isBold = false, bool isCenter = false, int maxLine = 0, FontWeight? weight, double? letterSpacing = 0}) => Text( this, textAlign: isCenter ? TextAlign.center : null, maxLines: (maxLine > 0) ? maxLine : null, @@ -139,7 +138,7 @@ extension EmailValidator on String { bool isCenter = false, FontWeight? weight, int? maxlines, - double? letterSpacing = -1, + double? letterSpacing = 0, double? height, TextOverflow? textOverflow}) => Text( diff --git a/lib/features/book_appointments/book_appointments_view_model.dart b/lib/features/book_appointments/book_appointments_view_model.dart index c74b176..155a388 100644 --- a/lib/features/book_appointments/book_appointments_view_model.dart +++ b/lib/features/book_appointments/book_appointments_view_model.dart @@ -24,6 +24,7 @@ import 'package:hmg_patient_app_new/presentation/home/navigation_screen.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/common_bottom_sheet.dart'; +import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart'; import 'package:location/location.dart' show Location; @@ -378,7 +379,7 @@ class BookAppointmentsViewModel extends ChangeNotifier { LoadingUtils.hideFullScreenLoader(); Navigator.pushAndRemoveUntil( navigationService.navigatorKey.currentContext!, - FadePage( + CustomPageRoute( page: LandingNavigation(), ), (r) => false); diff --git a/lib/features/my_appointments/appointment_via_region_viewmodel.dart b/lib/features/my_appointments/appointment_via_region_viewmodel.dart index a49e1c4..1525280 100644 --- a/lib/features/my_appointments/appointment_via_region_viewmodel.dart +++ b/lib/features/my_appointments/appointment_via_region_viewmodel.dart @@ -2,6 +2,7 @@ import 'package:flutter/foundation.dart' show ChangeNotifier; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/doctor_list_api_response.dart'; import 'package:hmg_patient_app_new/presentation/book_appointment/select_clinic_page.dart'; import 'package:hmg_patient_app_new/services/navigation_service.dart'; +import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart'; enum AppointmentViaRegionState { @@ -39,7 +40,7 @@ class AppointmentViaRegionViewmodel extends ChangeNotifier { void handleLastStep(){ navigationService.pop(); - navigationService.push(FadePage( + navigationService.push(CustomPageRoute( page: SelectClinicPage(), ),); } diff --git a/lib/features/my_appointments/my_appointments_view_model.dart b/lib/features/my_appointments/my_appointments_view_model.dart index 779f2b6..55fafc4 100644 --- a/lib/features/my_appointments/my_appointments_view_model.dart +++ b/lib/features/my_appointments/my_appointments_view_model.dart @@ -79,6 +79,11 @@ class MyAppointmentsViewModel extends ChangeNotifier { } Future getPatientAppointments(bool isActiveAppointment, bool isArrivedAppointments, {Function(dynamic)? onSuccess, Function(String)? onError}) async { + + patientAppointmentsHistoryList.clear(); + patientUpcomingAppointmentsHistoryList.clear(); + patientArrivedAppointmentsHistoryList.clear(); + final result = await myAppointmentsRepo.getPatientAppointments(isActiveAppointment: isActiveAppointment, isArrivedAppointments: isArrivedAppointments); final resultArrived = await myAppointmentsRepo.getPatientAppointments(isActiveAppointment: false, isArrivedAppointments: true); diff --git a/lib/features/payfort/payfort_view_model.dart b/lib/features/payfort/payfort_view_model.dart index 9c9df6a..d99de80 100644 --- a/lib/features/payfort/payfort_view_model.dart +++ b/lib/features/payfort/payfort_view_model.dart @@ -99,6 +99,7 @@ class PayfortViewModel extends ChangeNotifier { String? applePayShaType, String? applePayShaRequestPhrase, }) async { + var sdkTokenResponse; try { String? deviceId = await _payfort.getDeviceId(); @@ -125,6 +126,7 @@ class PayfortViewModel extends ChangeNotifier { // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); } else if (apiResponse.messageStatus == 1) { // payfortProjectDetailsRespModel = apiResponse.data!; + sdkTokenResponse = apiResponse.data; isApplePayConfigurationLoading = false; notifyListeners(); } @@ -133,7 +135,7 @@ class PayfortViewModel extends ChangeNotifier { } catch (e) { print("Error here: ${e.toString()}"); } - return null; + return sdkTokenResponse; } Future paymentWithApplePay({ diff --git a/lib/presentation/appointments/appointment_details_page.dart b/lib/presentation/appointments/appointment_details_page.dart index 42ace37..e1c8662 100644 --- a/lib/presentation/appointments/appointment_details_page.dart +++ b/lib/presentation/appointments/appointment_details_page.dart @@ -28,6 +28,7 @@ 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/common_bottom_sheet.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:hmg_patient_app_new/widgets/shimmer/movies_shimmer_widget.dart'; import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart'; import 'package:maps_launcher/maps_launcher.dart'; @@ -72,7 +73,7 @@ class _AppointmentDetailsPageState extends State { Expanded( child: CollapsingListView( title: "Appointment Details".needTranslation, - report: () {}, + report: AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel) ? () {} : null, child: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -331,7 +332,7 @@ class _AppointmentDetailsPageState extends State { ).onPress(() { prescriptionVM.setPrescriptionsDetailsLoading(); Navigator.of(context).push( - FadePage( + CustomPageRoute( page: PrescriptionDetailPage(prescriptionsResponseModel: getPrescriptionRequestModel()), ), ); @@ -364,7 +365,7 @@ class _AppointmentDetailsPageState extends State { onPressed: () { Navigator.of(context) .push( - FadePage( + CustomPageRoute( page: PrescriptionsListPage(), ), ) @@ -425,8 +426,8 @@ class _AppointmentDetailsPageState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - LocaleKeys.upcomingPaymentNow.tr(context: context).toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor), - "VAT 15%(${widget.patientAppointmentHistoryResponseModel.patientTaxAmount})".needTranslation.toText14(isBold: true, color: AppColors.greyTextColor), + Expanded(child: LocaleKeys.upcomingPaymentNow.tr(context: context).toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor)), + "VAT 15%(${widget.patientAppointmentHistoryResponseModel.patientTaxAmount})".needTranslation.toText14(isBold: true, color: AppColors.greyTextColor, letterSpacing: -2), ], ), SizedBox(height: 18.h), @@ -560,7 +561,7 @@ class _AppointmentDetailsPageState extends State { case 20: myAppointmentsViewModel.setIsPatientAppointmentShareLoading(true); Navigator.of(context).push( - FadePage( + CustomPageRoute( page: AppointmentPaymentPage(patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel), ), ); diff --git a/lib/presentation/appointments/appointment_payment_page.dart b/lib/presentation/appointments/appointment_payment_page.dart index a617647..4d5fd8f 100644 --- a/lib/presentation/appointments/appointment_payment_page.dart +++ b/lib/presentation/appointments/appointment_payment_page.dart @@ -27,6 +27,7 @@ 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/common_bottom_sheet.dart'; import 'package:hmg_patient_app_new/widgets/in_app_browser/InAppBrowser.dart'; +import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:hmg_patient_app_new/widgets/shimmer/movies_shimmer_widget.dart'; import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart'; import 'package:provider/provider.dart'; @@ -79,118 +80,116 @@ class _AppointmentPaymentPageState extends State { child: CollapsingListView( title: "Appointment Payment".needTranslation, child: SingleChildScrollView( - child: myAppointmentsVM.isAppointmentPatientShareLoading - ? const MoviesShimmerWidget().paddingAll(24.h) - : Column( - crossAxisAlignment: CrossAxisAlignment.start, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: 24.h), + Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 20.h, + hasShadow: false, + ), + child: Row( + mainAxisSize: MainAxisSize.max, children: [ - SizedBox(height: 24.h), - Container( - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - borderRadius: 20.h, - hasShadow: false, - ), - child: Row( - mainAxisSize: MainAxisSize.max, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Image.asset(AppAssets.mada, width: 72.h, height: 25.h), - SizedBox(height: 16.h), - "Mada".needTranslation.toText16(isBold: true), - ], - ), - SizedBox(width: 8.h), - const Spacer(), - Utils.buildSvgWithAssets( - icon: AppAssets.forward_arrow_icon, - iconColor: AppColors.blackColor, - width: 18.h, - height: 13.h, - fit: BoxFit.contain, - ), - ], - ).paddingSymmetrical(16.h, 16.h), - ).paddingSymmetrical(24.h, 0.h).onPress(() { - selectedPaymentMethod = "MADA"; - openPaymentURL("mada"); - }), - SizedBox(height: 16.h), - Container( - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - borderRadius: 20.h, - hasShadow: false, - ), - child: Row( - mainAxisSize: MainAxisSize.max, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Image.asset(AppAssets.visa, width: 50.h, height: 50.h), - SizedBox(width: 8.h), - Image.asset(AppAssets.Mastercard, width: 40.h, height: 40.h), - ], - ), - SizedBox(height: 16.h), - "Visa or Mastercard".needTranslation.toText16(isBold: true), - ], - ), - SizedBox(width: 8.h), - const Spacer(), - Utils.buildSvgWithAssets( - icon: AppAssets.forward_arrow_icon, - iconColor: AppColors.blackColor, - width: 18.h, - height: 13.h, - fit: BoxFit.contain, - ), - ], - ).paddingSymmetrical(16.h, 16.h), - ).paddingSymmetrical(24.h, 0.h).onPress(() { - selectedPaymentMethod = "VISA"; - openPaymentURL("visa"); - }), - SizedBox(height: 16.h), - Container( - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - borderRadius: 20.h, - hasShadow: false, - ), - child: Row( - mainAxisSize: MainAxisSize.max, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Image.asset(AppAssets.tamara_en, width: 72.h, height: 25.h), - SizedBox(height: 16.h), - "Tamara".needTranslation.toText16(isBold: true), - ], - ), - SizedBox(width: 8.h), - const Spacer(), - Utils.buildSvgWithAssets( - icon: AppAssets.forward_arrow_icon, - iconColor: AppColors.blackColor, - width: 18.h, - height: 13.h, - fit: BoxFit.contain, - ), - ], - ).paddingSymmetrical(16.h, 16.h), - ).paddingSymmetrical(24.h, 0.h).onPress(() { - selectedPaymentMethod = "TAMARA"; - openPaymentURL("tamara"); - }), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Image.asset(AppAssets.mada, width: 72.h, height: 25.h).toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading), + SizedBox(height: 16.h), + "Mada".needTranslation.toText16(isBold: true).toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading), + ], + ), + SizedBox(width: 8.h), + const Spacer(), + Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon, + iconColor: AppColors.blackColor, + width: 18.h, + height: 13.h, + fit: BoxFit.contain, + ).toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading), + ], + ).paddingSymmetrical(16.h, 16.h), + ).paddingSymmetrical(24.h, 0.h).onPress(() { + selectedPaymentMethod = "MADA"; + openPaymentURL("mada"); + }), + SizedBox(height: 16.h), + Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 20.h, + hasShadow: false, + ), + child: Row( + mainAxisSize: MainAxisSize.max, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Image.asset(AppAssets.visa, width: 50.h, height: 50.h), + SizedBox(width: 8.h), + Image.asset(AppAssets.Mastercard, width: 40.h, height: 40.h), + ], + ).toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading), + SizedBox(height: 16.h), + "Visa or Mastercard".needTranslation.toText16(isBold: true).toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading), + ], + ), + SizedBox(width: 8.h), + const Spacer(), + Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon, + iconColor: AppColors.blackColor, + width: 18.h, + height: 13.h, + fit: BoxFit.contain, + ).toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading), ], + ).paddingSymmetrical(16.h, 16.h), + ).paddingSymmetrical(24.h, 0.h).onPress(() { + selectedPaymentMethod = "VISA"; + openPaymentURL("visa"); + }), + SizedBox(height: 16.h), + Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 20.h, + hasShadow: false, ), + child: Row( + mainAxisSize: MainAxisSize.max, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Image.asset(AppAssets.tamara_en, width: 72.h, height: 25.h).toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading), + SizedBox(height: 16.h), + "Tamara".needTranslation.toText16(isBold: true).toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading), + ], + ), + SizedBox(width: 8.h), + const Spacer(), + Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon, + iconColor: AppColors.blackColor, + width: 18.h, + height: 13.h, + fit: BoxFit.contain, + ).toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading), + ], + ).paddingSymmetrical(16.h, 16.h), + ).paddingSymmetrical(24.h, 0.h).onPress(() { + selectedPaymentMethod = "TAMARA"; + openPaymentURL("tamara"); + }), + ], + ), ), ), ), @@ -204,81 +203,79 @@ class _AppointmentPaymentPageState extends State { ), child: Consumer(builder: (context, payfortVM, child) { //TODO: Need to add loading state & animation for Apple Pay Configuration - return payfortVM.isApplePayConfigurationLoading - ? const MoviesShimmerWidget().paddingAll(16.h) - : Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - (myAppointmentsVM.patientAppointmentShareResponseModel!.isCash ?? true) - ? Container( - height: 50.h, - decoration: ShapeDecoration( - color: AppColors.secondaryLightRedBorderColor, - shape: SmoothRectangleBorder( - borderRadius: BorderRadius.only(topLeft: Radius.circular(24), topRight: Radius.circular(24)), - smoothness: 1, - ), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - "Insurance expired or inactive".needTranslation.toText14(color: AppColors.primaryRedColor, weight: FontWeight.w500).paddingSymmetrical(24.h, 0.h), - CustomButton( - text: LocaleKeys.updateInsurance.tr(context: context), - onPressed: () { - Navigator.of(context).push( - FadePage( - page: InsuranceHomePage(), - ), - ); - }, - backgroundColor: AppColors.primaryRedColor, - borderColor: AppColors.secondaryLightRedBorderColor, - textColor: AppColors.whiteColor, - fontSize: 10, - fontWeight: FontWeight.w500, - borderRadius: 8, - padding: EdgeInsets.fromLTRB(15, 0, 15, 0), - height: 30.h, - ).paddingSymmetrical(24.h, 0.h), - ], - ), - ) - : const SizedBox(), - SizedBox(height: 24.h), - "Total amount to pay".needTranslation.toText18(isBold: true).paddingSymmetrical(24.h, 0.h), - SizedBox(height: 17.h), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - "Total amount to pay".needTranslation.toText14(isBold: true), - Utils.getPaymentAmountWithSymbol(myAppointmentsVM.patientAppointmentShareResponseModel!.patientShare!.toString().toText16(isBold: true), AppColors.blackColor, 13, - isSaudiCurrency: true), - ], - ).paddingSymmetrical(24.h, 0.h), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - "VAT 15%".needTranslation.toText14(isBold: true, color: AppColors.greyTextColor), - Utils.getPaymentAmountWithSymbol( - myAppointmentsVM.patientAppointmentShareResponseModel!.patientTaxAmount!.toString().toText14(isBold: true, color: AppColors.greyTextColor), - AppColors.greyTextColor, - 13, - isSaudiCurrency: true), - ], - ).paddingSymmetrical(24.h, 0.h), - SizedBox(height: 17.h), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - "".needTranslation.toText14(isBold: true), - Utils.getPaymentAmountWithSymbol( - myAppointmentsVM.patientAppointmentShareResponseModel!.patientShareWithTax!.toString().toText24(isBold: true), AppColors.blackColor, 17, - isSaudiCurrency: true), - ], - ).paddingSymmetrical(24.h, 0.h), - //TODO: Add Apple Pay Privileges - Utils.buildSvgWithAssets( + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + (myAppointmentsVM.patientAppointmentShareResponseModel!.isCash ?? true) + ? Container( + height: 50.h, + decoration: ShapeDecoration( + color: AppColors.secondaryLightRedBorderColor, + shape: SmoothRectangleBorder( + borderRadius: BorderRadius.only(topLeft: Radius.circular(24), topRight: Radius.circular(24)), + smoothness: 1, + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + "Insurance expired or inactive".needTranslation.toText14(color: AppColors.primaryRedColor, weight: FontWeight.w500).paddingSymmetrical(24.h, 0.h), + CustomButton( + text: LocaleKeys.updateInsurance.tr(context: context), + onPressed: () { + Navigator.of(context).push( + CustomPageRoute( + page: InsuranceHomePage(), + ), + ); + }, + backgroundColor: AppColors.primaryRedColor, + borderColor: AppColors.secondaryLightRedBorderColor, + textColor: AppColors.whiteColor, + fontSize: 10, + fontWeight: FontWeight.w500, + borderRadius: 8, + padding: EdgeInsets.fromLTRB(15, 0, 15, 0), + height: 30.h, + ).paddingSymmetrical(24.h, 0.h), + ], + ), + ) + : const SizedBox(), + SizedBox(height: 24.h), + "Total amount to pay".needTranslation.toText18(isBold: true).paddingSymmetrical(24.h, 0.h), + SizedBox(height: 17.h), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + "Total amount to pay".needTranslation.toText14(isBold: true), + Utils.getPaymentAmountWithSymbol(myAppointmentsVM.patientAppointmentShareResponseModel!.patientShare!.toString().toText16(isBold: true), AppColors.blackColor, 13, + isSaudiCurrency: true), + ], + ).paddingSymmetrical(24.h, 0.h), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + "VAT 15%".needTranslation.toText14(isBold: true, color: AppColors.greyTextColor), + Utils.getPaymentAmountWithSymbol( + myAppointmentsVM.patientAppointmentShareResponseModel!.patientTaxAmount!.toString().toText14(isBold: true, color: AppColors.greyTextColor), + AppColors.greyTextColor, + 13, + isSaudiCurrency: true), + ], + ).paddingSymmetrical(24.h, 0.h), + SizedBox(height: 17.h), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + "".needTranslation.toText14(isBold: true), + Utils.getPaymentAmountWithSymbol(myAppointmentsVM.patientAppointmentShareResponseModel!.patientShareWithTax!.toString().toText24(isBold: true), AppColors.blackColor, 17, + isSaudiCurrency: true), + ], + ).paddingSymmetrical(24.h, 0.h), + //TODO: Add Apple Pay Privileges + Platform.isIOS + ? Utils.buildSvgWithAssets( icon: AppAssets.apple_pay_button, width: 200.h, height: 80.h, @@ -286,10 +283,11 @@ class _AppointmentPaymentPageState extends State { ).paddingSymmetrical(24.h, 0.h).onPress(() { // payfortVM.setIsApplePayConfigurationLoading(true); startApplePay(); - }), - SizedBox(height: 12.h), - ], - ); + }) + : SizedBox(height: 12.h), + SizedBox(height: 12.h), + ], + ); }), ), ], @@ -389,12 +387,12 @@ class _AppointmentPaymentPageState extends State { Navigator.of(context).pop(); Navigator.pushAndRemoveUntil( context, - FadePage( + CustomPageRoute( page: LandingNavigation(), ), (r) => false); Navigator.of(context).push( - FadePage(page: MyAppointmentsPage()), + CustomPageRoute(page: MyAppointmentsPage()), ); }); }); @@ -528,6 +526,7 @@ class _AppointmentPaymentPageState extends State { onSucceeded: (successResult) async { Navigator.of(context).pop(); log("successResult: ${successResult.responseMessage.toString()}"); + selectedPaymentMethod = successResult.paymentOption ?? "VISA"; checkPaymentStatus(); }, // projectId: appo.projectID, diff --git a/lib/presentation/appointments/my_appointments_page.dart b/lib/presentation/appointments/my_appointments_page.dart index 4c16a17..5972435 100644 --- a/lib/presentation/appointments/my_appointments_page.dart +++ b/lib/presentation/appointments/my_appointments_page.dart @@ -6,6 +6,7 @@ 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/my_appointments/models/resp_models/patient_appointment_history_response_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart'; import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_card.dart'; import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart'; @@ -85,7 +86,15 @@ class _MyAppointmentsPageState extends State { : 1, itemBuilder: (context, index) { return myAppointmentsVM.isMyAppointmentsLoading - ? const MoviesShimmerWidget().paddingSymmetrical(24.h, 0.h) + ? Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true), + child: AppointmentCard( + patientAppointmentHistoryResponseModel: PatientAppointmentHistoryResponseModel(), + myAppointmentsViewModel: myAppointmentsViewModel, + isLoading: true, + isFromHomePage: false, + ), + ).paddingSymmetrical(24.h, 0.h) : myAppointmentsVM.patientAppointmentsHistoryList.isNotEmpty ? AnimationConfiguration.staggeredList( position: index, @@ -100,6 +109,8 @@ class _MyAppointmentsPageState extends State { child: AppointmentCard( patientAppointmentHistoryResponseModel: myAppointmentsVM.patientAppointmentsHistoryList[index], myAppointmentsViewModel: myAppointmentsViewModel, + isLoading: false, + isFromHomePage: false, ), ).paddingSymmetrical(24.h, 0.h), ), diff --git a/lib/presentation/appointments/widgets/appointment_card.dart b/lib/presentation/appointments/widgets/appointment_card.dart index 29694ed..a87012c 100644 --- a/lib/presentation/appointments/widgets/appointment_card.dart +++ b/lib/presentation/appointments/widgets/appointment_card.dart @@ -16,15 +16,16 @@ import 'package:hmg_patient_app_new/presentation/appointments/appointment_detail import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; +import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart'; -import 'package:smooth_corner/smooth_corner.dart'; class AppointmentCard extends StatefulWidget { - AppointmentCard({super.key, required this.patientAppointmentHistoryResponseModel, required this.myAppointmentsViewModel, this.isLoading = false}); + AppointmentCard({super.key, required this.patientAppointmentHistoryResponseModel, required this.myAppointmentsViewModel, this.isLoading = false, this.isFromHomePage = false}); PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel; MyAppointmentsViewModel myAppointmentsViewModel; bool isLoading; + bool isFromHomePage; @override State createState() => _AppointmentCardState(); @@ -38,7 +39,7 @@ class _AppointmentCardState extends State { onTap: () { Navigator.of(context) .push( - FadePage( + CustomPageRoute( page: AppointmentDetailsPage(patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel), ), ) @@ -66,9 +67,11 @@ class _AppointmentCardState extends State { mainAxisSize: MainAxisSize.min, children: [ CustomButton( - text: appState.isArabic() - ? widget.patientAppointmentHistoryResponseModel.isInOutPatientDescriptionN! - : widget.patientAppointmentHistoryResponseModel.isInOutPatientDescription!, + text: widget.isLoading + ? "OutPatient" + : appState.isArabic() + ? widget.patientAppointmentHistoryResponseModel.isInOutPatientDescriptionN! + : widget.patientAppointmentHistoryResponseModel.isInOutPatientDescription!, onPressed: () {}, backgroundColor: AppColors.primaryRedColor.withOpacity(0.1), borderColor: AppColors.primaryRedColor.withOpacity(0.0), @@ -85,7 +88,7 @@ class _AppointmentCardState extends State { mainAxisSize: MainAxisSize.min, children: [ CustomButton( - text: AppointmentType.getAppointmentStatusType(widget.patientAppointmentHistoryResponseModel.patientStatusType!), + text: widget.isLoading ? "Booked" : AppointmentType.getAppointmentStatusType(widget.patientAppointmentHistoryResponseModel.patientStatusType!), onPressed: () {}, backgroundColor: AppColors.successColor.withOpacity(0.1), borderColor: AppColors.successColor.withOpacity(0.0), @@ -99,11 +102,11 @@ class _AppointmentCardState extends State { ], ), ], - ), + ).toShimmer2(isShow: widget.isLoading), ), // TODO: Implement the logic to enable/disable the switch based on reminder status AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel) - ? SizedBox() + ? SizedBox().toShimmer2(isShow: widget.isLoading) : Switch( activeColor: AppColors.successColor, activeTrackColor: AppColors.successColor.withValues(alpha: .15), @@ -115,13 +118,13 @@ class _AppointmentCardState extends State { return const Icon(Icons.close); // Icon when switch is OFF }, ), - value: widget.patientAppointmentHistoryResponseModel.hasReminder!, + value: widget.isLoading ? false : widget.patientAppointmentHistoryResponseModel.hasReminder!, onChanged: (newValue) { setState(() { widget.myAppointmentsViewModel.setAppointmentReminder(newValue, widget.patientAppointmentHistoryResponseModel); }); }, - ), + ).toShimmer2(isShow: widget.isLoading), ], ), SizedBox(height: 16.h), @@ -129,30 +132,38 @@ class _AppointmentCardState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Image.network( - widget.patientAppointmentHistoryResponseModel.doctorImageURL!, + widget.isLoading ? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png" : widget.patientAppointmentHistoryResponseModel.doctorImageURL!, width: 63.h, height: 63.h, fit: BoxFit.fill, - ).circle(100), + ).circle(100).toShimmer2(isShow: widget.isLoading), SizedBox(width: 16.h), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - widget.patientAppointmentHistoryResponseModel.doctorNameObj!.toText16(isBold: true), + (widget.isLoading ? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png" : widget.patientAppointmentHistoryResponseModel.doctorNameObj!) + .toText16(isBold: true) + .toShimmer2(isShow: widget.isLoading), + SizedBox(height: 8.h), Wrap( direction: Axis.horizontal, spacing: 3.h, runSpacing: 4.h, children: [ - AppCustomChipWidget(labelText: widget.patientAppointmentHistoryResponseModel.clinicName!), - AppCustomChipWidget(labelText: widget.patientAppointmentHistoryResponseModel.projectName!), + widget.isFromHomePage ? SizedBox.shrink() : AppCustomChipWidget(labelText: widget.isLoading ? "Cardiology" : widget.patientAppointmentHistoryResponseModel.clinicName!).toShimmer2(isShow: widget.isLoading), + widget.isFromHomePage ? SizedBox.shrink() : AppCustomChipWidget(labelText: widget.isLoading ? "Olaya" : widget.patientAppointmentHistoryResponseModel.projectName!).toShimmer2(isShow: widget.isLoading), AppCustomChipWidget( - icon: AppAssets.appointment_calendar_icon, - labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(widget.patientAppointmentHistoryResponseModel.appointmentDate), false)), + icon: AppAssets.appointment_calendar_icon, + labelText: + widget.isLoading ? "Cardiology" : DateUtil.formatDateToDate(DateUtil.convertStringToDate(widget.patientAppointmentHistoryResponseModel.appointmentDate), false)) + .toShimmer2(isShow: widget.isLoading), AppCustomChipWidget( - icon: AppAssets.appointment_time_icon, - labelText: DateUtil.formatDateToTimeLang(DateUtil.convertStringToDate(widget.patientAppointmentHistoryResponseModel.appointmentDate), false)), + icon: AppAssets.appointment_time_icon, + labelText: widget.isLoading + ? "Cardiology" + : DateUtil.formatDateToTimeLang(DateUtil.convertStringToDate(widget.patientAppointmentHistoryResponseModel.appointmentDate), false)) + .toShimmer2(isShow: widget.isLoading), ], ), ], @@ -166,12 +177,12 @@ class _AppointmentCardState extends State { Expanded( flex: 6, child: AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel) - ? getArrivedAppointmentButton() + ? getArrivedAppointmentButton().toShimmer2(isShow: widget.isLoading) : CustomButton( text: AppointmentType.getNextActionText(widget.patientAppointmentHistoryResponseModel.nextAction), onPressed: () { Navigator.of(context) - .push(FadePage( + .push(CustomPageRoute( page: AppointmentDetailsPage(patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel), )) .then((val) { @@ -189,8 +200,8 @@ class _AppointmentCardState extends State { height: 40.h, icon: AppointmentType.getNextActionIcon(widget.patientAppointmentHistoryResponseModel.nextAction), iconColor: AppointmentType.getNextActionTextColor(widget.patientAppointmentHistoryResponseModel.nextAction), - iconSize: 14.h, - ), + iconSize: 15.h, + ).toShimmer2(isShow: widget.isLoading), ), SizedBox(width: 8.h), Expanded( @@ -211,10 +222,10 @@ class _AppointmentCardState extends State { fit: BoxFit.contain, ), ), - ).onPress(() { + ).toShimmer2(isShow: widget.isLoading).onPress(() { Navigator.of(context) .push( - FadePage( + CustomPageRoute( page: AppointmentDetailsPage(patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel), ), ) diff --git a/lib/presentation/appointments/widgets/appointment_checkin_bottom_sheet.dart b/lib/presentation/appointments/widgets/appointment_checkin_bottom_sheet.dart index 77fec61..1c9649b 100644 --- a/lib/presentation/appointments/widgets/appointment_checkin_bottom_sheet.dart +++ b/lib/presentation/appointments/widgets/appointment_checkin_bottom_sheet.dart @@ -19,6 +19,7 @@ import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:barcode_scan2/barcode_scan2.dart'; import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart'; import 'package:hmg_patient_app_new/widgets/nfc/nfc_reader_sheet.dart'; +import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart'; class AppointmentCheckinBottomSheet extends StatelessWidget { @@ -110,12 +111,14 @@ class AppointmentCheckinBottomSheet extends StatelessWidget { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - title.toText16(isBold: true, color: AppColors.textColor), - subTitle.toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor), - ], + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + title.toText16(isBold: true, color: AppColors.textColor), + subTitle.toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor), + ], + ), ), Utils.buildSvgWithAssets( icon: AppAssets.forward_arrow_icon, @@ -144,12 +147,12 @@ class AppointmentCheckinBottomSheet extends StatelessWidget { Navigator.of(context).pop(); Navigator.pushAndRemoveUntil( context, - FadePage( + CustomPageRoute( page: LandingNavigation(), ), (r) => false); Navigator.of(context).push( - FadePage(page: MyAppointmentsPage()), + CustomPageRoute(page: MyAppointmentsPage()), ); }, isFullScreen: false); }, diff --git a/lib/presentation/authentication/saved_login_screen.dart b/lib/presentation/authentication/saved_login_screen.dart index 073ff8b..44918ed 100644 --- a/lib/presentation/authentication/saved_login_screen.dart +++ b/lib/presentation/authentication/saved_login_screen.dart @@ -65,7 +65,7 @@ class _SavedLogin extends State { body: SafeArea( child: Padding( padding: EdgeInsets.symmetric(horizontal: 24.h), - child: Column( + child: appState.getSelectDeviceByImeiRespModelElement != null ? Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ const Spacer(flex: 2), @@ -297,7 +297,7 @@ class _SavedLogin extends State { ), const SizedBox(height: 20), ], - ), + ) : SizedBox.shrink(), ), ), ); diff --git a/lib/presentation/book_appointment/book_appointment_page.dart b/lib/presentation/book_appointment/book_appointment_page.dart index 482d864..825a9e9 100644 --- a/lib/presentation/book_appointment/book_appointment_page.dart +++ b/lib/presentation/book_appointment/book_appointment_page.dart @@ -14,15 +14,14 @@ import 'package:hmg_patient_app_new/features/my_appointments/appointment_via_reg import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/doctor_list_api_response.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/appointments/widgets/faculity_selection/facility_type_selection_widget.dart'; -import 'package:hmg_patient_app_new/presentation/appointments/widgets/region_bottomsheet/region_list_widget.dart' - show RegionBottomSheetBody; +import 'package:hmg_patient_app_new/presentation/appointments/widgets/region_bottomsheet/region_list_widget.dart' show RegionBottomSheetBody; import 'package:hmg_patient_app_new/presentation/book_appointment/search_doctor_by_name.dart'; import 'package:hmg_patient_app_new/presentation/book_appointment/select_clinic_page.dart'; import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; -import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart' - show showCommonBottomSheetWithoutHeight; +import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart' show showCommonBottomSheetWithoutHeight; import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart'; +import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart'; import 'package:provider/provider.dart'; @@ -52,13 +51,12 @@ class _BookAppointmentPageState extends State { Widget build(BuildContext context) { bookAppointmentsViewModel = Provider.of(context, listen: false); appState = getIt.get(); - regionalViewModel = - Provider.of(context, listen: true); + regionalViewModel = Provider.of(context, listen: true); return Scaffold( backgroundColor: AppColors.bgScaffoldColor, body: CollapsingListView( title: LocaleKeys.bookAppo.tr(context: context), - isLeading: false, + isLeading: Navigator.canPop(context), child: SingleChildScrollView( child: Consumer(builder: (context, bookAppointmentsVM, child) { return Column( @@ -125,7 +123,7 @@ class _BookAppointmentPageState extends State { bookAppointmentsViewModel.setLoadSpecificClinic(false); bookAppointmentsViewModel.setProjectID(null); Navigator.of(context).push( - FadePage( + CustomPageRoute( page: SelectClinicPage(), ), ); @@ -154,7 +152,7 @@ class _BookAppointmentPageState extends State { ).onPress(() { bookAppointmentsViewModel.setIsDoctorSearchByNameStarted(false); Navigator.of(context).push( - FadePage( + CustomPageRoute( page: SearchDoctorByName(), ), ); @@ -198,24 +196,21 @@ class _BookAppointmentPageState extends State { void openRegionListBottomSheet(BuildContext context) { regionalViewModel.flush(); // AppointmentViaRegionViewmodel? viewmodel = null; - showCommonBottomSheetWithoutHeight(context, - title: "", - titleWidget: Consumer( - builder: (_, data, __) => getTitle(data)), - isDismissible: false, + showCommonBottomSheetWithoutHeight(context, title: "", titleWidget: Consumer(builder: (_, data, __) => getTitle(data)), isDismissible: false, child: Consumer(builder: (_, data, __) { return getRegionalSelectionWidget(data); - }), callBackFunc: () { - }); + }), callBackFunc: () {}); } Widget getRegionalSelectionWidget(AppointmentViaRegionViewmodel data) { if (data.bottomSheetState == AppointmentViaRegionState.REGION_SELECTION) { return RegionBottomSheetBody(); } - if(data.bottomSheetState == AppointmentViaRegionState.TYPE_SELECTION){ + if (data.bottomSheetState == AppointmentViaRegionState.TYPE_SELECTION) { bookAppointmentsViewModel.resetFilterList(); - return FacilityTypeSelectionWidget(selectedRegion: data.selectedRegionId??"",); + return FacilityTypeSelectionWidget( + selectedRegion: data.selectedRegionId ?? "", + ); } if (data.bottomSheetState == AppointmentViaRegionState.HOSPITAL_SELECTION) { return HospitalBottomSheetBody(); @@ -225,9 +220,7 @@ class _BookAppointmentPageState extends State { bookAppointmentsViewModel.setIsClinicsListLoading(true); bookAppointmentsViewModel.setLoadSpecificClinic(true); bookAppointmentsViewModel.setProjectID(regionalViewModel.selectedHospital?.hospitalList.first?.mainProjectID.toString()); - - } - else { + } else { SizedBox.shrink(); } return SizedBox.shrink(); @@ -237,9 +230,7 @@ class _BookAppointmentPageState extends State { if (data.selectedRegionId == null) { return LocaleKeys.selectRegion.tr().toText20(weight: FontWeight.w600); } else { - return Utils.buildSvgWithAssets( - icon: AppAssets.arrow_back, iconColor: Color(0xff2B353E)) - .onPress(() { + return Utils.buildSvgWithAssets(icon: AppAssets.arrow_back, iconColor: Color(0xff2B353E)).onPress(() { data.handleBackPress(); }); } diff --git a/lib/presentation/book_appointment/review_appointment_page.dart b/lib/presentation/book_appointment/review_appointment_page.dart index bd43a9f..d3804d8 100644 --- a/lib/presentation/book_appointment/review_appointment_page.dart +++ b/lib/presentation/book_appointment/review_appointment_page.dart @@ -16,6 +16,7 @@ import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; +import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart'; import 'package:provider/provider.dart'; @@ -214,7 +215,7 @@ class _ReviewAppointmentPageState extends State { LoadingUtils.hideFullScreenLoader(); Navigator.pushAndRemoveUntil( context, - FadePage( + CustomPageRoute( page: LandingNavigation(), ), (r) => false); diff --git a/lib/presentation/book_appointment/search_doctor_by_name.dart b/lib/presentation/book_appointment/search_doctor_by_name.dart index 23c5c18..e6b0ba1 100644 --- a/lib/presentation/book_appointment/search_doctor_by_name.dart +++ b/lib/presentation/book_appointment/search_doctor_by_name.dart @@ -18,6 +18,7 @@ import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart'; import 'package:hmg_patient_app_new/widgets/input_widget.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:hmg_patient_app_new/widgets/transitions/fade_page.dart'; import 'package:provider/provider.dart'; @@ -122,7 +123,7 @@ class _SearchDoctorByNameState extends State { await bookAppointmentsVM.getDoctorProfile(onSuccess: (dynamic respData) { LoaderBottomSheet.hideLoader(); Navigator.of(context).push( - FadePage( + CustomPageRoute( page: DoctorProfilePage(), ), ); diff --git a/lib/presentation/book_appointment/select_clinic_page.dart b/lib/presentation/book_appointment/select_clinic_page.dart index 214d4ad..0580480 100644 --- a/lib/presentation/book_appointment/select_clinic_page.dart +++ b/lib/presentation/book_appointment/select_clinic_page.dart @@ -19,6 +19,7 @@ import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/clinic import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/input_widget.dart'; +import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart'; import 'package:provider/provider.dart'; @@ -141,13 +142,13 @@ class _SelectClinicPageState extends State { bookAppointmentsViewModel.setIsDoctorsListLoading(true); if (clinic.isLiveCareClinicAndOnline ?? false) { Navigator.of(context).push( - FadePage( + CustomPageRoute( page: SelectLivecareClinicPage(), ), ); } else { Navigator.of(context).push( - FadePage( + CustomPageRoute( page: SelectDoctorPage(), ), ); diff --git a/lib/presentation/book_appointment/select_doctor_page.dart b/lib/presentation/book_appointment/select_doctor_page.dart index 43449e4..27a60f6 100644 --- a/lib/presentation/book_appointment/select_doctor_page.dart +++ b/lib/presentation/book_appointment/select_doctor_page.dart @@ -20,6 +20,7 @@ import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart'; import 'package:hmg_patient_app_new/widgets/input_widget.dart'; import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart'; +import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart'; import 'package:provider/provider.dart'; @@ -124,7 +125,7 @@ class _SelectDoctorPageState extends State { await bookAppointmentsVM.getDoctorProfile(onSuccess: (dynamic respData) { LoaderBottomSheet.hideLoader(); Navigator.of(context).push( - FadePage( + CustomPageRoute( page: DoctorProfilePage(), ), ); diff --git a/lib/presentation/book_appointment/select_livecare_clinic_page.dart b/lib/presentation/book_appointment/select_livecare_clinic_page.dart index ef682c3..76d85af 100644 --- a/lib/presentation/book_appointment/select_livecare_clinic_page.dart +++ b/lib/presentation/book_appointment/select_livecare_clinic_page.dart @@ -10,6 +10,7 @@ import 'package:hmg_patient_app_new/presentation/book_appointment/select_doctor_ import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.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/routes/custom_page_route.dart'; import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart'; class SelectLivecareClinicPage extends StatelessWidget { @@ -122,7 +123,7 @@ class SelectLivecareClinicPage extends StatelessWidget { onPressed: () { Navigator.of(context).pop(); Navigator.of(context).push( - FadePage( + CustomPageRoute( page: SelectDoctorPage(), ), ); diff --git a/lib/presentation/book_appointment/widgets/appointment_calendar.dart b/lib/presentation/book_appointment/widgets/appointment_calendar.dart index c880238..046003a 100644 --- a/lib/presentation/book_appointment/widgets/appointment_calendar.dart +++ b/lib/presentation/book_appointment/widgets/appointment_calendar.dart @@ -19,6 +19,7 @@ import 'package:hmg_patient_app_new/presentation/home/navigation_screen.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/common_bottom_sheet.dart'; +import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart'; import 'package:lottie/lottie.dart'; import 'package:provider/provider.dart'; @@ -106,7 +107,7 @@ class _AppointmentCalendarState extends State { ), view: CalendarView.month, todayHighlightColor: Colors.transparent, - todayTextStyle: TextStyle(color: AppColors.textColor), + todayTextStyle: TextStyle(color: AppColors.textColor, fontWeight: FontWeight.bold), selectionDecoration: ShapeDecoration( color: AppColors.transparent, shape: SmoothRectangleBorder( @@ -151,8 +152,8 @@ class _AppointmentCalendarState extends State { child: Wrap( direction: Axis.horizontal, alignment: WrapAlignment.start, - spacing: 8.h, - runSpacing: 8.h, + spacing: 6.h, + runSpacing: 6.h, children: List.generate( dayEvents.length, // Generate a large number of items to ensure scrolling (index) => TimeSlotChip( @@ -177,7 +178,7 @@ class _AppointmentCalendarState extends State { bookAppointmentsViewModel.setSelectedAppointmentDateTime(selectedDate, selectedTime); Navigator.of(context).pop(); Navigator.of(context).push( - FadePage( + CustomPageRoute( page: ReviewAppointmentPage(), ), ); @@ -216,7 +217,7 @@ class _AppointmentCalendarState extends State { Navigator.of(context).pop(); Navigator.pushAndRemoveUntil( context, - FadePage( + CustomPageRoute( page: LandingNavigation(), ), (r) => false); @@ -320,7 +321,7 @@ class TimeSlotChip extends StatelessWidget { return GestureDetector( onTap: onTap, child: Container( - padding: EdgeInsets.symmetric(horizontal: 18.h, vertical: 8.h), + padding: EdgeInsets.symmetric(horizontal: 14.h, vertical: 8.h), decoration: ShapeDecoration( color: AppColors.whiteColor, shape: SmoothRectangleBorder( diff --git a/lib/presentation/habib_wallet/habib_wallet_page.dart b/lib/presentation/habib_wallet/habib_wallet_page.dart index 1be3e12..6add7bd 100644 --- a/lib/presentation/habib_wallet/habib_wallet_page.dart +++ b/lib/presentation/habib_wallet/habib_wallet_page.dart @@ -13,6 +13,7 @@ import 'package:hmg_patient_app_new/presentation/habib_wallet/recharge_wallet_pa import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.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/routes/custom_page_route.dart'; import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart'; import 'package:provider/provider.dart'; @@ -84,7 +85,7 @@ class _HabibWalletState extends State { text: "Recharge".needTranslation, onPressed: () { Navigator.of(context).push( - FadePage( + CustomPageRoute( page: RechargeWalletPage(), ), ); diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart index 01b1490..ff17d63 100644 --- a/lib/presentation/home/landing_page.dart +++ b/lib/presentation/home/landing_page.dart @@ -16,10 +16,12 @@ 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/authentication/authentication_view_model.dart'; import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_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/features/my_appointments/my_appointments_view_model.dart'; import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/appointments/my_appointments_page.dart'; +import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_card.dart'; import 'package:hmg_patient_app_new/presentation/authentication/quick_login.dart'; import 'package:hmg_patient_app_new/presentation/book_appointment/book_appointment_page.dart'; import 'package:hmg_patient_app_new/presentation/home/data/landing_page_data.dart'; @@ -98,39 +100,37 @@ class _LandingPageState extends State { children: [ Row( spacing: 8.h, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - appState.isAuthenticated - ? WelcomeWidget( - onTap: () { - Navigator.of(context).push( - springPageRoute(ProfileSettings()) - ); - }, - name: ('${appState.getAuthenticatedUser()!.firstName!} ${appState.getAuthenticatedUser()!.lastName!}'), - imageUrl: appState.getAuthenticatedUser()?.gender == 1 ? AppAssets.male_img : AppAssets.femaleImg, - ).expanded - : CustomButton( - text: LocaleKeys.loginOrRegister.tr(context: context), - onPressed: () async { - await authVM.onLoginPressed(); - }, - backgroundColor: Color(0xffFEE9EA), - borderColor: Color(0xffFEE9EA), - textColor: Color(0xffED1C2B), - fontSize: 16, - fontWeight: FontWeight.w500, - borderRadius: 12, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 50, - ), - Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + appState.isAuthenticated + ? WelcomeWidget( + onTap: () { + Navigator.of(context).push(springPageRoute(ProfileSettings())); + }, + name: ('${appState.getAuthenticatedUser()!.firstName!} ${appState.getAuthenticatedUser()!.lastName!}'), + imageUrl: appState.getAuthenticatedUser()?.gender == 1 ? AppAssets.male_img : AppAssets.femaleImg, + ).expanded + : CustomButton( + text: LocaleKeys.loginOrRegister.tr(context: context), + onPressed: () async { + await authVM.onLoginPressed(); + }, + backgroundColor: Color(0xffFEE9EA), + borderColor: Color(0xffFEE9EA), + textColor: Color(0xffED1C2B), + fontSize: 16, + fontWeight: FontWeight.w500, + borderRadius: 12, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 50, + ), + Row( mainAxisSize: MainAxisSize.min, spacing: 12.h, children: [ Utils.buildSvgWithAssets(icon: AppAssets.bell, height: 20, width: 20).onPress(() { Navigator.of(context).push( - FadePage( + CustomPageRoute( page: MedicalFilePage(), // page: LoginScreen(), ), @@ -138,7 +138,7 @@ class _LandingPageState extends State { }), Utils.buildSvgWithAssets(icon: AppAssets.search_icon, height: 20, width: 20).onPress(() { Navigator.of(context).push( - FadePage( + CustomPageRoute( page: MedicalFilePage(), // page: LoginScreen(), ), @@ -146,7 +146,7 @@ class _LandingPageState extends State { }), Utils.buildSvgWithAssets(icon: AppAssets.contact_icon, height: 20, width: 20).onPress(() { Navigator.of(context).push( - FadePage( + CustomPageRoute( page: MedicalFilePage(), // page: LoginScreen(), ), @@ -180,62 +180,94 @@ class _LandingPageState extends State { ); }), SizedBox(height: 12.h), - Swiper( - itemCount: 3, - layout: SwiperLayout.STACK, - loop: true, - itemWidth: MediaQuery.of(context).size.width - 42, - indicatorLayout: PageIndicatorLayout.COLOR, - axisDirection: AxisDirection.right, - controller: _controller, - itemHeight: 210 + 16, - pagination: const SwiperPagination( - alignment: Alignment.bottomCenter, - margin: EdgeInsets.only(top: 210 + 8 + 24), - builder: DotSwiperPaginationBuilder(color: Color(0xffD9D9D9), activeColor: AppColors.blackBgColor), - ), - itemBuilder: (BuildContext context, int index) { - return FamilyCardWidget().paddingOnly(right: 16); - }, - ), - // Container( - // width: double.infinity, - // decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - // color: AppColors.whiteColor, - // borderRadius: 24, - // ), - // child: Padding( - // padding: EdgeInsets.all(12.h), - // child: Column( - // children: [ - // Utils.buildSvgWithAssets(icon: AppAssets.home_calendar_icon, width: 32.h, height: 32.h), - // SizedBox(height: 12.h), - // "You do not have any upcoming appointment. Please book an appointment".toText12(isCenter: true), - // SizedBox(height: 12.h), - // CustomButton( - // text: LocaleKeys.bookAppo.tr(context: context), - // onPressed: () { - // Navigator.of(context).push( - // FadePage( - // page: BookAppointmentPage(), - // ), - // ); - // }, - // backgroundColor: Color(0xffFEE9EA), - // borderColor: Color(0xffFEE9EA), - // textColor: Color(0xffED1C2B), - // fontSize: 14, - // fontWeight: FontWeight.w500, - // borderRadius: 12, - // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - // height: 40, - // icon: AppAssets.add_icon, - // iconColor: AppColors.primaryRedColor, - // ), - // ], - // ), - // ), - // ).paddingSymmetrical(24.h, 0.h), + Consumer(builder: (context, myAppointmentsVM, child) { + return myAppointmentsVM.isMyAppointmentsLoading + ? Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true), + child: AppointmentCard( + patientAppointmentHistoryResponseModel: PatientAppointmentHistoryResponseModel(), + myAppointmentsViewModel: myAppointmentsViewModel, + isLoading: true, + isFromHomePage: true, + ), + ).paddingSymmetrical(24.h, 0.h) + : myAppointmentsVM.patientAppointmentsHistoryList.isNotEmpty + ? myAppointmentsVM.patientAppointmentsHistoryList.length == 1 + ? Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true), + child: AppointmentCard( + patientAppointmentHistoryResponseModel: myAppointmentsVM.patientAppointmentsHistoryList.first, + myAppointmentsViewModel: myAppointmentsViewModel, + isLoading: false, + isFromHomePage: true, + ), + ).paddingSymmetrical(24.h, 0.h) + : Swiper( + itemCount: myAppointmentsVM.isMyAppointmentsLoading + ? 3 + : myAppointmentsVM.patientAppointmentsHistoryList.length < 3 + ? myAppointmentsVM.patientAppointmentsHistoryList.length + : 3, + layout: SwiperLayout.STACK, + loop: true, + itemWidth: MediaQuery.of(context).size.width - 72, + indicatorLayout: PageIndicatorLayout.COLOR, + axisDirection: AxisDirection.right, + controller: _controller, + itemHeight: 210 + 25, + pagination: const SwiperPagination( + alignment: Alignment.bottomCenter, + margin: EdgeInsets.only(top: 210 + 8 + 24), + builder: DotSwiperPaginationBuilder(color: Color(0xffD9D9D9), activeColor: AppColors.blackBgColor), + ), + itemBuilder: (BuildContext context, int index) { + return Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: true), + child: AppointmentCard( + patientAppointmentHistoryResponseModel: myAppointmentsVM.patientAppointmentsHistoryList[index], + myAppointmentsViewModel: myAppointmentsViewModel, + isLoading: false, + isFromHomePage: true, + ), + ); + }, + ) + : Container( + width: double.infinity, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24, hasShadow: true), + child: Padding( + padding: EdgeInsets.all(12.h), + child: Column( + children: [ + Utils.buildSvgWithAssets(icon: AppAssets.home_calendar_icon, width: 32.h, height: 32.h), + SizedBox(height: 12.h), + "You do not have any upcoming appointment. Please book an appointment".needTranslation.toText12(isCenter: true), + SizedBox(height: 12.h), + 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, + fontWeight: FontWeight.w500, + borderRadius: 12, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 40, + icon: AppAssets.add_icon, + iconColor: AppColors.primaryRedColor, + ), + ], + ), + ), + ).paddingSymmetrical(24.h, 0.h); + }), SizedBox(height: 12.h), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -251,7 +283,7 @@ class _LandingPageState extends State { ], ).paddingSymmetrical(24.h, 0.h).onPress(() { Navigator.of(context).push( - FadePage( + CustomPageRoute( page: MedicalFilePage(), ), ); diff --git a/lib/presentation/home/widgets/habib_wallet_card.dart b/lib/presentation/home/widgets/habib_wallet_card.dart index 3509000..6ea4507 100644 --- a/lib/presentation/home/widgets/habib_wallet_card.dart +++ b/lib/presentation/home/widgets/habib_wallet_card.dart @@ -8,6 +8,7 @@ import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_view_mode import 'package:hmg_patient_app_new/presentation/habib_wallet/habib_wallet_page.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/routes/custom_page_route.dart'; import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart'; import 'package:provider/provider.dart'; @@ -98,7 +99,7 @@ class HabibWalletCard extends StatelessWidget { ], ).onPress(() { Navigator.of(context).push( - FadePage( + CustomPageRoute( page: HabibWalletPage(), ), ); diff --git a/lib/presentation/home/widgets/small_service_card.dart b/lib/presentation/home/widgets/small_service_card.dart index 6e1c588..fba96eb 100644 --- a/lib/presentation/home/widgets/small_service_card.dart +++ b/lib/presentation/home/widgets/small_service_card.dart @@ -7,6 +7,7 @@ import 'package:hmg_patient_app_new/presentation/insurance/insurance_home_page.d import 'package:hmg_patient_app_new/presentation/lab/lab_orders_page.dart'; import 'package:hmg_patient_app_new/presentation/medical_file/patient_sickleaves_list_page.dart'; import 'package:hmg_patient_app_new/presentation/prescriptions/prescriptions_list_page.dart'; +import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart'; import '../../../core/utils/utils.dart'; @@ -61,28 +62,28 @@ class SmallServiceCard extends StatelessWidget { switch (serviceName) { case "lab_results": Navigator.of(context).push( - FadePage( + CustomPageRoute( page: LabOrdersPage(), ), ); break; case "radiology_results": Navigator.of(context).push( - FadePage( + CustomPageRoute( page: RadiologyOrdersPage(), ), ); break; case "prescriptions": Navigator.of(context).push( - FadePage( + CustomPageRoute( page: PrescriptionsListPage(), ), ); break; case "insurance_update": Navigator.of(context).push( - FadePage( + CustomPageRoute( page: InsuranceHomePage(), ), ); @@ -90,7 +91,7 @@ class SmallServiceCard extends StatelessWidget { case "my_doctors": Navigator.of(context).push( - FadePage( + CustomPageRoute( page: MyDoctorsPage(), ), ); @@ -98,7 +99,7 @@ class SmallServiceCard extends StatelessWidget { case "sick_leaves": Navigator.of(context).push( - FadePage( + CustomPageRoute( page: PatientSickleavesListPage(), ), ); diff --git a/lib/presentation/medical_file/medical_file_page.dart b/lib/presentation/medical_file/medical_file_page.dart index acaf622..09ab37e 100644 --- a/lib/presentation/medical_file/medical_file_page.dart +++ b/lib/presentation/medical_file/medical_file_page.dart @@ -40,6 +40,7 @@ import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart'; import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart'; import 'package:hmg_patient_app_new/widgets/input_widget.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:hmg_patient_app_new/widgets/shimmer/movies_shimmer_widget.dart'; import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart'; import 'package:provider/provider.dart'; @@ -314,7 +315,7 @@ class _MedicalFilePageState extends State { ], ).paddingSymmetrical(24.h, 0.h).onPress(() { Navigator.of(context).push( - FadePage( + CustomPageRoute( page: MyAppointmentsPage(), ), ); @@ -447,7 +448,7 @@ class _MedicalFilePageState extends State { ).onPress(() { prescriptionVM.setPrescriptionsDetailsLoading(); Navigator.of(context).push( - FadePage( + CustomPageRoute( page: PrescriptionDetailPage(prescriptionsResponseModel: prescriptionVM.patientPrescriptionOrders[index]), ), ); @@ -468,7 +469,7 @@ class _MedicalFilePageState extends State { text: "All Prescriptions".needTranslation, onPressed: () { Navigator.of(context).push( - FadePage( + CustomPageRoute( page: PrescriptionsListPage(), ), ); @@ -526,7 +527,7 @@ class _MedicalFilePageState extends State { myAppointmentsViewModel.setIsPatientMyDoctorsLoading(true); myAppointmentsViewModel.getPatientMyDoctors(); Navigator.of(context).push( - FadePage( + CustomPageRoute( page: MyDoctorsPage(), ), ); @@ -631,7 +632,7 @@ class _MedicalFilePageState extends State { iconSize: 40.h, ).onPress(() { Navigator.of(context).push( - FadePage( + CustomPageRoute( page: VaccineListPage(), ), ); @@ -673,7 +674,7 @@ class _MedicalFilePageState extends State { iconSize: 36.h) .onPress(() { Navigator.of(context).push( - FadePage( + CustomPageRoute( page: InsuranceHomePage(), ), ); @@ -747,7 +748,7 @@ class _MedicalFilePageState extends State { medicalFileViewModel.setIsPatientMedicalReportsLoading(true); medicalFileViewModel.getPatientMedicalReportList(); Navigator.of(context).push( - FadePage( + CustomPageRoute( page: MedicalReportsPage(), ), ); @@ -761,7 +762,7 @@ class _MedicalFilePageState extends State { iconSize: 40.h, ).onPress(() { Navigator.of(context).push( - FadePage( + CustomPageRoute( page: PatientSickleavesListPage(), ), ); diff --git a/lib/presentation/medical_file/widgets/medical_file_appointment_card.dart b/lib/presentation/medical_file/widgets/medical_file_appointment_card.dart index 6d13ee7..a991ab8 100644 --- a/lib/presentation/medical_file/widgets/medical_file_appointment_card.dart +++ b/lib/presentation/medical_file/widgets/medical_file_appointment_card.dart @@ -13,6 +13,7 @@ import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/appointments/appointment_details_page.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/routes/custom_page_route.dart'; import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart'; class MedicalFileAppointmentCard extends StatelessWidget { @@ -86,7 +87,7 @@ class MedicalFileAppointmentCard extends StatelessWidget { text: AppointmentType.getNextActionText(patientAppointmentHistoryResponseModel.nextAction), onPressed: () { Navigator.of(context) - .push(FadePage( + .push(CustomPageRoute( page: AppointmentDetailsPage(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel), )) .then((val) { @@ -129,7 +130,7 @@ class MedicalFileAppointmentCard extends StatelessWidget { ).toShimmer2(isShow: myAppointmentsViewModel.isMyAppointmentsLoading).onPress(() { Navigator.of(context) .push( - FadePage( + CustomPageRoute( page: AppointmentDetailsPage(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel), ), ) diff --git a/lib/presentation/medical_file/widgets/patient_sick_leave_card.dart b/lib/presentation/medical_file/widgets/patient_sick_leave_card.dart index 438013f..e1999a7 100644 --- a/lib/presentation/medical_file/widgets/patient_sick_leave_card.dart +++ b/lib/presentation/medical_file/widgets/patient_sick_leave_card.dart @@ -17,6 +17,7 @@ import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.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:hmg_patient_app_new/widgets/transitions/fade_page.dart'; import 'package:open_filex/open_filex.dart'; import 'package:provider/provider.dart'; @@ -147,7 +148,7 @@ class PatientSickLeaveCard extends StatelessWidget { ), ).toShimmer2(isShow: isLoading).onPress(() { Navigator.of(context).push( - FadePage( + CustomPageRoute( page: PatientSickleavesListPage(), ), ); diff --git a/lib/presentation/prescriptions/prescriptions_list_page.dart b/lib/presentation/prescriptions/prescriptions_list_page.dart index 148afb1..3d246f3 100644 --- a/lib/presentation/prescriptions/prescriptions_list_page.dart +++ b/lib/presentation/prescriptions/prescriptions_list_page.dart @@ -15,6 +15,7 @@ import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/presentation/prescriptions/prescription_detail_page.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/routes/custom_page_route.dart'; import 'package:hmg_patient_app_new/widgets/shimmer/movies_shimmer_widget.dart'; import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart'; import 'package:provider/provider.dart'; @@ -258,7 +259,7 @@ class _PrescriptionsListPageState extends State { ).onPress(() { model.setPrescriptionsDetailsLoading(); Navigator.of(context).push( - FadePage( + CustomPageRoute( page: PrescriptionDetailPage(prescriptionsResponseModel: prescription), ), ); diff --git a/lib/presentation/profile_settings/profile_settings.dart b/lib/presentation/profile_settings/profile_settings.dart index 832031a..4610361 100644 --- a/lib/presentation/profile_settings/profile_settings.dart +++ b/lib/presentation/profile_settings/profile_settings.dart @@ -115,7 +115,7 @@ class _ProfileSettingsState extends State { iconSize: 24.h, iconColor: AppColors.infoColor, textColor: AppColors.infoColor, - text: "Recharge", + text: "Recharge".needTranslation, borderWidth: 0.h, fontWeight: FontWeight.w500, borderColor: Colors.transparent, diff --git a/lib/presentation/radiology/radiology_orders_page.dart b/lib/presentation/radiology/radiology_orders_page.dart index 19d0908..ad28a5a 100644 --- a/lib/presentation/radiology/radiology_orders_page.dart +++ b/lib/presentation/radiology/radiology_orders_page.dart @@ -12,8 +12,11 @@ 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/features/lab/lab_view_model.dart'; import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart'; +import 'package:hmg_patient_app_new/presentation/radiology/radiology_result_page.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; +import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; +import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:hmg_patient_app_new/widgets/shimmer/movies_shimmer_widget.dart'; import 'package:provider/provider.dart'; @@ -49,156 +52,145 @@ class _RadiologyOrdersPageState extends State { child: SingleChildScrollView( child: Consumer( builder: (context, model, child) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox(height: 16.h), - // Expandable list - ListView.builder( - shrinkWrap: true, - physics: NeverScrollableScrollPhysics(), - itemCount: model.isRadiologyOrdersLoading ? 5 : model.patientRadiologyOrders.length, - itemBuilder: (context, index) { - final isExpanded = expandedIndex == index; - return model.isRadiologyOrdersLoading - ? const MoviesShimmerWidget() - : 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, - margin: EdgeInsets.symmetric(vertical: 8.h), - decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true), - child: InkWell( - onTap: () { - setState(() { - expandedIndex = isExpanded ? null : index; - }); - }, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: EdgeInsets.all(16.h), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + return Padding( + padding: EdgeInsets.symmetric(horizontal: 24.h), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Expandable list + ListView.builder( + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemCount: model.isRadiologyOrdersLoading ? 5 : model.patientRadiologyOrders.length, + itemBuilder: (context, index) { + final isExpanded = expandedIndex == 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, + margin: EdgeInsets.symmetric(vertical: 8.h), + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: true), + child: InkWell( + onTap: () { + setState(() { + expandedIndex = isExpanded ? null : index; + }); + }, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.all(16.h), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AppCustomChipWidget( + labelText: LocaleKeys.resultsAvailable.tr(context: context), + backgroundColor: AppColors.successColor.withOpacity(0.15), + textColor: AppColors.successColor, + ).toShimmer2(isShow: model.isRadiologyOrdersLoading, width: 100), + SizedBox(height: 8.h), + Row( children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - CustomButton( - text: LocaleKeys.resultsAvailable.tr(context: context), - onPressed: () {}, - backgroundColor: AppColors.successColor.withOpacity(0.15), - borderColor: AppColors.successColor.withOpacity(0.01), - textColor: AppColors.successColor, - fontSize: 10, - fontWeight: FontWeight.w500, - borderRadius: 8, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 30.h, - ), - Icon(isExpanded ? Icons.expand_less : Icons.expand_more), - ], - ), - SizedBox(height: 8.h), - Row( - children: [ - Image.network( - model.patientRadiologyOrders[index].doctorImageURL!, - width: 24.h, - height: 24.h, - fit: BoxFit.fill, - ).circle(100), - SizedBox(width: 4.h), - model.patientRadiologyOrders[index].doctorName!.toText16(isBold: true) - ], - ), - SizedBox(height: 8.h), - Row( + Image.network( + model.isRadiologyOrdersLoading + ? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png" + : model.patientRadiologyOrders[index].doctorImageURL!, + width: 24.h, + height: 24.h, + fit: BoxFit.fill, + ).circle(100).toShimmer2(isShow: model.isRadiologyOrdersLoading), + SizedBox(width: 4.h), + (model.isRadiologyOrdersLoading ? "Dr John Smith" : model.patientRadiologyOrders[index].doctorName!) + .toText16(isBold: true) + .toShimmer2(isShow: model.isRadiologyOrdersLoading) + ], + ), + SizedBox(height: 8.h), + Wrap( + direction: Axis.horizontal, + spacing: 3.h, + runSpacing: 4.h, + children: [ + AppCustomChipWidget( + icon: AppAssets.doctor_calendar_icon, + labelText: model.isRadiologyOrdersLoading + ? "01 Jan 2025" + : DateUtil.formatDateToDate(DateUtil.convertStringToDate(model.patientRadiologyOrders[index].orderDate), false), + ).toShimmer2(isShow: model.isRadiologyOrdersLoading), + AppCustomChipWidget( + labelText: model.isRadiologyOrdersLoading ? "01 Jan 2025" : model.patientRadiologyOrders[index].clinicDescription!, + ).toShimmer2(isShow: model.isRadiologyOrdersLoading), + + // AppCustomChipWidget(labelText: "").toShimmer2(isShow: model.isRadiologyOrdersLoading, width: 16.h), + // AppCustomChipWidget(labelText: "").toShimmer2(isShow: model.isRadiologyOrdersLoading, width: 16.h), + ], + ), + ], + ), + ), + model.isRadiologyOrdersLoading + ? SizedBox.shrink() + : AnimatedCrossFade( + firstChild: SizedBox.shrink(), + secondChild: Padding( + padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 8.h), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - CustomButton( - text: DateUtil.formatDateToDate(DateUtil.convertStringToDate(model.patientRadiologyOrders[index].orderDate), false), - onPressed: () {}, - backgroundColor: AppColors.greyColor, - borderColor: AppColors.greyColor, - textColor: AppColors.blackColor, - fontSize: 12, - fontWeight: FontWeight.w500, - borderRadius: 8, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 24.h, + Padding( + padding: EdgeInsets.only(bottom: 8.h), + child: '● ${model.patientRadiologyOrders[index].description}'.toText14(weight: FontWeight.w500), ), - SizedBox(width: 8.h), - CustomButton( - text: model.patientRadiologyOrders[index].clinicDescription!, - onPressed: () {}, - backgroundColor: AppColors.greyColor, - borderColor: AppColors.greyColor, - textColor: AppColors.blackColor, - fontSize: 12, - fontWeight: FontWeight.w500, - borderRadius: 8, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 24.h, + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + SizedBox(), + CustomButton( + icon: AppAssets.view_report_icon, + iconColor: AppColors.primaryRedColor, + iconSize: 16.h, + text: LocaleKeys.viewReport.tr(context: context), + onPressed: () { + Navigator.of(context).push( + CustomPageRoute( + page: RadiologyResultPage(patientRadiologyResponseModel: model.patientRadiologyOrders[index]), + ), + ); + }, + backgroundColor: AppColors.secondaryLightRedColor, + borderColor: AppColors.secondaryLightRedColor, + textColor: AppColors.primaryRedColor, + fontSize: 14, + fontWeight: FontWeight.bold, + borderRadius: 12, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 40.h, + ), + ], ), ], ), - ], - ), - ), - AnimatedCrossFade( - firstChild: SizedBox.shrink(), - secondChild: Padding( - padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 8.h), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: EdgeInsets.only(bottom: 8.h), - child: '● ${model.patientRadiologyOrders[index].description}'.toText14(weight: FontWeight.w500), - ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - SizedBox(), - CustomButton( - icon: AppAssets.view_report_icon, - iconColor: AppColors.primaryRedColor, - iconSize: 16.h, - text: LocaleKeys.viewReport.tr(context: context), - onPressed: () {}, - backgroundColor: AppColors.secondaryLightRedColor, - borderColor: AppColors.secondaryLightRedColor, - textColor: AppColors.primaryRedColor, - fontSize: 14, - fontWeight: FontWeight.bold, - borderRadius: 12, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 40.h, - ), - ], - ), - ], ), + crossFadeState: isExpanded ? CrossFadeState.showSecond : CrossFadeState.showFirst, + duration: Duration(milliseconds: 300), ), - crossFadeState: isExpanded ? CrossFadeState.showSecond : CrossFadeState.showFirst, - duration: Duration(milliseconds: 300), - ), - ], - ), - ), + ], ), ), ), - ); - }, - ), - ], + ), + ), + ); + }, + ), + ], + ), ); }, ), diff --git a/lib/presentation/radiology/radiology_result_page.dart b/lib/presentation/radiology/radiology_result_page.dart new file mode 100644 index 0000000..cc4a4e7 --- /dev/null +++ b/lib/presentation/radiology/radiology_result_page.dart @@ -0,0 +1,76 @@ +import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/app_assets.dart'; +import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; +import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; +import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; +import 'package:hmg_patient_app_new/features/radiology/models/resp_models/patient_radiology_response_model.dart'; +import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; +import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; + +class RadiologyResultPage extends StatefulWidget { + RadiologyResultPage({super.key, required this.patientRadiologyResponseModel}); + + PatientRadiologyResponseModel patientRadiologyResponseModel; + + @override + State createState() => _RadiologyResultPageState(); +} + +class _RadiologyResultPageState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: AppColors.bgScaffoldColor, + body: CollapsingListView( + title: "Radiology Result".needTranslation, + child: SingleChildScrollView( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 24.h), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: 24.h), + Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 20.h, + hasShadow: true, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: 16.h), + widget.patientRadiologyResponseModel.description!.toText16(isBold: true), + SizedBox(height: 8.h), + widget.patientRadiologyResponseModel.reportData!.trim().toText12(isBold: true, color: AppColors.textColorLight), + SizedBox(height: 16.h), + CustomButton( + text: "View Radiology Image".needTranslation, + onPressed: () async {}, + backgroundColor: AppColors.primaryRedColor, + borderColor: AppColors.primaryRedColor, + textColor: AppColors.whiteColor, + fontSize: 14, + fontWeight: FontWeight.w500, + borderRadius: 12, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 40.h, + icon: AppAssets.calendar, + iconColor: AppColors.whiteColor, + iconSize: 20.h, + ), + SizedBox(height: 16.h), + ], + ).paddingSymmetrical(16.h, 0.h), + ), + SizedBox(height: 24.h), + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/splashPage.dart b/lib/splashPage.dart index f85f01e..f363bc3 100644 --- a/lib/splashPage.dart +++ b/lib/splashPage.dart @@ -21,6 +21,7 @@ import 'package:provider/provider.dart'; import 'core/cache_consts.dart'; import 'core/utils/local_notifications.dart'; import 'core/utils/push_notification_handler.dart'; +import 'widgets/routes/custom_page_route.dart'; class SplashPage extends StatefulWidget { @override @@ -42,7 +43,7 @@ class _SplashScreenState extends State { Timer(Duration(seconds: 2, milliseconds: 500), () async { LocalNotification.init(onNotificationClick: (payload) {}); Navigator.of(context).pushReplacement( - FadePage( + CustomPageRoute( page: LandingNavigation(), // page: LoginScreen(), ), From c9206f1ab85aae159dc6f6a9fcc2c1bb0272da35 Mon Sep 17 00:00:00 2001 From: Haroon Amjad <> Date: Sat, 20 Sep 2025 20:24:39 +0300 Subject: [PATCH 07/12] Radiology report implemented --- assets/images/svg/home_lab_result_icon.svg | 4 + lib/core/api/api_client.dart | 4 +- lib/core/app_assets.dart | 1 + .../patient_radiology_response_model.dart | 6 +- lib/features/radiology/radiology_repo.dart | 101 +++++++++++ .../radiology/radiology_view_model.dart | 53 ++++++ .../home/data/landing_page_data.dart | 4 +- .../medical_file/medical_file_page.dart | 6 +- .../radiology/radiology_orders_page.dart | 4 +- .../radiology/radiology_result_page.dart | 164 +++++++++++++----- 10 files changed, 296 insertions(+), 51 deletions(-) create mode 100644 assets/images/svg/home_lab_result_icon.svg diff --git a/assets/images/svg/home_lab_result_icon.svg b/assets/images/svg/home_lab_result_icon.svg new file mode 100644 index 0000000..245048d --- /dev/null +++ b/assets/images/svg/home_lab_result_icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index b0a5c78..a75a1ab 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -176,8 +176,8 @@ class ApiClientImp implements ApiClient { body[_appState.isAuthenticated ? 'TokenID' : 'LogInTokenID'] = _appState.appAuthToken; } - // body['TokenID'] = "@dm!n"; - // body['PatientID'] = "4767477"; + body['TokenID'] = "@dm!n"; + body['PatientID'] = 3628599; } body.removeWhere((key, value) => value == null); diff --git a/lib/core/app_assets.dart b/lib/core/app_assets.dart index 0a414d0..aead424 100644 --- a/lib/core/app_assets.dart +++ b/lib/core/app_assets.dart @@ -131,6 +131,7 @@ class AppAssets { static const String smart_phone_fill = '$svgBasePath/smart_phone_fill.svg'; static const String touch_face_id = '$svgBasePath/touch_face_id.svg'; static const String minus = '$svgBasePath/minus.svg'; + static const String home_lab_result_icon = '$svgBasePath/home_lab_result_icon.svg'; //bottom navigation// static const String homeBottom = '$svgBasePath/home_bottom.svg'; diff --git a/lib/features/radiology/models/resp_models/patient_radiology_response_model.dart b/lib/features/radiology/models/resp_models/patient_radiology_response_model.dart index b5568bf..740c275 100644 --- a/lib/features/radiology/models/resp_models/patient_radiology_response_model.dart +++ b/lib/features/radiology/models/resp_models/patient_radiology_response_model.dart @@ -1,3 +1,5 @@ +import 'package:hmg_patient_app_new/core/utils/date_util.dart'; + class PatientRadiologyResponseModel { String? setupID; int? projectID; @@ -6,7 +8,7 @@ class PatientRadiologyResponseModel { int? invoiceNo; int? doctorID; int? clinicID; - String? orderDate; + DateTime? orderDate; String? reportData; String? imageURL; String? procedureID; @@ -120,7 +122,7 @@ class PatientRadiologyResponseModel { invoiceNo = json['InvoiceNo']; doctorID = json['DoctorID']; clinicID = json['ClinicID']; - orderDate = json['OrderDate']; + orderDate = DateUtil.convertStringToDate(json['OrderDate']); reportData = json['ReportData']; imageURL = json['ImageURL']; procedureID = json['ProcedureID']; diff --git a/lib/features/radiology/radiology_repo.dart b/lib/features/radiology/radiology_repo.dart index 9db803d..0a44428 100644 --- a/lib/features/radiology/radiology_repo.dart +++ b/lib/features/radiology/radiology_repo.dart @@ -3,11 +3,17 @@ 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/core/utils/utils.dart'; +import 'package:hmg_patient_app_new/features/authentication/models/resp_models/authenticated_user_resp_model.dart'; import 'package:hmg_patient_app_new/features/radiology/models/resp_models/patient_radiology_response_model.dart'; import 'package:hmg_patient_app_new/services/logger_service.dart'; abstract class RadiologyRepo { Future>>> getPatientRadiologyOrders({required String patientId}); + + Future>> getRadiologyImage({required PatientRadiologyResponseModel patientRadiologyResponseModel}); + + Future>> getRadiologyReportPDF({required PatientRadiologyResponseModel patientRadiologyResponseModel, required AuthenticatedUser authenticatedUser}); } class RadiologyRepoImp implements RadiologyRepo { @@ -58,4 +64,99 @@ class RadiologyRepoImp implements RadiologyRepo { return Left(UnknownFailure(e.toString())); } } + + @override + Future>> getRadiologyImage({required PatientRadiologyResponseModel patientRadiologyResponseModel}) async { + Map mapDevice = { + "InvoiceNo": Utils.isVidaPlusProject(patientRadiologyResponseModel.projectID!) ? "0" : patientRadiologyResponseModel.invoiceNo, + "InvoiceNo_VP": Utils.isVidaPlusProject(patientRadiologyResponseModel.projectID!) ? patientRadiologyResponseModel.invoiceNo : "0", + "LineItemNo": patientRadiologyResponseModel.invoiceLineItemNo, + "ProjectID": patientRadiologyResponseModel.projectID!, + "InvoiceType": patientRadiologyResponseModel.invoiceType!, + "ExamId": patientRadiologyResponseModel.examId ?? "", + }; + + try { + GenericApiModel? apiResponse; + Failure? failure; + await apiClient.post( + GET_RAD_IMAGE_URL, + body: mapDevice, + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + }, + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { + try { + apiResponse = GenericApiModel( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: null, + data: response["Data"], + ); + } 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>> getRadiologyReportPDF({required PatientRadiologyResponseModel patientRadiologyResponseModel, required AuthenticatedUser authenticatedUser}) async { + Map mapDevice = { + "InvoiceNo": Utils.isVidaPlusProject(patientRadiologyResponseModel.projectID!) ? 0 : patientRadiologyResponseModel.invoiceNo, + "InvoiceNo_VP": Utils.isVidaPlusProject(patientRadiologyResponseModel.projectID!) ? patientRadiologyResponseModel.invoiceNo : 0, + "LineItemNo": patientRadiologyResponseModel.invoiceLineItemNo, + "InvoiceLineItemNo": patientRadiologyResponseModel.invoiceLineItemNo, + "ProjectID": patientRadiologyResponseModel.projectID!, + "InvoiceType": patientRadiologyResponseModel.invoiceType!, + "SetupID": patientRadiologyResponseModel.setupID!, + // "ExamId": patientRadiologyResponseModel.examId ?? "", + "IsDownload": true, + 'ClinicName': patientRadiologyResponseModel.clinicDescription, + 'DateofBirth': authenticatedUser.dateofBirth, + 'DoctorName': patientRadiologyResponseModel.doctorName, + 'OrderDate': '${patientRadiologyResponseModel.orderDate!.year}-${patientRadiologyResponseModel.orderDate!.month}-${patientRadiologyResponseModel.orderDate!.day}', + 'PatientIditificationNum': authenticatedUser.patientIdentificationNo, + 'PatientMobileNumber': authenticatedUser.mobileNumber, + 'PatientName': "${authenticatedUser.firstName!} ${authenticatedUser.lastName!}", + 'ProjectName': patientRadiologyResponseModel.projectName, + 'RadResult': patientRadiologyResponseModel.reportData, + "To": authenticatedUser.emailAddress + }; + + try { + GenericApiModel? apiResponse; + Failure? failure; + await apiClient.post( + SEND_RAD_REPORT_EMAIL, + body: mapDevice, + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + }, + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { + try { + apiResponse = GenericApiModel( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: null, + data: response["Base64Data"], + ); + } 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())); + } + } } diff --git a/lib/features/radiology/radiology_view_model.dart b/lib/features/radiology/radiology_view_model.dart index 1bdba04..3441881 100644 --- a/lib/features/radiology/radiology_view_model.dart +++ b/lib/features/radiology/radiology_view_model.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/features/authentication/models/resp_models/authenticated_user_resp_model.dart'; import 'package:hmg_patient_app_new/features/radiology/radiology_repo.dart'; import 'package:hmg_patient_app_new/services/error_handler_service.dart'; @@ -6,17 +7,23 @@ import 'models/resp_models/patient_radiology_response_model.dart'; class RadiologyViewModel extends ChangeNotifier { bool isRadiologyOrdersLoading = false; + bool isRadiologyPDFReportLoading = false; RadiologyRepo radiologyRepo; ErrorHandlerService errorHandlerService; List patientRadiologyOrders = []; + String radiologyImageURL = ""; + String patientRadiologyReportPDFBase64 = ""; + RadiologyViewModel({required this.radiologyRepo, required this.errorHandlerService}); initRadiologyProvider() { patientRadiologyOrders.clear(); isRadiologyOrdersLoading = true; + isRadiologyPDFReportLoading = true; + radiologyImageURL = ""; getPatientRadiologyOrders(); notifyListeners(); } @@ -40,4 +47,50 @@ class RadiologyViewModel extends ChangeNotifier { }, ); } + + Future getRadiologyImage({required PatientRadiologyResponseModel patientRadiologyResponseModel, Function(dynamic)? onSuccess, Function(String)? onError}) async { + final result = await radiologyRepo.getRadiologyImage(patientRadiologyResponseModel: patientRadiologyResponseModel); + + result.fold( + (failure) async => await errorHandlerService.handleError(failure: failure), + (apiResponse) { + if (apiResponse.messageStatus == 2) { + // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); + } else if (apiResponse.messageStatus == 1) { + radiologyImageURL = apiResponse.data!; + notifyListeners(); + if (onSuccess != null) { + onSuccess(apiResponse); + } + } + }, + ); + } + + Future getRadiologyPDF( + {required PatientRadiologyResponseModel patientRadiologyResponseModel, required AuthenticatedUser authenticatedUser, Function(dynamic)? onSuccess, Function(String)? onError}) async { + final result = await radiologyRepo.getRadiologyReportPDF(patientRadiologyResponseModel: patientRadiologyResponseModel, authenticatedUser: authenticatedUser); + + result.fold( + (failure) async => await errorHandlerService.handleError( + failure: failure, + onOkPressed: () { + onError!(failure.message); + }, + ), + (apiResponse) { + if (apiResponse.messageStatus == 2) { + onError!(apiResponse.errorMessage!); + // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); + } else if (apiResponse.messageStatus == 1) { + patientRadiologyReportPDFBase64 = apiResponse.data!; + isRadiologyPDFReportLoading = false; + notifyListeners(); + if (onSuccess != null) { + onSuccess(apiResponse); + } + } + }, + ); + } } diff --git a/lib/presentation/home/data/landing_page_data.dart b/lib/presentation/home/data/landing_page_data.dart index ad524e3..31b4598 100644 --- a/lib/presentation/home/data/landing_page_data.dart +++ b/lib/presentation/home/data/landing_page_data.dart @@ -80,7 +80,7 @@ class LandingPageData { ), ServiceCardData( serviceName: "lab_results", - icon: AppAssets.lab_result_icon, + icon: AppAssets.home_lab_result_icon, title: "My Lab", subtitle: "Results", backgroundColor: AppColors.whiteColor, @@ -90,7 +90,7 @@ class LandingPageData { ), ServiceCardData( serviceName: "radiology_results", - icon: AppAssets.lab_result_icon, + icon: AppAssets.home_lab_result_icon, title: "My Radiology", subtitle: "Results", backgroundColor: AppColors.whiteColor, diff --git a/lib/presentation/medical_file/medical_file_page.dart b/lib/presentation/medical_file/medical_file_page.dart index 09ab37e..22de759 100644 --- a/lib/presentation/medical_file/medical_file_page.dart +++ b/lib/presentation/medical_file/medical_file_page.dart @@ -416,8 +416,8 @@ class _MedicalFilePageState extends State { children: [ Image.network( prescriptionVM.patientPrescriptionOrders[index].doctorImageURL!, - width: 63.h, - height: 63.h, + width: 40.h, + height: 40.h, fit: BoxFit.fill, ).circle(100), SizedBox(width: 16.h), @@ -442,7 +442,7 @@ class _MedicalFilePageState extends State { ], ), ), - SizedBox(width: 40.h), + // SizedBox(width: 40.h), Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, width: 15.h, height: 15.h, fit: BoxFit.contain, iconColor: AppColors.textColor), ], ).onPress(() { diff --git a/lib/presentation/radiology/radiology_orders_page.dart b/lib/presentation/radiology/radiology_orders_page.dart index ad28a5a..c7732a4 100644 --- a/lib/presentation/radiology/radiology_orders_page.dart +++ b/lib/presentation/radiology/radiology_orders_page.dart @@ -119,9 +119,7 @@ class _RadiologyOrdersPageState extends State { children: [ AppCustomChipWidget( icon: AppAssets.doctor_calendar_icon, - labelText: model.isRadiologyOrdersLoading - ? "01 Jan 2025" - : DateUtil.formatDateToDate(DateUtil.convertStringToDate(model.patientRadiologyOrders[index].orderDate), false), + labelText: model.isRadiologyOrdersLoading ? "01 Jan 2025" : DateUtil.formatDateToDate(model.patientRadiologyOrders[index].orderDate!, false), ).toShimmer2(isShow: model.isRadiologyOrdersLoading), AppCustomChipWidget( labelText: model.isRadiologyOrdersLoading ? "01 Jan 2025" : model.patientRadiologyOrders[index].clinicDescription!, diff --git a/lib/presentation/radiology/radiology_result_page.dart b/lib/presentation/radiology/radiology_result_page.dart index cc4a4e7..f0f9af4 100644 --- a/lib/presentation/radiology/radiology_result_page.dart +++ b/lib/presentation/radiology/radiology_result_page.dart @@ -1,13 +1,24 @@ +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_state.dart'; +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/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/radiology/models/resp_models/patient_radiology_response_model.dart'; +import 'package:hmg_patient_app_new/features/radiology/radiology_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.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/common_bottom_sheet.dart'; +import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart'; +import 'package:open_filex/open_filex.dart'; +import 'package:provider/provider.dart'; +import 'package:url_launcher/url_launcher.dart'; class RadiologyResultPage extends StatefulWidget { RadiologyResultPage({super.key, required this.patientRadiologyResponseModel}); @@ -19,57 +30,132 @@ class RadiologyResultPage extends StatefulWidget { } class _RadiologyResultPageState extends State { + late RadiologyViewModel radiologyViewModel; + + @override + void initState() { + scheduleMicrotask(() { + radiologyViewModel.getRadiologyImage(patientRadiologyResponseModel: widget.patientRadiologyResponseModel); + }); + super.initState(); + } + @override Widget build(BuildContext context) { + radiologyViewModel = Provider.of(context); + AppState _appState = getIt.get(); return Scaffold( backgroundColor: AppColors.bgScaffoldColor, - body: CollapsingListView( - title: "Radiology Result".needTranslation, - child: SingleChildScrollView( - child: Padding( - padding: EdgeInsets.symmetric(horizontal: 24.h), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox(height: 24.h), - Container( - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - borderRadius: 20.h, - hasShadow: true, - ), + body: Column( + children: [ + Expanded( + child: CollapsingListView( + title: "Radiology Result".needTranslation, + child: SingleChildScrollView( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 24.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - SizedBox(height: 16.h), - widget.patientRadiologyResponseModel.description!.toText16(isBold: true), - SizedBox(height: 8.h), - widget.patientRadiologyResponseModel.reportData!.trim().toText12(isBold: true, color: AppColors.textColorLight), - SizedBox(height: 16.h), - CustomButton( - text: "View Radiology Image".needTranslation, - onPressed: () async {}, - backgroundColor: AppColors.primaryRedColor, - borderColor: AppColors.primaryRedColor, - textColor: AppColors.whiteColor, - fontSize: 14, - fontWeight: FontWeight.w500, - borderRadius: 12, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 40.h, - icon: AppAssets.calendar, - iconColor: AppColors.whiteColor, - iconSize: 20.h, + SizedBox(height: 24.h), + Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 20.h, + hasShadow: true, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: 16.h), + widget.patientRadiologyResponseModel.description!.toText16(isBold: true), + SizedBox(height: 8.h), + widget.patientRadiologyResponseModel.reportData!.trim().toText12(isBold: true, color: AppColors.textColorLight), + SizedBox(height: 16.h), + CustomButton( + text: "View Radiology Image".needTranslation, + onPressed: () async { + if (radiologyViewModel.radiologyImageURL.isNotEmpty) { + Uri uri = Uri.parse(radiologyViewModel.radiologyImageURL); + launchUrl(uri, mode: LaunchMode.platformDefault, webOnlyWindowName: ""); + } else { + Utils.showToast("Radiology image not available".needTranslation); + } + }, + backgroundColor: AppColors.primaryRedColor, + borderColor: AppColors.primaryRedColor, + textColor: AppColors.whiteColor, + fontSize: 14, + fontWeight: FontWeight.w500, + borderRadius: 12, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 40.h, + icon: AppAssets.download, + iconColor: AppColors.whiteColor, + iconSize: 20.h, + ), + SizedBox(height: 16.h), + ], + ).paddingSymmetrical(16.h, 0.h), ), - SizedBox(height: 16.h), + SizedBox(height: 24.h), ], - ).paddingSymmetrical(16.h, 0.h), + ), ), - SizedBox(height: 24.h), - ], + ), + ), + ), + Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24.h, + hasShadow: true, ), + child: CustomButton( + text: "Download report".needTranslation, + onPressed: () async { + LoaderBottomSheet.showLoader(); + await radiologyViewModel.getRadiologyPDF(patientRadiologyResponseModel: widget.patientRadiologyResponseModel, authenticatedUser: _appState.getAuthenticatedUser()!, onError: (err) { + LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight( + context, + child: Utils.getErrorWidget(loadingText: err), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + }).then((val) async { + LoaderBottomSheet.hideLoader(); + if (radiologyViewModel.patientRadiologyReportPDFBase64.isNotEmpty) { + String path = await Utils.createFileFromString(radiologyViewModel.patientRadiologyReportPDFBase64, "pdf"); + try { + OpenFilex.open(path); + } catch (ex) { + showCommonBottomSheetWithoutHeight( + context, + child: Utils.getErrorWidget(loadingText: "Cannot open file".needTranslation), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + } + } + }); + }, + backgroundColor: AppColors.successColor, + borderColor: AppColors.successColor, + textColor: AppColors.whiteColor, + fontSize: 16, + fontWeight: FontWeight.w500, + borderRadius: 12, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 45.h, + icon: AppAssets.download, + iconColor: AppColors.whiteColor, + iconSize: 20.h, + ).paddingSymmetrical(24.h, 24.h), ), - ), + ], ), ); } From a4854bbe4ad4a423e7436f6982af998c1f4bec42 Mon Sep 17 00:00:00 2001 From: Haroon Amjad <> Date: Sat, 20 Sep 2025 20:46:16 +0300 Subject: [PATCH 08/12] Habib Wallet updates --- lib/core/api/api_client.dart | 4 ++-- lib/core/api_consts.dart | 2 +- .../habib_wallet/recharge_wallet_page.dart | 21 +------------------ .../widgets/select-medical_file.dart | 9 -------- .../profile_settings/profile_settings.dart | 2 +- pubspec.yaml | 1 - 6 files changed, 5 insertions(+), 34 deletions(-) diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index a75a1ab..62339bf 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -176,8 +176,8 @@ class ApiClientImp implements ApiClient { body[_appState.isAuthenticated ? 'TokenID' : 'LogInTokenID'] = _appState.appAuthToken; } - body['TokenID'] = "@dm!n"; - body['PatientID'] = 3628599; + // body['TokenID'] = "@dm!n"; + // body['PatientID'] = 3628599; } body.removeWhere((key, value) => value == null); diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index d31679c..f802818 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -723,7 +723,7 @@ const DEACTIVATE_ACCOUNT = 'Services/Patients.svc/REST/PatientAppleActivation_In class ApiConsts { static const maxSmallScreen = 660; - static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.prod; + static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.uat; // static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT diff --git a/lib/presentation/habib_wallet/recharge_wallet_page.dart b/lib/presentation/habib_wallet/recharge_wallet_page.dart index 02a9426..8b35f8b 100644 --- a/lib/presentation/habib_wallet/recharge_wallet_page.dart +++ b/lib/presentation/habib_wallet/recharge_wallet_page.dart @@ -1,5 +1,4 @@ import 'package:easy_localization/easy_localization.dart'; -import 'package:family_bottom_sheet/family_bottom_sheet.dart'; import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; @@ -125,25 +124,7 @@ class _RechargeWalletPageState extends State { ], ).onPress(() async { // showCommonBottomSheetWithoutHeight(context, title: "Select Medical File".needTranslation, child: SelectMedicalFile(), callBackFunc: () {}, isFullScreen: false); - // showCommonBottomSheetWithoutHeight(context, title: "Select Medical File".needTranslation, child: const MultiPageBottomSheet(), callBackFunc: () {}, isFullScreen: false); - await FamilyModalSheet.show( - context: context, - contentBackgroundColor: AppColors.scaffoldBgColor, - backgroundColor: AppColors.bottomSheetBgColor, - mainContentPadding: EdgeInsets.all(24.h), - isScrollControlled: true, - safeAreaMinimum: EdgeInsets.zero, - useSafeArea: false, - sheetAnimationStyle: AnimationStyle( - duration: Duration(milliseconds: 500), // Custom animation duration - reverseDuration: Duration(milliseconds: 300), // Custom reverse animation duration - ), - builder: (ctx) { - return const MultiPageBottomSheet(); - }, - - // Optional configurations - ); + showCommonBottomSheetWithoutHeight(context, title: "Select Medical File".needTranslation, child: const MultiPageBottomSheet(), callBackFunc: () {}, isFullScreen: false); }), SizedBox(height: 16.h), Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h), diff --git a/lib/presentation/habib_wallet/widgets/select-medical_file.dart b/lib/presentation/habib_wallet/widgets/select-medical_file.dart index 4724ea1..ab777c0 100644 --- a/lib/presentation/habib_wallet/widgets/select-medical_file.dart +++ b/lib/presentation/habib_wallet/widgets/select-medical_file.dart @@ -48,15 +48,6 @@ class _MultiPageBottomSheetState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - "Select Medical File".toText20(weight: FontWeight.w600).expanded, - Utils.buildSvgWithAssets(icon: AppAssets.close_bottom_sheet_icon, iconColor: Color(0xff2B353E)).onPress(() { - Navigator.of(context).pop(); - }), - ], - ), Container( decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.whiteColor, diff --git a/lib/presentation/profile_settings/profile_settings.dart b/lib/presentation/profile_settings/profile_settings.dart index 4610361..6894d50 100644 --- a/lib/presentation/profile_settings/profile_settings.dart +++ b/lib/presentation/profile_settings/profile_settings.dart @@ -100,7 +100,7 @@ class _ProfileSettingsState extends State { crossAxisAlignment: CrossAxisAlignment.center, children: [ Utils.buildSvgWithAssets(icon: AppAssets.wallet, width: 40.h, height: 40.h), - "Al Habib Wallet".needTranslation.toText14(weight: FontWeight.w600, maxlines: 2).expanded, + "Habib Wallet".needTranslation.toText14(weight: FontWeight.w600, maxlines: 2).expanded, Utils.buildSvgWithAssets(icon: AppAssets.arrow_forward), ], ), diff --git a/pubspec.yaml b/pubspec.yaml index 5423904..ea41d43 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -80,7 +80,6 @@ dependencies: path_provider: ^2.0.8 open_filex: ^4.7.0 flutter_swiper_view: ^1.1.8 - family_bottom_sheet: ^0.1.0 location: ^8.0.1 gms_check: ^1.0.4 From 6048b3b5f1cbc867b23de69e5be4e3b815679aa6 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Sun, 21 Sep 2025 17:09:44 +0300 Subject: [PATCH 09/12] Advance payment module implementation contd. --- assets/images/svg/visa_mastercard.svg | 14 + lib/core/app_assets.dart | 1 + lib/core/app_state.dart | 5 +- lib/core/utils/utils.dart | 18 +- .../authentication_view_model.dart | 196 ++++----- .../check_activation_code_resp_model.dart | 32 -- .../book_appointments_repo.dart | 13 +- .../habib_wallet/habib_wallet_repo.dart | 171 ++++++++ .../habib_wallet/habib_wallet_view_model.dart | 124 ++++++ lib/features/payfort/payfort_view_model.dart | 2 + .../appointment_payment_page.dart | 11 +- .../hospital_list_items.dart | 33 +- .../habib_wallet/habib_wallet_page.dart | 18 +- .../habib_wallet/recharge_wallet_page.dart | 338 +++++++++------ .../wallet_payment_confirm_page.dart | 385 ++++++++++++++++++ .../widgets/hospital_list_item.dart | 103 +++++ .../widgets/select-medical_file.dart | 203 +++++---- .../widgets/select_hospital_bottom_sheet.dart | 96 +++++ .../medical_file/medical_file_page.dart | 142 +++---- .../profile_settings/profile_settings.dart | 2 +- pubspec.yaml | 2 +- 21 files changed, 1455 insertions(+), 454 deletions(-) create mode 100644 assets/images/svg/visa_mastercard.svg create mode 100644 lib/presentation/habib_wallet/wallet_payment_confirm_page.dart create mode 100644 lib/presentation/habib_wallet/widgets/hospital_list_item.dart create mode 100644 lib/presentation/habib_wallet/widgets/select_hospital_bottom_sheet.dart diff --git a/assets/images/svg/visa_mastercard.svg b/assets/images/svg/visa_mastercard.svg new file mode 100644 index 0000000..22e19fa --- /dev/null +++ b/assets/images/svg/visa_mastercard.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/lib/core/app_assets.dart b/lib/core/app_assets.dart index aead424..57e0ebc 100644 --- a/lib/core/app_assets.dart +++ b/lib/core/app_assets.dart @@ -132,6 +132,7 @@ class AppAssets { static const String touch_face_id = '$svgBasePath/touch_face_id.svg'; static const String minus = '$svgBasePath/minus.svg'; static const String home_lab_result_icon = '$svgBasePath/home_lab_result_icon.svg'; + static const String visa_mastercard_icon = '$svgBasePath/visa_mastercard.svg'; //bottom navigation// static const String homeBottom = '$svgBasePath/home_bottom.svg'; diff --git a/lib/core/app_state.dart b/lib/core/app_state.dart index e9abeaa..c906374 100644 --- a/lib/core/app_state.dart +++ b/lib/core/app_state.dart @@ -44,6 +44,7 @@ class AppState { setIsAuthenticated = true; _authenticatedRootUser = authenticatedUser; } + } AuthenticatedUser? getAuthenticatedUser({bool isFamily = false}) { @@ -97,7 +98,7 @@ class AppState { set setDeviceTypeID(v) => deviceTypeID = v; List vidaPlusProjectList = []; - List privilegeModelList = []; + List privilegeModelList = []; List hMCProjectListModel = []; List projectDetailListModel = []; @@ -105,7 +106,7 @@ class AppState { vidaPlusProjectList = vidaPlusProjectListModelInput; } - setPrivilegeModelList(List privilegeModelListInput) { + setPrivilegeModelList(List privilegeModelListInput) { privilegeModelList = privilegeModelListInput; } diff --git a/lib/core/utils/utils.dart b/lib/core/utils/utils.dart index 6b74a7b..e0eeb23 100644 --- a/lib/core/utils/utils.dart +++ b/lib/core/utils/utils.dart @@ -650,7 +650,7 @@ class Utils { ); } - static Widget getPaymentAmountWithSymbol2(num habibWalletAmount, Color iconColor, double iconSize, {bool isSaudiCurrency = true, bool isExpanded = true}) { + static Widget getPaymentAmountWithSymbol2(num habibWalletAmount, {double iconSize = 14, Color iconColor = AppColors.textColor, Color textColor = AppColors.blackColor, bool isSaudiCurrency = true, bool isExpanded = true}) { return RichText( maxLines: 1, text: TextSpan( @@ -658,11 +658,11 @@ class Utils { WidgetSpan( alignment: PlaceholderAlignment.baseline, baseline: TextBaseline.alphabetic, - child: Utils.buildSvgWithAssets(icon: AppAssets.saudi_riyal_icon, width: 14.h, height: 14.h, iconColor: Colors.black.withValues(alpha: 0.31)), + child: Utils.buildSvgWithAssets(icon: AppAssets.saudi_riyal_icon, width: iconSize.h, height: iconSize.h, iconColor: iconColor), ), TextSpan( text: " $habibWalletAmount", - style: TextStyle(color: AppColors.blackColor, fontSize: 32.fSize, letterSpacing: -4, fontWeight: FontWeight.w600, height: 1), + style: TextStyle(color: textColor, fontSize: 32.fSize, letterSpacing: -4, fontWeight: FontWeight.w600, height: 1), ), ], ), @@ -708,4 +708,16 @@ class Utils { await file.writeAsBytes(bytes); return file.path; } + + static bool havePrivilege(int id) { + bool isHavePrivilege = false; + try { + for (var element in appState.privilegeModelList) { + if (element.id == id) isHavePrivilege = element.previlege!; + } + } catch (e) { + print(e); + } + return isHavePrivilege; + } } diff --git a/lib/features/authentication/authentication_view_model.dart b/lib/features/authentication/authentication_view_model.dart index c0b20b5..9afdc97 100644 --- a/lib/features/authentication/authentication_view_model.dart +++ b/lib/features/authentication/authentication_view_model.dart @@ -23,6 +23,7 @@ import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/features/authentication/authentication_repo.dart'; import 'package:hmg_patient_app_new/features/authentication/models/request_models/check_activation_code_register_request_model.dart'; import 'package:hmg_patient_app_new/features/authentication/models/request_models/registration_payload_model.dart'; +import 'package:hmg_patient_app_new/features/authentication/models/resp_models/authenticated_user_resp_model.dart'; import 'package:hmg_patient_app_new/features/authentication/models/resp_models/check_activation_code_resp_model.dart'; import 'package:hmg_patient_app_new/features/authentication/models/resp_models/check_user_staus_nhic_response_model.dart'; import 'package:hmg_patient_app_new/features/authentication/models/resp_models/select_device_by_imei.dart'; @@ -59,8 +60,7 @@ class AuthenticationViewModel extends ChangeNotifier { required NavigationService navigationService, required CacheService cacheService, required LocalAuthService localAuthService, - }) - : _navigationService = navigationService, + }) : _navigationService = navigationService, _dialogService = dialogService, _errorHandlerService = errorHandlerService, _appState = appState, @@ -205,13 +205,13 @@ class AuthenticationViewModel extends ChangeNotifier { final result = await _authenticationRepo.selectDeviceByImei(firebaseToken: firebaseToken); result.fold( - (failure) async { + (failure) async { // LoadingUtils.hideFullScreenLoader(); // await _errorHandlerService.handleError(failure: failure); LoaderBottomSheet.hideLoader(); _navigationService.pushPage(page: LoginScreen()); }, - (apiResponse) { + (apiResponse) { // LoadingUtils.hideFullScreenLoader(); log("apiResponse: ${apiResponse.data.toString()}"); log("messageStatus: ${apiResponse.messageStatus.toString()}"); @@ -301,8 +301,7 @@ class AuthenticationViewModel extends ChangeNotifier { final result = await _authenticationRepo.checkPatientAuthentication(checkPatientAuthenticationReq: checkPatientAuthenticationReq); result.fold( - (failure) async => - await _errorHandlerService.handleError( + (failure) async => await _errorHandlerService.handleError( failure: failure, onUnHandledFailure: (failure) async { LoaderBottomSheet.hideLoader(); @@ -316,7 +315,7 @@ class AuthenticationViewModel extends ChangeNotifier { _navigationService.pop(); }); }), - (apiResponse) async { + (apiResponse) async { if (apiResponse.messageStatus == 2) { LoaderBottomSheet.hideLoader(); await _dialogService.showErrorBottomSheet(message: apiResponse.errorMessage ?? "ErrorEmpty", onOkPressed: () {}); @@ -359,8 +358,8 @@ class AuthenticationViewModel extends ChangeNotifier { patientOutSA: isForRegister ? isPatientOutsideSA(request: payload) : selectedCountrySignup.countryCode == CountryEnum.saudiArabia - ? false - : true, + ? false + : true, payload: payload, ); @@ -374,8 +373,8 @@ class AuthenticationViewModel extends ChangeNotifier { final resultEither = await _authenticationRepo.sendActivationCodeRepo(sendActivationCodeReq: request, isRegister: checkIsUserComingForRegister(request: payload), languageID: 'er'); resultEither.fold( - (failure) async => await _errorHandlerService.handleError(failure: failure), - (apiResponse) async { + (failure) async => await _errorHandlerService.handleError(failure: failure), + (apiResponse) async { if (apiResponse.messageStatus == 2) { LoaderBottomSheet.hideLoader(); await _dialogService.showCommonBottomSheetWithoutH( @@ -409,27 +408,27 @@ class AuthenticationViewModel extends ChangeNotifier { bool isForRegister = (_appState.getUserRegistrationPayload.healthId != null || _appState.getUserRegistrationPayload.patientOutSa == true || _appState.getUserRegistrationPayload.patientOutSa == 1); final request = RequestUtils.getCommonRequestWelcome( - phoneNumber: phoneNumberController.text, - otpTypeEnum: otpTypeEnum, - deviceToken: _appState.deviceToken, - // patientOutSA: _appState.getUserRegistrationPayload.projectOutSa == 1 ? true : false, - patientOutSA: isForRegister - ? _appState.getUserRegistrationPayload.projectOutSa == true - ? true - : false - : _appState.getSelectDeviceByImeiRespModelElement != null - ? _appState.getSelectDeviceByImeiRespModelElement!.outSa! - : selectedCountrySignup == CountryEnum.saudiArabia - ? false - : true, - loginTokenID: _appState.appAuthToken, - registeredData: isForRegister ? _appState.getUserRegistrationPayload : null, - nationIdText: nationalIdController.text, - countryCode: _appState.getSelectDeviceByImeiRespModelElement != null && _appState.getSelectDeviceByImeiRespModelElement!.outSa == true - ? CountryEnum.unitedArabEmirates.countryCode - : selectedCountrySignup.countryCode, - //TODO: Error Here IN Zip Code. - loginType: loginTypeEnum.toInt) + phoneNumber: phoneNumberController.text, + otpTypeEnum: otpTypeEnum, + deviceToken: _appState.deviceToken, + // patientOutSA: _appState.getUserRegistrationPayload.projectOutSa == 1 ? true : false, + patientOutSA: isForRegister + ? _appState.getUserRegistrationPayload.projectOutSa == true + ? true + : false + : _appState.getSelectDeviceByImeiRespModelElement != null + ? _appState.getSelectDeviceByImeiRespModelElement!.outSa! + : selectedCountrySignup == CountryEnum.saudiArabia + ? false + : true, + loginTokenID: _appState.appAuthToken, + registeredData: isForRegister ? _appState.getUserRegistrationPayload : null, + nationIdText: nationalIdController.text, + countryCode: _appState.getSelectDeviceByImeiRespModelElement != null && _appState.getSelectDeviceByImeiRespModelElement!.outSa == true + ? CountryEnum.unitedArabEmirates.countryCode + : selectedCountrySignup.countryCode, + //TODO: Error Here IN Zip Code. + loginType: loginTypeEnum.toInt) .toJson(); LoaderBottomSheet.showLoader(); if (isForRegister) { @@ -445,8 +444,7 @@ class AuthenticationViewModel extends ChangeNotifier { LoaderBottomSheet.hideLoader(); resultEither.fold( - (failure) async => - await _errorHandlerService.handleError( + (failure) async => await _errorHandlerService.handleError( failure: failure, onUnHandledFailure: (failure) async { LoaderBottomSheet.hideLoader(); @@ -473,8 +471,7 @@ class AuthenticationViewModel extends ChangeNotifier { final resultEither = await _authenticationRepo.checkActivationCodeRepo(newRequest: CheckActivationCodeRegisterReq.fromJson(request), activationCode: activationCode, isRegister: false); resultEither.fold( - (failure) async => - await _errorHandlerService.handleError( + (failure) async => await _errorHandlerService.handleError( failure: failure, onUnHandledFailure: (failure) async { LoaderBottomSheet.hideLoader(); @@ -504,6 +501,7 @@ class AuthenticationViewModel extends ChangeNotifier { } else { if (activation.list != null && activation.list!.isNotEmpty) { _appState.setAuthenticatedUser(activation.list!.first); + _appState.setPrivilegeModelList(activation.list!.first.listPrivilege!); } _appState.setUserBloodGroup = (activation.patientBlodType ?? ""); _appState.setAppAuthToken = activation.authenticationTokenId; @@ -658,15 +656,15 @@ class AuthenticationViewModel extends ChangeNotifier { bool isOutSidePatient = selectedCountrySignup.countryCode == CountryEnum.unitedArabEmirates.countryCode ? true : false; LoaderBottomSheet.showLoader(); final request = await RequestUtils.getPatientAuthenticationRequest( - phoneNumber: phoneNumberController.text, - nationId: nationalIdController.text, - patientOutSA: isOutSidePatient, - otpTypeEnum: otpTypeEnum, - isForRegister: true, - patientId: 0, - zipCode: selectedCountrySignup.countryCode, - calenderType: calenderType, - dob: dob) + phoneNumber: phoneNumberController.text, + nationId: nationalIdController.text, + patientOutSA: isOutSidePatient, + otpTypeEnum: otpTypeEnum, + isForRegister: true, + patientId: 0, + zipCode: selectedCountrySignup.countryCode, + calenderType: calenderType, + dob: dob) .toJson(); var nRequest = Map.from(request); @@ -802,22 +800,22 @@ class AuthenticationViewModel extends ChangeNotifier { Future insertPatientIMEIData(int loginType) async { final resultEither = await _authenticationRepo.insertPatientIMEIData( patientIMEIDataRequest: PatientInsertDeviceImei( - imei: _appState.deviceToken, - deviceTypeId: _appState.getDeviceTypeID(), - patientId: _appState.getAuthenticatedUser()!.patientId!, - patientIdentificationNo: _appState.getAuthenticatedUser()!.patientIdentificationNo!, - identificationNo: _appState.getAuthenticatedUser()!.patientIdentificationNo!, - firstName: _appState.getAuthenticatedUser()!.firstName!, - lastName: _appState.getAuthenticatedUser()!.lastName!, - patientTypeId: _appState.getAuthenticatedUser()!.patientType, - mobileNo: _appState.getAuthenticatedUser()!.mobileNumber!, - logInTypeId: loginType, - patientOutSa: _appState.getAuthenticatedUser()!.outSa!, - outSa: _appState.getAuthenticatedUser()!.outSa == 1 ? true : false, - biometricEnabled: loginType == 1 || loginType == 2 ? false : true, - firstNameN: _appState.getAuthenticatedUser()!.firstNameN, - lastNameN: _appState.getAuthenticatedUser()!.lastNameN, - ).toJson()); + imei: _appState.deviceToken, + deviceTypeId: _appState.getDeviceTypeID(), + patientId: _appState.getAuthenticatedUser()!.patientId!, + patientIdentificationNo: _appState.getAuthenticatedUser()!.patientIdentificationNo!, + identificationNo: _appState.getAuthenticatedUser()!.patientIdentificationNo!, + firstName: _appState.getAuthenticatedUser()!.firstName!, + lastName: _appState.getAuthenticatedUser()!.lastName!, + patientTypeId: _appState.getAuthenticatedUser()!.patientType, + mobileNo: _appState.getAuthenticatedUser()!.mobileNumber!, + logInTypeId: loginType, + patientOutSa: _appState.getAuthenticatedUser()!.outSa!, + outSa: _appState.getAuthenticatedUser()!.outSa == 1 ? true : false, + biometricEnabled: loginType == 1 || loginType == 2 ? false : true, + firstNameN: _appState.getAuthenticatedUser()!.firstNameN, + lastNameN: _appState.getAuthenticatedUser()!.lastNameN, + ).toJson()); resultEither.fold((failure) async => await _errorHandlerService.handleError(failure: failure), (apiResponse) async { if (apiResponse.messageStatus == 1) { log("Insert IMEI Success"); @@ -831,20 +829,20 @@ class AuthenticationViewModel extends ChangeNotifier { Future insertPatientDeviceData(int loginType) async { final resultEither = await _authenticationRepo.insertPatientDeviceData( patientDeviceDataRequest: InsertPatientMobileDeviceInfo( - deviceToken: _appState.deviceToken, - deviceTypeId: _appState.getDeviceTypeID(), - patientId: _appState.getAuthenticatedUser()!.patientId!, - patientTypeId: _appState.getAuthenticatedUser()!.patientType, - patientOutSa: _appState.getAuthenticatedUser()!.outSa!, - loginType: loginType, - languageId: _appState.getLanguageID(), - latitude: _appState.userLat, - longitude: _appState.userLong, - voipToken: "", - deviceType: _appState.deviceTypeID, - patientMobileNumber: _appState.getAuthenticatedUser()!.mobileNumber, - nationalId: _appState.getAuthenticatedUser()!.patientIdentificationNo, - gender: _appState.getAuthenticatedUser()!.gender) + deviceToken: _appState.deviceToken, + deviceTypeId: _appState.getDeviceTypeID(), + patientId: _appState.getAuthenticatedUser()!.patientId!, + patientTypeId: _appState.getAuthenticatedUser()!.patientType, + patientOutSa: _appState.getAuthenticatedUser()!.outSa!, + loginType: loginType, + languageId: _appState.getLanguageID(), + latitude: _appState.userLat, + longitude: _appState.userLong, + voipToken: "", + deviceType: _appState.deviceTypeID, + patientMobileNumber: _appState.getAuthenticatedUser()!.mobileNumber, + nationalId: _appState.getAuthenticatedUser()!.patientIdentificationNo, + gender: _appState.getAuthenticatedUser()!.gender) .toJson()); resultEither.fold((failure) async => await _errorHandlerService.handleError(failure: failure), (apiResponse) async { if (apiResponse.messageStatus == 1) { @@ -858,18 +856,18 @@ class AuthenticationViewModel extends ChangeNotifier { Future getPatientDeviceData(int loginType) async { final resultEither = await _authenticationRepo.getPatientDeviceData( patientDeviceDataRequest: GetUserMobileDeviceData( - deviceToken: _appState.deviceToken, - deviceTypeId: _appState.getDeviceTypeID(), - patientId: _appState.getSelectDeviceByImeiRespModelElement!.patientId!, - patientType: _appState.getSelectDeviceByImeiRespModelElement!.patientType, - patientOutSa: _appState.getSelectDeviceByImeiRespModelElement!.outSa == true ? 1 : 0, - loginType: loginType, - languageId: _appState.getLanguageID(), - latitude: _appState.userLat, - longitude: _appState.userLong, - mobileNo: _appState.getSelectDeviceByImeiRespModelElement!.mobile!, - patientMobileNumber: int.parse(_appState.getSelectDeviceByImeiRespModelElement!.mobile!), - nationalId: _appState.getSelectDeviceByImeiRespModelElement!.identificationNo) + deviceToken: _appState.deviceToken, + deviceTypeId: _appState.getDeviceTypeID(), + patientId: _appState.getSelectDeviceByImeiRespModelElement!.patientId!, + patientType: _appState.getSelectDeviceByImeiRespModelElement!.patientType, + patientOutSa: _appState.getSelectDeviceByImeiRespModelElement!.outSa == true ? 1 : 0, + loginType: loginType, + languageId: _appState.getLanguageID(), + latitude: _appState.userLat, + longitude: _appState.userLong, + mobileNo: _appState.getSelectDeviceByImeiRespModelElement!.mobile!, + patientMobileNumber: int.parse(_appState.getSelectDeviceByImeiRespModelElement!.mobile!), + nationalId: _appState.getSelectDeviceByImeiRespModelElement!.identificationNo) .toJson()); resultEither.fold((failure) async => await _errorHandlerService.handleError(failure: failure), (apiResponse) async { if (apiResponse.messageStatus == 1) { @@ -885,11 +883,15 @@ class AuthenticationViewModel extends ChangeNotifier { message: apiResponse.errorMessage ?? "", label: LocaleKeys.notice.tr(), onOkPressed: () { - _dialogService.showPhoneNumberPickerSheet(label:"Where would you like to receive OTP?", message:"Please select from the below options to receive OTP.", onSMSPress: () { - checkUserAuthentication(otpTypeEnum: OTPTypeEnum.sms); - }, onWhatsappPress: () { - checkUserAuthentication(otpTypeEnum: OTPTypeEnum.whatsapp); - }); + _dialogService.showPhoneNumberPickerSheet( + label: "Where would you like to receive OTP?", + message: "Please select from the below options to receive OTP.", + onSMSPress: () { + checkUserAuthentication(otpTypeEnum: OTPTypeEnum.sms); + }, + onWhatsappPress: () { + checkUserAuthentication(otpTypeEnum: OTPTypeEnum.whatsapp); + }); }, onCancelPressed: () { _navigationService.pop(); @@ -908,21 +910,21 @@ class AuthenticationViewModel extends ChangeNotifier { Future getServicePrivilege() async { final resultEither = await _authenticationRepo.getServicePrivilege(); - List privilegeModelList = []; + List privilegeModelList = []; List vidaPlusProjectListModel = []; List hMCProjectListModel = []; List projectDetailListModel = []; resultEither.fold( - (failure) async => await _errorHandlerService.handleError(failure: failure), - (apiResponse) async { + (failure) async => await _errorHandlerService.handleError(failure: failure), + (apiResponse) async { if (apiResponse.messageStatus == 2) { await _dialogService.showErrorBottomSheet(message: apiResponse.errorMessage ?? "ErrorEmpty"); } else { apiResponse.data["ServicePrivilegeList"].forEach((v) { - privilegeModelList.add(PrivilegeModel.fromJson(v)); + privilegeModelList.add(ListPrivilege.fromJson(v)); }); - _appState.setPrivilegeModelList(privilegeModelList); + _appState.setPrivilegeModelList(privilegeModelList.cast()); apiResponse.data["ProjectListVidaPlus"].forEach((v) { vidaPlusProjectListModel.add(VidaPlusProjectListModel.fromJson(v)); diff --git a/lib/features/authentication/models/resp_models/check_activation_code_resp_model.dart b/lib/features/authentication/models/resp_models/check_activation_code_resp_model.dart index 2682f0a..67848c6 100644 --- a/lib/features/authentication/models/resp_models/check_activation_code_resp_model.dart +++ b/lib/features/authentication/models/resp_models/check_activation_code_resp_model.dart @@ -613,35 +613,3 @@ class ListElement { "status": listStatus, }; } - -class ListPrivilege { - int? id; - String? serviceName; - bool? previlege; - dynamic region; - - ListPrivilege({ - this.id, - this.serviceName, - this.previlege, - this.region, - }); - - factory ListPrivilege.fromRawJson(String str) => ListPrivilege.fromJson(json.decode(str)); - - String toRawJson() => json.encode(toJson()); - - factory ListPrivilege.fromJson(Map json) => ListPrivilege( - id: json["ID"], - serviceName: json["ServiceName"], - previlege: json["Previlege"], - region: json["Region"], - ); - - Map toJson() => { - "ID": id, - "ServiceName": serviceName, - "Previlege": previlege, - "Region": region, - }; -} diff --git a/lib/features/book_appointments/book_appointments_repo.dart b/lib/features/book_appointments/book_appointments_repo.dart index 7454b80..81faf91 100644 --- a/lib/features/book_appointments/book_appointments_repo.dart +++ b/lib/features/book_appointments/book_appointments_repo.dart @@ -42,11 +42,9 @@ abstract class BookAppointmentsRepo { Function(dynamic)? onSuccess, Function(String)? onError}); - Future>>> - getProjectList(); + Future>>> getProjectList(); Future>>> getClinicsWithRespectToClinicId(String projectID); - } class BookAppointmentsRepoImp implements BookAppointmentsRepo { @@ -371,8 +369,7 @@ class BookAppointmentsRepoImp implements BookAppointmentsRepo { } @override - Future>>> - getProjectList() async { + Future>>> getProjectList() async { Map request = {}; try { @@ -388,11 +385,7 @@ class BookAppointmentsRepoImp implements BookAppointmentsRepo { try { final list = response['ListProject']; - final appointmentsList = list - .map((item) => - HospitalsModel.fromJson(item as Map)) - .toList() - .cast(); + final appointmentsList = list.map((item) => HospitalsModel.fromJson(item as Map)).toList().cast(); apiResponse = GenericApiModel>( messageStatus: messageStatus, diff --git a/lib/features/habib_wallet/habib_wallet_repo.dart b/lib/features/habib_wallet/habib_wallet_repo.dart index 5f47f6c..659510d 100644 --- a/lib/features/habib_wallet/habib_wallet_repo.dart +++ b/lib/features/habib_wallet/habib_wallet_repo.dart @@ -3,10 +3,20 @@ 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/my_appointments/models/resp_models/hospital_model.dart'; import 'package:hmg_patient_app_new/services/logger_service.dart'; abstract class HabibWalletRepo { Future>> getPatientBalanceAmount(); + + Future>>> getProjectList(); + + Future>> HISCreateAdvancePayment( + {required String paymentMethodName, required num paidAmount, required String paymentReference, required String patientID, required int projectID, required String depositorName}); + + Future>> addAdvanceNumberRequest({required String advanceNumber, required String paymentReference}); + + Future>> getPatientInfoByPatientID({required String patientID}); } class HabibWalletRepoImp implements HabibWalletRepo { @@ -55,4 +65,165 @@ class HabibWalletRepoImp implements HabibWalletRepo { return Left(UnknownFailure(e.toString())); } } + + @override + Future>>> getProjectList() async { + Map request = {"IsOnlineCheckIn": true, "IsAdvancePayment": true}; + + try { + GenericApiModel>? 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)).toList().cast(); + + apiResponse = GenericApiModel>( + 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())); + } + } + + @override + Future> HISCreateAdvancePayment( + {required String paymentMethodName, required num paidAmount, required String paymentReference, required String patientID, required int projectID, required String depositorName}) async { + Map request = { + "CustName": depositorName, + "CustID": patientID, + "SetupID": "010266", + "ProjectID": projectID, + "PatientID": patientID, + "AccountID": patientID, + "PaymentAmount": paidAmount, + "NationalityID": null, + "DepositorName": depositorName, + "CreatedBy": 3, + "PaymentMethodName": paymentMethodName, + "PaymentReference": paymentReference, + "PaymentMethod": paymentMethodName, + "IsAncillaryOrder": false + }; + + try { + GenericApiModel? apiResponse; + Failure? failure; + await apiClient.post( + HIS_CREATE_ADVANCE_PAYMENT, + body: request, + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + }, + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { + try { + apiResponse = GenericApiModel( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: errorMessage, + data: response, + ); + } 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> addAdvanceNumberRequest({required String advanceNumber, required String paymentReference}) async { + Map requestBody = { + "AdvanceNumber": advanceNumber, + "AdvanceNumber_VP": advanceNumber, + "PaymentReferenceNumber": paymentReference, + "AppointmentID": 0, + }; + + try { + GenericApiModel? apiResponse; + Failure? failure; + await apiClient.post( + ADD_ADVANCE_NUMBER_REQUEST, + body: requestBody, + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + }, + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { + try { + apiResponse = GenericApiModel( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: null, + data: response, + ); + } 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> getPatientInfoByPatientID({required String patientID}) async { + Map requestBody = {"SearchPatientID": patientID}; + + try { + GenericApiModel? apiResponse; + Failure? failure; + await apiClient.post( + GET_PATIENT_INFO_BY_ID, + body: requestBody, + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + }, + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { + try { + apiResponse = GenericApiModel( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: null, + data: response, + ); + } 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())); + } + } } diff --git a/lib/features/habib_wallet/habib_wallet_view_model.dart b/lib/features/habib_wallet/habib_wallet_view_model.dart index 8e4fc26..c620b08 100644 --- a/lib/features/habib_wallet/habib_wallet_view_model.dart +++ b/lib/features/habib_wallet/habib_wallet_view_model.dart @@ -1,23 +1,66 @@ import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_repo.dart'; +import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart'; import 'package:hmg_patient_app_new/services/error_handler_service.dart'; class HabibWalletViewModel extends ChangeNotifier { bool isWalletAmountLoading = false; num habibWalletAmount = 0; + num walletRechargeAmount = 0; + + int currentIndex = 0; + + List advancePaymentHospitals = []; + + HospitalsModel? selectedHospital; HabibWalletRepo habibWalletRepo; ErrorHandlerService errorHandlerService; + String fileNumber = ''; + String depositorName = ''; + String mobileNumber = ''; + HabibWalletViewModel({required this.habibWalletRepo, required this.errorHandlerService}); initHabibWalletProvider() { isWalletAmountLoading = true; habibWalletAmount = 0; + walletRechargeAmount = 0; + advancePaymentHospitals.clear(); + selectedHospital = null; + fileNumber = ''; + depositorName = ''; + mobileNumber = ''; + notifyListeners(); + } + + setSelectedHospital(HospitalsModel hospital) { + selectedHospital = hospital; + notifyListeners(); + } + + setWalletRechargeAmount(num amount) { + walletRechargeAmount = amount; + notifyListeners(); + } + + setDepositorDetails(String fileNum, String depositor, String mobile) { + fileNumber = fileNum; + depositorName = depositor; + mobileNumber = mobile; + notifyListeners(); + } + + setCurrentIndex(int index) { + currentIndex = index; notifyListeners(); } Future getPatientBalanceAmount({Function(dynamic)? onSuccess, Function(String)? onError}) async { + isWalletAmountLoading = true; + notifyListeners(); + final result = await habibWalletRepo.getPatientBalanceAmount(); result.fold( @@ -36,4 +79,85 @@ class HabibWalletViewModel extends ChangeNotifier { }, ); } + + Future getProjectsList() async { + advancePaymentHospitals.clear(); + notifyListeners(); + final result = await habibWalletRepo.getProjectList(); + + result.fold( + (failure) async => await errorHandlerService.handleError(failure: failure), + (apiResponse) async { + if (apiResponse.messageStatus == 2) { + // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); + } else if (apiResponse.messageStatus == 1) { + advancePaymentHospitals = apiResponse.data!; + notifyListeners(); + } + }, + ); + } + + Future HISCreateAdvancePayment( + {required String paymentMethodName, + required num paidAmount, + required String paymentReference, + required String patientID, + required int projectID, + required String depositorName, + Function(dynamic)? onSuccess, + Function(String)? onError}) async { + final result = await habibWalletRepo.HISCreateAdvancePayment( + paymentMethodName: paymentMethodName, paidAmount: paidAmount, paymentReference: paymentReference, patientID: patientID, projectID: projectID, depositorName: depositorName); + + result.fold( + (failure) async => await errorHandlerService.handleError(failure: failure), + (apiResponse) { + if (apiResponse.messageStatus == 2) { + // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); + } else if (apiResponse.messageStatus == 1) { + notifyListeners(); + if (onSuccess != null) { + onSuccess(apiResponse); + } + } + }, + ); + } + + Future addAdvanceNumberRequest({required String advanceNumber, required String paymentReference, Function(dynamic)? onSuccess, Function(String)? onError}) async { + final result = await habibWalletRepo.addAdvanceNumberRequest(advanceNumber: advanceNumber, paymentReference: paymentReference); + + result.fold( + (failure) async => await errorHandlerService.handleError(failure: failure), + (apiResponse) { + if (apiResponse.messageStatus == 2) { + // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); + } else if (apiResponse.messageStatus == 1) { + notifyListeners(); + if (onSuccess != null) { + onSuccess(apiResponse); + } + } + }, + ); + } + + Future getPatientInfoByPatientID({required String patientID, Function(dynamic)? onSuccess, Function(String)? onError}) async { + final result = await habibWalletRepo.getPatientInfoByPatientID(patientID: patientID); + + result.fold( + (failure) async => await errorHandlerService.handleError(failure: failure), + (apiResponse) { + if (apiResponse.messageStatus == 2) { + // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); + } else if (apiResponse.messageStatus == 1) { + notifyListeners(); + if (onSuccess != null) { + onSuccess(apiResponse); + } + } + }, + ); + } } diff --git a/lib/features/payfort/payfort_view_model.dart b/lib/features/payfort/payfort_view_model.dart index d99de80..6b67ce9 100644 --- a/lib/features/payfort/payfort_view_model.dart +++ b/lib/features/payfort/payfort_view_model.dart @@ -7,6 +7,7 @@ import 'package:hmg_patient_app_new/features/payfort/models/payfort_project_deta import 'package:hmg_patient_app_new/features/payfort/models/sdk_token_response_model.dart'; import 'package:hmg_patient_app_new/features/payfort/payfort_repo.dart'; import 'package:hmg_patient_app_new/services/error_handler_service.dart'; +import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart'; import 'package:network_info_plus/network_info_plus.dart'; class PayfortViewModel extends ChangeNotifier { @@ -183,6 +184,7 @@ class PayfortViewModel extends ChangeNotifier { isApplePayConfigurationLoading = false; notifyListeners(); + LoaderBottomSheet.hideLoader(); _payfort.callPayFortForApplePay( request: request, diff --git a/lib/presentation/appointments/appointment_payment_page.dart b/lib/presentation/appointments/appointment_payment_page.dart index 4d5fd8f..e68e000 100644 --- a/lib/presentation/appointments/appointment_payment_page.dart +++ b/lib/presentation/appointments/appointment_payment_page.dart @@ -273,7 +273,6 @@ class _AppointmentPaymentPageState extends State { isSaudiCurrency: true), ], ).paddingSymmetrical(24.h, 0.h), - //TODO: Add Apple Pay Privileges Platform.isIOS ? Utils.buildSvgWithAssets( icon: AppAssets.apple_pay_button, @@ -282,7 +281,11 @@ class _AppointmentPaymentPageState extends State { fit: BoxFit.contain, ).paddingSymmetrical(24.h, 0.h).onPress(() { // payfortVM.setIsApplePayConfigurationLoading(true); - startApplePay(); + if (Utils.havePrivilege(103)) { + startApplePay(); + } else { + openPaymentURL(selectedPaymentMethod); + } }) : SizedBox(height: 12.h), SizedBox(height: 12.h), @@ -363,8 +366,8 @@ class _AppointmentPaymentPageState extends State { appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo.toString(), payedAmount: payfortViewModel.payfortCheckPaymentStatusResponseModel!.amount!, paymentReference: payfortViewModel.payfortCheckPaymentStatusResponseModel!.fortId!, - patientID: "4767477", - patientType: 1, + patientID: appState.getAuthenticatedUser()!.patientId.toString(), + patientType: appState.getAuthenticatedUser()!.patientType!, onSuccess: (value) async { print(value); await myAppointmentsViewModel.addAdvanceNumberRequest( diff --git a/lib/presentation/appointments/widgets/hospital_bottom_sheet/hospital_list_items.dart b/lib/presentation/appointments/widgets/hospital_bottom_sheet/hospital_list_items.dart index 41fb924..81cc318 100644 --- a/lib/presentation/appointments/widgets/hospital_bottom_sheet/hospital_list_items.dart +++ b/lib/presentation/appointments/widgets/hospital_bottom_sheet/hospital_list_items.dart @@ -17,8 +17,7 @@ class HospitalListItem extends StatelessWidget { late AppState appState; - HospitalListItem( - {super.key, required this.hospitalData, required this.isLocationEnabled}); + HospitalListItem({super.key, required this.hospitalData, required this.isLocationEnabled}); @override Widget build(BuildContext context) { @@ -70,24 +69,17 @@ class HospitalListItem extends StatelessWidget { ); Widget get distanceInfo => Row( - children: [ Visibility( - visible: (hospitalData?.distanceInKMs != "0"), - child: - - - AppCustomChipWidget( - labelText: - "${hospitalData?.distanceInKMs ?? ""} km".needTranslation, - deleteIcon: AppAssets.location_red, - deleteIconSize: Size(9, 12), - backgroundColor: AppColors.secondaryLightRedColor, - textColor: AppColors.errorColor, - ), - - - ), + visible: (hospitalData?.distanceInKMs != "0"), + child: AppCustomChipWidget( + labelText: "${hospitalData?.distanceInKMs ?? ""} km".needTranslation, + deleteIcon: AppAssets.location_red, + deleteIconSize: Size(9, 12), + backgroundColor: AppColors.secondaryLightRedColor, + textColor: AppColors.errorColor, + ), + ), Visibility( visible: (hospitalData?.distanceInKMs == "0"), child: Row( @@ -96,8 +88,9 @@ class HospitalListItem extends StatelessWidget { labelText: "Distance not available".needTranslation, textColor: AppColors.blackColor, ), - SizedBox(width: 8.h,) - + SizedBox( + width: 8.h, + ) ], )), Visibility( diff --git a/lib/presentation/habib_wallet/habib_wallet_page.dart b/lib/presentation/habib_wallet/habib_wallet_page.dart index 6add7bd..e1d1ba2 100644 --- a/lib/presentation/habib_wallet/habib_wallet_page.dart +++ b/lib/presentation/habib_wallet/habib_wallet_page.dart @@ -14,7 +14,6 @@ import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.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/routes/custom_page_route.dart'; -import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart'; import 'package:provider/provider.dart'; class HabibWalletPage extends StatefulWidget { @@ -25,8 +24,11 @@ class HabibWalletPage extends StatefulWidget { } class _HabibWalletState extends State { + late HabibWalletViewModel habibWalletVM; + @override Widget build(BuildContext context) { + habibWalletVM = Provider.of(context, listen: false); AppState _appState = getIt.get(); return Scaffold( backgroundColor: AppColors.bgScaffoldColor, @@ -66,10 +68,10 @@ class _HabibWalletState extends State { ), Spacer(), LocaleKeys.balanceAmount.tr(context: context).toText14(weight: FontWeight.w500, color: AppColors.whiteColor), + SizedBox(height: 4.h), Consumer(builder: (context, habibWalletVM, child) { - return Utils.getPaymentAmountWithSymbol(habibWalletVM.habibWalletAmount.toString().toText32(isBold: true, color: AppColors.whiteColor), AppColors.whiteColor, 13.h, - isExpanded: false) - .toShimmer2(isShow: habibWalletVM.isWalletAmountLoading, radius: 12.h, width: 80.h, height: 40.h); + return Utils.getPaymentAmountWithSymbol2(habibWalletVM.habibWalletAmount, textColor: AppColors.whiteColor, iconColor: AppColors.whiteColor, iconSize: 13, isExpanded: false) + .toShimmer2(isShow: habibWalletVM.isWalletAmountLoading, radius: 12.h, width: 80.h, height: 24.h); }), ], ), @@ -84,11 +86,15 @@ class _HabibWalletState extends State { iconSize: 21.h, text: "Recharge".needTranslation, onPressed: () { - Navigator.of(context).push( + Navigator.of(context) + .push( CustomPageRoute( page: RechargeWalletPage(), ), - ); + ) + .then((val) { + habibWalletVM.getPatientBalanceAmount(); + }); }, backgroundColor: AppColors.infoColor, borderColor: AppColors.infoColor, diff --git a/lib/presentation/habib_wallet/recharge_wallet_page.dart b/lib/presentation/habib_wallet/recharge_wallet_page.dart index 8b35f8b..098610b 100644 --- a/lib/presentation/habib_wallet/recharge_wallet_page.dart +++ b/lib/presentation/habib_wallet/recharge_wallet_page.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; @@ -7,12 +9,17 @@ 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/habib_wallet/habib_wallet_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/presentation/habib_wallet/wallet_payment_confirm_page.dart'; +import 'package:hmg_patient_app_new/presentation/habib_wallet/widgets/select_hospital_bottom_sheet.dart'; import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.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/common_bottom_sheet.dart'; import 'package:hmg_patient_app_new/widgets/input_widget.dart'; +import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; +import 'package:provider/provider.dart'; import 'widgets/select-medical_file.dart'; @@ -26,8 +33,20 @@ class RechargeWalletPage extends StatefulWidget { class _RechargeWalletPageState extends State { FocusNode textFocusNode = FocusNode(); + late HabibWalletViewModel habibWalletVM; + final TextEditingController amountTextController = TextEditingController(); + + @override + void initState() { + scheduleMicrotask(() { + habibWalletVM.getProjectsList(); + }); + super.initState(); + } + @override Widget build(BuildContext context) { + habibWalletVM = Provider.of(context, listen: false); AppState appState = getIt.get(); return Scaffold( backgroundColor: AppColors.bgScaffoldColor, @@ -35,171 +54,197 @@ class _RechargeWalletPageState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( - child: CollapsingListView( - title: LocaleKeys.createAdvancedPayment.tr(context: context), - child: SingleChildScrollView( - child: Padding( - padding: EdgeInsets.all(24.h), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - height: 135.h, - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - borderRadius: 24.h, - hasShadow: false, - side: BorderSide(color: AppColors.textColor, width: 2.h), - ), - child: Padding( - padding: EdgeInsets.all(16.h), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - "Enter an amount".needTranslation.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), - Spacer(), - Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Utils.getPaymentAmountWithSymbol( - SizedBox( - width: 150.h, - child: TextInputWidget( - labelText: "", - hintText: "", - isEnable: true, - prefix: null, - isAllowRadius: true, - isBorderAllowed: false, - isAllowLeadingIcon: true, - autoFocus: true, - fontSize: 40, - padding: EdgeInsets.symmetric(horizontal: 8.h, vertical: 0.h), - focusNode: textFocusNode, - isWalletAmountInput: true, - // leadingIcon: AppAssets.student_card, + child: CollapsingListView( + title: LocaleKeys.createAdvancedPayment.tr(context: context), + child: SingleChildScrollView( + child: Padding( + padding: EdgeInsets.all(24.h), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + height: 135.h, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24.h, + hasShadow: false, + side: BorderSide(color: AppColors.textColor, width: 2.h), + ), + child: Padding( + padding: EdgeInsets.all(16.h), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + //TODO: Check with hussain to show AED or SAR + "Enter an amount".needTranslation.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), + Spacer(), + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Utils.getPaymentAmountWithSymbol( + SizedBox( + width: 150.h, + child: TextInputWidget( + controller: amountTextController, + labelText: "", + hintText: "", + isEnable: true, + prefix: null, + isAllowRadius: true, + isBorderAllowed: false, + isAllowLeadingIcon: true, + autoFocus: true, + fontSize: 40, + padding: EdgeInsets.symmetric(horizontal: 8.h, vertical: 0.h), + focusNode: textFocusNode, + isWalletAmountInput: true, + keyboardType: TextInputType.numberWithOptions(signed: false, decimal: true), + // leadingIcon: AppAssets.student_card, + ), ), - ), - AppColors.textColor, - 13.h, - isExpanded: false), - const Spacer(), - "SAR".needTranslation.toText20(color: AppColors.greyTextColor, weight: FontWeight.w500), - ], - ), - ], + AppColors.textColor, + 13.h, + isExpanded: false), + const Spacer(), + "SAR".needTranslation.toText20(color: AppColors.greyTextColor, weight: FontWeight.w500), + ], + ), + ], + ), ), ), - ), - SizedBox(height: 24.h), - Container( - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - borderRadius: 24.h, - hasShadow: false, - ), - child: Padding( - padding: EdgeInsets.all(16.h), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + SizedBox(height: 24.h), + Consumer(builder: (context, habibWalletVM, child) { + return Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24.h, + hasShadow: false, + ), + child: Padding( + padding: EdgeInsets.all(16.h), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Utils.buildSvgWithAssets(icon: AppAssets.my_account_icon, width: 40.h, height: 40.h), - SizedBox(width: 8.h), - Column( - crossAxisAlignment: CrossAxisAlignment.start, + Row( children: [ - LocaleKeys.myAccount.tr(context: context).toText16(color: AppColors.textColor, weight: FontWeight.w500), - "${LocaleKeys.medicalFile.tr(context: context)}: ${appState.getAuthenticatedUser()!.patientId}" - .toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), + Utils.buildSvgWithAssets(icon: AppAssets.my_account_icon, width: 40.h, height: 40.h), + SizedBox(width: 8.h), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.myAccount.tr(context: context).toText16(color: AppColors.textColor, weight: FontWeight.w500), + "${LocaleKeys.medicalFile.tr(context: context)}: ${appState.getAuthenticatedUser()!.patientId}" + .toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), + ], + ), ], ), + Utils.buildSvgWithAssets(icon: AppAssets.arrow_down, width: 25.h, height: 25.h), ], - ), - Utils.buildSvgWithAssets(icon: AppAssets.arrow_down, width: 25.h, height: 25.h), - ], - ).onPress(() async { - // showCommonBottomSheetWithoutHeight(context, title: "Select Medical File".needTranslation, child: SelectMedicalFile(), callBackFunc: () {}, isFullScreen: false); - showCommonBottomSheetWithoutHeight(context, title: "Select Medical File".needTranslation, child: const MultiPageBottomSheet(), callBackFunc: () {}, isFullScreen: false); - }), - SizedBox(height: 16.h), - Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h), - SizedBox(height: 16.h), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ + ).onPress(() async { + habibWalletVM.setCurrentIndex(0); + showCommonBottomSheetWithoutHeight(context, title: "Select Medical File".needTranslation, + titleWidget: Consumer(builder: (context, habibWalletVM, child) { + return habibWalletVM.currentIndex != 0 + ? IconButton( + icon: Utils.buildSvgWithAssets(icon: AppAssets.arrow_back, width: 24.h, height: 24.h), + padding: EdgeInsets.zero, + onPressed: () => habibWalletVM.setCurrentIndex(0), + highlightColor: Colors.transparent, + ) + : "Select Medical File".needTranslation.toText20(weight: FontWeight.w600); + }), child: Consumer(builder: (context, habibWalletVM, child) { + return MultiPageBottomSheet(); + }), callBackFunc: () {}, isFullScreen: false, isCloseButtonVisible: true); + }), + SizedBox(height: 16.h), + Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h), + SizedBox(height: 16.h), Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Utils.buildSvgWithAssets(icon: AppAssets.select_hospital_icon, width: 40.h, height: 40.h), - SizedBox(width: 8.h), - Column( - crossAxisAlignment: CrossAxisAlignment.start, + Row( children: [ - LocaleKeys.hospital.tr(context: context).toText16(color: AppColors.textColor, weight: FontWeight.w500), - "Olaya".toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), + Utils.buildSvgWithAssets(icon: AppAssets.select_hospital_icon, width: 40.h, height: 40.h), + SizedBox(width: 8.h), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.hospital.tr(context: context).toText16(color: AppColors.textColor, weight: FontWeight.w500), + SizedBox( + width: MediaQuery.of(context).size.width * 0.55, + child: (habibWalletVM.selectedHospital != null ? habibWalletVM.selectedHospital!.name : LocaleKeys.selectHospital.tr(context: context))! + .toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), + ), + ], + ), ], - ), + ).onPress(() { + showCommonBottomSheetWithoutHeight(context, + title: LocaleKeys.selectHospital.tr(context: context), isDismissible: false, child: SelectHospitalBottomSheet(), callBackFunc: () {}); + }), + Utils.buildSvgWithAssets(icon: AppAssets.arrow_down, width: 25.h, height: 25.h), ], ), - Utils.buildSvgWithAssets(icon: AppAssets.arrow_down, width: 25.h, height: 25.h), - ], - ), - SizedBox(height: 16.h), - Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h), - SizedBox(height: 16.h), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ + SizedBox(height: 16.h), + Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h), + SizedBox(height: 16.h), Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Utils.buildSvgWithAssets(icon: AppAssets.email_icon, width: 40.h, height: 40.h), - SizedBox(width: 8.h), - Column( - crossAxisAlignment: CrossAxisAlignment.start, + Row( children: [ - LocaleKeys.email.tr(context: context).toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500), - "${appState.getAuthenticatedUser()!.emailAddress}".toText16(color: AppColors.textColor, weight: FontWeight.w500), + Utils.buildSvgWithAssets(icon: AppAssets.email_icon, width: 40.h, height: 40.h), + SizedBox(width: 8.h), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.email.tr(context: context).toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500), + "${appState.getAuthenticatedUser()!.emailAddress}".toText16(color: AppColors.textColor, weight: FontWeight.w500), + ], + ), ], ), ], ), - ], - ), - SizedBox(height: 16.h), - Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h), - SizedBox(height: 16.h), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ + SizedBox(height: 16.h), + Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h), + SizedBox(height: 16.h), Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Utils.buildSvgWithAssets(icon: AppAssets.notes_icon, width: 40.h, height: 40.h), - SizedBox(width: 8.h), - Column( - crossAxisAlignment: CrossAxisAlignment.start, + Row( children: [ - LocaleKeys.notes.tr(context: context).toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500), - "Lorem Ipsum".toText16(color: AppColors.textColor, weight: FontWeight.w500), + Utils.buildSvgWithAssets(icon: AppAssets.notes_icon, width: 40.h, height: 40.h), + SizedBox(width: 8.h), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.notes.tr(context: context).toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500), + "Lorem Ipsum".toText16(color: AppColors.textColor, weight: FontWeight.w500), + ], + ), ], ), ], ), + SizedBox(height: 8.h), ], ), - SizedBox(height: 8.h), - ], - ), - ), - ), - ], + ), + ); + }), + ], + ), ), ), ), - )), + ), + //TODO: Handle Family member selection & Other Account Selection Container( decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.whiteColor, @@ -208,7 +253,38 @@ class _RechargeWalletPageState extends State { ), child: CustomButton( text: LocaleKeys.next.tr(context: context), - onPressed: () {}, + onPressed: () { + if (amountTextController.text.isEmpty) { + showCommonBottomSheetWithoutHeight( + context, + child: Utils.getErrorWidget(loadingText: "Please enter amount to continue.".needTranslation), + callBackFunc: () { + textFocusNode.requestFocus(); + }, + isFullScreen: false, + isCloseButtonVisible: true, + ); + } else if (habibWalletVM.selectedHospital == null) { + showCommonBottomSheetWithoutHeight( + context, + child: Utils.getErrorWidget(loadingText: "Please select hospital to continue.".needTranslation), + callBackFunc: () { + textFocusNode.requestFocus(); + }, + isFullScreen: false, + isCloseButtonVisible: true, + ); + } else { + habibWalletVM.setWalletRechargeAmount(num.parse(amountTextController.text)); + habibWalletVM.setDepositorDetails(appState.getAuthenticatedUser()!.patientId.toString(), "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}", + appState.getAuthenticatedUser()!.mobileNumber!); + Navigator.of(context).push( + CustomPageRoute( + page: WalletPaymentConfirmPage(), + ), + ); + } + }, backgroundColor: AppColors.primaryRedColor, borderColor: AppColors.primaryRedColor, textColor: AppColors.whiteColor, diff --git a/lib/presentation/habib_wallet/wallet_payment_confirm_page.dart b/lib/presentation/habib_wallet/wallet_payment_confirm_page.dart new file mode 100644 index 0000000..c22a939 --- /dev/null +++ b/lib/presentation/habib_wallet/wallet_payment_confirm_page.dart @@ -0,0 +1,385 @@ +import 'dart:async'; +import 'dart:developer'; +import 'dart:io'; + +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/app_assets.dart'; +import 'package:hmg_patient_app_new/core/app_state.dart'; +import 'package:hmg_patient_app_new/core/cache_consts.dart'; +import 'package:hmg_patient_app_new/core/dependencies.dart'; +import 'package:hmg_patient_app_new/core/enums.dart'; +import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; +import 'package:hmg_patient_app_new/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/habib_wallet/habib_wallet_view_model.dart'; +import 'package:hmg_patient_app_new/features/payfort/models/apple_pay_request_insert_model.dart'; +import 'package:hmg_patient_app_new/features/payfort/payfort_view_model.dart'; +import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; +import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; +import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart'; +import 'package:hmg_patient_app_new/widgets/in_app_browser/InAppBrowser.dart'; +import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart'; +import 'package:provider/provider.dart'; + +class WalletPaymentConfirmPage extends StatefulWidget { + const WalletPaymentConfirmPage({super.key}); + + @override + State createState() => _WalletPaymentConfirmPageState(); +} + +class _WalletPaymentConfirmPageState extends State { + late PayfortViewModel payfortViewModel; + late AppState appState; + late HabibWalletViewModel habibWalletVM; + + MyInAppBrowser? browser; + String selectedPaymentMethod = ""; + + String transID = ""; + + @override + void initState() { + scheduleMicrotask(() { + payfortViewModel.initPayfortViewModel(); + }); + super.initState(); + } + + @override + Widget build(BuildContext context) { + appState = getIt.get(); + habibWalletVM = Provider.of(context, listen: false); + payfortViewModel = Provider.of(context, listen: false); + return Scaffold( + backgroundColor: AppColors.bgScaffoldColor, + body: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: CollapsingListView( + title: "Select Payment Method", + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: 24.h), + Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 20.h, + hasShadow: false, + ), + child: Row( + mainAxisSize: MainAxisSize.max, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Image.asset(AppAssets.mada, width: 72.h, height: 25.h).toShimmer2(isShow: false), + SizedBox(height: 16.h), + "Mada".needTranslation.toText16(isBold: true).toShimmer2(isShow: false), + ], + ), + SizedBox(width: 8.h), + const Spacer(), + Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon, + iconColor: AppColors.blackColor, + width: 18.h, + height: 13.h, + fit: BoxFit.contain, + ).toShimmer2(isShow: false), + ], + ).paddingSymmetrical(16.h, 16.h), + ).paddingSymmetrical(24.h, 0.h).onPress(() { + selectedPaymentMethod = "MADA"; + // openPaymentURL("mada"); + }), + SizedBox(height: 16.h), + Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 20.h, + hasShadow: false, + ), + child: Row( + mainAxisSize: MainAxisSize.max, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Image.asset(AppAssets.visa, width: 40.h, height: 40.h), + SizedBox(width: 8.h), + Image.asset(AppAssets.Mastercard, width: 40.h, height: 40.h), + ], + ).toShimmer2(isShow: false), + SizedBox(height: 16.h), + "Visa or Mastercard".needTranslation.toText16(isBold: true).toShimmer2(isShow: false), + ], + ), + SizedBox(width: 8.h), + const Spacer(), + Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon, + iconColor: AppColors.blackColor, + width: 18.h, + height: 13.h, + fit: BoxFit.contain, + ).toShimmer2(isShow: false), + ], + ).paddingSymmetrical(16.h, 16.h), + ).paddingSymmetrical(24.h, 0.h).onPress(() { + selectedPaymentMethod = "VISA"; + // openPaymentURL("visa"); + }), + ], + ), + ), + ), + ), + Container( + // height: 200.h, + width: MediaQuery.of(context).size.width, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 24.h, + hasShadow: true, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: 24.h), + habibWalletVM.depositorName.toText18(isBold: true).paddingSymmetrical(24.h, 0.h), + SizedBox(height: 12.h), + Wrap( + direction: Axis.horizontal, + spacing: 4.h, + runSpacing: 4.h, + children: [ + AppCustomChipWidget(labelText: "${LocaleKeys.fileno.tr(context: context)}.: ${habibWalletVM.fileNumber}"), + AppCustomChipWidget(labelText: "${LocaleKeys.mobileNumber.tr(context: context)}: ${habibWalletVM.mobileNumber}"), + AppCustomChipWidget(labelText: "${habibWalletVM.selectedHospital!.name}"), + ], + ).paddingSymmetrical(24.h, 0.h), + SizedBox(height: 16.h), + Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h).paddingSymmetrical(24.h, 0.h), + SizedBox(height: 16.h), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + "Total amount to pay".needTranslation.toText16(isBold: true), + Utils.getPaymentAmountWithSymbol(habibWalletVM.walletRechargeAmount.toString().toText24(isBold: true), AppColors.blackColor, 15.h, isSaudiCurrency: true), + ], + ).paddingSymmetrical(24.h, 0.h), + SizedBox(height: 12.h), + Platform.isIOS + ? Utils.buildSvgWithAssets( + icon: AppAssets.apple_pay_button, + width: 200.h, + height: 56.h, + fit: BoxFit.contain, + ).paddingSymmetrical(24.h, 0.h).onPress(() { + if (Utils.havePrivilege(103)) { + startApplePay(); + } else {} + }) + : SizedBox(height: 12.h), + SizedBox(height: 32.h), + ], + ), + ), + ], + ), + ); + } + + startApplePay() async { + LoaderBottomSheet.showLoader(); + ApplePayInsertRequest applePayInsertRequest = ApplePayInsertRequest(); + + transID = Utils.getAdvancePaymentTransID(habibWalletVM.selectedHospital!.iD!, int.parse(habibWalletVM.fileNumber)); + + await payfortViewModel.getPayfortConfigurations(serviceId: ServiceTypeEnum.advancePayment.getIdFromServiceEnum(), projectId: habibWalletVM.selectedHospital!.iD!, integrationId: 2); + + applePayInsertRequest.clientRequestID = transID; + applePayInsertRequest.clinicID = 0; + + applePayInsertRequest.currency = appState.getAuthenticatedUser()!.outSa! == 0 ? "SAR" : "AED"; + applePayInsertRequest.customerEmail = "CustID_${appState.getAuthenticatedUser()!.patientId.toString()}@HMG.com"; + applePayInsertRequest.customerID = appState.getAuthenticatedUser()!.patientId.toString(); + applePayInsertRequest.customerName = "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}"; + + applePayInsertRequest.deviceToken = await Utils.getStringFromPrefs(CacheConst.pushToken); + applePayInsertRequest.voipToken = await Utils.getStringFromPrefs(CacheConst.voipToken); + applePayInsertRequest.doctorID = 0; + applePayInsertRequest.projectID = habibWalletVM.selectedHospital!.iD!.toString(); + applePayInsertRequest.serviceID = ServiceTypeEnum.appointmentPayment.getIdFromServiceEnum().toString(); + applePayInsertRequest.channelID = 3; + applePayInsertRequest.patientID = appState.getAuthenticatedUser()!.patientId.toString(); + applePayInsertRequest.patientTypeID = appState.getAuthenticatedUser()!.patientType; + applePayInsertRequest.patientOutSA = appState.getAuthenticatedUser()!.outSa; + applePayInsertRequest.appointmentDate = null; + applePayInsertRequest.appointmentNo = 0; + applePayInsertRequest.orderDescription = "Advance Payment"; + applePayInsertRequest.liveServiceID = "0"; + applePayInsertRequest.latitude = "0.0"; + applePayInsertRequest.longitude = "0.0"; + applePayInsertRequest.amount = habibWalletVM.walletRechargeAmount.toString(); + applePayInsertRequest.isSchedule = "0"; + applePayInsertRequest.language = appState.isArabic() ? 'ar' : 'en'; + applePayInsertRequest.languageID = appState.isArabic() ? 1 : 2; + applePayInsertRequest.userName = appState.getAuthenticatedUser()!.patientId; + applePayInsertRequest.responseContinueURL = "http://hmg.com/Documents/success.html"; + applePayInsertRequest.backClickUrl = "http://hmg.com/Documents/success.html"; + applePayInsertRequest.paymentOption = "ApplePay"; + + applePayInsertRequest.isMobSDK = true; + applePayInsertRequest.merchantReference = transID; + applePayInsertRequest.merchantIdentifier = payfortViewModel.payfortProjectDetailsRespModel!.merchantIdentifier; + applePayInsertRequest.commandType = "PURCHASE"; + applePayInsertRequest.signature = payfortViewModel.payfortProjectDetailsRespModel!.signature; + applePayInsertRequest.accessCode = payfortViewModel.payfortProjectDetailsRespModel!.accessCode; + applePayInsertRequest.shaRequestPhrase = payfortViewModel.payfortProjectDetailsRespModel!.shaRequest; + applePayInsertRequest.shaResponsePhrase = payfortViewModel.payfortProjectDetailsRespModel!.shaResponse; + applePayInsertRequest.returnURL = ""; + + //TODO: Need to pass dynamic params to the Apple Pay instead of static values + await payfortViewModel.applePayRequestInsert(applePayInsertRequest: applePayInsertRequest).then((value) { + payfortViewModel.paymentWithApplePay( + customerName: "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}", + // customerEmail: projectViewModel.authenticatedUserObject.user.emailAddress, + customerEmail: "CustID_${appState.getAuthenticatedUser()!.patientId.toString()}@HMG.com", + orderDescription: "Appointment Payment", + orderAmount: double.parse(habibWalletVM.walletRechargeAmount.toString()), + merchantReference: transID, + merchantIdentifier: payfortViewModel.payfortProjectDetailsRespModel!.merchantIdentifier, + applePayAccessCode: payfortViewModel.payfortProjectDetailsRespModel!.accessCode, + applePayShaRequestPhrase: payfortViewModel.payfortProjectDetailsRespModel!.shaRequest, + currency: appState.getAuthenticatedUser()!.outSa! == 0 ? "SAR" : "AED", + onFailed: (failureResult) async { + log("failureResult: ${failureResult.message.toString()}"); + showCommonBottomSheetWithoutHeight( + context, + child: Utils.getErrorWidget(loadingText: failureResult.message.toString()), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + }, + onSucceeded: (successResult) async { + log("successResult: ${successResult.responseMessage.toString()}"); + selectedPaymentMethod = successResult.paymentOption ?? "VISA"; + checkPaymentStatus(); + }, + ); + }); + } + + void checkPaymentStatus() async { + LoaderBottomSheet.showLoader(); + await payfortViewModel.checkPaymentStatus( + transactionID: transID, + onSuccess: (apiResponse) async { + print(apiResponse.data); + if (payfortViewModel.payfortCheckPaymentStatusResponseModel!.responseMessage!.toLowerCase() == "success") { + await habibWalletVM.HISCreateAdvancePayment( + paymentMethodName: selectedPaymentMethod, + paidAmount: habibWalletVM.walletRechargeAmount, + paymentReference: payfortViewModel.payfortCheckPaymentStatusResponseModel!.fortId!, + patientID: habibWalletVM.fileNumber, + projectID: habibWalletVM.selectedHospital!.iD!, + depositorName: habibWalletVM.depositorName, + onSuccess: (value) async { + await habibWalletVM.addAdvanceNumberRequest( + advanceNumber: Utils.isVidaPlusProject(habibWalletVM.selectedHospital!.iD) + ? value.data['OnlineCheckInAppointments'][0]['AdvanceNumber_VP'].toString() + : value.data['OnlineCheckInAppointments'][0]['AdvanceNumber'].toString(), + paymentReference: payfortViewModel.payfortCheckPaymentStatusResponseModel!.fortId!, + onSuccess: (value) { + LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight( + context, + child: Utils.getSuccessWidget(loadingText: "Payment Successful!".needTranslation), + callBackFunc: () { + Navigator.of(context).pop(); + Navigator.of(context).pop(); + }, + isFullScreen: false, + isCloseButtonVisible: true, + ); + }, + onError: (err) { + LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight( + context, + child: Utils.getErrorWidget(loadingText: "Payment Failed - ${err}".needTranslation), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + }); + }, + onError: (err) {}); + + // await myAppointmentsViewModel.createAdvancePayment( + // paymentMethodName: selectedPaymentMethod, + // projectID: widget.patientAppointmentHistoryResponseModel.projectID, + // clinicID: widget.patientAppointmentHistoryResponseModel.clinicID, + // appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo.toString(), + // payedAmount: payfortViewModel.payfortCheckPaymentStatusResponseModel!.amount!, + // paymentReference: payfortViewModel.payfortCheckPaymentStatusResponseModel!.fortId!, + // patientID: "4767477", + // patientType: 1, + // onSuccess: (value) async { + // print(value); + // await myAppointmentsViewModel.addAdvanceNumberRequest( + // advanceNumber: Utils.isVidaPlusProject(widget.patientAppointmentHistoryResponseModel.projectID) + // ? value.data['OnlineCheckInAppointments'][0]['AdvanceNumber_VP'].toString() + // : value.data['OnlineCheckInAppointments'][0]['AdvanceNumber'].toString(), + // paymentReference: payfortViewModel.payfortCheckPaymentStatusResponseModel!.fortId!, + // appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo.toString(), + // onSuccess: (value) async { + // if (widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment!) { + // //TODO: Implement LiveCare Check-In API Call + // } else { + // await myAppointmentsViewModel.generateAppointmentQR( + // clinicID: widget.patientAppointmentHistoryResponseModel.clinicID, + // projectID: widget.patientAppointmentHistoryResponseModel.projectID, + // appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo.toString(), + // isFollowUp: myAppointmentsViewModel.patientAppointmentShareResponseModel!.isFollowup!, + // onSuccess: (apiResponse) { + // Future.delayed(Duration(milliseconds: 500), () { + // Navigator.of(context).pop(); + // Navigator.pushAndRemoveUntil( + // context, + // CustomPageRoute( + // page: LandingNavigation(), + // ), + // (r) => false); + // Navigator.of(context).push( + // CustomPageRoute(page: MyAppointmentsPage()), + // ); + // }); + // }); + // } + // }); + // }); + } else { + showCommonBottomSheetWithoutHeight( + context, + child: Utils.getErrorWidget(loadingText: "Payment Failed! Please try again.".needTranslation), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + } + }); + } +} diff --git a/lib/presentation/habib_wallet/widgets/hospital_list_item.dart b/lib/presentation/habib_wallet/widgets/hospital_list_item.dart new file mode 100644 index 0000000..e2151f2 --- /dev/null +++ b/lib/presentation/habib_wallet/widgets/hospital_list_item.dart @@ -0,0 +1,103 @@ +import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/app_assets.dart'; +import 'package:hmg_patient_app_new/core/app_export.dart'; +import 'package:hmg_patient_app_new/core/app_state.dart'; +import 'package:hmg_patient_app_new/core/dependencies.dart'; +import 'package:hmg_patient_app_new/core/utils/utils.dart'; +import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; +import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; + +class HospitalListItemAdvancePayment extends StatelessWidget { + final HospitalsModel hospitalModel; + final bool isLocationEnabled; + + late AppState appState; + + HospitalListItemAdvancePayment({super.key, required this.hospitalModel, required this.isLocationEnabled}); + + @override + Widget build(BuildContext context) { + appState = getIt.get(); + return DecoratedBox( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 20.h, + hasShadow: false, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 8.h, + children: [hospitalName], + ), + ), + Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon, + iconColor: AppColors.blackColor, + width: 18, + height: 13, + fit: BoxFit.contain, + ), + ], + ).paddingSymmetrical(16.h, 16.h), + ); + } + + Widget get hospitalName => Row( + children: [ + Utils.buildSvgWithAssets( + icon: (hospitalModel.isHMC == true) ? AppAssets.hmc : AppAssets.hmg, + ).paddingOnly(right: 10), + Expanded( + child: Text( + hospitalModel.name ?? "", + style: TextStyle( + fontWeight: FontWeight.w600, + fontSize: 16, + color: AppColors.blackColor, + ), + ), + ) + ], + ); + +// Widget get distanceInfo => Row( +// children: [ +// Visibility( +// visible: (hospitalModel.distanceInKMs != "0"), +// child: AppCustomChipWidget( +// labelText: "${hospitalData?.distanceInKMs ?? ""} km".needTranslation, +// deleteIcon: AppAssets.location_red, +// deleteIconSize: Size(9, 12), +// backgroundColor: AppColors.secondaryLightRedColor, +// textColor: AppColors.errorColor, +// ), +// ), +// Visibility( +// visible: (hospitalData?.distanceInKMs == "0"), +// child: Row( +// children: [ +// AppCustomChipWidget( +// labelText: "Distance not available".needTranslation, +// textColor: AppColors.blackColor, +// ), +// SizedBox( +// width: 8.h, +// ) +// ], +// )), +// Visibility( +// visible: !isLocationEnabled, +// child: AppCustomChipWidget( +// labelText: "Location turned off".needTranslation, +// deleteIcon: AppAssets.location_unavailable, +// deleteIconSize: Size(9, 12), +// textColor: AppColors.blackColor, +// )), +// ], +// ); +} diff --git a/lib/presentation/habib_wallet/widgets/select-medical_file.dart b/lib/presentation/habib_wallet/widgets/select-medical_file.dart index ab777c0..1c56cdd 100644 --- a/lib/presentation/habib_wallet/widgets/select-medical_file.dart +++ b/lib/presentation/habib_wallet/widgets/select-medical_file.dart @@ -27,8 +27,12 @@ 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/habib_wallet/habib_wallet_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.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/input_widget.dart'; +import 'package:provider/provider.dart'; class MultiPageBottomSheet extends StatefulWidget { const MultiPageBottomSheet({Key? key}) : super(key: key); @@ -40,80 +44,139 @@ class MultiPageBottomSheet extends StatefulWidget { class _MultiPageBottomSheetState extends State { late AppState appState; + TextEditingController fileNumberEditingController = TextEditingController(); + @override Widget build(BuildContext context) { appState = getIt.get(); - return SizedBox( - height: MediaQuery.of(context).size.height * 0.38, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - borderRadius: 16.h, - hasShadow: false, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - LocaleKeys.myMedicalFile.tr(context: context).toText16(color: AppColors.textColor, weight: FontWeight.w500), - "${LocaleKeys.fileno.tr(context: context)}: ${appState.getAuthenticatedUser()!.patientId}".toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500), - ], - ), - Utils.buildSvgWithAssets(icon: AppAssets.forward_chevron_icon, iconColor: AppColors.textColor, width: 15.h, height: 15.h), - ], - ).paddingAll(16.h), - ).onPress(() { - Navigator.of(context).pop(); - }), - SizedBox(height: 16.h), - Container( - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - borderRadius: 16.h, - hasShadow: false, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - LocaleKeys.familyTitle.tr(context: context).toText16(color: AppColors.textColor, weight: FontWeight.w500), - "Select a medical file from your family".needTranslation.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), - ], - ), - Utils.buildSvgWithAssets(icon: AppAssets.forward_chevron_icon, iconColor: AppColors.textColor, width: 15.h, height: 15.h), - ], - ).paddingAll(16.h), + return Consumer(builder: (context, habibWalletVM, child) { + return Padding( + padding: MediaQuery.of(context).viewInsets, + child: getCurrentIndexWidget(habibWalletVM), + ); + }); + } + + Widget getCurrentIndexWidget(HabibWalletViewModel habibWalletVM) { + switch (habibWalletVM.currentIndex) { + case 0: + return getSelectMedicalFileContent(habibWalletVM); + case 1: + return getOtherAccountContent(habibWalletVM); + case 2: + return getOtherAccountContent(habibWalletVM); + default: + return getSelectMedicalFileContent(habibWalletVM); + } + } + + Widget getOtherAccountContent(HabibWalletViewModel habibWalletVM) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Enter File Number".needTranslation.toText20(weight: FontWeight.w600), + SizedBox(height: 12.h), + TextInputWidget( + labelText: LocaleKeys.fileNumber.tr(), + hintText: "xxxxxxxxx", + controller: fileNumberEditingController, + // focusNode: _nationalIdFocusNode, + isEnable: true, + prefix: null, + isAllowRadius: true, + isBorderAllowed: false, + isAllowLeadingIcon: true, + autoFocus: true, + padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 8.h), + leadingIcon: AppAssets.requests, + ).withVerticalPadding(8), + SizedBox(height: 12.h), + CustomButton( + text: LocaleKeys.submit.tr(), + onPressed: () async { + await habibWalletVM.getPatientInfoByPatientID(patientID: fileNumberEditingController.text, onSuccess: (response) { + print(response.data["GetPatientInfoByPatientIDList"][0]["FullName"]); + }, onError: (error) {}); + }, + backgroundColor: AppColors.primaryRedColor, + borderColor: AppColors.primaryRedBorderColor, + textColor: AppColors.whiteColor, + ), + ], + ); + } + + Widget getSelectMedicalFileContent(HabibWalletViewModel habibWalletVM) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 16.h, + hasShadow: false, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.myMedicalFile.tr(context: context).toText16(color: AppColors.textColor, weight: FontWeight.w500), + "${LocaleKeys.fileno.tr(context: context)}: ${appState.getAuthenticatedUser()!.patientId}".toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500), + ], + ), + Utils.buildSvgWithAssets(icon: AppAssets.forward_chevron_icon, iconColor: AppColors.textColor, width: 15.h, height: 15.h), + ], + ).paddingAll(16.h), + ).onPress(() { + Navigator.of(context).pop(); + }), + SizedBox(height: 16.h), + Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 16.h, + hasShadow: false, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.familyTitle.tr(context: context).toText16(color: AppColors.textColor, weight: FontWeight.w500), + "Select a medical file from your family".needTranslation.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), + ], + ), + Utils.buildSvgWithAssets(icon: AppAssets.forward_chevron_icon, iconColor: AppColors.textColor, width: 15.h, height: 15.h), + ], + ).paddingAll(16.h), + ), + SizedBox(height: 16.h), + Container( + decoration: RoundedRectangleBorder().toSmoothCornerDecoration( + color: AppColors.whiteColor, + borderRadius: 16.h, + hasShadow: false, ), - SizedBox(height: 16.h), - Container( - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.whiteColor, - borderRadius: 16.h, - hasShadow: false, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - LocaleKeys.otherAccount.tr(context: context).toText16(color: AppColors.textColor, weight: FontWeight.w500), - "Any active medical file from HMG".toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), - ], - ), - Utils.buildSvgWithAssets(icon: AppAssets.forward_chevron_icon, iconColor: AppColors.textColor, width: 15.h, height: 15.h), - ], - ).paddingAll(16.h), - ).onPress(() {}), - ], - ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.otherAccount.tr(context: context).toText16(color: AppColors.textColor, weight: FontWeight.w500), + "Any active medical file from HMG".toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), + ], + ), + Utils.buildSvgWithAssets(icon: AppAssets.forward_chevron_icon, iconColor: AppColors.textColor, width: 15.h, height: 15.h), + ], + ).paddingAll(16.h), + ).onPress(() { + habibWalletVM.setCurrentIndex(2); + }), + ], ); } } diff --git a/lib/presentation/habib_wallet/widgets/select_hospital_bottom_sheet.dart b/lib/presentation/habib_wallet/widgets/select_hospital_bottom_sheet.dart new file mode 100644 index 0000000..54c6fb3 --- /dev/null +++ b/lib/presentation/habib_wallet/widgets/select_hospital_bottom_sheet.dart @@ -0,0 +1,96 @@ +import 'package:easy_localization/easy_localization.dart' show tr, StringTranslateExtension; +import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/enums.dart'; +import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; +import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; +import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; +import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart'; +import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_view_model.dart'; +import 'package:hmg_patient_app_new/features/my_appointments/appointment_via_region_viewmodel.dart'; +import 'package:hmg_patient_app_new/features/my_appointments/models/facility_selection.dart'; +import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart'; +import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/presentation/appointments/widgets/hospital_bottom_sheet/hospital_list_items.dart'; +import 'package:hmg_patient_app_new/presentation/appointments/widgets/hospital_bottom_sheet/type_selection_widget.dart'; +import 'package:hmg_patient_app_new/presentation/habib_wallet/widgets/hospital_list_item.dart'; +import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart' show AppColors; +import 'package:hmg_patient_app_new/widgets/input_widget.dart'; +import 'package:provider/provider.dart'; + +class SelectHospitalBottomSheet extends StatelessWidget { + late HabibWalletViewModel habibWalletVM; + final TextEditingController searchText = TextEditingController(); + + SelectHospitalBottomSheet({super.key}); + + @override + Widget build(BuildContext context) { + habibWalletVM = Provider.of(context, listen: false); + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Text( + // LocaleKeys.selectHospital.tr(), + // style: TextStyle( + // fontSize: 21, + // fontWeight: FontWeight.w600, + // color: AppColors.blackColor, + // ), + // ), + Text( + "Please select the hospital you want to make an advance payment for.".needTranslation, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: AppColors.greyTextColor, + ), + ), + SizedBox(height: 16.h), + // TextInputWidget( + // labelText: LocaleKeys.search.tr(), + // hintText: "Search Hospital".tr(), + // controller: searchText, + // onChange: (value) { + // // appointmentsViewModel.filterHospitalListByString(value, regionalViewModel.selectedRegionId , regionalViewModel.selectedFacilityType == + // // FacilitySelection.HMG.name); + // }, + // isEnable: true, + // prefix: null, + // autoFocus: false, + // isBorderAllowed: false, + // keyboardType: TextInputType.text, + // isAllowLeadingIcon: true, + // selectionType: SelectionTypeEnum.search, + // padding: EdgeInsets.symmetric( + // vertical: ResponsiveExtension(10).h, + // horizontal: ResponsiveExtension(15).h, + // ), + // ), + // SizedBox(height: 24.h), + // TypeSelectionWidget( + // hmcCount: "0", + // hmgCount: "0", + // ), + // SizedBox(height: 21.h), + SizedBox( + height: MediaQuery.sizeOf(context).height * .4, + child: ListView.separated( + itemBuilder: (_, index) { + return HospitalListItemAdvancePayment( + hospitalModel: habibWalletVM.advancePaymentHospitals[index], + isLocationEnabled: false, + ).onPress(() { + habibWalletVM.setSelectedHospital(habibWalletVM.advancePaymentHospitals[index]); + Navigator.of(context).pop(); + }); + }, + separatorBuilder: (_, __) => SizedBox( + height: 16.h, + ), + itemCount: habibWalletVM.advancePaymentHospitals.length), + ) + ], + ); + } +} diff --git a/lib/presentation/medical_file/medical_file_page.dart b/lib/presentation/medical_file/medical_file_page.dart index 22de759..d5e5d5a 100644 --- a/lib/presentation/medical_file/medical_file_page.dart +++ b/lib/presentation/medical_file/medical_file_page.dart @@ -22,6 +22,7 @@ import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_mo import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/appointments/my_appointments_page.dart'; import 'package:hmg_patient_app_new/presentation/appointments/my_doctors_page.dart'; +import 'package:hmg_patient_app_new/presentation/book_appointment/book_appointment_page.dart'; import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/appointment_calendar.dart'; import 'package:hmg_patient_app_new/presentation/insurance/insurance_home_page.dart'; import 'package:hmg_patient_app_new/presentation/insurance/widgets/patient_insurance_card.dart'; @@ -117,6 +118,7 @@ class _MedicalFilePageState extends State { child: Padding( padding: EdgeInsets.all(16.h), child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( crossAxisAlignment: CrossAxisAlignment.start, @@ -132,35 +134,19 @@ class _MedicalFilePageState extends State { children: [ "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}".toText18(isBold: true), SizedBox(height: 4.h), - Row( + Wrap( + direction: Axis.horizontal, + spacing: 4.h, + runSpacing: 4.h, children: [ - CustomButton( + AppCustomChipWidget( icon: AppAssets.file_icon, - iconColor: AppColors.blackColor, - iconSize: 12.h, - text: "File no: ${appState.getAuthenticatedUser()!.patientId}", - onPressed: () {}, - backgroundColor: AppColors.greyColor, - borderColor: AppColors.greyColor, - textColor: AppColors.blackColor, - fontSize: 10, - fontWeight: FontWeight.normal, - borderRadius: 12, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 30.h, + labelText: "File no: ${appState.getAuthenticatedUser()!.patientId}", ), - SizedBox(width: 4.h), - CustomButton( - text: LocaleKeys.verified.tr(context: context), - onPressed: () {}, - backgroundColor: AppColors.greyColor, - borderColor: AppColors.greyColor, - textColor: AppColors.blackColor, - fontSize: 10, - fontWeight: FontWeight.normal, - borderRadius: 12, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 30.h, + AppCustomChipWidget( + icon: AppAssets.checkmark_icon, + labelText: LocaleKeys.verified.tr(context: context), + iconColor: AppColors.successColor, ), ], ), @@ -171,55 +157,21 @@ class _MedicalFilePageState extends State { SizedBox(height: 16.h), Divider(color: AppColors.dividerColor, height: 1.h), SizedBox(height: 16.h), - Row( + Wrap( + direction: Axis.horizontal, + spacing: 4.h, + runSpacing: 4.h, children: [ - CustomButton( - text: "${appState.getAuthenticatedUser()!.age} Years Old", - onPressed: () {}, - backgroundColor: AppColors.greyColor, - borderColor: AppColors.greyColor, - textColor: AppColors.blackColor, - fontSize: 10, - fontWeight: FontWeight.normal, - borderRadius: 12, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 30.h, + AppCustomChipWidget( + labelText: "${appState.getAuthenticatedUser()!.age} Years Old", ), - SizedBox(width: 4.h), - CustomButton( + AppCustomChipWidget( icon: AppAssets.blood_icon, + labelText: "Blood: ${appState.getUserBloodGroup}", iconColor: AppColors.primaryRedColor, - iconSize: 13.h, - text: "Blood: ${appState.getUserBloodGroup}", - onPressed: () {}, - backgroundColor: AppColors.greyColor, - borderColor: AppColors.greyColor, - textColor: AppColors.blackColor, - fontSize: 10, - fontWeight: FontWeight.normal, - borderRadius: 12, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 30.h, ), - // SizedBox(width: 4.h), - // CustomButton( - // icon: AppAssets.insurance_active_icon, - // iconColor: AppColors.successColor, - // iconSize: 13.h, - // text: "Insurance Active", - // onPressed: () {}, - // backgroundColor: AppColors.bgGreenColor.withOpacity(0.20), - // borderColor: AppColors.bgGreenColor.withOpacity(0.0), - // textColor: AppColors.blackColor, - // fontSize: 10, - // fontWeight: FontWeight.normal, - // borderRadius: 12, - // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - // height: 30.h, - // ), ], ), - SizedBox(height: 8.h), ], ), ), @@ -327,7 +279,7 @@ class _MedicalFilePageState extends State { scrollDirection: Axis.horizontal, padding: EdgeInsets.only(top: 16.h, left: 24.h, right: 24.h, bottom: 0.h), shrinkWrap: true, - itemCount: myAppointmentsVM.isMyAppointmentsLoading ? 5 : myAppointmentsVM.patientAppointmentsHistoryList.length, + itemCount: myAppointmentsVM.isMyAppointmentsLoading ? 5 : (myAppointmentsVM.patientAppointmentsHistoryList.isNotEmpty ? myAppointmentsVM.patientAppointmentsHistoryList.length : 1), itemBuilder: (context, index) { return AnimationConfiguration.staggeredList( position: index, @@ -345,14 +297,50 @@ class _MedicalFilePageState extends State { onRescheduleTap: () {}, onAskDoctorTap: () {}, ) - : MedicalFileAppointmentCard( - patientAppointmentHistoryResponseModel: myAppointmentsVM.patientAppointmentsHistoryList[index], - myAppointmentsViewModel: myAppointmentsViewModel, - onRescheduleTap: () { - openDoctorScheduleCalendar(myAppointmentsVM.patientAppointmentsHistoryList[index]); - }, - onAskDoctorTap: () {}, - ), + : myAppointmentsVM.patientAppointmentsHistoryList.isNotEmpty + ? MedicalFileAppointmentCard( + patientAppointmentHistoryResponseModel: myAppointmentsVM.patientAppointmentsHistoryList[index], + myAppointmentsViewModel: myAppointmentsViewModel, + onRescheduleTap: () { + openDoctorScheduleCalendar(myAppointmentsVM.patientAppointmentsHistoryList[index]); + }, + onAskDoctorTap: () {}, + ) + : Container( + width: MediaQuery.of(context).size.width - 48.h, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24, hasShadow: true), + child: Padding( + padding: EdgeInsets.all(12.h), + child: Column( + children: [ + Utils.buildSvgWithAssets(icon: AppAssets.home_calendar_icon, width: 32.h, height: 32.h), + SizedBox(height: 12.h), + "You do not have any appointments. Please book an appointment".needTranslation.toText12(isCenter: true), + SizedBox(height: 12.h), + 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, + fontWeight: FontWeight.w500, + borderRadius: 12, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + height: 40, + icon: AppAssets.add_icon, + iconColor: AppColors.primaryRedColor, + ), + ], + ), + ), + ), ), ), ), diff --git a/lib/presentation/profile_settings/profile_settings.dart b/lib/presentation/profile_settings/profile_settings.dart index 6894d50..4328a58 100644 --- a/lib/presentation/profile_settings/profile_settings.dart +++ b/lib/presentation/profile_settings/profile_settings.dart @@ -106,7 +106,7 @@ class _ProfileSettingsState extends State { ), Spacer(), Consumer(builder: (context, habibWalletVM, child) { - return Utils.getPaymentAmountWithSymbol2(habibWalletVM.habibWalletAmount, AppColors.whiteColor, 13.h, isExpanded: false) + return Utils.getPaymentAmountWithSymbol2(habibWalletVM.habibWalletAmount, isExpanded: false) .toShimmer2(isShow: habibWalletVM.isWalletAmountLoading, radius: 12.h, width: 80.h, height: 24.h); }), CustomButton( diff --git a/pubspec.yaml b/pubspec.yaml index ea41d43..0466933 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -55,7 +55,7 @@ dependencies: uuid: ^4.5.1 health: ^13.1.3 # health: 12.0.1 - fl_chart: ^1.0.0 + fl_chart: ^1.1.1 geolocator: ^14.0.2 dropdown_search: ^6.0.2 google_maps_flutter: ^2.12.3 From 1c2564a1e22b64f6f5cf60c429da817b1845fa89 Mon Sep 17 00:00:00 2001 From: Haroon Amjad <> Date: Sun, 21 Sep 2025 22:14:55 +0300 Subject: [PATCH 10/12] updates --- lib/core/api/api_client.dart | 4 +- lib/core/api_consts.dart | 2 +- .../wallet_payment_confirm_page.dart | 234 ++++++++++-------- .../insurance/widgets/insurance_history.dart | 38 +-- lib/presentation/lab/lab_orders_page.dart | 17 ++ .../medical_file_appointment_card.dart | 17 +- lib/widgets/buttons/custom_button.dart | 2 +- lib/widgets/chip/app_custom_chip_widget.dart | 7 +- pubspec.yaml | 2 +- 9 files changed, 175 insertions(+), 148 deletions(-) diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index 62339bf..a75a1ab 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -176,8 +176,8 @@ class ApiClientImp implements ApiClient { body[_appState.isAuthenticated ? 'TokenID' : 'LogInTokenID'] = _appState.appAuthToken; } - // body['TokenID'] = "@dm!n"; - // body['PatientID'] = 3628599; + body['TokenID'] = "@dm!n"; + body['PatientID'] = 3628599; } body.removeWhere((key, value) => value == null); diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index f802818..d31679c 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -723,7 +723,7 @@ const DEACTIVATE_ACCOUNT = 'Services/Patients.svc/REST/PatientAppleActivation_In class ApiConsts { static const maxSmallScreen = 660; - static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.uat; + static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.prod; // static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT diff --git a/lib/presentation/habib_wallet/wallet_payment_confirm_page.dart b/lib/presentation/habib_wallet/wallet_payment_confirm_page.dart index c22a939..329a3fe 100644 --- a/lib/presentation/habib_wallet/wallet_payment_confirm_page.dart +++ b/lib/presentation/habib_wallet/wallet_payment_confirm_page.dart @@ -98,7 +98,7 @@ class _WalletPaymentConfirmPageState extends State { ).paddingSymmetrical(16.h, 16.h), ).paddingSymmetrical(24.h, 0.h).onPress(() { selectedPaymentMethod = "MADA"; - // openPaymentURL("mada"); + openPaymentURL("mada"); }), SizedBox(height: 16.h), Container( @@ -137,7 +137,7 @@ class _WalletPaymentConfirmPageState extends State { ).paddingSymmetrical(16.h, 16.h), ).paddingSymmetrical(24.h, 0.h).onPress(() { selectedPaymentMethod = "VISA"; - // openPaymentURL("visa"); + openPaymentURL("visa"); }), ], ), @@ -188,7 +188,9 @@ class _WalletPaymentConfirmPageState extends State { ).paddingSymmetrical(24.h, 0.h).onPress(() { if (Utils.havePrivilege(103)) { startApplePay(); - } else {} + } else { + openPaymentURL("applepay"); + } }) : SizedBox(height: 12.h), SizedBox(height: 32.h), @@ -285,101 +287,137 @@ class _WalletPaymentConfirmPageState extends State { void checkPaymentStatus() async { LoaderBottomSheet.showLoader(); await payfortViewModel.checkPaymentStatus( - transactionID: transID, - onSuccess: (apiResponse) async { - print(apiResponse.data); - if (payfortViewModel.payfortCheckPaymentStatusResponseModel!.responseMessage!.toLowerCase() == "success") { - await habibWalletVM.HISCreateAdvancePayment( - paymentMethodName: selectedPaymentMethod, - paidAmount: habibWalletVM.walletRechargeAmount, - paymentReference: payfortViewModel.payfortCheckPaymentStatusResponseModel!.fortId!, - patientID: habibWalletVM.fileNumber, - projectID: habibWalletVM.selectedHospital!.iD!, - depositorName: habibWalletVM.depositorName, - onSuccess: (value) async { - await habibWalletVM.addAdvanceNumberRequest( - advanceNumber: Utils.isVidaPlusProject(habibWalletVM.selectedHospital!.iD) - ? value.data['OnlineCheckInAppointments'][0]['AdvanceNumber_VP'].toString() - : value.data['OnlineCheckInAppointments'][0]['AdvanceNumber'].toString(), - paymentReference: payfortViewModel.payfortCheckPaymentStatusResponseModel!.fortId!, - onSuccess: (value) { - LoaderBottomSheet.hideLoader(); - showCommonBottomSheetWithoutHeight( - context, - child: Utils.getSuccessWidget(loadingText: "Payment Successful!".needTranslation), - callBackFunc: () { - Navigator.of(context).pop(); - Navigator.of(context).pop(); - }, - isFullScreen: false, - isCloseButtonVisible: true, - ); - }, - onError: (err) { - LoaderBottomSheet.hideLoader(); - showCommonBottomSheetWithoutHeight( - context, - child: Utils.getErrorWidget(loadingText: "Payment Failed - ${err}".needTranslation), - callBackFunc: () {}, - isFullScreen: false, - isCloseButtonVisible: true, - ); - }); - }, - onError: (err) {}); + transactionID: transID, + onSuccess: (apiResponse) async { + print(apiResponse.data); + if (payfortViewModel.payfortCheckPaymentStatusResponseModel!.responseMessage!.toLowerCase() == "success") { + await habibWalletVM.HISCreateAdvancePayment( + paymentMethodName: selectedPaymentMethod, + paidAmount: habibWalletVM.walletRechargeAmount, + paymentReference: payfortViewModel.payfortCheckPaymentStatusResponseModel!.fortId!, + patientID: habibWalletVM.fileNumber, + projectID: habibWalletVM.selectedHospital!.iD!, + depositorName: habibWalletVM.depositorName, + onSuccess: (value) async { + await habibWalletVM.addAdvanceNumberRequest( + advanceNumber: Utils.isVidaPlusProject(habibWalletVM.selectedHospital!.iD) + ? value.data['OnlineCheckInAppointments'][0]['AdvanceNumber_VP'].toString() + : value.data['OnlineCheckInAppointments'][0]['AdvanceNumber'].toString(), + paymentReference: payfortViewModel.payfortCheckPaymentStatusResponseModel!.fortId!, + onSuccess: (value) { + LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight( + context, + child: Utils.getSuccessWidget(loadingText: "Payment Successful!".needTranslation), + callBackFunc: () { + Navigator.of(context).pop(); + Navigator.of(context).pop(); + }, + isFullScreen: false, + isCloseButtonVisible: true, + ); + }, + onError: (err) { + LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight( + context, + child: Utils.getErrorWidget(loadingText: "Payment Failed - ${err}".needTranslation), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + }); + }, + onError: (err) {}); + } else { + showCommonBottomSheetWithoutHeight( + context, + child: Utils.getErrorWidget(loadingText: "Payment Failed! Please try again.".needTranslation), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + } + }, + ); + } + + onBrowserLoadStart(String url) { + print("onBrowserLoadStart"); + print(url); + + if (selectedPaymentMethod == "tamara") { + if (Platform.isAndroid) { + Uri uri = new Uri.dataFromString(url); + // tamaraPaymentStatus = uri.queryParameters['status']!; + // tamaraOrderID = uri.queryParameters['AuthorizePaymentId']!; + } else { + Uri uri = new Uri.dataFromString(url); + // tamaraPaymentStatus = uri.queryParameters['paymentStatus']!; + // tamaraOrderID = uri.queryParameters['orderId']!; + } + } + + // if(selectedPaymentMethod != "TAMARA") { + MyInAppBrowser.successURLS.forEach((element) { + if (url.contains(element)) { + browser?.close(); + MyInAppBrowser.isPaymentDone = true; + return; + } + }); + // } + + // if(selectedPaymentMethod != "TAMARA") { + MyInAppBrowser.errorURLS.forEach((element) { + if (url.contains(element)) { + browser?.close(); + MyInAppBrowser.isPaymentDone = false; + return; + } + }); + // } + } + + onBrowserExit(bool isPaymentMade) async { + print("onBrowserExit Called!!!!"); + if (selectedPaymentMethod == "TAMARA") { + // checkTamaraPaymentStatus(transID!, appo); + // if (tamaraPaymentStatus != null && tamaraPaymentStatus.toLowerCase() == "approved") { + // updateTamaraRequestStatus("success", "14", Utils.getAppointmentTransID(appo.projectID, appo.clinicID, appo.appointmentNo), tamaraOrderID, num.parse(selectedInstallments), appo); + // } else { + // updateTamaraRequestStatus("Failed", "00", Utils.getAppointmentTransID(appo.projectID, appo.clinicID, appo.appointmentNo), tamaraOrderID, num.parse(selectedInstallments), appo); + // } + } else { + checkPaymentStatus(); + // checkPaymentStatus(appo); + } + } + + openPaymentURL(String paymentMethod) { + browser = MyInAppBrowser(onExitCallback: onBrowserExit, onLoadStartCallback: onBrowserLoadStart, context: context); + transID = Utils.getAdvancePaymentTransID(habibWalletVM.selectedHospital!.iD!, int.parse(habibWalletVM.fileNumber)); - // await myAppointmentsViewModel.createAdvancePayment( - // paymentMethodName: selectedPaymentMethod, - // projectID: widget.patientAppointmentHistoryResponseModel.projectID, - // clinicID: widget.patientAppointmentHistoryResponseModel.clinicID, - // appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo.toString(), - // payedAmount: payfortViewModel.payfortCheckPaymentStatusResponseModel!.amount!, - // paymentReference: payfortViewModel.payfortCheckPaymentStatusResponseModel!.fortId!, - // patientID: "4767477", - // patientType: 1, - // onSuccess: (value) async { - // print(value); - // await myAppointmentsViewModel.addAdvanceNumberRequest( - // advanceNumber: Utils.isVidaPlusProject(widget.patientAppointmentHistoryResponseModel.projectID) - // ? value.data['OnlineCheckInAppointments'][0]['AdvanceNumber_VP'].toString() - // : value.data['OnlineCheckInAppointments'][0]['AdvanceNumber'].toString(), - // paymentReference: payfortViewModel.payfortCheckPaymentStatusResponseModel!.fortId!, - // appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo.toString(), - // onSuccess: (value) async { - // if (widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment!) { - // //TODO: Implement LiveCare Check-In API Call - // } else { - // await myAppointmentsViewModel.generateAppointmentQR( - // clinicID: widget.patientAppointmentHistoryResponseModel.clinicID, - // projectID: widget.patientAppointmentHistoryResponseModel.projectID, - // appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo.toString(), - // isFollowUp: myAppointmentsViewModel.patientAppointmentShareResponseModel!.isFollowup!, - // onSuccess: (apiResponse) { - // Future.delayed(Duration(milliseconds: 500), () { - // Navigator.of(context).pop(); - // Navigator.pushAndRemoveUntil( - // context, - // CustomPageRoute( - // page: LandingNavigation(), - // ), - // (r) => false); - // Navigator.of(context).push( - // CustomPageRoute(page: MyAppointmentsPage()), - // ); - // }); - // }); - // } - // }); - // }); - } else { - showCommonBottomSheetWithoutHeight( - context, - child: Utils.getErrorWidget(loadingText: "Payment Failed! Please try again.".needTranslation), - callBackFunc: () {}, - isFullScreen: false, - isCloseButtonVisible: true, - ); - } - }); + browser?.openPaymentBrowser( + habibWalletVM.walletRechargeAmount, + "Advance Payment", + transID, + habibWalletVM.selectedHospital!.iD!.toString(), + "CustID_${appState.getAuthenticatedUser()!.patientId.toString()}@HMG.com", + selectedPaymentMethod, + appState.getAuthenticatedUser()!.patientType.toString(), + "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}", + appState.getAuthenticatedUser()!.patientId.toString(), + appState.getAuthenticatedUser()!, + browser!, + false, + "3", + "0", + context, + "", + "", + "", + "", + "3"); } } diff --git a/lib/presentation/insurance/widgets/insurance_history.dart b/lib/presentation/insurance/widgets/insurance_history.dart index 397cb63..de5581c 100644 --- a/lib/presentation/insurance/widgets/insurance_history.dart +++ b/lib/presentation/insurance/widgets/insurance_history.dart @@ -10,6 +10,7 @@ import 'package:hmg_patient_app_new/features/insurance/insurance_view_model.dart import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; +import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/shimmer/movies_shimmer_widget.dart'; import 'package:provider/provider.dart'; @@ -73,7 +74,7 @@ class InsuranceHistory extends StatelessWidget { ], ), SizedBox(height: 8.h), - "Haroon Amjad".toText16(weight: FontWeight.w600), + // "Haroon Amjad".toText16(weight: FontWeight.w600), SizedBox(height: 8.h), Row( children: [ @@ -82,38 +83,11 @@ class InsuranceHistory extends StatelessWidget { spacing: 4.h, runSpacing: 4.h, children: [ - Row( - children: [ - CustomButton( - text: "File No.: 3628599", - onPressed: () {}, - backgroundColor: AppColors.greyColor, - borderColor: AppColors.greyColor, - textColor: AppColors.blackColor, - fontSize: 10, - fontWeight: FontWeight.w500, - borderRadius: 12, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 30.h, - ), - ], + AppCustomChipWidget( + labelText: "File No.: ${insuranceVM.patientInsuranceCardHistoryList[index].patientID}", ), - Row( - children: [ - CustomButton( - text: insuranceVM.patientInsuranceCardHistoryList[index].createdOn!, - // text: "test", - onPressed: () {}, - backgroundColor: AppColors.greyColor, - borderColor: AppColors.greyColor, - textColor: AppColors.blackColor, - fontSize: 10, - fontWeight: FontWeight.w500, - borderRadius: 12, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 30.h, - ), - ], + AppCustomChipWidget( + labelText: insuranceVM.patientInsuranceCardHistoryList[index].createdOn!, ), ], ), diff --git a/lib/presentation/lab/lab_orders_page.dart b/lib/presentation/lab/lab_orders_page.dart index 520bfec..0e14565 100644 --- a/lib/presentation/lab/lab_orders_page.dart +++ b/lib/presentation/lab/lab_orders_page.dart @@ -6,6 +6,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; import 'package:hmg_patient_app_new/core/enums.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; +import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; +import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/features/lab/models/resp_models/patient_lab_orders_response_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/features/lab/lab_view_model.dart'; @@ -13,6 +15,7 @@ import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.dart'; import 'package:hmg_patient_app_new/presentation/lab/search_lab_report.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/chip/custom_chip_widget.dart'; +import 'package:hmg_patient_app_new/widgets/custom_tab_bar.dart'; import 'package:provider/provider.dart'; import 'collapsing_list_view.dart'; @@ -65,6 +68,20 @@ class _LabOrdersPageState extends State { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ + SizedBox(height: 16.h), + CustomTabBar( + activeTextColor: Color(0xffED1C2B), + activeBackgroundColor: Color(0xffED1C2B).withValues(alpha: .1), + tabs: [ + CustomTabBarModel(null, "By Visit".needTranslation), + CustomTabBarModel(null, "By Test".needTranslation), + // CustomTabBarModel(null, "Completed".needTranslation), + ], + onTabChange: (index) { + // myAppointmentsViewModel.onTabChange(index); + }, + ), + SizedBox(height: 16.h), selectedFilterText!.isNotEmpty ? CustomChipWidget( chipText: selectedFilterText!, diff --git a/lib/presentation/medical_file/widgets/medical_file_appointment_card.dart b/lib/presentation/medical_file/widgets/medical_file_appointment_card.dart index a991ab8..a1a6f88 100644 --- a/lib/presentation/medical_file/widgets/medical_file_appointment_card.dart +++ b/lib/presentation/medical_file/widgets/medical_file_appointment_card.dart @@ -13,6 +13,7 @@ import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/appointments/appointment_details_page.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; +import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart'; @@ -30,20 +31,14 @@ class MedicalFileAppointmentCard extends StatelessWidget { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - CustomButton( - text: DateUtil.formatDateToDate(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false), - onPressed: () {}, - backgroundColor: AppointmentType.isArrived(patientAppointmentHistoryResponseModel) ? AppColors.greyColor : AppColors.secondaryLightRedColor, - borderColor: AppointmentType.isArrived(patientAppointmentHistoryResponseModel) ? AppColors.greyLightColor : AppColors.secondaryLightRedColor, - textColor: AppointmentType.isArrived(patientAppointmentHistoryResponseModel) ? AppColors.textColor : AppColors.primaryRedColor, - fontSize: 12, - fontWeight: FontWeight.w500, - borderRadius: 12.h, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 40.h, + AppCustomChipWidget( + richText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false).toText12().paddingSymmetrical(12.h, 0.h), icon: AppointmentType.isArrived(patientAppointmentHistoryResponseModel) ? AppAssets.appointment_calendar_icon : AppAssets.alarm_clock_icon, iconColor: AppointmentType.isArrived(patientAppointmentHistoryResponseModel) ? AppColors.textColor : AppColors.primaryRedColor, iconSize: 16.h, + backgroundColor: AppointmentType.isArrived(patientAppointmentHistoryResponseModel) ? AppColors.greyColor : AppColors.secondaryLightRedColor, + textColor: AppointmentType.isArrived(patientAppointmentHistoryResponseModel) ? AppColors.textColor : AppColors.primaryRedColor, + padding: EdgeInsets.only(top: 12.h, bottom: 12.h, left: 8.h, right: 8.h), ).toShimmer2(isShow: myAppointmentsViewModel.isMyAppointmentsLoading), SizedBox(height: 16.h), Container( diff --git a/lib/widgets/buttons/custom_button.dart b/lib/widgets/buttons/custom_button.dart index 30e4e5d..7a15eca 100644 --- a/lib/widgets/buttons/custom_button.dart +++ b/lib/widgets/buttons/custom_button.dart @@ -62,7 +62,7 @@ class CustomButton extends StatelessWidget { children: [ if (icon != null) Padding( - padding: const EdgeInsets.only(right: 8.0), + padding: const EdgeInsets.only(right: 8.0, left: 8.0, bottom: 4.5), child: Utils.buildSvgWithAssets(icon: icon!, iconColor: iconColor, isDisabled: isDisabled, width: iconSize, height: iconSize), ), Text( diff --git a/lib/widgets/chip/app_custom_chip_widget.dart b/lib/widgets/chip/app_custom_chip_widget.dart index 85c13f2..b29f6e6 100644 --- a/lib/widgets/chip/app_custom_chip_widget.dart +++ b/lib/widgets/chip/app_custom_chip_widget.dart @@ -23,6 +23,7 @@ class AppCustomChipWidget extends StatelessWidget { this.deleteIconSize = const Size(12, 12), this.deleteIconColor = AppColors.textColor, this.deleteIconHasColor = false, + this.padding = EdgeInsets.zero, }); final String? labelText; @@ -38,6 +39,7 @@ class AppCustomChipWidget extends StatelessWidget { final bool iconHasColor; final bool deleteIconHasColor; final OutlinedBorder? shape; + final EdgeInsets? padding; @override Widget build(BuildContext context) { @@ -50,7 +52,7 @@ class AppCustomChipWidget extends StatelessWidget { color: Colors.transparent, // Crucially, set color to transparent style: BorderStyle.none, ), - borderRadius: BorderRadius.circular(8.0), // Apply a border radius of 16.0 + borderRadius: BorderRadius.circular(10.0), // Apply a border radius of 16.0 ), ), child: icon.isNotEmpty @@ -67,7 +69,8 @@ class AppCustomChipWidget extends StatelessWidget { weight: FontWeight.w500, letterSpacing: -0.64, color: textColor), - padding: EdgeInsets.all(0.0), + // padding: EdgeInsets.all(0.0), + padding: padding, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, labelPadding: EdgeInsets.only( left: -4.h, diff --git a/pubspec.yaml b/pubspec.yaml index 0466933..ea41d43 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -55,7 +55,7 @@ dependencies: uuid: ^4.5.1 health: ^13.1.3 # health: 12.0.1 - fl_chart: ^1.1.1 + fl_chart: ^1.0.0 geolocator: ^14.0.2 dropdown_search: ^6.0.2 google_maps_flutter: ^2.12.3 From 97038f1a258dc894756b5fe4cb0031bc0f14fc0c Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Mon, 22 Sep 2025 13:37:12 +0300 Subject: [PATCH 11/12] advance payment implementation done for self & other file number --- lib/core/api/api_client.dart | 4 +- lib/core/api_consts.dart | 2 +- .../habib_wallet/habib_wallet_view_model.dart | 37 ++++++++++++++++++- .../widgets/appointment_card.dart | 8 +++- .../habib_wallet/habib_wallet_page.dart | 2 +- .../habib_wallet/recharge_wallet_page.dart | 14 ++++--- .../wallet_payment_confirm_page.dart | 17 +++++---- .../widgets/select-medical_file.dart | 27 +++++++++++--- lib/widgets/buttons/custom_button.dart | 19 ++++++---- 9 files changed, 96 insertions(+), 34 deletions(-) diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index a75a1ab..62339bf 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -176,8 +176,8 @@ class ApiClientImp implements ApiClient { body[_appState.isAuthenticated ? 'TokenID' : 'LogInTokenID'] = _appState.appAuthToken; } - body['TokenID'] = "@dm!n"; - body['PatientID'] = 3628599; + // body['TokenID'] = "@dm!n"; + // body['PatientID'] = 3628599; } body.removeWhere((key, value) => value == null); diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index d31679c..f802818 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -723,7 +723,7 @@ const DEACTIVATE_ACCOUNT = 'Services/Patients.svc/REST/PatientAppleActivation_In class ApiConsts { static const maxSmallScreen = 660; - static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.prod; + static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.uat; // static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT diff --git a/lib/features/habib_wallet/habib_wallet_view_model.dart b/lib/features/habib_wallet/habib_wallet_view_model.dart index c620b08..5291646 100644 --- a/lib/features/habib_wallet/habib_wallet_view_model.dart +++ b/lib/features/habib_wallet/habib_wallet_view_model.dart @@ -1,6 +1,8 @@ +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_repo.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/error_handler_service.dart'; class HabibWalletViewModel extends ChangeNotifier { @@ -8,6 +10,10 @@ class HabibWalletViewModel extends ChangeNotifier { num habibWalletAmount = 0; num walletRechargeAmount = 0; + bool isBottomSheetContentLoading = false; + + bool isSearchedFileNumberDataShown = false; + int currentIndex = 0; List advancePaymentHospitals = []; @@ -21,12 +27,16 @@ class HabibWalletViewModel extends ChangeNotifier { String depositorName = ''; String mobileNumber = ''; + num selectedRechargeType = 1; + HabibWalletViewModel({required this.habibWalletRepo, required this.errorHandlerService}); initHabibWalletProvider() { isWalletAmountLoading = true; + isBottomSheetContentLoading = false; habibWalletAmount = 0; walletRechargeAmount = 0; + selectedRechargeType = 1; advancePaymentHospitals.clear(); selectedHospital = null; fileNumber = ''; @@ -35,6 +45,11 @@ class HabibWalletViewModel extends ChangeNotifier { notifyListeners(); } + setSelectedRechargeType(num type) { + selectedRechargeType = type; + notifyListeners(); + } + setSelectedHospital(HospitalsModel hospital) { selectedHospital = hospital; notifyListeners(); @@ -57,6 +72,19 @@ class HabibWalletViewModel extends ChangeNotifier { notifyListeners(); } + String getSelectedRechargeTypeValue() { + switch (selectedRechargeType) { + case 1: + return LocaleKeys.myAccount.tr(); + case 2: + return LocaleKeys.family.tr(); + case 3: + return LocaleKeys.otherAccount.tr(); + default: + return LocaleKeys.myAccount.tr(); + } + } + Future getPatientBalanceAmount({Function(dynamic)? onSuccess, Function(String)? onError}) async { isWalletAmountLoading = true; notifyListeners(); @@ -144,14 +172,21 @@ class HabibWalletViewModel extends ChangeNotifier { } Future getPatientInfoByPatientID({required String patientID, Function(dynamic)? onSuccess, Function(String)? onError}) async { + isBottomSheetContentLoading = true; + notifyListeners(); final result = await habibWalletRepo.getPatientInfoByPatientID(patientID: patientID); result.fold( - (failure) async => await errorHandlerService.handleError(failure: failure), + (failure) async { + isBottomSheetContentLoading = false; + notifyListeners(); + await errorHandlerService.handleError(failure: failure); + }, (apiResponse) { if (apiResponse.messageStatus == 2) { // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); } else if (apiResponse.messageStatus == 1) { + isBottomSheetContentLoading = false; notifyListeners(); if (onSuccess != null) { onSuccess(apiResponse); diff --git a/lib/presentation/appointments/widgets/appointment_card.dart b/lib/presentation/appointments/widgets/appointment_card.dart index a87012c..a4705d9 100644 --- a/lib/presentation/appointments/widgets/appointment_card.dart +++ b/lib/presentation/appointments/widgets/appointment_card.dart @@ -151,8 +151,12 @@ class _AppointmentCardState extends State { spacing: 3.h, runSpacing: 4.h, children: [ - widget.isFromHomePage ? SizedBox.shrink() : AppCustomChipWidget(labelText: widget.isLoading ? "Cardiology" : widget.patientAppointmentHistoryResponseModel.clinicName!).toShimmer2(isShow: widget.isLoading), - widget.isFromHomePage ? SizedBox.shrink() : AppCustomChipWidget(labelText: widget.isLoading ? "Olaya" : widget.patientAppointmentHistoryResponseModel.projectName!).toShimmer2(isShow: widget.isLoading), + widget.isFromHomePage + ? SizedBox.shrink() + : AppCustomChipWidget(labelText: widget.isLoading ? "Cardiology" : widget.patientAppointmentHistoryResponseModel.clinicName!).toShimmer2(isShow: widget.isLoading), + widget.isFromHomePage + ? SizedBox.shrink() + : AppCustomChipWidget(labelText: widget.isLoading ? "Olaya" : widget.patientAppointmentHistoryResponseModel.projectName!).toShimmer2(isShow: widget.isLoading), AppCustomChipWidget( icon: AppAssets.appointment_calendar_icon, labelText: diff --git a/lib/presentation/habib_wallet/habib_wallet_page.dart b/lib/presentation/habib_wallet/habib_wallet_page.dart index e1d1ba2..2e909d2 100644 --- a/lib/presentation/habib_wallet/habib_wallet_page.dart +++ b/lib/presentation/habib_wallet/habib_wallet_page.dart @@ -102,7 +102,7 @@ class _HabibWalletState extends State { fontSize: 14, fontWeight: FontWeight.bold, borderRadius: 12, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + // padding: EdgeInsets.fromLTRB(10, 0, 10, 0), height: 40.h, ), ], diff --git a/lib/presentation/habib_wallet/recharge_wallet_page.dart b/lib/presentation/habib_wallet/recharge_wallet_page.dart index 098610b..0cd2d69 100644 --- a/lib/presentation/habib_wallet/recharge_wallet_page.dart +++ b/lib/presentation/habib_wallet/recharge_wallet_page.dart @@ -34,11 +34,15 @@ class _RechargeWalletPageState extends State { FocusNode textFocusNode = FocusNode(); late HabibWalletViewModel habibWalletVM; + late AppState appState; final TextEditingController amountTextController = TextEditingController(); @override void initState() { scheduleMicrotask(() { + habibWalletVM.setDepositorDetails(appState.getAuthenticatedUser()!.patientId.toString(), "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}", + appState.getAuthenticatedUser()!.mobileNumber!); + habibWalletVM.setSelectedRechargeType(0); habibWalletVM.getProjectsList(); }); super.initState(); @@ -47,7 +51,7 @@ class _RechargeWalletPageState extends State { @override Widget build(BuildContext context) { habibWalletVM = Provider.of(context, listen: false); - AppState appState = getIt.get(); + appState = getIt.get(); return Scaffold( backgroundColor: AppColors.bgScaffoldColor, body: Column( @@ -136,8 +140,8 @@ class _RechargeWalletPageState extends State { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - LocaleKeys.myAccount.tr(context: context).toText16(color: AppColors.textColor, weight: FontWeight.w500), - "${LocaleKeys.medicalFile.tr(context: context)}: ${appState.getAuthenticatedUser()!.patientId}" + (habibWalletVM.getSelectedRechargeTypeValue()).toText16(color: AppColors.textColor, weight: FontWeight.w500), + "${LocaleKeys.medicalFile.tr(context: context)}: ${habibWalletVM.fileNumber}" .toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), ], ), @@ -276,8 +280,8 @@ class _RechargeWalletPageState extends State { ); } else { habibWalletVM.setWalletRechargeAmount(num.parse(amountTextController.text)); - habibWalletVM.setDepositorDetails(appState.getAuthenticatedUser()!.patientId.toString(), "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}", - appState.getAuthenticatedUser()!.mobileNumber!); + // habibWalletVM.setDepositorDetails(appState.getAuthenticatedUser()!.patientId.toString(), "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}", + // appState.getAuthenticatedUser()!.mobileNumber!); Navigator.of(context).push( CustomPageRoute( page: WalletPaymentConfirmPage(), diff --git a/lib/presentation/habib_wallet/wallet_payment_confirm_page.dart b/lib/presentation/habib_wallet/wallet_payment_confirm_page.dart index 329a3fe..c10a025 100644 --- a/lib/presentation/habib_wallet/wallet_payment_confirm_page.dart +++ b/lib/presentation/habib_wallet/wallet_payment_confirm_page.dart @@ -189,7 +189,7 @@ class _WalletPaymentConfirmPageState extends State { if (Utils.havePrivilege(103)) { startApplePay(); } else { - openPaymentURL("applepay"); + openPaymentURL("ApplePay"); } }) : SizedBox(height: 12.h), @@ -214,8 +214,8 @@ class _WalletPaymentConfirmPageState extends State { applePayInsertRequest.clinicID = 0; applePayInsertRequest.currency = appState.getAuthenticatedUser()!.outSa! == 0 ? "SAR" : "AED"; - applePayInsertRequest.customerEmail = "CustID_${appState.getAuthenticatedUser()!.patientId.toString()}@HMG.com"; - applePayInsertRequest.customerID = appState.getAuthenticatedUser()!.patientId.toString(); + applePayInsertRequest.customerEmail = "CustID_${habibWalletVM.fileNumber.toString()}@HMG.com"; + applePayInsertRequest.customerID = habibWalletVM.fileNumber.toString(); applePayInsertRequest.customerName = "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}"; applePayInsertRequest.deviceToken = await Utils.getStringFromPrefs(CacheConst.pushToken); @@ -224,7 +224,7 @@ class _WalletPaymentConfirmPageState extends State { applePayInsertRequest.projectID = habibWalletVM.selectedHospital!.iD!.toString(); applePayInsertRequest.serviceID = ServiceTypeEnum.appointmentPayment.getIdFromServiceEnum().toString(); applePayInsertRequest.channelID = 3; - applePayInsertRequest.patientID = appState.getAuthenticatedUser()!.patientId.toString(); + applePayInsertRequest.patientID = habibWalletVM.fileNumber.toString(); applePayInsertRequest.patientTypeID = appState.getAuthenticatedUser()!.patientType; applePayInsertRequest.patientOutSA = appState.getAuthenticatedUser()!.outSa; applePayInsertRequest.appointmentDate = null; @@ -237,7 +237,7 @@ class _WalletPaymentConfirmPageState extends State { applePayInsertRequest.isSchedule = "0"; applePayInsertRequest.language = appState.isArabic() ? 'ar' : 'en'; applePayInsertRequest.languageID = appState.isArabic() ? 1 : 2; - applePayInsertRequest.userName = appState.getAuthenticatedUser()!.patientId; + applePayInsertRequest.userName = int.parse(habibWalletVM.fileNumber); applePayInsertRequest.responseContinueURL = "http://hmg.com/Documents/success.html"; applePayInsertRequest.backClickUrl = "http://hmg.com/Documents/success.html"; applePayInsertRequest.paymentOption = "ApplePay"; @@ -330,6 +330,7 @@ class _WalletPaymentConfirmPageState extends State { }, onError: (err) {}); } else { + LoaderBottomSheet.hideLoader(); showCommonBottomSheetWithoutHeight( context, child: Utils.getErrorWidget(loadingText: "Payment Failed! Please try again.".needTranslation), @@ -403,11 +404,11 @@ class _WalletPaymentConfirmPageState extends State { "Advance Payment", transID, habibWalletVM.selectedHospital!.iD!.toString(), - "CustID_${appState.getAuthenticatedUser()!.patientId.toString()}@HMG.com", + "CustID_${habibWalletVM.fileNumber.toString()}@HMG.com", selectedPaymentMethod, appState.getAuthenticatedUser()!.patientType.toString(), - "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}", - appState.getAuthenticatedUser()!.patientId.toString(), + habibWalletVM.depositorName, + habibWalletVM.fileNumber.toString(), appState.getAuthenticatedUser()!, browser!, false, diff --git a/lib/presentation/habib_wallet/widgets/select-medical_file.dart b/lib/presentation/habib_wallet/widgets/select-medical_file.dart index 1c56cdd..73a7dfe 100644 --- a/lib/presentation/habib_wallet/widgets/select-medical_file.dart +++ b/lib/presentation/habib_wallet/widgets/select-medical_file.dart @@ -29,6 +29,7 @@ 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/habib_wallet/habib_wallet_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; +import 'package:hmg_patient_app_new/services/dialog_service.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/input_widget.dart'; @@ -43,6 +44,7 @@ class MultiPageBottomSheet extends StatefulWidget { class _MultiPageBottomSheetState extends State { late AppState appState; + static final DialogService _dialogService = getIt.get(); TextEditingController fileNumberEditingController = TextEditingController(); @@ -52,7 +54,7 @@ class _MultiPageBottomSheetState extends State { return Consumer(builder: (context, habibWalletVM, child) { return Padding( padding: MediaQuery.of(context).viewInsets, - child: getCurrentIndexWidget(habibWalletVM), + child: habibWalletVM.isBottomSheetContentLoading ? Utils.getLoadingWidget() : getCurrentIndexWidget(habibWalletVM), ); }); } @@ -80,13 +82,12 @@ class _MultiPageBottomSheetState extends State { labelText: LocaleKeys.fileNumber.tr(), hintText: "xxxxxxxxx", controller: fileNumberEditingController, - // focusNode: _nationalIdFocusNode, isEnable: true, prefix: null, isAllowRadius: true, isBorderAllowed: false, isAllowLeadingIcon: true, - autoFocus: true, + autoFocus: false, padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 8.h), leadingIcon: AppAssets.requests, ).withVerticalPadding(8), @@ -94,9 +95,23 @@ class _MultiPageBottomSheetState extends State { CustomButton( text: LocaleKeys.submit.tr(), onPressed: () async { - await habibWalletVM.getPatientInfoByPatientID(patientID: fileNumberEditingController.text, onSuccess: (response) { - print(response.data["GetPatientInfoByPatientIDList"][0]["FullName"]); - }, onError: (error) {}); + await habibWalletVM.getPatientInfoByPatientID( + patientID: fileNumberEditingController.text, + onSuccess: (response) async { + print(response.data["GetPatientInfoByPatientIDList"][0]["FullName"]); + await _dialogService.showCommonBottomSheetWithoutH( + message: "A file was found with name: ${response.data["GetPatientInfoByPatientIDList"][0]["FullName"]}, Would you like to recharge wallet for this file number?".needTranslation, + label: LocaleKeys.notice.tr(), + onOkPressed: () { + habibWalletVM.setSelectedRechargeType(3); + habibWalletVM.setDepositorDetails(response.data["GetPatientInfoByPatientIDList"][0]["PatientID"].toString(), response.data["GetPatientInfoByPatientIDList"][0]["FullName"], + response.data["GetPatientInfoByPatientIDList"][0]["MobileNumber"]); + Navigator.of(context).pop(); + Navigator.of(context).pop(); + }, + onCancelPressed: () {}); + }, + onError: (error) {}); }, backgroundColor: AppColors.primaryRedColor, borderColor: AppColors.primaryRedBorderColor, diff --git a/lib/widgets/buttons/custom_button.dart b/lib/widgets/buttons/custom_button.dart index 81eb292..d0b4a6c 100644 --- a/lib/widgets/buttons/custom_button.dart +++ b/lib/widgets/buttons/custom_button.dart @@ -62,16 +62,19 @@ class CustomButton extends StatelessWidget { children: [ if (icon != null) Padding( - padding: const EdgeInsets.only(right: 8.0, left: 8.0, bottom: 4.5), + padding: const EdgeInsets.only(right: 8.0, left: 8.0), child: Utils.buildSvgWithAssets(icon: icon!, iconColor: iconColor, isDisabled: isDisabled, width: iconSize, height: iconSize), ), - Text( - text, - style: context.dynamicTextStyle( - fontSize: fontSize.fSize, - color: isDisabled ? textColor.withOpacity(0.5) : textColor, - letterSpacing: -0.4, - fontWeight: fontWeight, + Padding( + padding: EdgeInsets.only(top: 2.5), + child: Text( + text, + style: context.dynamicTextStyle( + fontSize: fontSize.fSize, + color: isDisabled ? textColor.withOpacity(0.5) : textColor, + letterSpacing: -0.4, + fontWeight: fontWeight, + ), ), ), ], From 836a72ec229e7475b3c3f33480ab39fc18dd88f8 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Mon, 22 Sep 2025 14:34:13 +0300 Subject: [PATCH 12/12] App directionality changes --- .../appointment_details_page.dart | 18 ++++--- .../appointment_payment_page.dart | 51 +++++++++++-------- .../appointments/my_doctors_page.dart | 7 ++- .../widgets/appointment_card.dart | 14 +++-- .../appointment_checkin_bottom_sheet.dart | 20 +++++--- .../facility_selection_item.dart | 18 ++++--- .../hospital_list_items.dart | 15 +++--- .../region_bottomsheet/region_list_item.dart | 51 ++++++++----------- .../book_appointment_page.dart | 9 ++-- .../book_appointment/widgets/clinic_card.dart | 7 ++- .../wallet_payment_confirm_page.dart | 34 ++++++++----- .../widgets/hospital_list_item.dart | 15 +++--- .../lab/collapsing_list_view.dart | 18 ++++--- .../medical_file/medical_file_page.dart | 8 +-- .../medical_file/widgets/lab_rad_card.dart | 15 +++--- .../medical_file_appointment_card.dart | 20 +++++--- .../widgets/patient_sick_leave_card.dart | 13 +++-- .../prescriptions_list_page.dart | 16 ++++-- 18 files changed, 209 insertions(+), 140 deletions(-) diff --git a/lib/presentation/appointments/appointment_details_page.dart b/lib/presentation/appointments/appointment_details_page.dart index e1c8662..7a98b9d 100644 --- a/lib/presentation/appointments/appointment_details_page.dart +++ b/lib/presentation/appointments/appointment_details_page.dart @@ -5,6 +5,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.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/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; @@ -34,6 +35,7 @@ import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart'; import 'package:maps_launcher/maps_launcher.dart'; import 'package:provider/provider.dart'; +import '../../core/dependencies.dart'; import '../medical_file/widgets/medical_file_card.dart'; class AppointmentDetailsPage extends StatefulWidget { @@ -63,6 +65,7 @@ class _AppointmentDetailsPageState extends State { @override Widget build(BuildContext context) { + AppState appState = getIt.get(); myAppointmentsViewModel = Provider.of(context, listen: false); prescriptionsViewModel = Provider.of(context, listen: false); bookAppointmentsViewModel = Provider.of(context, listen: false); @@ -313,12 +316,15 @@ class _AppointmentDetailsPageState extends State { ], ), SizedBox(width: 68.h), - Utils.buildSvgWithAssets( - icon: AppAssets.forward_arrow_icon, - iconColor: AppColors.blackColor, - width: 18.h, - height: 13.h, - fit: BoxFit.contain, + Transform.flip( + flipX: appState.isArabic() ? true : false, + child: Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon, + iconColor: AppColors.blackColor, + width: 18.h, + height: 13.h, + fit: BoxFit.contain, + ), ), ], ), diff --git a/lib/presentation/appointments/appointment_payment_page.dart b/lib/presentation/appointments/appointment_payment_page.dart index e68e000..77d5d03 100644 --- a/lib/presentation/appointments/appointment_payment_page.dart +++ b/lib/presentation/appointments/appointment_payment_page.dart @@ -103,13 +103,16 @@ class _AppointmentPaymentPageState extends State { ), SizedBox(width: 8.h), const Spacer(), - Utils.buildSvgWithAssets( - icon: AppAssets.forward_arrow_icon, - iconColor: AppColors.blackColor, - width: 18.h, - height: 13.h, - fit: BoxFit.contain, - ).toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading), + Transform.flip( + flipX: appState.isArabic() ? true : false, + child: Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon, + iconColor: AppColors.blackColor, + width: 18.h, + height: 13.h, + fit: BoxFit.contain, + ).toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading), + ), ], ).paddingSymmetrical(16.h, 16.h), ).paddingSymmetrical(24.h, 0.h).onPress(() { @@ -142,13 +145,16 @@ class _AppointmentPaymentPageState extends State { ), SizedBox(width: 8.h), const Spacer(), - Utils.buildSvgWithAssets( - icon: AppAssets.forward_arrow_icon, - iconColor: AppColors.blackColor, - width: 18.h, - height: 13.h, - fit: BoxFit.contain, - ).toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading), + Transform.flip( + flipX: appState.isArabic() ? true : false, + child: Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon, + iconColor: AppColors.blackColor, + width: 18.h, + height: 13.h, + fit: BoxFit.contain, + ).toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading), + ), ], ).paddingSymmetrical(16.h, 16.h), ).paddingSymmetrical(24.h, 0.h).onPress(() { @@ -175,13 +181,16 @@ class _AppointmentPaymentPageState extends State { ), SizedBox(width: 8.h), const Spacer(), - Utils.buildSvgWithAssets( - icon: AppAssets.forward_arrow_icon, - iconColor: AppColors.blackColor, - width: 18.h, - height: 13.h, - fit: BoxFit.contain, - ).toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading), + Transform.flip( + flipX: appState.isArabic() ? true : false, + child: Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon, + iconColor: AppColors.blackColor, + width: 18.h, + height: 13.h, + fit: BoxFit.contain, + ).toShimmer2(isShow: myAppointmentsVM.isAppointmentPatientShareLoading), + ), ], ).paddingSymmetrical(16.h, 16.h), ).paddingSymmetrical(24.h, 0.h).onPress(() { diff --git a/lib/presentation/appointments/my_doctors_page.dart b/lib/presentation/appointments/my_doctors_page.dart index 89b120c..0b002c9 100644 --- a/lib/presentation/appointments/my_doctors_page.dart +++ b/lib/presentation/appointments/my_doctors_page.dart @@ -2,6 +2,8 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.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/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; @@ -21,6 +23,7 @@ class MyDoctorsPage extends StatelessWidget { @override Widget build(BuildContext context) { + AppState appState = getIt.get(); myAppointmentsViewModel = Provider.of(context, listen: false); return Scaffold( backgroundColor: AppColors.bgScaffoldColor, @@ -136,7 +139,9 @@ class MyDoctorsPage extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ "".toText16(), - Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, width: 15.h, height: 15.h, fit: BoxFit.contain, iconColor: AppColors.textColor), + Transform.flip( + flipX: appState.isArabic() ? true : false, + child: Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, width: 15.h, height: 15.h, fit: BoxFit.contain, iconColor: AppColors.textColor)), ], ), ], diff --git a/lib/presentation/appointments/widgets/appointment_card.dart b/lib/presentation/appointments/widgets/appointment_card.dart index a4705d9..c345099 100644 --- a/lib/presentation/appointments/widgets/appointment_card.dart +++ b/lib/presentation/appointments/widgets/appointment_card.dart @@ -219,11 +219,15 @@ class _AppointmentCardState extends State { ), child: Padding( padding: EdgeInsets.all(10.h), - child: Utils.buildSvgWithAssets( - icon: AppAssets.forward_arrow_icon, - width: 10.h, - height: 10.h, - fit: BoxFit.contain, + child: Transform.flip( + flipX: appState.isArabic() ? true : false, + child: Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon, + iconColor: AppColors.whiteColor, + width: 10.h, + height: 10.h, + fit: BoxFit.contain, + ), ), ), ).toShimmer2(isShow: widget.isLoading).onPress(() { diff --git a/lib/presentation/appointments/widgets/appointment_checkin_bottom_sheet.dart b/lib/presentation/appointments/widgets/appointment_checkin_bottom_sheet.dart index b67ab7c..e79f26f 100644 --- a/lib/presentation/appointments/widgets/appointment_checkin_bottom_sheet.dart +++ b/lib/presentation/appointments/widgets/appointment_checkin_bottom_sheet.dart @@ -31,11 +31,12 @@ class AppointmentCheckinBottomSheet extends StatelessWidget { bool _supportsNFC = false; late LocationUtils locationUtils; + late AppState appState; ProjectDetailListModel projectDetailListModel = ProjectDetailListModel(); @override Widget build(BuildContext context) { - AppState _appState = getIt.get(); + appState = getIt.get(); FlutterNfcKit.nfcAvailability.then((value) { _supportsNFC = (value == NFCAvailability.available); }); @@ -53,7 +54,7 @@ class AppointmentCheckinBottomSheet extends StatelessWidget { // appState: myAppointmentsViewModel.appState, // ); locationUtils.getCurrentLocation(onSuccess: (value) { - projectDetailListModel = Utils.getProjectDetailObj(_appState, patientAppointmentHistoryResponseModel.projectID); + projectDetailListModel = Utils.getProjectDetailObj(appState, patientAppointmentHistoryResponseModel.projectID); double dist = Utils.distance(value.latitude, value.longitude, double.parse(projectDetailListModel.latitude!), double.parse(projectDetailListModel.longitude!)).ceilToDouble() * 1000; print(dist); if (dist <= projectDetailListModel.geofenceRadius!) { @@ -120,12 +121,15 @@ class AppointmentCheckinBottomSheet extends StatelessWidget { ], ), ), - Utils.buildSvgWithAssets( - icon: AppAssets.forward_arrow_icon, - iconColor: AppColors.blackColor, - width: 18.h, - height: 13.h, - fit: BoxFit.contain, + Transform.flip( + flipX: appState.isArabic() ? true : false, + child: Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon, + iconColor: AppColors.blackColor, + width: 18.h, + height: 13.h, + fit: BoxFit.contain, + ), ), ], ), diff --git a/lib/presentation/appointments/widgets/faculity_selection/facility_selection_item.dart b/lib/presentation/appointments/widgets/faculity_selection/facility_selection_item.dart index 1660146..b267ee4 100644 --- a/lib/presentation/appointments/widgets/faculity_selection/facility_selection_item.dart +++ b/lib/presentation/appointments/widgets/faculity_selection/facility_selection_item.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.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/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; @@ -21,6 +23,7 @@ class FacilitySelectionItem extends StatelessWidget { @override Widget build(BuildContext context) { + AppState appState = getIt.get(); return Container( decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.whiteColor, @@ -42,12 +45,15 @@ class FacilitySelectionItem extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ info, - Utils.buildSvgWithAssets( - icon: AppAssets.forward_arrow_icon, - iconColor: AppColors.blackColor, - width: 18, - height: 13, - fit: BoxFit.contain, + Transform.flip( + flipX: appState.isArabic() ? true : false, + child: Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon, + iconColor: AppColors.blackColor, + width: 18, + height: 13, + fit: BoxFit.contain, + ), ), ], ) diff --git a/lib/presentation/appointments/widgets/hospital_bottom_sheet/hospital_list_items.dart b/lib/presentation/appointments/widgets/hospital_bottom_sheet/hospital_list_items.dart index 81cc318..036c0e3 100644 --- a/lib/presentation/appointments/widgets/hospital_bottom_sheet/hospital_list_items.dart +++ b/lib/presentation/appointments/widgets/hospital_bottom_sheet/hospital_list_items.dart @@ -38,12 +38,15 @@ class HospitalListItem extends StatelessWidget { children: [hospitalName, distanceInfo], ), ), - Utils.buildSvgWithAssets( - icon: AppAssets.forward_arrow_icon, - iconColor: AppColors.blackColor, - width: 18, - height: 13, - fit: BoxFit.contain, + Transform.flip( + flipX: appState.isArabic() ? true : false, + child: Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon, + iconColor: AppColors.blackColor, + width: 18, + height: 13, + fit: BoxFit.contain, + ), ), ], ).paddingSymmetrical(16.h, 16.h), diff --git a/lib/presentation/appointments/widgets/region_bottomsheet/region_list_item.dart b/lib/presentation/appointments/widgets/region_bottomsheet/region_list_item.dart index ab8e21f..64263de 100644 --- a/lib/presentation/appointments/widgets/region_bottomsheet/region_list_item.dart +++ b/lib/presentation/appointments/widgets/region_bottomsheet/region_list_item.dart @@ -1,6 +1,8 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; +import 'package:hmg_patient_app_new/core/app_state.dart'; +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/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; @@ -15,15 +17,11 @@ class RegionListItem extends StatelessWidget { final String hmgCount; final String subTitle; - const RegionListItem( - {super.key, - required this.title, - required this.subTitle, - required this.hmcCount, - required this.hmgCount}); + const RegionListItem({super.key, required this.title, required this.subTitle, required this.hmcCount, required this.hmgCount}); @override Widget build(BuildContext context) { + AppState appState = getIt.get(); return Container( decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.whiteColor, @@ -40,18 +38,19 @@ class RegionListItem extends StatelessWidget { Row( spacing: 8.h, children: [ - placesCountItem( - AppAssets.hmg, hmgCount, " ${LocaleKeys.hospital.tr()}"), - placesCountItem(AppAssets.hmc, hmcCount, - " ${LocaleKeys.medicalCenters.tr()}"), + placesCountItem(AppAssets.hmg, hmgCount, " ${LocaleKeys.hospital.tr()}"), + placesCountItem(AppAssets.hmc, hmcCount, " ${LocaleKeys.medicalCenters.tr()}"), ], ), - Utils.buildSvgWithAssets( - icon: AppAssets.forward_arrow_icon, - iconColor: AppColors.blackColor, - width: 18, - height: 13, - fit: BoxFit.contain, + Transform.flip( + flipX: appState.isArabic() ? true : false, + child: Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon, + iconColor: AppColors.blackColor, + width: 18, + height: 13, + fit: BoxFit.contain, + ), ), ], ) @@ -66,24 +65,14 @@ class RegionListItem extends StatelessWidget { icon: svgPath, iconHasColor: false, richText: RichText( - text: TextSpan( - text: count, - style: TextStyle( - fontSize: 12.h, - fontWeight: FontWeight.w700, - color: AppColors.blackColor), - children: [ - TextSpan( - text: title, - style: TextStyle( - fontSize: 12.h, - fontWeight: FontWeight.w500, - color: AppColors.blackColor)) - ])), + text: TextSpan( + text: count, + style: TextStyle(fontSize: 12.h, fontWeight: FontWeight.w700, color: AppColors.blackColor), + children: [TextSpan(text: title, style: TextStyle(fontSize: 12.h, fontWeight: FontWeight.w500, color: AppColors.blackColor))])), ); } - Widget get header => Column( + Widget get header => Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ diff --git a/lib/presentation/book_appointment/book_appointment_page.dart b/lib/presentation/book_appointment/book_appointment_page.dart index f2430cb..bb659c4 100644 --- a/lib/presentation/book_appointment/book_appointment_page.dart +++ b/lib/presentation/book_appointment/book_appointment_page.dart @@ -117,7 +117,8 @@ class _BookAppointmentPageState extends State { ), ], ), - Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 15.h, height: 15.h), + Transform.flip( + flipX: appState.isArabic() ? true : false, child: Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 15.h, height: 15.h)), ], ).onPress(() { bookAppointmentsViewModel.setIsClinicsListLoading(true); @@ -148,7 +149,8 @@ class _BookAppointmentPageState extends State { ), ], ), - Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 15.h, height: 15.h), + Transform.flip( + flipX: appState.isArabic() ? true : false, child: Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 15.h, height: 15.h)), ], ).onPress(() { bookAppointmentsViewModel.setIsDoctorSearchByNameStarted(false); @@ -177,7 +179,8 @@ class _BookAppointmentPageState extends State { ), ], ), - Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 15.h, height: 15.h), + Transform.flip( + flipX: appState.isArabic() ? true : false, child: Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 15.h, height: 15.h)), ], ).onPress(() { openRegionListBottomSheet(context); diff --git a/lib/presentation/book_appointment/widgets/clinic_card.dart b/lib/presentation/book_appointment/widgets/clinic_card.dart index 5cfc624..57315e6 100644 --- a/lib/presentation/book_appointment/widgets/clinic_card.dart +++ b/lib/presentation/book_appointment/widgets/clinic_card.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.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/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; @@ -15,6 +17,7 @@ class ClinicCard extends StatelessWidget { @override Widget build(BuildContext context) { + AppState appState = getIt.get(); return Container( padding: EdgeInsets.all(16.h), decoration: RoundedRectangleBorder().toSmoothCornerDecoration( @@ -33,7 +36,9 @@ class ClinicCard extends StatelessWidget { SizedBox(height: 16.h), Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded(child: (isLoading ? "Cardiology" : clinicsListResponseModel.clinicDescription!).toText16(isBold: true).toShimmer2(isShow: isLoading)), - Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, width: 15.h, height: 15.h, fit: BoxFit.contain, iconColor: AppColors.textColor).toShimmer2(isShow: isLoading), + Transform.flip( + flipX: appState.isArabic() ? true : false, + child: Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, width: 15.h, height: 15.h, fit: BoxFit.contain, iconColor: AppColors.textColor).toShimmer2(isShow: isLoading)), ]), ], ), diff --git a/lib/presentation/habib_wallet/wallet_payment_confirm_page.dart b/lib/presentation/habib_wallet/wallet_payment_confirm_page.dart index c10a025..115557f 100644 --- a/lib/presentation/habib_wallet/wallet_payment_confirm_page.dart +++ b/lib/presentation/habib_wallet/wallet_payment_confirm_page.dart @@ -87,13 +87,16 @@ class _WalletPaymentConfirmPageState extends State { ), SizedBox(width: 8.h), const Spacer(), - Utils.buildSvgWithAssets( - icon: AppAssets.forward_arrow_icon, - iconColor: AppColors.blackColor, - width: 18.h, - height: 13.h, - fit: BoxFit.contain, - ).toShimmer2(isShow: false), + Transform.flip( + flipX: appState.isArabic() ? true : false, + child: Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon, + iconColor: AppColors.blackColor, + width: 18.h, + height: 13.h, + fit: BoxFit.contain, + ).toShimmer2(isShow: false), + ), ], ).paddingSymmetrical(16.h, 16.h), ).paddingSymmetrical(24.h, 0.h).onPress(() { @@ -126,13 +129,16 @@ class _WalletPaymentConfirmPageState extends State { ), SizedBox(width: 8.h), const Spacer(), - Utils.buildSvgWithAssets( - icon: AppAssets.forward_arrow_icon, - iconColor: AppColors.blackColor, - width: 18.h, - height: 13.h, - fit: BoxFit.contain, - ).toShimmer2(isShow: false), + Transform.flip( + flipX: appState.isArabic() ? true : false, + child: Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon, + iconColor: AppColors.blackColor, + width: 18.h, + height: 13.h, + fit: BoxFit.contain, + ).toShimmer2(isShow: false), + ), ], ).paddingSymmetrical(16.h, 16.h), ).paddingSymmetrical(24.h, 0.h).onPress(() { diff --git a/lib/presentation/habib_wallet/widgets/hospital_list_item.dart b/lib/presentation/habib_wallet/widgets/hospital_list_item.dart index e2151f2..c5583e2 100644 --- a/lib/presentation/habib_wallet/widgets/hospital_list_item.dart +++ b/lib/presentation/habib_wallet/widgets/hospital_list_item.dart @@ -35,12 +35,15 @@ class HospitalListItemAdvancePayment extends StatelessWidget { children: [hospitalName], ), ), - Utils.buildSvgWithAssets( - icon: AppAssets.forward_arrow_icon, - iconColor: AppColors.blackColor, - width: 18, - height: 13, - fit: BoxFit.contain, + Transform.flip( + flipX: appState.isArabic() ? true : false, + child: Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon, + iconColor: AppColors.blackColor, + width: 18, + height: 13, + fit: BoxFit.contain, + ), ), ], ).paddingSymmetrical(16.h, 16.h), diff --git a/lib/presentation/lab/collapsing_list_view.dart b/lib/presentation/lab/collapsing_list_view.dart index 8f63f76..b18c6ee 100644 --- a/lib/presentation/lab/collapsing_list_view.dart +++ b/lib/presentation/lab/collapsing_list_view.dart @@ -5,12 +5,14 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_export.dart'; +import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; +import '../../core/dependencies.dart'; class CollapsingListView extends StatelessWidget { final String title; @@ -27,6 +29,7 @@ class CollapsingListView extends StatelessWidget { @override Widget build(BuildContext context) { + AppState appState = getIt.get(); return Scaffold( backgroundColor: AppColors.bgScaffoldColor, body: Column( @@ -42,11 +45,14 @@ class CollapsingListView extends StatelessWidget { surfaceTintColor: Colors.transparent, backgroundColor: AppColors.bgScaffoldColor, leading: isLeading - ? IconButton( - icon: Utils.buildSvgWithAssets(icon: isClose ? AppAssets.closeBottomNav : AppAssets.arrow_back, width: 32.h, height: 32.h), - padding: EdgeInsets.only(left: 12), - onPressed: () => Navigator.pop(context), - highlightColor: Colors.transparent, + ? Transform.flip( + flipX: appState.isArabic() ? true : false, + child: IconButton( + icon: Utils.buildSvgWithAssets(icon: isClose ? AppAssets.closeBottomNav : AppAssets.arrow_back, width: 32.h, height: 32.h), + padding: EdgeInsets.only(left: 12), + onPressed: () => Navigator.pop(context), + highlightColor: Colors.transparent, + ), ) : SizedBox.shrink(), flexibleSpace: LayoutBuilder( @@ -71,7 +77,7 @@ class CollapsingListView extends StatelessWidget { t, )!, child: Padding( - padding: EdgeInsets.only(left: leftPadding, bottom: bottomPadding), + padding: EdgeInsets.only(left: appState.isArabic() ? 0 : leftPadding, right: appState.isArabic() ? leftPadding : 0, bottom: bottomPadding), child: Row( spacing: 4.h, children: [ diff --git a/lib/presentation/medical_file/medical_file_page.dart b/lib/presentation/medical_file/medical_file_page.dart index d5e5d5a..43f0537 100644 --- a/lib/presentation/medical_file/medical_file_page.dart +++ b/lib/presentation/medical_file/medical_file_page.dart @@ -141,7 +141,7 @@ class _MedicalFilePageState extends State { children: [ AppCustomChipWidget( icon: AppAssets.file_icon, - labelText: "File no: ${appState.getAuthenticatedUser()!.patientId}", + labelText: "${LocaleKeys.fileNo.tr(context: context)}: ${appState.getAuthenticatedUser()!.patientId}", ), AppCustomChipWidget( icon: AppAssets.checkmark_icon, @@ -167,7 +167,7 @@ class _MedicalFilePageState extends State { ), AppCustomChipWidget( icon: AppAssets.blood_icon, - labelText: "Blood: ${appState.getUserBloodGroup}", + labelText: "${LocaleKeys.bloodType.tr(context: context)}: ${appState.getUserBloodGroup}", iconColor: AppColors.primaryRedColor, ), ], @@ -431,7 +431,9 @@ class _MedicalFilePageState extends State { ), ), // SizedBox(width: 40.h), - Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, width: 15.h, height: 15.h, fit: BoxFit.contain, iconColor: AppColors.textColor), + Transform.flip( + flipX: appState.isArabic() ? true : false, + child: Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, width: 15.h, height: 15.h, fit: BoxFit.contain, iconColor: AppColors.textColor)), ], ).onPress(() { prescriptionVM.setPrescriptionsDetailsLoading(); diff --git a/lib/presentation/medical_file/widgets/lab_rad_card.dart b/lib/presentation/medical_file/widgets/lab_rad_card.dart index aa53b2f..66021b2 100644 --- a/lib/presentation/medical_file/widgets/lab_rad_card.dart +++ b/lib/presentation/medical_file/widgets/lab_rad_card.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.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/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; @@ -15,6 +17,7 @@ class LabRadCard extends StatelessWidget { @override Widget build(BuildContext context) { + AppState appState = getIt.get(); return Container( decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.h, hasShadow: false), child: Column( @@ -49,13 +52,11 @@ class LabRadCard extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ SizedBox.shrink(), - Utils.buildSvgWithAssets( - icon: AppAssets.forward_arrow_icon, - width: 15.h, - height: 15.h, - fit: BoxFit.contain, - iconColor: AppColors.textColor - ).toShimmer2(isShow: false, radius: 12.h), + Transform.flip( + flipX: appState.isArabic() ? true : false, + child: Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, width: 15.h, height: 15.h, fit: BoxFit.contain, iconColor: AppColors.textColor) + .toShimmer2(isShow: false, radius: 12.h), + ), ], ) ], diff --git a/lib/presentation/medical_file/widgets/medical_file_appointment_card.dart b/lib/presentation/medical_file/widgets/medical_file_appointment_card.dart index a1a6f88..3e7b7c9 100644 --- a/lib/presentation/medical_file/widgets/medical_file_appointment_card.dart +++ b/lib/presentation/medical_file/widgets/medical_file_appointment_card.dart @@ -1,6 +1,8 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; +import 'package:hmg_patient_app_new/core/app_state.dart'; +import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/core/utils/date_util.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; @@ -28,11 +30,14 @@ class MedicalFileAppointmentCard extends StatelessWidget { @override Widget build(BuildContext context) { + AppState appState = getIt.get(); return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ AppCustomChipWidget( - richText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false).toText12().paddingSymmetrical(12.h, 0.h), + richText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false) + .toText12(color: AppointmentType.isArrived(patientAppointmentHistoryResponseModel) ? AppColors.textColor : AppColors.primaryRedColor, fontWeight: FontWeight.w500) + .paddingOnly(left: 8.h), icon: AppointmentType.isArrived(patientAppointmentHistoryResponseModel) ? AppAssets.appointment_calendar_icon : AppAssets.alarm_clock_icon, iconColor: AppointmentType.isArrived(patientAppointmentHistoryResponseModel) ? AppColors.textColor : AppColors.primaryRedColor, iconSize: 16.h, @@ -115,11 +120,14 @@ class MedicalFileAppointmentCard extends StatelessWidget { ), child: Padding( padding: EdgeInsets.all(10.h), - child: Utils.buildSvgWithAssets( - icon: AppAssets.forward_arrow_icon, - width: 10.h, - height: 10.h, - fit: BoxFit.contain, + child: Transform.flip( + flipX: appState.isArabic() ? true : false, + child: Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon, + width: 10.h, + height: 10.h, + fit: BoxFit.contain, + ), ), ), ).toShimmer2(isShow: myAppointmentsViewModel.isMyAppointmentsLoading).onPress(() { diff --git a/lib/presentation/medical_file/widgets/patient_sick_leave_card.dart b/lib/presentation/medical_file/widgets/patient_sick_leave_card.dart index e1999a7..ba1bee5 100644 --- a/lib/presentation/medical_file/widgets/patient_sick_leave_card.dart +++ b/lib/presentation/medical_file/widgets/patient_sick_leave_card.dart @@ -139,11 +139,14 @@ class PatientSickLeaveCard extends StatelessWidget { ), child: Padding( padding: EdgeInsets.all(10.h), - child: Utils.buildSvgWithAssets( - icon: AppAssets.forward_arrow_icon, - width: 10.h, - height: 10.h, - fit: BoxFit.contain, + child: Transform.flip( + flipX: _appState.isArabic() ? true : false, + child: Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon, + width: 10.h, + height: 10.h, + fit: BoxFit.contain, + ), ), ), ).toShimmer2(isShow: isLoading).onPress(() { diff --git a/lib/presentation/prescriptions/prescriptions_list_page.dart b/lib/presentation/prescriptions/prescriptions_list_page.dart index 3d246f3..3bca56d 100644 --- a/lib/presentation/prescriptions/prescriptions_list_page.dart +++ b/lib/presentation/prescriptions/prescriptions_list_page.dart @@ -4,6 +4,8 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.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/utils/date_util.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; @@ -42,6 +44,7 @@ class _PrescriptionsListPageState extends State { @override Widget build(BuildContext context) { + AppState appState = getIt.get(); prescriptionsViewModel = Provider.of(context, listen: false); return Scaffold( backgroundColor: AppColors.bgScaffoldColor, @@ -249,11 +252,14 @@ class _PrescriptionsListPageState extends State { ), child: Padding( padding: EdgeInsets.all(8.h), - child: Utils.buildSvgWithAssets( - icon: AppAssets.forward_arrow_icon, - width: 10.h, - height: 10.h, - fit: BoxFit.contain, + child: Transform.flip( + flipX: appState.isArabic() ? true : false, + child: Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon, + width: 10.h, + height: 10.h, + fit: BoxFit.contain, + ), ), ), ).onPress(() {