From f9e7c8988a7e3bd322378db43160812e48d4def2 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Tue, 16 Sep 2025 17:18:33 +0300 Subject: [PATCH 1/6] updates --- lib/core/api_consts.dart | 2 +- .../authentication/authentication_view_model.dart | 15 ++++++++------- lib/presentation/authentication/register.dart | 1 + 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index bad2e4c..42f10f4 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -726,7 +726,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/authentication/authentication_view_model.dart b/lib/features/authentication/authentication_view_model.dart index bb41af6..eb4cd78 100644 --- a/lib/features/authentication/authentication_view_model.dart +++ b/lib/features/authentication/authentication_view_model.dart @@ -48,6 +48,7 @@ class AuthenticationViewModel extends ChangeNotifier { final DialogService _dialogService; final NavigationService _navigationService; final LocalAuthService _localAuthService; + AuthenticationViewModel({ required AppState appState, required AuthenticationRepo authenticationRepo, @@ -106,7 +107,6 @@ class AuthenticationViewModel extends ChangeNotifier { } Future clearDefaultInputValues() async { - nationalIdController.clear(); phoneNumberController.clear(); emailController.clear(); @@ -622,19 +622,20 @@ class AuthenticationViewModel extends ChangeNotifier { } checkLastLoginStatus(Function() onSuccess) async { - Future.delayed(Duration(seconds: 1), () async { - if(cacheService.getBool(key: CacheConst.quickLoginEnabled) == null){ + if (cacheService.getBool(key: CacheConst.quickLoginEnabled) == null) { if (_appState.getSelectDeviceByImeiRespModelElement != null && (_appState.getSelectDeviceByImeiRespModelElement!.logInType == 1 || _appState.getSelectDeviceByImeiRespModelElement!.logInType == 4)) { - phoneNumberController.text = - (_appState.getAuthenticatedUser()!.mobileNumber!.startsWith("0") ? _appState.getAuthenticatedUser()!.mobileNumber!.replaceFirst("0", "") : _appState.getAuthenticatedUser()!.mobileNumber)!; + phoneNumberController.text = (_appState.getAuthenticatedUser()!.mobileNumber!.startsWith("0") + ? _appState.getAuthenticatedUser()!.mobileNumber!.replaceFirst("0", "") + : _appState.getAuthenticatedUser()!.mobileNumber)!; nationalIdController.text = _appState.getAuthenticatedUser()!.nationalityId!; onSuccess(); } else if ((loginTypeEnum == LoginTypeEnum.sms || loginTypeEnum == LoginTypeEnum.whatsapp && _appState.getSelectDeviceByImeiRespModelElement == null) && _appState.getAuthenticatedUser() != null) { - phoneNumberController.text = - (_appState.getAuthenticatedUser()!.mobileNumber!.startsWith("0") ? _appState.getAuthenticatedUser()!.mobileNumber!.replaceFirst("0", "") : _appState.getAuthenticatedUser()!.mobileNumber)!; + phoneNumberController.text = (_appState.getAuthenticatedUser()!.mobileNumber!.startsWith("0") + ? _appState.getAuthenticatedUser()!.mobileNumber!.replaceFirst("0", "") + : _appState.getAuthenticatedUser()!.mobileNumber)!; nationalIdController.text = _appState.getAuthenticatedUser()!.nationalityId!; onSuccess(); } diff --git a/lib/presentation/authentication/register.dart b/lib/presentation/authentication/register.dart index 8ec988d..f9da835 100644 --- a/lib/presentation/authentication/register.dart +++ b/lib/presentation/authentication/register.dart @@ -296,6 +296,7 @@ class _RegisterNew extends State { borderColor: AppColors.borderOnlyColor, textColor: AppColors.textColor, icon: AppAssets.whatsapp, + iconColor: null, ), ), ], From 15c07cb4e234c5d4a4226715207aa1e22c962f16 Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Wed, 17 Sep 2025 14:42:54 +0300 Subject: [PATCH 2/6] otp screen & register Uae & resend Activation Code. --- assets/langs/ar-SA.json | 3 +- assets/langs/en-US.json | 3 +- lib/core/api_consts.dart | 2 +- lib/core/app_state.dart | 2 +- .../authentication_view_model.dart | 30 ++++++---- .../widgets/otp_verification_screen.dart | 60 ++++++++++++++++--- lib/generated/locale_keys.g.dart | 3 +- lib/presentation/authentication/login.dart | 7 +++ lib/presentation/authentication/register.dart | 44 +++++++++++--- .../authentication/saved_login_screen.dart | 29 ++++----- lib/services/navigation_service.dart | 14 +---- 11 files changed, 138 insertions(+), 59 deletions(-) diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index fd34e55..fb6a919 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -817,5 +817,6 @@ "news": "أخبار", "ready": "جاهز", "enterValidNationalId": "الرجاء إدخال رقم الهوية الوطنية أو رقم الملف الصحيح", - "enterValidPhoneNumber": "الرجاء إدخال رقم هاتف صالح" + "enterValidPhoneNumber": "الرجاء إدخال رقم هاتف صالح", + "iAcceptThe" : "أوافق على" } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index b4cd340..81d20d4 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -813,5 +813,6 @@ "enterValidNationalId": "Please enter a valid national ID or file number", "enterValidPhoneNumber": "Please enter a valid phone number", "ready": "Ready", - "news": "News" + "news": "News", + "iAcceptThe" : "I Accept the" } \ No newline at end of file diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index bad2e4c..42f10f4 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -726,7 +726,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/core/app_state.dart b/lib/core/app_state.dart index 52500bf..4973e8d 100644 --- a/lib/core/app_state.dart +++ b/lib/core/app_state.dart @@ -62,7 +62,7 @@ class AppState { SelectDeviceByImeiRespModelElement? _selectDeviceByImeiRespModelElement; - void setSelectDeviceByImeiRespModelElement(SelectDeviceByImeiRespModelElement value) { + void setSelectDeviceByImeiRespModelElement(SelectDeviceByImeiRespModelElement? value) { _selectDeviceByImeiRespModelElement = value; } diff --git a/lib/features/authentication/authentication_view_model.dart b/lib/features/authentication/authentication_view_model.dart index bb41af6..0b76716 100644 --- a/lib/features/authentication/authentication_view_model.dart +++ b/lib/features/authentication/authentication_view_model.dart @@ -48,6 +48,7 @@ class AuthenticationViewModel extends ChangeNotifier { final DialogService _dialogService; final NavigationService _navigationService; final LocalAuthService _localAuthService; + AuthenticationViewModel({ required AppState appState, required AuthenticationRepo authenticationRepo, @@ -79,6 +80,8 @@ class AuthenticationViewModel extends ChangeNotifier { CalenderEnum calenderType = CalenderEnum.gregorian; LoginTypeEnum loginTypeEnum = LoginTypeEnum.sms; + final ValueNotifier otpScreenNotifier = ValueNotifier(false); + //================== String errorMsg = ''; @@ -106,7 +109,6 @@ class AuthenticationViewModel extends ChangeNotifier { } Future clearDefaultInputValues() async { - nationalIdController.clear(); phoneNumberController.clear(); emailController.clear(); @@ -394,12 +396,8 @@ class AuthenticationViewModel extends ChangeNotifier { return isUserComingForRegister; } - Future checkActivationCode({ - required String? activationCode, - required OTPTypeEnum otpTypeEnum, - required Function(String? message) onWrongActivationCode, - Function()? onResendActivation, - }) async { + Future checkActivationCode( + {required String? activationCode, required OTPTypeEnum otpTypeEnum, required Function(String? message) onWrongActivationCode, Function()? onResendActivation}) async { bool isForRegister = (_appState.getUserRegistrationPayload.healthId != null || _appState.getUserRegistrationPayload.patientOutSa == true || _appState.getUserRegistrationPayload.patientOutSa == 1); final request = RequestUtils.getCommonRequestWelcome( @@ -422,6 +420,7 @@ class AuthenticationViewModel extends ChangeNotifier { 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(); @@ -469,6 +468,7 @@ class AuthenticationViewModel extends ChangeNotifier { failure: failure, onUnHandledFailure: (failure) async { LoaderBottomSheet.hideLoader(); + otpScreenNotifier.value = true; await _dialogService.showCommonBottomSheetWithoutH(message: failure.message, label: LocaleKeys.notice.tr(), onOkPressed: () {}); }, onMessageStatusFailure: (failure) async { @@ -595,6 +595,7 @@ class AuthenticationViewModel extends ChangeNotifier { } Future onWrongActivationCode({String? message}) async { + otpScreenNotifier.value = true; await _dialogService.showErrorBottomSheet(message: message ?? "Something went wrong. ", onOkPressed: () {}); } @@ -622,19 +623,20 @@ class AuthenticationViewModel extends ChangeNotifier { } checkLastLoginStatus(Function() onSuccess) async { - Future.delayed(Duration(seconds: 1), () async { - if(cacheService.getBool(key: CacheConst.quickLoginEnabled) == null){ + if (cacheService.getBool(key: CacheConst.quickLoginEnabled) == null) { if (_appState.getSelectDeviceByImeiRespModelElement != null && (_appState.getSelectDeviceByImeiRespModelElement!.logInType == 1 || _appState.getSelectDeviceByImeiRespModelElement!.logInType == 4)) { - phoneNumberController.text = - (_appState.getAuthenticatedUser()!.mobileNumber!.startsWith("0") ? _appState.getAuthenticatedUser()!.mobileNumber!.replaceFirst("0", "") : _appState.getAuthenticatedUser()!.mobileNumber)!; + phoneNumberController.text = (_appState.getAuthenticatedUser()!.mobileNumber!.startsWith("0") + ? _appState.getAuthenticatedUser()!.mobileNumber!.replaceFirst("0", "") + : _appState.getAuthenticatedUser()!.mobileNumber)!; nationalIdController.text = _appState.getAuthenticatedUser()!.nationalityId!; onSuccess(); } else if ((loginTypeEnum == LoginTypeEnum.sms || loginTypeEnum == LoginTypeEnum.whatsapp && _appState.getSelectDeviceByImeiRespModelElement == null) && _appState.getAuthenticatedUser() != null) { - phoneNumberController.text = - (_appState.getAuthenticatedUser()!.mobileNumber!.startsWith("0") ? _appState.getAuthenticatedUser()!.mobileNumber!.replaceFirst("0", "") : _appState.getAuthenticatedUser()!.mobileNumber)!; + phoneNumberController.text = (_appState.getAuthenticatedUser()!.mobileNumber!.startsWith("0") + ? _appState.getAuthenticatedUser()!.mobileNumber!.replaceFirst("0", "") + : _appState.getAuthenticatedUser()!.mobileNumber)!; nationalIdController.text = _appState.getAuthenticatedUser()!.nationalityId!; onSuccess(); } @@ -921,4 +923,6 @@ class AuthenticationViewModel extends ChangeNotifier { }, ); } + +// === OTP Widget Logics ===// } diff --git a/lib/features/authentication/widgets/otp_verification_screen.dart b/lib/features/authentication/widgets/otp_verification_screen.dart index db7b1eb..7755ee6 100644 --- a/lib/features/authentication/widgets/otp_verification_screen.dart +++ b/lib/features/authentication/widgets/otp_verification_screen.dart @@ -7,8 +7,10 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; +import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/appbar/app_bar_widget.dart'; +import 'package:provider/provider.dart'; typedef OnDone = void Function(String text); @@ -90,6 +92,7 @@ class OTPWidgetState extends State with SingleTickerProviderStateMixi int currentIndex = 0; List strList = []; bool hasFocus = false; + AuthenticationViewModel? authVm; @override void didUpdateWidget(OTPWidget oldWidget) { @@ -124,6 +127,7 @@ class OTPWidgetState extends State with SingleTickerProviderStateMixi @override void initState() { super.initState(); + authVm = context.read(); focusNode = widget.focusNode ?? FocusNode(); _highlightAnimationController = AnimationController(vsync: this); _initTextController(); @@ -132,12 +136,15 @@ class OTPWidgetState extends State with SingleTickerProviderStateMixi widget.controller!.addListener(_controllerListener); } focusNode.addListener(_focusListener); + authVm?.otpScreenNotifier.addListener(_onOtpScreenNotifierChanged); } void _controllerListener() { if (mounted == true) { setState(() { _initTextController(); + text = widget.controller?.text ?? ""; + currentIndex = text.length; }); var onTextChanged = widget.onTextChanged; if (onTextChanged != null) { @@ -154,6 +161,41 @@ class OTPWidgetState extends State with SingleTickerProviderStateMixi } } + void onWrongOtpClear() { + if (mounted) { + setState(() { + text = ""; + currentIndex = 0; + strList.clear(); + _calculateStrList(); + }); + + // Clear the controller if it exists + if (widget.controller != null) { + widget.controller!.clear(); + } + + // Remove focus from the input + if (focusNode.hasFocus) { + focusNode.unfocus(); + } + + // Optionally refocus after a short delay to allow user to re-enter OTP + Future.delayed(const Duration(milliseconds: 100), () { + if (mounted && widget.autoFocus) { + FocusScope.of(context).requestFocus(focusNode); + } + }); + } + } + + void _onOtpScreenNotifierChanged() { + if (authVm?.otpScreenNotifier.value == true) { + onWrongOtpClear(); + authVm?.otpScreenNotifier.value = false; + } + } + void _initTextController() { if (widget.controller == null) { return; @@ -304,19 +346,17 @@ class OTPWidgetState extends State with SingleTickerProviderStateMixi ); } - Widget _buildPinCode(int i, BuildContext context) { Color pinBoxColor; if (widget.hasError) { pinBoxColor = widget.errorBorderColor; } else if (text.length == widget.maxLength) { - // Check for completion first, before individual box logic pinBoxColor = AppColors.successColor; } else if (i < text.length) { - pinBoxColor = AppColors.blackBgColor; // Custom color for filled boxes + pinBoxColor = AppColors.blackBgColor; } else { - pinBoxColor = widget.pinBoxColor; // Default white color + pinBoxColor = widget.pinBoxColor; } EdgeInsets insets; @@ -355,7 +395,6 @@ class OTPWidgetState extends State with SingleTickerProviderStateMixi ); } - // Widget _buildPinCode(int i, BuildContext context) { // Color pinBoxColor = widget.pinBoxColor; // @@ -455,7 +494,7 @@ class _OTPVerificationScreenState extends State { Timer? _resendTimer; int _resendTime = 120; bool _isOtpComplete = false; - bool _isVerifying = false; // Flag to prevent multiple verification calls + bool _isVerifying = false; @override void initState() { @@ -504,11 +543,18 @@ class _OTPVerificationScreenState extends State { }); _otpController.clear(); _startResendTimer(); - // autoFillOtp("1234"); widget.onResendOTPPressed(widget.phoneNumber); } } + void _clearOtpAndResetState() { + setState(() { + _isVerifying = false; + _isOtpComplete = false; + }); + _otpController.clear(); + } + String _getMaskedPhoneNumber() { final phone = widget.phoneNumber; return phone.length > 4 ? '05xxxxxx${phone.substring(phone.length - 2)}' : phone; diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 9a341a2..640c4cd 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -812,9 +812,10 @@ abstract class LocaleKeys { static const notNow = 'notNow'; static const pendingActivation = 'pendingActivation'; static const awaitingApproval = 'awaitingApproval'; + static const news = 'news'; static const ready = 'ready'; static const enterValidNationalId = 'enterValidNationalId'; static const enterValidPhoneNumber = 'enterValidPhoneNumber'; + static const iAcceptThe = 'iAcceptThe'; - static const news = 'news'; } diff --git a/lib/presentation/authentication/login.dart b/lib/presentation/authentication/login.dart index 2a8c744..f3d7664 100644 --- a/lib/presentation/authentication/login.dart +++ b/lib/presentation/authentication/login.dart @@ -4,6 +4,8 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/gestures.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/enums.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; @@ -153,6 +155,7 @@ class LoginScreenState extends State { required TextEditingController? phoneNumberController, required AuthenticationViewModel authViewModel, }) { + AppState appState = getIt(); context.showBottomSheet( isScrollControlled: true, isDismissible: false, @@ -180,6 +183,8 @@ class LoginScreenState extends State { onOkPress: () { Navigator.of(context).pop(); })) { + Navigator.of(context).pop(); + appState.setSelectDeviceByImeiRespModelElement(null); await authViewModel.checkUserAuthentication(otpTypeEnum: OTPTypeEnum.sms); } }, @@ -209,6 +214,8 @@ class LoginScreenState extends State { onOkPress: () { Navigator.of(context).pop(); })) { + Navigator.of(context).pop(); + appState.setSelectDeviceByImeiRespModelElement(null); await authViewModel.checkUserAuthentication(otpTypeEnum: OTPTypeEnum.whatsapp); } }, diff --git a/lib/presentation/authentication/register.dart b/lib/presentation/authentication/register.dart index 8ec988d..5150b0c 100644 --- a/lib/presentation/authentication/register.dart +++ b/lib/presentation/authentication/register.dart @@ -2,6 +2,8 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/gestures.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/enums.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; @@ -152,12 +154,36 @@ class _RegisterNew extends State { }, ), SizedBox(width: 12.h), - Expanded( - child: Text( - LocaleKeys.iAcceptTermsConditions.tr(), - style: context.dynamicTextStyle(fontSize: 14.fSize, fontWeight: FontWeight.w500, color: Color(0xFF2E3039)), - ), + Row( + children: [ + Text( + LocaleKeys.iAcceptThe.tr(), + style: context.dynamicTextStyle(fontSize: 14.fSize, fontWeight: FontWeight.w500, color: Color(0xFF2E3039)), + ), + GestureDetector( + onTap: () { + // Navigate to terms and conditions page + Navigator.of(context).pushNamed('/terms'); + }, + child: Text( + LocaleKeys.termsConditoins.tr(), + style: context.dynamicTextStyle( + fontSize: 14.fSize, + fontWeight: FontWeight.w500, + color: AppColors.primaryRedColor, + decoration: TextDecoration.underline, + decorationColor: AppColors.primaryRedBorderColor, + ), + ), + ), + ], ), + // Expanded( + // child: Text( + // LocaleKeys.iAcceptTermsConditions.tr().split("the").first, + // style: context.dynamicTextStyle(fontSize: 14.fSize, fontWeight: FontWeight.w500, color: Color(0xFF2E3039)), + // ), + // ), ], ), ), @@ -224,6 +250,7 @@ class _RegisterNew extends State { } void showRegisterModel({required BuildContext context, required AuthenticationViewModel authVM}) { + AppState appState = getIt.get(); showModalBottomSheet( context: context, isScrollControlled: true, @@ -235,7 +262,7 @@ class _RegisterNew extends State { child: SingleChildScrollView( child: GenericBottomSheet( countryCode: authVM.selectedCountrySignup.countryCode, - initialPhoneNumber: "", + initialPhoneNumber: authVM.phoneNumberController.text, textController: authVM.phoneNumberController, isEnableCountryDropdown: false, onCountryChange: authVM.onCountryChange, @@ -256,6 +283,7 @@ class _RegisterNew extends State { Navigator.of(context).pop(); }, )) { + appState.setSelectDeviceByImeiRespModelElement(null); await authVM.onRegistrationStart(otpTypeEnum: OTPTypeEnum.sms); } }, @@ -280,15 +308,14 @@ class _RegisterNew extends State { child: CustomButton( text: LocaleKeys.sendOTPWHATSAPP.tr(), onPressed: () async { - // Dismiss keyboard before validation FocusScope.of(context).unfocus(); - if (ValidationUtils.isValidatePhone( phoneNumber: authVM.phoneNumberController.text, onOkPress: () { Navigator.of(context).pop(); }, )) { + appState.setSelectDeviceByImeiRespModelElement(null); await authVM.onRegistrationStart(otpTypeEnum: OTPTypeEnum.whatsapp); } }, @@ -296,6 +323,7 @@ class _RegisterNew extends State { borderColor: AppColors.borderOnlyColor, textColor: AppColors.textColor, icon: AppAssets.whatsapp, + iconColor: null, ), ), ], diff --git a/lib/presentation/authentication/saved_login_screen.dart b/lib/presentation/authentication/saved_login_screen.dart index 0a6138c..073ff8b 100644 --- a/lib/presentation/authentication/saved_login_screen.dart +++ b/lib/presentation/authentication/saved_login_screen.dart @@ -12,6 +12,8 @@ import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/authentication/login.dart'; +import 'package:hmg_patient_app_new/presentation/home/landing_page.dart'; +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/appbar/app_bar_widget.dart'; import 'package:hmg_patient_app_new/widgets/bottomsheet/generic_bottom_sheet.dart'; @@ -164,17 +166,16 @@ class _SavedLogin extends State { Padding( padding: EdgeInsets.only(bottom: 10.h), child: CustomButton( - text: LocaleKeys.sendOTPSMS.tr(), - onPressed: () { - Navigator.of(context).pop(); - loginType = LoginTypeEnum.sms; - authVm.checkUserAuthentication(otpTypeEnum: OTPTypeEnum.sms); - }, - backgroundColor: AppColors.primaryRedColor, - borderColor: AppColors.primaryRedBorderColor, - textColor: AppColors.whiteColor, - icon: AppAssets.sms, - ), + text: LocaleKeys.sendOTPSMS.tr(), + onPressed: () { + Navigator.of(context).pop(); + loginType = LoginTypeEnum.sms; + authVm.checkUserAuthentication(otpTypeEnum: OTPTypeEnum.sms); + }, + backgroundColor: AppColors.primaryRedColor, + borderColor: AppColors.primaryRedColor, + textColor: AppColors.whiteColor, + icon: AppAssets.sms), ), Row( crossAxisAlignment: CrossAxisAlignment.center, @@ -247,13 +248,13 @@ class _SavedLogin extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( - child: Container( + child: SizedBox( height: 56, child: CustomButton( text: LocaleKeys.guest.tr(), onPressed: () { Navigator.of(context).pushReplacement( - MaterialPageRoute(builder: (BuildContext context) => LoginScreen()), + MaterialPageRoute(builder: (BuildContext context) => LandingNavigation()), ); }, backgroundColor: Color(0xffFEE9EA), @@ -277,7 +278,7 @@ class _SavedLogin extends State { text: LocaleKeys.switchAccount.tr(), onPressed: () async { await authVm.clearDefaultInputValues(); - Navigator.of(context).pushReplacement( + Navigator.of(context).push( MaterialPageRoute(builder: (BuildContext context) => LoginScreen()), ); }, diff --git a/lib/services/navigation_service.dart b/lib/services/navigation_service.dart index 9835bba..420c4cf 100644 --- a/lib/services/navigation_service.dart +++ b/lib/services/navigation_service.dart @@ -22,19 +22,9 @@ class NavigationService { navigatorKey.currentState?.pushReplacementNamed(routeName); } - Future pushToOtpScreen({ - required String phoneNumber, - required Function(int code) checkActivationCode, - required Function(String phoneNumber) onResendOTPPressed, - }) { + Future pushToOtpScreen({required String phoneNumber, required Function(int code) checkActivationCode, required Function(String phoneNumber) onResendOTPPressed}) { return navigatorKey.currentState!.push( - MaterialPageRoute( - builder: (_) => OTPVerificationScreen( - phoneNumber: phoneNumber, - checkActivationCode: checkActivationCode, - onResendOTPPressed: onResendOTPPressed, - ), - ), + MaterialPageRoute(builder: (_) => OTPVerificationScreen(phoneNumber: phoneNumber, checkActivationCode: checkActivationCode, onResendOTPPressed: onResendOTPPressed)), ); } From 5de5fc8be9d165078b2a92529d37dd8213b3f45b Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Wed, 17 Sep 2025 15:03:07 +0300 Subject: [PATCH 3/6] updates --- lib/features/insurance/insurance_repo.dart | 4 +- .../insurance/insurance_view_model.dart | 7 +- .../medical_file/medical_file_repo.dart | 4 +- .../patient_sickleave_response_model.dart | 4 +- .../my_appointments_view_model.dart | 180 ++++++------------ .../prescriptions_view_model.dart | 5 +- .../medical_file/medical_file_page.dart | 12 +- 7 files changed, 80 insertions(+), 136 deletions(-) diff --git a/lib/features/insurance/insurance_repo.dart b/lib/features/insurance/insurance_repo.dart index 874cc28..65f97ae 100644 --- a/lib/features/insurance/insurance_repo.dart +++ b/lib/features/insurance/insurance_repo.dart @@ -9,7 +9,7 @@ import 'package:hmg_patient_app_new/features/insurance/models/resp_models/patien import 'package:hmg_patient_app_new/services/logger_service.dart'; abstract class InsuranceRepo { - Future>>> getPatientInsuranceDetails({required String patientId}); + Future>>> getPatientInsuranceDetails(); Future>>> getPatientInsuranceCardHistory({required String patientId}); @@ -23,7 +23,7 @@ class InsuranceRepoImp implements InsuranceRepo { InsuranceRepoImp({required this.loggerService, required this.apiClient}); @override - Future>>> getPatientInsuranceDetails({required String patientId}) async { + Future>>> getPatientInsuranceDetails() async { Map mapDevice = {}; try { diff --git a/lib/features/insurance/insurance_view_model.dart b/lib/features/insurance/insurance_view_model.dart index 527c180..8319634 100644 --- a/lib/features/insurance/insurance_view_model.dart +++ b/lib/features/insurance/insurance_view_model.dart @@ -49,10 +49,13 @@ class InsuranceViewModel extends ChangeNotifier { } Future getPatientInsuranceDetails({Function(dynamic)? onSuccess, Function(String)? onError}) async { - final result = await insuranceRepo.getPatientInsuranceDetails(patientId: "1231755"); + final result = await insuranceRepo.getPatientInsuranceDetails(); result.fold( - (failure) async => await errorHandlerService.handleError(failure: failure), + // (failure) async => await errorHandlerService.handleError(failure: failure), + (failure) async { + isInsuranceLoading = false; + }, (apiResponse) { if (apiResponse.messageStatus == 2) { // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); diff --git a/lib/features/medical_file/medical_file_repo.dart b/lib/features/medical_file/medical_file_repo.dart index affe564..bbb4fcd 100644 --- a/lib/features/medical_file/medical_file_repo.dart +++ b/lib/features/medical_file/medical_file_repo.dart @@ -91,13 +91,13 @@ class MedicalFileRepoImp implements MedicalFileRepo { // throw Exception("lab list is empty"); // } - final vaccinesList = list.map((item) => PatientSickLeavesResponseModel.fromJson(item as Map)).toList().cast(); + final sickLeavesList = list.map((item) => PatientSickLeavesResponseModel.fromJson(item as Map)).toList().cast(); apiResponse = GenericApiModel>( messageStatus: messageStatus, statusCode: statusCode, errorMessage: null, - data: vaccinesList, + data: sickLeavesList, ); } catch (e) { failure = DataParsingFailure(e.toString()); diff --git a/lib/features/medical_file/models/patient_sickleave_response_model.dart b/lib/features/medical_file/models/patient_sickleave_response_model.dart index b0381a8..3bf732c 100644 --- a/lib/features/medical_file/models/patient_sickleave_response_model.dart +++ b/lib/features/medical_file/models/patient_sickleave_response_model.dart @@ -14,7 +14,7 @@ class PatientSickLeavesResponseModel { num? actualDoctorRate; String? appointmentDate; String? clinicName; - double? decimalDoctorRate; + num? decimalDoctorRate; String? doctorImageURL; String? doctorName; num? doctorRate; @@ -32,7 +32,7 @@ class PatientSickLeavesResponseModel { String? isInOutPatientDescriptionN; bool? isLiveCareAppointment; dynamic medicalDirectorApprovedStatus; - int? noOfPatientsRate; + num? noOfPatientsRate; dynamic patientName; String? projectName; String? qR; diff --git a/lib/features/my_appointments/my_appointments_view_model.dart b/lib/features/my_appointments/my_appointments_view_model.dart index ce303de..1ada721 100644 --- a/lib/features/my_appointments/my_appointments_view_model.dart +++ b/lib/features/my_appointments/my_appointments_view_model.dart @@ -3,8 +3,7 @@ import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/core/cache_consts.dart' show CacheConst; import 'package:hmg_patient_app_new/core/utils/utils.dart' show Utils; import 'package:hmg_patient_app_new/features/my_appointments/models/facility_selection.dart'; -import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/doctor_list_api_response.dart' - show RegionList, PatientDoctorAppointmentListByRegion; +import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/doctor_list_api_response.dart' show RegionList, PatientDoctorAppointmentListByRegion; 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/models/resp_models/patient_appointment_share_response_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_repo.dart'; @@ -13,7 +12,6 @@ import 'package:location/location.dart' show Location; import '../../core/utils/doctor_response_mapper.dart' show DoctorMapper; - class MyAppointmentsViewModel extends ChangeNotifier { int selectedTabIndex = 0; @@ -26,16 +24,12 @@ class MyAppointmentsViewModel extends ChangeNotifier { bool isTimeLineAppointmentsLoading = false; bool isPatientMyDoctorsLoading = false; - List patientAppointmentsHistoryList = - []; + List patientAppointmentsHistoryList = []; - List - patientUpcomingAppointmentsHistoryList = []; - List - patientArrivedAppointmentsHistoryList = []; + List patientUpcomingAppointmentsHistoryList = []; + List patientArrivedAppointmentsHistoryList = []; - List patientTimelineAppointmentsList = - []; + List patientTimelineAppointmentsList = []; List patientMyDoctorsList = []; @@ -46,15 +40,13 @@ class MyAppointmentsViewModel extends ChangeNotifier { FacilitySelection currentlySelectedFacility = FacilitySelection.ALL; bool isRegionListLoading = false; - MyAppointmentsViewModel( - {required this.myAppointmentsRepo, required this.errorHandlerService,required this.appState}); + MyAppointmentsViewModel({required this.myAppointmentsRepo, required this.errorHandlerService, required this.appState}); void onTabChange(int index) { selectedTabIndex = index; notifyListeners(); } - initAppointmentsViewModel() { patientAppointmentsHistoryList.clear(); patientUpcomingAppointmentsHistoryList.clear(); @@ -89,8 +81,7 @@ class MyAppointmentsViewModel extends ChangeNotifier { notifyListeners(); } - setAppointmentReminder( - bool value, PatientAppointmentHistoryResponseModel item) { + setAppointmentReminder(bool value, PatientAppointmentHistoryResponseModel item) { int index = patientAppointmentsHistoryList.indexOf(item); if (index != -1) { patientAppointmentsHistoryList[index].hasReminder = value; @@ -98,18 +89,12 @@ class MyAppointmentsViewModel extends ChangeNotifier { } } - Future getPatientAppointments( - bool isActiveAppointment, bool isArrivedAppointments, - {Function(dynamic)? onSuccess, Function(String)? onError}) async { - final result = await myAppointmentsRepo.getPatientAppointments( - isActiveAppointment: isActiveAppointment, - isArrivedAppointments: isArrivedAppointments); - final resultArrived = await myAppointmentsRepo.getPatientAppointments( - isActiveAppointment: false, isArrivedAppointments: true); + Future getPatientAppointments(bool isActiveAppointment, bool isArrivedAppointments, {Function(dynamic)? onSuccess, Function(String)? onError}) async { + final result = await myAppointmentsRepo.getPatientAppointments(isActiveAppointment: isActiveAppointment, isArrivedAppointments: isArrivedAppointments); + final resultArrived = await myAppointmentsRepo.getPatientAppointments(isActiveAppointment: false, isArrivedAppointments: true); result.fold( - (failure) async => - await errorHandlerService.handleError(failure: failure), + (failure) async => await errorHandlerService.handleError(failure: failure), (apiResponse) { if (apiResponse.messageStatus == 2) { // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); @@ -125,8 +110,7 @@ class MyAppointmentsViewModel extends ChangeNotifier { ); resultArrived.fold( - (failure) async => - await errorHandlerService.handleError(failure: failure), + (failure) async => await errorHandlerService.handleError(failure: failure), (apiResponse) { if (apiResponse.messageStatus == 2) { // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); @@ -141,27 +125,19 @@ class MyAppointmentsViewModel extends ChangeNotifier { }, ); - patientAppointmentsHistoryList - .addAll(patientUpcomingAppointmentsHistoryList); - patientAppointmentsHistoryList - .addAll(patientArrivedAppointmentsHistoryList); + patientAppointmentsHistoryList.addAll(patientUpcomingAppointmentsHistoryList); + patientAppointmentsHistoryList.addAll(patientArrivedAppointmentsHistoryList); - print( - 'Upcoming Appointments: ${patientUpcomingAppointmentsHistoryList.length}'); - print( - 'Arrived Appointments: ${patientArrivedAppointmentsHistoryList.length}'); + print('Upcoming Appointments: ${patientUpcomingAppointmentsHistoryList.length}'); + print('Arrived Appointments: ${patientArrivedAppointmentsHistoryList.length}'); print('All Appointments: ${patientAppointmentsHistoryList.length}'); } - Future getPatientShareAppointment( - int projectID, int clinicID, String appointmentNo, - {Function(dynamic)? onSuccess, Function(String)? onError}) async { - final result = await myAppointmentsRepo.getPatientShareAppointment( - projectID: projectID, clinicID: clinicID, appointmentNo: appointmentNo); + Future getPatientShareAppointment(int projectID, int clinicID, String appointmentNo, {Function(dynamic)? onSuccess, Function(String)? onError}) async { + final result = await myAppointmentsRepo.getPatientShareAppointment(projectID: projectID, clinicID: clinicID, appointmentNo: appointmentNo); result.fold( - (failure) async => - await errorHandlerService.handleError(failure: failure), + (failure) async => await errorHandlerService.handleError(failure: failure), (apiResponse) { if (apiResponse.messageStatus == 2) { // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); @@ -178,19 +154,11 @@ class MyAppointmentsViewModel extends ChangeNotifier { } Future addAdvanceNumberRequest( - {required String advanceNumber, - required String paymentReference, - required String appointmentNo, - Function(dynamic)? onSuccess, - Function(String)? onError}) async { - final result = await myAppointmentsRepo.addAdvanceNumberRequest( - advanceNumber: advanceNumber, - paymentReference: paymentReference, - appointmentNo: appointmentNo); + {required String advanceNumber, required String paymentReference, required String appointmentNo, Function(dynamic)? onSuccess, Function(String)? onError}) async { + final result = await myAppointmentsRepo.addAdvanceNumberRequest(advanceNumber: advanceNumber, paymentReference: paymentReference, appointmentNo: appointmentNo); result.fold( - (failure) async => - await errorHandlerService.handleError(failure: failure), + (failure) async => await errorHandlerService.handleError(failure: failure), (apiResponse) { if (apiResponse.messageStatus == 2) { // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); @@ -205,21 +173,11 @@ class MyAppointmentsViewModel extends ChangeNotifier { } Future generateAppointmentQR( - {required int clinicID, - required int projectID, - required String appointmentNo, - required int isFollowUp, - Function(dynamic)? onSuccess, - Function(String)? onError}) async { - final result = await myAppointmentsRepo.generateAppointmentQR( - clinicID: clinicID, - projectID: projectID, - appointmentNo: appointmentNo, - isFollowUp: isFollowUp); + {required int clinicID, required int projectID, required String appointmentNo, required int isFollowUp, Function(dynamic)? onSuccess, Function(String)? onError}) async { + final result = await myAppointmentsRepo.generateAppointmentQR(clinicID: clinicID, projectID: projectID, appointmentNo: appointmentNo, isFollowUp: isFollowUp); result.fold( - (failure) async => - await errorHandlerService.handleError(failure: failure), + (failure) async => await errorHandlerService.handleError(failure: failure), (apiResponse) { if (apiResponse.messageStatus == 2) { // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); @@ -233,18 +191,11 @@ class MyAppointmentsViewModel extends ChangeNotifier { ); } - Future cancelAppointment( - {required PatientAppointmentHistoryResponseModel - patientAppointmentHistoryResponseModel, - Function(dynamic)? onSuccess, - Function(String)? onError}) async { - final result = await myAppointmentsRepo.cancelAppointment( - patientAppointmentHistoryResponseModel: - patientAppointmentHistoryResponseModel); + Future cancelAppointment({required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel, Function(dynamic)? onSuccess, Function(String)? onError}) async { + final result = await myAppointmentsRepo.cancelAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel); result.fold( - (failure) async => - await errorHandlerService.handleError(failure: failure), + (failure) async => await errorHandlerService.handleError(failure: failure), (apiResponse) { if (apiResponse.messageStatus == 2) { onError!(apiResponse.errorMessage!); @@ -259,18 +210,11 @@ class MyAppointmentsViewModel extends ChangeNotifier { ); } - Future confirmAppointment( - {required PatientAppointmentHistoryResponseModel - patientAppointmentHistoryResponseModel, - Function(dynamic)? onSuccess, - Function(String)? onError}) async { - final result = await myAppointmentsRepo.confirmAppointment( - patientAppointmentHistoryResponseModel: - patientAppointmentHistoryResponseModel); + Future confirmAppointment({required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel, Function(dynamic)? onSuccess, Function(String)? onError}) async { + final result = await myAppointmentsRepo.confirmAppointment(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel); result.fold( - (failure) async => - await errorHandlerService.handleError(failure: failure), + (failure) async => await errorHandlerService.handleError(failure: failure), (apiResponse) { if (apiResponse.messageStatus == 2) { onError!(apiResponse.errorMessage!); @@ -307,8 +251,7 @@ class MyAppointmentsViewModel extends ChangeNotifier { patientType: patientType); result.fold( - (failure) async => - await errorHandlerService.handleError(failure: failure), + (failure) async => await errorHandlerService.handleError(failure: failure), (apiResponse) { if (apiResponse.messageStatus == 2) { // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); @@ -323,21 +266,15 @@ class MyAppointmentsViewModel extends ChangeNotifier { } Future sendCheckInNfcRequest( - {required PatientAppointmentHistoryResponseModel - patientAppointmentHistoryResponseModel, + {required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel, required String scannedCode, required int checkInType, Function(dynamic)? onSuccess, Function(String)? onError}) async { - final result = await myAppointmentsRepo.sendCheckInNfcRequest( - patientAppointmentHistoryResponseModel: - patientAppointmentHistoryResponseModel, - scannedCode: scannedCode, - checkInType: checkInType); + final result = await myAppointmentsRepo.sendCheckInNfcRequest(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel, scannedCode: scannedCode, checkInType: checkInType); result.fold( - (failure) async => - await errorHandlerService.handleError(failure: failure), + (failure) async => await errorHandlerService.handleError(failure: failure), (apiResponse) { if (apiResponse.messageStatus == 2) { onError!(apiResponse.errorMessage!); @@ -352,13 +289,14 @@ class MyAppointmentsViewModel extends ChangeNotifier { ); } - Future getPatientMyDoctors( - {Function(dynamic)? onSuccess, Function(String)? onError}) async { + Future getPatientMyDoctors({Function(dynamic)? onSuccess, Function(String)? onError}) async { final result = await myAppointmentsRepo.getPatientDoctorsList(); result.fold( - (failure) async => - await errorHandlerService.handleError(failure: failure), + // (failure) async => await errorHandlerService.handleError(failure: failure), + (failure) async { + isPatientMyDoctorsLoading = false; + }, (apiResponse) { if (apiResponse.messageStatus == 2) { // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); @@ -375,7 +313,7 @@ class MyAppointmentsViewModel extends ChangeNotifier { } Future getRegionMappedProjectList() async { - if(hospitalList != null && hospitalList!.registeredDoctorMap != null && hospitalList!.registeredDoctorMap!.isNotEmpty){ + if (hospitalList != null && hospitalList!.registeredDoctorMap != null && hospitalList!.registeredDoctorMap!.isNotEmpty) { filteredHospitalList = hospitalList; return; } @@ -384,21 +322,18 @@ class MyAppointmentsViewModel extends ChangeNotifier { final result = await myAppointmentsRepo.getProjectList(); result.fold( - (failure) async => - await errorHandlerService.handleError(failure: failure), + (failure) async => await errorHandlerService.handleError(failure: failure), (apiResponse) async { if (apiResponse.messageStatus == 2) { // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); } else if (apiResponse.messageStatus == 1) { var projectList = apiResponse.data!; - hospitalList = await DoctorMapper.getMappedHospitals(projectList, - isArabic: false); + hospitalList = await DoctorMapper.getMappedHospitals(projectList, isArabic: false); var lat = await Utils.getNumFromPrefs(CacheConst.userLat); var lng = await Utils.getNumFromPrefs(CacheConst.userLong); var isLocationEnabled = (lat != 0) && (lng != 0); - hospitalList = - await DoctorMapper.sortList(isLocationEnabled, hospitalList!); + hospitalList = await DoctorMapper.sortList(isLocationEnabled, hospitalList!); isRegionListLoading = false; filteredHospitalList = hospitalList; @@ -414,22 +349,21 @@ class MyAppointmentsViewModel extends ChangeNotifier { } void filterHospitalListByString(String? value, String? selectedRegionId, bool isHMG) { - if(value ==null || value.isEmpty){ + if (value == null || value.isEmpty) { filteredHospitalList = hospitalList; } else { filteredHospitalList = RegionList(); - var list = isHMG - ? hospitalList?.registeredDoctorMap![selectedRegionId]!.hmgDoctorList - : hospitalList?.registeredDoctorMap![selectedRegionId]!.hmcDoctorList; + var list = isHMG ? hospitalList?.registeredDoctorMap![selectedRegionId]!.hmgDoctorList : hospitalList?.registeredDoctorMap![selectedRegionId]!.hmcDoctorList; - if(list != null && list.isEmpty){ notifyListeners(); return;} + if (list != null && list.isEmpty) { + notifyListeners(); + return; + } - var filteredList = list!.where((element) => - element.filterName!.toLowerCase().contains(value.toLowerCase()) - ).toList(); + var filteredList = list!.where((element) => element.filterName!.toLowerCase().contains(value.toLowerCase())).toList(); var regionData = PatientDoctorAppointmentListByRegion(); - if(isHMG){ + if (isHMG) { regionData.hmgDoctorList = filteredList; regionData.hmgSize = filteredList.length; } else { @@ -437,19 +371,17 @@ class MyAppointmentsViewModel extends ChangeNotifier { regionData.hmcSize = filteredList.length; } - filteredHospitalList?.registeredDoctorMap = { - selectedRegionId! : regionData - }; + filteredHospitalList?.registeredDoctorMap = {selectedRegionId!: regionData}; } notifyListeners(); } - Future isLocationEnabled() async{ - return await Location().serviceEnabled(); + Future isLocationEnabled() async { + return await Location().serviceEnabled(); } bool getLocationStatus() { - bool isLocationAvaiable = false; + bool isLocationAvaiable = false; isLocationEnabled().then((value) => isLocationAvaiable = value); return isLocationAvaiable; } diff --git a/lib/features/prescriptions/prescriptions_view_model.dart b/lib/features/prescriptions/prescriptions_view_model.dart index 535d78f..f5f32a7 100644 --- a/lib/features/prescriptions/prescriptions_view_model.dart +++ b/lib/features/prescriptions/prescriptions_view_model.dart @@ -68,7 +68,10 @@ class PrescriptionsViewModel extends ChangeNotifier { final result = await prescriptionsRepo.getPatientPrescriptionOrders(patientId: "1231755"); result.fold( - (failure) async => await errorHandlerService.handleError(failure: failure), + // (failure) async => await errorHandlerService.handleError(failure: failure), + (failure) async { + isPrescriptionsOrdersLoading = false; + }, (apiResponse) { if (apiResponse.messageStatus == 2) { // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); diff --git a/lib/presentation/medical_file/medical_file_page.dart b/lib/presentation/medical_file/medical_file_page.dart index 871a97c..acaf622 100644 --- a/lib/presentation/medical_file/medical_file_page.dart +++ b/lib/presentation/medical_file/medical_file_page.dart @@ -70,6 +70,7 @@ class _MedicalFilePageState extends State { insuranceViewModel.initInsuranceProvider(); medicalFileViewModel.setIsPatientSickLeaveListLoading(true); medicalFileViewModel.getPatientSickLeaveList(); + medicalFileViewModel.onTabChanged(0); } }); super.initState(); @@ -647,9 +648,14 @@ class _MedicalFilePageState extends State { Consumer(builder: (context, insuranceVM, child) { return insuranceVM.isInsuranceLoading ? const MoviesShimmerWidget().paddingSymmetrical(24.h, 0.0) - : PatientInsuranceCard( - insuranceCardDetailsModel: insuranceVM.patientInsuranceList.first, - isInsuranceExpired: DateTime.now().isAfter(DateUtil.convertStringToDate(insuranceVM.patientInsuranceList.first.cardValidTo))); + : insuranceVM.patientInsuranceList.isNotEmpty + ? PatientInsuranceCard( + insuranceCardDetailsModel: insuranceVM.patientInsuranceList.first, + isInsuranceExpired: DateTime.now().isAfter( + DateUtil.convertStringToDate(insuranceVM.patientInsuranceList.first.cardValidTo), + ), + ) + : SizedBox.shrink(); }), SizedBox(height: 10.h), GridView( From 3ab2546d102237baa9a41d13342fcecb5cb6ed35 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Wed, 17 Sep 2025 15:06:12 +0300 Subject: [PATCH 4/6] merge fixes --- .../my_appointments_view_model.dart | 85 ------------------- 1 file changed, 85 deletions(-) diff --git a/lib/features/my_appointments/my_appointments_view_model.dart b/lib/features/my_appointments/my_appointments_view_model.dart index 1ada721..779f2b6 100644 --- a/lib/features/my_appointments/my_appointments_view_model.dart +++ b/lib/features/my_appointments/my_appointments_view_model.dart @@ -1,14 +1,9 @@ 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' show CacheConst; -import 'package:hmg_patient_app_new/core/utils/utils.dart' show Utils; -import 'package:hmg_patient_app_new/features/my_appointments/models/facility_selection.dart'; -import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/doctor_list_api_response.dart' show RegionList, PatientDoctorAppointmentListByRegion; 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/models/resp_models/patient_appointment_share_response_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_repo.dart'; import 'package:hmg_patient_app_new/services/error_handler_service.dart'; -import 'package:location/location.dart' show Location; import '../../core/utils/doctor_response_mapper.dart' show DoctorMapper; @@ -35,11 +30,6 @@ class MyAppointmentsViewModel extends ChangeNotifier { PatientAppointmentShareResponseModel? patientAppointmentShareResponseModel; - RegionList? hospitalList; - RegionList? filteredHospitalList; - FacilitySelection currentlySelectedFacility = FacilitySelection.ALL; - bool isRegionListLoading = false; - MyAppointmentsViewModel({required this.myAppointmentsRepo, required this.errorHandlerService, required this.appState}); void onTabChange(int index) { @@ -57,7 +47,6 @@ class MyAppointmentsViewModel extends ChangeNotifier { isAppointmentPatientShareLoading = true; isTimeLineAppointmentsLoading = true; isPatientMyDoctorsLoading = true; - isRegionListLoading = true; notifyListeners(); } @@ -311,78 +300,4 @@ class MyAppointmentsViewModel extends ChangeNotifier { }, ); } - - Future getRegionMappedProjectList() async { - if (hospitalList != null && hospitalList!.registeredDoctorMap != null && hospitalList!.registeredDoctorMap!.isNotEmpty) { - filteredHospitalList = hospitalList; - return; - } - isRegionListLoading = true; - notifyListeners(); - final result = await myAppointmentsRepo.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) { - var projectList = apiResponse.data!; - hospitalList = await DoctorMapper.getMappedHospitals(projectList, isArabic: false); - var lat = await Utils.getNumFromPrefs(CacheConst.userLat); - - var lng = await Utils.getNumFromPrefs(CacheConst.userLong); - var isLocationEnabled = (lat != 0) && (lng != 0); - hospitalList = await DoctorMapper.sortList(isLocationEnabled, hospitalList!); - - isRegionListLoading = false; - filteredHospitalList = hospitalList; - notifyListeners(); - } - }, - ); - } - - void setSelectedFacility(FacilitySelection selection) { - currentlySelectedFacility = selection; - notifyListeners(); - } - - void filterHospitalListByString(String? value, String? selectedRegionId, bool isHMG) { - if (value == null || value.isEmpty) { - filteredHospitalList = hospitalList; - } else { - filteredHospitalList = RegionList(); - - var list = isHMG ? hospitalList?.registeredDoctorMap![selectedRegionId]!.hmgDoctorList : hospitalList?.registeredDoctorMap![selectedRegionId]!.hmcDoctorList; - - if (list != null && list.isEmpty) { - notifyListeners(); - return; - } - - var filteredList = list!.where((element) => element.filterName!.toLowerCase().contains(value.toLowerCase())).toList(); - var regionData = PatientDoctorAppointmentListByRegion(); - if (isHMG) { - regionData.hmgDoctorList = filteredList; - regionData.hmgSize = filteredList.length; - } else { - regionData.hmcDoctorList = filteredList; - regionData.hmcSize = filteredList.length; - } - - filteredHospitalList?.registeredDoctorMap = {selectedRegionId!: regionData}; - } - notifyListeners(); - } - - Future isLocationEnabled() async { - return await Location().serviceEnabled(); - } - - bool getLocationStatus() { - bool isLocationAvaiable = false; - isLocationEnabled().then((value) => isLocationAvaiable = value); - return isLocationAvaiable; - } } From 5de8314f3fd8293849e55b5514451facc05d253b Mon Sep 17 00:00:00 2001 From: aamir-csol Date: Wed, 17 Sep 2025 15:38:57 +0300 Subject: [PATCH 5/6] otp screen & register Uae & resend Activation Code. --- assets/langs/ar-SA.json | 7 +- assets/langs/en-US.json | 4 +- lib/core/api_consts.dart | 2 +- lib/extensions/string_extensions.dart | 9 ++- .../authentication_view_model.dart | 20 ++++-- lib/generated/locale_keys.g.dart | 4 +- .../authentication/register_step2.dart | 49 +++++++++----- lib/widgets/dropdown/dropdown_widget.dart | 38 ++++++----- lib/widgets/input_widget.dart | 66 ++++++++++--------- 9 files changed, 120 insertions(+), 79 deletions(-) diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 4504325..08ef65c 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -817,13 +817,14 @@ "news": "أخبار", "ready": "جاهز", "enterValidNationalId": "الرجاء إدخال رقم الهوية الوطنية أو رقم الملف الصحيح", - "enterValidPhoneNumber": "الرجاء إدخال رقم هاتف صالح" + "enterValidPhoneNumber": "الرجاء إدخال رقم هاتف صالح", "medicalCentersWithCount": "{count} مراكز طبية", "medicalCenters": "مراكز طبية", "hospitalsWithCount": "{count} مستشفيات", "selectRegion": "اختر المنطقة", "selectFacility": "اختر المرافق", "selectFacilitiesSubTitle": "يرجى اختيار المرفق للموعد", - "selectHospitalSubTitle": "يرجى اختيار المستشفى للموعد" - "iAcceptThe" : "أوافق على" + "selectHospitalSubTitle": "يرجى اختيار المستشفى للموعد", + "iAcceptThe" : "أوافق على", + "personalDetailsVerification": "التحقق من التفاصيل الشخصية", } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index b3c1ffb..b8506f4 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -821,5 +821,7 @@ "selectFacilitiesSubTitle": "Please select the facility for the appointment", "selectHospitalSubTitle": "Please select the hospital for the appointment", "news": "News", - "iAcceptThe" : "I Accept the" + "iAcceptThe" : "I Accept the", + "personalDetailsVerification": "Personal Details Verification" + } \ No newline at end of file diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index 6c9a835..bd2eb71 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/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index 509385c..41b604f 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -221,10 +221,15 @@ extension EmailValidator on String { style: TextStyle(height: 23 / 24, color: color ?? AppColors.blackColor, fontSize: 24.fSize, letterSpacing: -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal), ); - Widget toText26({Color? color, bool isBold = false, double? height, bool isCenter = false}) => Text( + Widget toText26({Color? color, bool isBold = false, double? height, bool isCenter = false, FontWeight? weight, double? letterSpacing}) => Text( this, textAlign: isCenter ? TextAlign.center : null, - style: TextStyle(height: height ?? 23 / 26, color: color ?? AppColors.blackColor, fontSize: 26.fSize, letterSpacing: -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal), + style: TextStyle( + height: height ?? 23 / 26, + color: color ?? AppColors.blackColor, + fontSize: 26.fSize, + letterSpacing: letterSpacing ?? -1, + fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal)), ); Widget toText28({Color? color, bool isBold = false, double? height, bool isCenter = false}) => Text( diff --git a/lib/features/authentication/authentication_view_model.dart b/lib/features/authentication/authentication_view_model.dart index 0b76716..3c05b52 100644 --- a/lib/features/authentication/authentication_view_model.dart +++ b/lib/features/authentication/authentication_view_model.dart @@ -161,6 +161,10 @@ class AuthenticationViewModel extends ChangeNotifier { notifyListeners(); } + void clearEmailInput() { + emailController.text = ""; + } + void onUAEUserCountrySelection(String? value) { pickedCountryByUAEUser = countriesList!.firstWhere((element) => element.name == value); notifyListeners(); @@ -676,21 +680,27 @@ class AuthenticationViewModel extends ChangeNotifier { } Future onRegistrationComplete() async { - LoaderBottomSheet.showLoader(); + // LoaderBottomSheet.showLoader(); + LoadingUtils.showFullScreenLoader(loadingText: "Setting up your medical file.\nMay take a moment."); + var request = RequestUtils.getUserSignupCompletionRequest(fullName: nameController.text, emailAddress: emailController.text, gender: genderType, maritalStatus: maritalStatus); final resultEither = await _authenticationRepo.registerUser(registrationPayloadDataModelRequest: request); resultEither.fold((failure) async => await _errorHandlerService.handleError(failure: failure), (apiResponse) async { if (apiResponse.data is String) { //TODO: This Section Need to Be Testing. + LoadingUtils.hideFullScreenLoader(); _dialogService.showExceptionBottomSheet(message: apiResponse.data, onOkPressed: () {}, onCancelPressed: () {}); //TODO: Here We Need to Show a Dialog Of Something in the case of Fail With OK and Cancel and the Display Variable WIll be result. } else { - print(apiResponse.data as Map); + LoadingUtils.hideFullScreenLoader(); if (apiResponse.data["MessageStatus"] == 1) { - LoaderBottomSheet.hideLoader(); + LoadingUtils.showFullScreenLoader(isSuccessDialog: true); //TODO: Here We Need to Show a Dialog Of Something in the case of Success. await clearDefaultInputValues(); // This will Clear All Default Values Of User. - _navigationService.pushAndReplace(AppRoutes.loginScreen); + Future.delayed(Duration(seconds: 1), () { + LoadingUtils.hideFullScreenLoader(); + _navigationService.pushAndReplace(AppRoutes.loginScreen); + }); } } }); @@ -738,6 +748,8 @@ class AuthenticationViewModel extends ChangeNotifier { } else { //TODO: Here Hide Loader And Show TOAST //TODO: if (response['ErrorCode'] == '-986') Toast With OK, And Show response as Output. + LoaderBottomSheet.hideLoader(); + _dialogService.showErrorBottomSheet(message: response['ErrorMessage']); } } diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 5f587c9..85c4d6d 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -816,7 +816,6 @@ abstract class LocaleKeys { static const ready = 'ready'; static const enterValidNationalId = 'enterValidNationalId'; static const enterValidPhoneNumber = 'enterValidPhoneNumber'; - static const iAcceptThe = 'iAcceptThe'; static const medicalCentersWithCount = 'medicalCentersWithCount'; static const medicalCenters = 'medicalCenters'; static const hospitalsWithCount = 'hospitalsWithCount'; @@ -824,4 +823,7 @@ abstract class LocaleKeys { static const selectFacility = 'selectFacility'; static const selectFacilitiesSubTitle = 'selectFacilitiesSubTitle'; static const selectHospitalSubTitle = 'selectHospitalSubTitle'; + static const iAcceptThe = 'iAcceptThe'; + static const personalDetailsVerification = 'personalDetailsVerification'; + } diff --git a/lib/presentation/authentication/register_step2.dart b/lib/presentation/authentication/register_step2.dart index f31909f..23ea7ae 100644 --- a/lib/presentation/authentication/register_step2.dart +++ b/lib/presentation/authentication/register_step2.dart @@ -44,20 +44,24 @@ class _RegisterNew extends State { Widget build(BuildContext context) { AppState appState = getIt.get(); return Scaffold( + backgroundColor: AppColors.bgScaffoldColor, appBar: CustomAppBar( onBackPressed: () { Navigator.of(context).pop(); // authVM!.clearDefaultInputValues(); + authVM!.clearEmailInput(); }, onLanguageChanged: (lang) {}, hideLogoAndLang: true, ), body: SingleChildScrollView( reverse: false, - padding: EdgeInsets.only(left: 24.h, right: 24.h, top: 24.h), + 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( @@ -66,18 +70,20 @@ class _RegisterNew extends State { child: Column( children: [ TextInputWidget( - labelText: authVM!.isUserFromUAE() ? LocaleKeys.fullName.tr() : LocaleKeys.name.tr(), - hintText: authVM!.isUserFromUAE() ? LocaleKeys.enterNameHere.tr() : ("${appState.getNHICUserData.firstNameEn!.toUpperCase()} ${appState.getNHICUserData.lastNameEn!.toUpperCase()}"), - 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) - .paddingSymmetrical(0.h, 16.h), + labelText: authVM!.isUserFromUAE() ? LocaleKeys.fullName.tr() : LocaleKeys.name.tr(), + hintText: + authVM!.isUserFromUAE() ? LocaleKeys.enterNameHere.tr() : ("${appState.getNHICUserData.firstNameEn!.toUpperCase()} ${appState.getNHICUserData.lastNameEn!.toUpperCase()}"), + 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(), @@ -89,6 +95,7 @@ class _RegisterNew extends State { isBorderAllowed: false, isAllowLeadingIcon: true, isReadOnly: true, + labelColor: AppColors.textColor, leadingIcon: AppAssets.student_card) .paddingSymmetrical(0.h, 16.h), Divider(height: 1, color: AppColors.greyColor), @@ -108,6 +115,7 @@ class _RegisterNew extends State { 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, @@ -124,6 +132,7 @@ class _RegisterNew extends State { 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), @@ -143,6 +152,7 @@ class _RegisterNew extends State { 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, @@ -160,6 +170,7 @@ class _RegisterNew extends State { isBorderAllowed: false, isAllowLeadingIcon: true, isReadOnly: true, + labelColor: AppColors.textColor, leadingIcon: AppAssets.smart_phone, onChange: (value) {}) .paddingSymmetrical(0.h, 16.h), @@ -190,6 +201,7 @@ class _RegisterNew extends State { 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, @@ -208,6 +220,7 @@ class _RegisterNew extends State { isBorderAllowed: false, isAllowLeadingIcon: true, isReadOnly: true, + labelColor: AppColors.textColor, leadingIcon: AppAssets.globe, onChange: (value) {}) .paddingSymmetrical(0.h, 16.h), @@ -224,6 +237,7 @@ class _RegisterNew extends State { isAllowRadius: false, isBorderAllowed: false, isAllowLeadingIcon: true, + labelColor: AppColors.textColor, isReadOnly: true, leadingIcon: AppAssets.call) .paddingSymmetrical(0.h, 16.h), @@ -240,6 +254,7 @@ class _RegisterNew extends State { isBorderAllowed: false, isAllowLeadingIcon: true, isReadOnly: true, + labelColor: AppColors.textColor, leadingIcon: AppAssets.birthday_cake, selectionType: null, ).paddingSymmetrical(0.h, 16.h), @@ -269,12 +284,12 @@ class _RegisterNew extends State { ), Expanded( child: CustomButton( - backgroundColor: AppColors.lightGreenColor, - borderColor: AppColors.lightGreenColor, - textColor: AppColors.textGreenColor, + backgroundColor: AppColors.primaryRedColor, + borderColor: AppColors.primaryRedColor, + textColor: AppColors.whiteColor, text: LocaleKeys.confirm.tr(), icon: AppAssets.confirm, - iconColor: AppColors.textGreenColor, + iconColor: AppColors.whiteColor, onPressed: () { if (appState.getUserRegistrationPayload.zipCode != CountryEnum.saudiArabia.countryCode) { if (ValidationUtils.validateUaeRegistration( diff --git a/lib/widgets/dropdown/dropdown_widget.dart b/lib/widgets/dropdown/dropdown_widget.dart index 2a0cad3..f093f0b 100644 --- a/lib/widgets/dropdown/dropdown_widget.dart +++ b/lib/widgets/dropdown/dropdown_widget.dart @@ -18,29 +18,31 @@ class DropdownWidget extends StatelessWidget { final bool hasSelectionCustomIcon; final String? selectionCustomIcon; final String? leadingIcon; + final Color? labelColor; - const DropdownWidget({ - Key? key, - required this.labelText, - required this.hintText, - required this.dropdownItems, - this.selectedValue, - this.onChange, - this.isEnable = true, - this.isBorderAllowed = true, - this.isAllowRadius = true, - this.padding, - this.hasSelectionCustomIcon = false, - this.selectionCustomIcon, - this.leadingIcon, - }) : super(key: key); + const DropdownWidget( + {Key? key, + required this.labelText, + required this.hintText, + required this.dropdownItems, + this.selectedValue, + this.onChange, + this.isEnable = true, + this.isBorderAllowed = true, + this.isAllowRadius = true, + this.padding, + this.hasSelectionCustomIcon = false, + this.selectionCustomIcon, + this.leadingIcon, + this.labelColor}) + : super(key: key); @override Widget build(BuildContext context) { Widget content = Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, - children: [_buildLabelText(), _buildDropdown(context)], + children: [_buildLabelText(labelColor), _buildDropdown(context)], ); return Container( @@ -75,13 +77,13 @@ class DropdownWidget extends StatelessWidget { child: Utils.buildSvgWithAssets(icon: leadingIcon!)); } - Widget _buildLabelText() { + Widget _buildLabelText(Color? labelColor) { return Text( labelText, style: TextStyle( fontSize: 12.fSize, fontWeight: FontWeight.w500, - color: Color(0xff898A8D), + color: labelColor ?? Color(0xff898A8D), letterSpacing: -0.2, height: 18 / 12, ), diff --git a/lib/widgets/input_widget.dart b/lib/widgets/input_widget.dart index c11ae65..fa2d873 100644 --- a/lib/widgets/input_widget.dart +++ b/lib/widgets/input_widget.dart @@ -41,39 +41,41 @@ class TextInputWidget extends StatelessWidget { final num? fontSize; final bool? isWalletAmountInput; final Widget? suffix; + final Color? labelColor; // final List countryList; // final Function(Country)? onCountryChange; - TextInputWidget({ - super.key, - required this.labelText, - required this.hintText, - this.controller, - this.onChange, - this.onCalendarTypeChanged, - this.prefix, - this.isEnable = true, - this.isBorderAllowed = true, - this.isAllowRadius = true, - this.isReadOnly = false, - this.keyboardType = TextInputType.number, - this.focusNode, - this.autoFocus = false, - this.padding, - this.isAllowLeadingIcon = false, - this.leadingIcon, - this.isCountryDropDown = false, - this.hasError = false, - this.errorMessage, - this.onCountryChange, - this.selectionType, - this.fontSize = 14, - this.isWalletAmountInput = false, - this.suffix, - // this.countryList = const [], - // this.onCountryChange, - }); + TextInputWidget( + {super.key, + required this.labelText, + required this.hintText, + this.controller, + this.onChange, + this.onCalendarTypeChanged, + this.prefix, + this.isEnable = true, + this.isBorderAllowed = true, + this.isAllowRadius = true, + this.isReadOnly = false, + this.keyboardType = TextInputType.number, + this.focusNode, + this.autoFocus = false, + this.padding, + this.isAllowLeadingIcon = false, + this.leadingIcon, + this.isCountryDropDown = false, + this.hasError = false, + this.errorMessage, + this.onCountryChange, + this.selectionType, + this.fontSize = 14, + this.isWalletAmountInput = false, + this.suffix, + this.labelColor + // this.countryList = const [], + // this.onCountryChange, + }); final FocusNode _focusNode = FocusNode(); @@ -135,7 +137,7 @@ class TextInputWidget extends StatelessWidget { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - _buildLabelText().paddingOnly(right: (appState.getLanguageCode() == "ar" ? 10 : 0)), + _buildLabelText(labelColor).paddingOnly(right: (appState.getLanguageCode() == "ar" ? 10 : 0)), _buildTextField(context), ], ), @@ -206,13 +208,13 @@ class TextInputWidget extends StatelessWidget { ); } - Widget _buildLabelText() { + Widget _buildLabelText(Color? labelColor) { return Text( labelText, style: TextStyle( fontSize: 12.fSize, fontWeight: FontWeight.w500, - color: AppColors.inputLabelTextColor, + color: labelColor ?? AppColors.inputLabelTextColor, letterSpacing: -0.2, height: 18 / 12, ), From fe36c2a1c10c84d5e379b374bd183fc4030be9d8 Mon Sep 17 00:00:00 2001 From: Sultan khan Date: Wed, 17 Sep 2025 15:48:28 +0300 Subject: [PATCH 6/6] auto sms --- .../authentication_view_model.dart | 12 ++++++++++- .../widgets/otp_verification_screen.dart | 20 ++++++++++++++++++- pubspec.yaml | 1 + 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/lib/features/authentication/authentication_view_model.dart b/lib/features/authentication/authentication_view_model.dart index bb41af6..73e1706 100644 --- a/lib/features/authentication/authentication_view_model.dart +++ b/lib/features/authentication/authentication_view_model.dart @@ -1,5 +1,6 @@ import 'dart:convert'; import 'dart:developer'; +import 'dart:io'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/services.dart' show rootBundle; import 'package:flutter/material.dart'; @@ -36,6 +37,7 @@ import 'package:hmg_patient_app_new/services/localauth_service.dart'; import 'package:hmg_patient_app_new/services/navigation_service.dart'; import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart'; import 'package:hmg_patient_app_new/widgets/bottomsheet/exception_bottom_sheet.dart'; +import 'package:sms_otp_auto_verify/sms_otp_auto_verify.dart'; import 'models/request_models/get_user_mobile_device_data.dart'; import 'models/request_models/insert_patient_mobile_deviceinfo.dart'; @@ -355,7 +357,7 @@ class AuthenticationViewModel extends ChangeNotifier { ); // TODO: GET APP SMS SIGNATURE HERE - request.sMSSignature = "enKTDcqbOVd"; + request.sMSSignature =await getSignature(); if (checkIsUserComingForRegister(request: payload)) { _appState.setUserRegistrationPayload = RegistrationDataModelPayload.fromJson(payload); @@ -921,4 +923,12 @@ class AuthenticationViewModel extends ChangeNotifier { }, ); } + Future getSignature() async { + if (Platform.isAndroid) { + return await SmsVerification.getAppSignature(); + } else { + return null; + } + } + } diff --git a/lib/features/authentication/widgets/otp_verification_screen.dart b/lib/features/authentication/widgets/otp_verification_screen.dart index db7b1eb..8e77f81 100644 --- a/lib/features/authentication/widgets/otp_verification_screen.dart +++ b/lib/features/authentication/widgets/otp_verification_screen.dart @@ -9,6 +9,7 @@ import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/appbar/app_bar_widget.dart'; +import 'package:sms_otp_auto_verify/sms_otp_auto_verify.dart'; typedef OnDone = void Function(String text); @@ -132,6 +133,7 @@ class OTPWidgetState extends State with SingleTickerProviderStateMixi widget.controller!.addListener(_controllerListener); } focusNode.addListener(_focusListener); + checkSignature(); } void _controllerListener() { @@ -209,7 +211,15 @@ class OTPWidgetState extends State with SingleTickerProviderStateMixi ], ); } - + void checkSignature() async { + SmsVerification.startListeningSms().then((message) { + final intRegex = RegExp(r'\d+', multiLine: true); + var otp = SmsVerification.getCode(message, intRegex); + widget.controller!.text = otp; + _onTextChanged(text); + SmsVerification.stopListening(); + }); + } Widget _touchPinBoxRow() { return widget.hideDefaultKeyboard ? _pinBoxRow(context) @@ -462,6 +472,7 @@ class _OTPVerificationScreenState extends State { super.initState(); _otpController = TextEditingController(); _startResendTimer(); + } @override @@ -506,6 +517,7 @@ class _OTPVerificationScreenState extends State { _startResendTimer(); // autoFillOtp("1234"); widget.onResendOTPPressed(widget.phoneNumber); + } } @@ -618,5 +630,11 @@ class _OTPVerificationScreenState extends State { if (otp.length != _otpLength) return; _isVerifying = false; _otpController.text = otp; + + setState(() { + + }); } + + } diff --git a/pubspec.yaml b/pubspec.yaml index 055fb7b..4e8d4ea 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -66,6 +66,7 @@ dependencies: firebase_analytics: ^11.5.1 jiffy: ^6.4.3 hijri_gregorian_calendar: ^0.1.1 + sms_otp_auto_verify: ^2.2.0 web: any flutter_staggered_animations: ^1.1.1