diff --git a/lib/config/localized_values.dart b/lib/config/localized_values.dart index a4d89d0e..0ed4b76f 100644 --- a/lib/config/localized_values.dart +++ b/lib/config/localized_values.dart @@ -2362,6 +2362,7 @@ const Map localizedValues = { "enterPhoneDesc": {"en": "Enter your phone number to receive OTP verification code", "ar":"أدخل رقم هاتفك لتلقي رمز التحقق OTP"}, "otpVerification": {"en": "OTP Verification", "ar":"التحقق من OTP"}, "submiT": {"en": "Submit", "ar":"إرسال"}, + "notice": {"en": "Notice", "ar":"إشعار"}, diff --git a/lib/new_ui/exception_widget/ExceptionBottomSheet.dart b/lib/new_ui/exception_widget/ExceptionBottomSheet.dart index dc72c42b..d44fc55c 100644 --- a/lib/new_ui/exception_widget/ExceptionBottomSheet.dart +++ b/lib/new_ui/exception_widget/ExceptionBottomSheet.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:google_fonts/google_fonts.dart'; @@ -32,6 +34,7 @@ class _ExceptionBottomSheetState extends State { @override Widget build(BuildContext context) { return SafeArea( + bottom: Platform.isIOS ? false : true, // Adjust for iOS to avoid bottom padding child: GestureDetector( onTap: () { FocusScope.of(context).unfocus(); // Dismiss the keyboard when tapping outside @@ -53,7 +56,7 @@ class _ExceptionBottomSheetState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - AppText("Error", fontSize: 28, letterSpacing: -2, color: Color(0xFF2E3039), fontWeight: FontWeight.w600), + AppText(TranslationBase.of(context).notice, fontSize: 28, letterSpacing: -2, color: Color(0xFF2E3039), fontWeight: FontWeight.w600), InkWell( onTap: () { Navigator.of(context).pop(); diff --git a/lib/pages/login/register_new.dart b/lib/pages/login/register_new.dart index 480cf8e7..5d40eaab 100644 --- a/lib/pages/login/register_new.dart +++ b/lib/pages/login/register_new.dart @@ -717,7 +717,7 @@ class _RegisterNew extends State { }); } else { if (value['IsAuthenticated']) { - checkActivationCode(); + checkActivationCode(onWrongActivationCode: (String? message, bool? isReroute) {}); } } }).catchError((err) { @@ -757,7 +757,7 @@ class _RegisterNew extends State { } } - Future checkActivationCode({value, type, skipRegistration}) async { + Future checkActivationCode({value, type, skipRegistration, required Function(String? message, bool? isReroute) onWrongActivationCode}) async { final isSaudi = selectedCountry.countryCode == "966"; final isHijriDate = isHijri == 1; final dobString = isHijriDate ? selectedDOB!.toString() : dateFormat.format(selectedDOB!); @@ -802,15 +802,7 @@ class _RegisterNew extends State { final activation = CheckActivationCode.fromJson(result as Map); if (activation.errorCode == '699') { GifLoaderDialogUtils.hideDialog(context); - context.showBottomSheet( - child: ExceptionBottomSheet( - message: activation.errorEndUserMessage, - showCancel: false, - onOkPressed: () { - Navigator.popUntil(context, (route) => Utils.route(route, equalsTo: WelcomeLogin)); - }, - ), - ); + onWrongActivationCode(activation.errorEndUserMessage.toString(), true); } else { await sharedPref.remove(FAMILY_FILE); activation.list!.isFamily = false; @@ -829,15 +821,16 @@ class _RegisterNew extends State { } } else { GifLoaderDialogUtils.hideDialog(context); - context.showBottomSheet( - child: ExceptionBottomSheet( - message: result, - showCancel: false, - onOkPressed: () { - Navigator.of(context).pop(); - }, - ), - ); + onWrongActivationCode(result.toString(), false); + // context.showBottomSheet( + // child: ExceptionBottomSheet( + // message: result, + // showCancel: false, + // onOkPressed: () { + // Navigator.of(context).pop(); + // }, + // ), + // ); projectViewModel.analytics.loginRegistration.login_fail(error: result); projectViewModel.analytics.errorTracking.log('otp_verification_at_confirm_login', error: result); } @@ -851,29 +844,31 @@ class _RegisterNew extends State { // Optionally: Navigator.popUntil(context, (route) => Utils.route(route, equalsTo: RegisterNew)); } else { GifLoaderDialogUtils.hideDialog(context); - context.showBottomSheet( - child: ExceptionBottomSheet( - message: result, - showCancel: false, - onOkPressed: () { - Navigator.of(context).pop(); - }, - ), - ); + onWrongActivationCode(result.toString(), false); + // context.showBottomSheet( + // child: ExceptionBottomSheet( + // message: result, + // showCancel: false, + // onOkPressed: () { + // Navigator.of(context).pop(); + // }, + // ), + // ); // Optionally: log analytics here } } } catch (err) { GifLoaderDialogUtils.hideDialog(context); - context.showBottomSheet( - child: ExceptionBottomSheet( - message: err.toString(), - showCancel: false, - onOkPressed: () { - Navigator.of(context).pop(); - }, - ), - ); + onWrongActivationCode(err.toString(), false); + // context.showBottomSheet( + // child: ExceptionBottomSheet( + // message: err.toString(), + // showCancel: false, + // onOkPressed: () { + // Navigator.of(context).pop(); + // }, + // ), + // ); } } @@ -918,14 +913,38 @@ class _RegisterNew extends State { } startSMSService(type, skipRegistration) { - late SMSOTP smsOtp; // Declare the variable first + late SMSOTP smsOtp; smsOtp = SMSOTP( context, type, mobileNo, (code) { - smsOtp.dispose(); - checkActivationCode(value: code, type: type, skipRegistration: skipRegistration); + checkActivationCode( + value: code, + type: type, + skipRegistration: skipRegistration, + onWrongActivationCode: (String? message, bool? isReroute) { + if (isReroute== true) { + context.showBottomSheet( + child: ExceptionBottomSheet( + message: message.toString(), + showCancel: false, + onOkPressed: () { + Navigator.popUntil(context, (route) => Utils.route(route, equalsTo: WelcomeLogin)); + }, + ), + ); + } else { + context.showBottomSheet( + child: ExceptionBottomSheet( + message: message.toString(), + onOkPressed: () { + Navigator.of(context).pop(); + }, + ), + ); + } + }); }, () { smsOtp.dispose(); // Now we can reference it diff --git a/lib/pages/login/welcome.dart b/lib/pages/login/welcome.dart index d6ba111f..84a0669b 100644 --- a/lib/pages/login/welcome.dart +++ b/lib/pages/login/welcome.dart @@ -328,15 +328,15 @@ class _WelcomeLogin extends State { if (value['isSMSSent']) { sharedPref.setString(LOGIN_TOKEN_ID, value['LogInTokenID']), - this.loginTokenID = value['LogInTokenID'], + loginTokenID = value['LogInTokenID'], sharedPref.setObject(REGISTER_DATA_FOR_LOGIIN, request), // Future.delayed(Duration(seconds: 1), () { - this.sendActivationCode(type) + sendActivationCode(type) // }) } else { - if (value['IsAuthenticated']) {this.checkActivationCode()} + if (value['IsAuthenticated']) {checkActivationCode(onWrongActivationCode: (String? message) {})} } }) .catchError((err) { @@ -407,7 +407,7 @@ class _WelcomeLogin extends State { } } - Future checkActivationCode({dynamic value}) async { + Future checkActivationCode({dynamic value, required Function(String? message) onWrongActivationCode}) async { GifLoaderDialogUtils.showMyDialog(context); final request = getCommonRequest().toJson(); dynamic res; @@ -429,14 +429,7 @@ class _WelcomeLogin extends State { } } else { GifLoaderDialogUtils.hideDialog(context); - context.showBottomSheet( - child: ExceptionBottomSheet( - message: result.toString(), - onOkPressed: () { - Navigator.of(context).pop(); - }, - ), - ); + onWrongActivationCode(result.toString()); projectViewModel.analytics.loginRegistration.login_fail(error: result); projectViewModel.analytics.errorTracking.log('otp_verification_at_confirm_login', error: result); } @@ -448,14 +441,15 @@ class _WelcomeLogin extends State { final activation = CheckActivationCode.fromJson(result as Map); if (activation.errorCode == '699') { GifLoaderDialogUtils.hideDialog(context); - context.showBottomSheet( - child: ExceptionBottomSheet( - message: activation.errorEndUserMessage, - onOkPressed: () { - Navigator.of(context).pop(); - }, - ), - ); + onWrongActivationCode(activation.errorEndUserMessage); + // context.showBottomSheet( + // child: ExceptionBottomSheet( + // message: activation.errorEndUserMessage, + // onOkPressed: () { + // Navigator.of(context).pop(); + // }, + // ), + // ); return; } else if (registerd_data?.isRegister == true) { Navigator.popUntil(context, (route) => Utils.route(route, equalsTo: RegisterNew)); @@ -477,28 +471,30 @@ class _WelcomeLogin extends State { } } else { GifLoaderDialogUtils.hideDialog(context); - context.showBottomSheet( - child: ExceptionBottomSheet( - message: result.toString(), - onOkPressed: () { - Navigator.of(context).pop(); - }, - ), - ); + onWrongActivationCode(result.toString()); + // context.showBottomSheet( + // child: ExceptionBottomSheet( + // message: result.toString(), + // onOkPressed: () { + // Navigator.of(context).pop(); + // }, + // ), + // ); projectViewModel.analytics.loginRegistration.login_fail(error: result); projectViewModel.analytics.errorTracking.log('otp_verification_at_confirm_login', error: result); } } } catch (err) { GifLoaderDialogUtils.hideDialog(context); - context.showBottomSheet( - child: ExceptionBottomSheet( - message: err.toString(), - onOkPressed: () { - Navigator.of(context).pop(); - }, - ), - ); + onWrongActivationCode(err.toString()); + // context.showBottomSheet( + // child: ExceptionBottomSheet( + // message: err.toString(), + // onOkPressed: () { + // Navigator.of(context).pop(); + // }, + // ), + // ); } } @@ -509,11 +505,24 @@ class _WelcomeLogin extends State { type, phoneNumber, (code) { - smsOtp.dispose(); - checkActivationCode(value: code); + // smsOtp.dispose(); + checkActivationCode( + value: code, + onWrongActivationCode: (String? message) { + // smsOtp.pauseTimer(); + context.showBottomSheet( + child: ExceptionBottomSheet( + message: message.toString(), + onOkPressed: () { + Navigator.of(context).pop(); + // Don't resume timer here, let it continue naturally when user tries again + }, + ), + ); + }); }, () { - smsOtp.dispose(); + // smsOtp.dispose(); Navigator.pop(context); }, ); diff --git a/lib/services/authentication/auth_provider.dart b/lib/services/authentication/auth_provider.dart index a85807c5..1c57453f 100644 --- a/lib/services/authentication/auth_provider.dart +++ b/lib/services/authentication/auth_provider.dart @@ -422,8 +422,8 @@ class AuthProvider with ChangeNotifier { requestN.healthId = requestN.patientobject!.eHealthIdField; } - requestN.dob =requestN.isHijri ==1 ? requestN.patientobject!.dateofBirth :dateFormat2.format(dateFormat.parse(requestN.patientobject!.strDateofBirth!)); - requestN.isHijri =requestN.isHijri; + requestN.dob = requestN.isHijri == 1 ? requestN.patientobject!.dateofBirth : dateFormat2.format(dateFormat.parse(requestN.patientobject!.strDateofBirth!)); + requestN.isHijri = requestN.isHijri; requestN.patientIdentificationID = requestN.patientobject!.patientIdentificationNo; requestN.patientMobileNumber = requestN.patientobject!.mobileNumber.toString(); requestN.logInTokenID = await sharedPref.getString(LOGIN_TOKEN_ID); diff --git a/lib/uitl/translations_delegate_base.dart b/lib/uitl/translations_delegate_base.dart index 0a25d042..ecc98192 100644 --- a/lib/uitl/translations_delegate_base.dart +++ b/lib/uitl/translations_delegate_base.dart @@ -3509,6 +3509,7 @@ class TranslationBase { String get enterPhoneDesc => localizedValues["enterPhoneDesc"][locale.languageCode]; String get otpVerfication => localizedValues["otpVerification"][locale.languageCode]; String get submiT => localizedValues["submiT"][locale.languageCode]; + String get notice => localizedValues["notice"][locale.languageCode]; } diff --git a/lib/widgets/otp/sms-popup.dart b/lib/widgets/otp/sms-popup.dart index 0487cf33..92bd1ed3 100644 --- a/lib/widgets/otp/sms-popup.dart +++ b/lib/widgets/otp/sms-popup.dart @@ -113,6 +113,8 @@ class SMSOTP { Utils.changeAppLanguage(context: context); }, body: SafeArea( + top: false, + bottom: Platform.isIOS ? false : true, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 21, vertical: 20), child: Column( @@ -147,7 +149,6 @@ class SMSOTP { pinTextAnimatedSwitcherDuration: Duration(milliseconds: 300), pinBoxRadius: 18, keyboardType: TextInputType.number, - ), ), SizedBox(height: 30), @@ -181,103 +182,6 @@ class SMSOTP { }); }, ); - - // return showDialog( - // context: context, - // barrierColor: Colors.black.withOpacity(0.63), - // builder: (context) { - // projectProvider = Provider.of(context); - // - // return Dialog( - // backgroundColor: Colors.white, - // shape: RoundedRectangleBorder(), - // insetPadding: EdgeInsets.only(left: 21, right: 21), - // child: StatefulBuilder(builder: (context, setState) { - // if (displayTime == '') { - // startTimer(setState); - // if (Platform.isAndroid ) { - // if (type == 1) checkSignature(); - // else if(type == 4) _listenWhatsAppCode(); - // } - // } - // - // return Container( - // padding: EdgeInsets.only(left: 21, right: 18, top: 39, bottom: 59), - // child: Column( - // mainAxisSize: MainAxisSize.min, - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Row( - // crossAxisAlignment: CrossAxisAlignment.start, - // mainAxisAlignment: MainAxisAlignment.spaceBetween, - // children: [ - // SvgPicture.asset( - // type == 1 ? "assets/images/new/verify_sms.svg" : "assets/images/new/verify_whatsapp.svg", - // height: 50, - // width: 50, - // ), - // IconButton( - // padding: EdgeInsets.zero, - // icon: Icon(Icons.close), - // constraints: BoxConstraints(), - // onPressed: () { - // Navigator.pop(context); - // - // this.onFailure(); - // }, - // ) - // ], - // ), - // SizedBox(height: 22), - // Text( - // TranslationBase.of(context).pleaseEnterTheVerificationCode + ' xxxxxxxx' + mobileNo.toString().substring(mobileNo.toString().length - 3), - // style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Color(0xff2B353E), letterSpacing: -0.48), - // ), - // SizedBox(height: 18), - // Directionality( - // textDirection: TextDirection.ltr, - // child: Center( - // child: OTPWidget( - // autoFocus: true, - // controller: _pinPutController, - // defaultBorderColor: Color(0xffD8D8D8), - // maxLength: 4, - // onTextChanged: (text) {}, - // pinBoxColor: Colors.white, - // onDone: (code) => _onOtpCallBack(code, false), - // textBorderColor: Color(0xffD8D8D8), - // pinBoxWidth: 60, - // pinBoxHeight: 60, - // pinTextStyle: TextStyle( - // fontSize: 24.0, - // color: Color(0xff2B353E), - // ), - // pinTextAnimatedSwitcherTransition: ProvidedPinBoxTextAnimation.scalingTransition, - // pinTextAnimatedSwitcherDuration: Duration(milliseconds: 300), - // pinBoxRadius: 10, - // keyboardType: TextInputType.number, - // ), - // ), - // ), - // SizedBox(height: 30), - // RichText( - // text: TextSpan( - // text: TranslationBase.of(context).validationMessage + '\n', - // style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Color(0xff2B353E), letterSpacing: -0.48), - // children: [ - // TextSpan( - // text: displayTime, - // style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Color(0xffD02127), letterSpacing: -0.48), - // ), - // ], - // ), - // ), - // ], - // ), - // ); - // }), - // ); - // }); } TextStyle buildTextStyle() { @@ -289,26 +193,18 @@ class SMSOTP { InputDecoration buildInputDecoration(BuildContext context) { return InputDecoration( counterText: " ", - - // ts/images/password_icon.png - - // contentPadding: EdgeInsets.only(top: 20, bottom: 20), - enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(10)), borderSide: BorderSide(color: Colors.black), ), - focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(10.0)), borderSide: BorderSide(color: Theme.of(context).primaryColor), ), - errorBorder: OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(10.0)), borderSide: BorderSide(color: CustomColors.accentColor), ), - focusedErrorBorder: OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(10.0)), borderSide: BorderSide(color: CustomColors.accentColor), @@ -383,16 +279,42 @@ class SMSOTP { _timer = null; } - static void hideSMSBox(context) { - Navigator.pop(context); + // New method for flexible timer handling - pause timer without disposing + void pauseTimer() { + _timer?.cancel(); + _timer = null; } - _onOtpCallBack(String otpCode, bool isAutofill) { - if (otpCode.length == 4) { - onSuccess(otpCode); + // Method to resume the timer from current remaining time + void resumeTimer(setState) { + if (!_isDisposed && remainingTime > 0) { + startTimer(setState); + } + } + + // Method to reset timer to original time and restart + void resetTimer(setState, {int? newTime}) { + _timer?.cancel(); + if (newTime != null) { + remainingTime = newTime; + } else { + remainingTime = 120; // Reset to original 2 minutes + } + if (!_isDisposed) { + startTimer(setState); } } + // Method to check if timer is currently running + bool isTimerRunning() { + return _timer != null && _timer!.isActive; + } + + // Method to get current remaining time + int getCurrentRemainingTime() { + return remainingTime; + } + checkSignature() async { SmsVerification.startListeningSms().then((message) { // setState(() { @@ -427,4 +349,14 @@ class SMSOTP { return null; } } + + static void hideSMSBox(context) { + Navigator.pop(context); + } + + _onOtpCallBack(String otpCode, bool isAutofill) { + if (otpCode.length == 4) { + onSuccess(otpCode); + } + } }