|  |  |  | @ -6,6 +6,7 @@ import 'package:flutter/material.dart'; | 
		
	
		
			
				|  |  |  |  | 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/theme/colors.dart'; | 
		
	
		
			
				|  |  |  |  | import 'package:hmg_patient_app_new/widgets/appbar/app_bar_widget.dart'; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
	
		
			
				
					|  |  |  | @ -50,12 +51,12 @@ class OTPWidget extends StatefulWidget { | 
		
	
		
			
				|  |  |  |  |   final TextInputType keyboardType; | 
		
	
		
			
				|  |  |  |  |   final EdgeInsets pinBoxOuterPadding; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   OTPWidget({ | 
		
	
		
			
				|  |  |  |  |   const OTPWidget({ | 
		
	
		
			
				|  |  |  |  |     Key? key, | 
		
	
		
			
				|  |  |  |  |     this.maxLength = 4, | 
		
	
		
			
				|  |  |  |  |     this.controller, | 
		
	
		
			
				|  |  |  |  |     this.pinBoxWidth = 70.0, | 
		
	
		
			
				|  |  |  |  |     this.pinBoxHeight = 100.0, | 
		
	
		
			
				|  |  |  |  |     this.pinBoxHeight = 70.0, | 
		
	
		
			
				|  |  |  |  |     this.pinTextStyle, | 
		
	
		
			
				|  |  |  |  |     this.onDone, | 
		
	
		
			
				|  |  |  |  |     this.defaultBorderColor = Colors.black, | 
		
	
	
		
			
				
					|  |  |  | @ -127,7 +128,9 @@ class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixi | 
		
	
		
			
				|  |  |  |  |     _highlightAnimationController = AnimationController(vsync: this); | 
		
	
		
			
				|  |  |  |  |     _initTextController(); | 
		
	
		
			
				|  |  |  |  |     _calculateStrList(); | 
		
	
		
			
				|  |  |  |  |     if (widget.controller != null) { | 
		
	
		
			
				|  |  |  |  |       widget.controller!.addListener(_controllerListener); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     focusNode.addListener(_focusListener); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
	
		
			
				
					|  |  |  | @ -190,7 +193,9 @@ class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixi | 
		
	
		
			
				|  |  |  |  |       focusNode.removeListener(_focusListener); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     _highlightAnimationController.dispose(); | 
		
	
		
			
				|  |  |  |  |     widget.controller?.removeListener(_controllerListener); | 
		
	
		
			
				|  |  |  |  |     if (widget.controller != null) { | 
		
	
		
			
				|  |  |  |  |       widget.controller!.removeListener(_controllerListener); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     super.dispose(); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
	
		
			
				
					|  |  |  | @ -231,7 +236,7 @@ class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixi | 
		
	
		
			
				|  |  |  |  |         width: 0.0, | 
		
	
		
			
				|  |  |  |  |       ), | 
		
	
		
			
				|  |  |  |  |     ); | 
		
	
		
			
				|  |  |  |  |     return SizedBox( | 
		
	
		
			
				|  |  |  |  |     return Container( | 
		
	
		
			
				|  |  |  |  |       width: _width, | 
		
	
		
			
				|  |  |  |  |       height: widget.pinBoxHeight, | 
		
	
		
			
				|  |  |  |  |       child: TextField( | 
		
	
	
		
			
				
					|  |  |  | @ -241,8 +246,6 @@ class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixi | 
		
	
		
			
				|  |  |  |  |         controller: widget.controller, | 
		
	
		
			
				|  |  |  |  |         keyboardType: widget.keyboardType, | 
		
	
		
			
				|  |  |  |  |         inputFormatters: widget.keyboardType == TextInputType.number ? <TextInputFormatter>[FilteringTextInputFormatter.digitsOnly] : null, | 
		
	
		
			
				|  |  |  |  |         // Enable SMS autofill | 
		
	
		
			
				|  |  |  |  |         autofillHints: const [AutofillHints.oneTimeCode], | 
		
	
		
			
				|  |  |  |  |         style: TextStyle( | 
		
	
		
			
				|  |  |  |  |           height: 0.1, | 
		
	
		
			
				|  |  |  |  |           color: Colors.transparent, | 
		
	
	
		
			
				
					|  |  |  | @ -301,33 +304,28 @@ class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixi | 
		
	
		
			
				|  |  |  |  |       return _buildPinCode(i, context); | 
		
	
		
			
				|  |  |  |  |     }); | 
		
	
		
			
				|  |  |  |  |     return Row( | 
		
	
		
			
				|  |  |  |  |       children: pinCodes, | 
		
	
		
			
				|  |  |  |  |       mainAxisSize: MainAxisSize.min, | 
		
	
		
			
				|  |  |  |  |       mainAxisAlignment: MainAxisAlignment.spaceBetween, | 
		
	
		
			
				|  |  |  |  |       children: pinCodes, | 
		
	
		
			
				|  |  |  |  |     ); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   Widget _buildPinCode(int i, BuildContext context) { | 
		
	
		
			
				|  |  |  |  |     Color borderColor; | 
		
	
		
			
				|  |  |  |  |     Color pinBoxColor; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     // Determine if OTP is complete | 
		
	
		
			
				|  |  |  |  |     bool isComplete = text.length == widget.maxLength; | 
		
	
		
			
				|  |  |  |  |     Color pinBoxColor = widget.pinBoxColor; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     if (widget.hasError) { | 
		
	
		
			
				|  |  |  |  |       borderColor = widget.errorBorderColor; | 
		
	
		
			
				|  |  |  |  |       pinBoxColor = widget.pinBoxColor; | 
		
	
		
			
				|  |  |  |  |     } else if (isComplete) { | 
		
	
		
			
				|  |  |  |  |       borderColor = Colors.transparent; | 
		
	
		
			
				|  |  |  |  |       pinBoxColor = AppColors.successColor; | 
		
	
		
			
				|  |  |  |  |       pinBoxColor = widget.errorBorderColor; | 
		
	
		
			
				|  |  |  |  |     } else if (i < text.length) { | 
		
	
		
			
				|  |  |  |  |       borderColor = Colors.transparent; | 
		
	
		
			
				|  |  |  |  |       pinBoxColor = AppColors.blackBgColor; | 
		
	
		
			
				|  |  |  |  |       pinBoxColor = AppColors.blackBgColor; // Custom color for filled boxes | 
		
	
		
			
				|  |  |  |  |     } else { | 
		
	
		
			
				|  |  |  |  |       borderColor = Colors.transparent; | 
		
	
		
			
				|  |  |  |  |       pinBoxColor = widget.pinBoxColor; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     // Change color to success when all fields are complete | 
		
	
		
			
				|  |  |  |  |     if (text.length == widget.maxLength) { | 
		
	
		
			
				|  |  |  |  |       pinBoxColor = AppColors.successColor; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     EdgeInsets insets; | 
		
	
		
			
				|  |  |  |  |     if (i == 0) { | 
		
	
		
			
				|  |  |  |  |       insets = EdgeInsets.only( | 
		
	
	
		
			
				
					|  |  |  | @ -346,22 +344,21 @@ class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixi | 
		
	
		
			
				|  |  |  |  |     } else { | 
		
	
		
			
				|  |  |  |  |       insets = widget.pinBoxOuterPadding; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     return Container( | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     return AnimatedContainer( | 
		
	
		
			
				|  |  |  |  |       duration: const Duration(milliseconds: 200), | 
		
	
		
			
				|  |  |  |  |       curve: Curves.easeInOut, | 
		
	
		
			
				|  |  |  |  |       key: ValueKey<String>("container$i"), | 
		
	
		
			
				|  |  |  |  |       alignment: Alignment.center, | 
		
	
		
			
				|  |  |  |  |       padding: EdgeInsets.symmetric(vertical: 4.0, horizontal: 1.0), | 
		
	
		
			
				|  |  |  |  |       margin: insets, | 
		
	
		
			
				|  |  |  |  |       decoration: BoxDecoration( | 
		
	
		
			
				|  |  |  |  |         border: Border.all( | 
		
	
		
			
				|  |  |  |  |           color: borderColor, | 
		
	
		
			
				|  |  |  |  |           width: widget.pinBoxBorderWidth, | 
		
	
		
			
				|  |  |  |  |         ), | 
		
	
		
			
				|  |  |  |  |       child: _animatedTextBox(strList[i], i), | 
		
	
		
			
				|  |  |  |  |       decoration: RoundedRectangleBorder().toSmoothCornerDecoration( | 
		
	
		
			
				|  |  |  |  |         color: pinBoxColor, | 
		
	
		
			
				|  |  |  |  |         borderRadius: BorderRadius.circular(widget.pinBoxRadius), | 
		
	
		
			
				|  |  |  |  |         borderRadius: widget.pinBoxRadius, | 
		
	
		
			
				|  |  |  |  |       ), | 
		
	
		
			
				|  |  |  |  |       width: widget.pinBoxWidth, | 
		
	
		
			
				|  |  |  |  |       height: widget.pinBoxHeight, | 
		
	
		
			
				|  |  |  |  |       child: _animatedTextBox(strList[i], i), | 
		
	
		
			
				|  |  |  |  |     ); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
	
		
			
				
					|  |  |  | @ -407,10 +404,12 @@ class OTPVerificationScreen extends StatefulWidget { | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | class _OTPVerificationScreenState extends State<OTPVerificationScreen> { | 
		
	
		
			
				|  |  |  |  |   final int _otpLength = 4; | 
		
	
		
			
				|  |  |  |  |   late TextEditingController _otpController; | 
		
	
		
			
				|  |  |  |  |   late final TextEditingController _otpController; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   Timer? _resendTimer; | 
		
	
		
			
				|  |  |  |  |   int _resendTime = 60; | 
		
	
		
			
				|  |  |  |  |   bool _isOtpComplete = false; | 
		
	
		
			
				|  |  |  |  |   bool _isVerifying = false; // Flag to prevent multiple verification calls | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   @override | 
		
	
		
			
				|  |  |  |  |   void initState() { | 
		
	
	
		
			
				
					|  |  |  | @ -437,27 +436,25 @@ class _OTPVerificationScreenState extends State<OTPVerificationScreen> { | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   void _onOtpChanged(String value) { | 
		
	
		
			
				|  |  |  |  |     // Handle clipboard paste or programmatic input | 
		
	
		
			
				|  |  |  |  |     if (value.length > 1) { | 
		
	
		
			
				|  |  |  |  |       String? otp = _extractOtpFromText(value); | 
		
	
		
			
				|  |  |  |  |       if (otp != null) { | 
		
	
		
			
				|  |  |  |  |         autoFillOtp(otp); | 
		
	
		
			
				|  |  |  |  |         return; | 
		
	
		
			
				|  |  |  |  |       } | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     setState(() { | 
		
	
		
			
				|  |  |  |  |       _isOtpComplete = value.length == _otpLength; | 
		
	
		
			
				|  |  |  |  |     }); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     // The OTPWidget will automatically call onDone when complete | 
		
	
		
			
				|  |  |  |  |     // This method can be used for any additional logic on text change | 
		
	
		
			
				|  |  |  |  |     if (_isOtpComplete && !_isVerifying) { | 
		
	
		
			
				|  |  |  |  |       _isVerifying = true; | 
		
	
		
			
				|  |  |  |  |       _verifyOtp(value); | 
		
	
		
			
				|  |  |  |  |     } else if (!_isOtpComplete) { | 
		
	
		
			
				|  |  |  |  |       // Reset the flag when OTP is incomplete (user is editing) | 
		
	
		
			
				|  |  |  |  |       _isVerifying = false; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   void _onOtpCompleted(String otp) { | 
		
	
		
			
				|  |  |  |  |     debugPrint('OTP Completed: $otp'); | 
		
	
		
			
				|  |  |  |  |     widget.checkActivationCode(int.parse(otp)); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   void _resendOtp() { | 
		
	
		
			
				|  |  |  |  |     if (_resendTime == 0) { | 
		
	
		
			
				|  |  |  |  |       setState(() => _resendTime = 60); | 
		
	
		
			
				|  |  |  |  |       setState(() { | 
		
	
		
			
				|  |  |  |  |         _resendTime = 60; | 
		
	
		
			
				|  |  |  |  |         _isVerifying = false; // Reset verification flag | 
		
	
		
			
				|  |  |  |  |       }); | 
		
	
		
			
				|  |  |  |  |       _startResendTimer(); | 
		
	
		
			
				|  |  |  |  |       autoFillOtp("1234"); | 
		
	
		
			
				|  |  |  |  |       widget.onResendOTPPressed(widget.phoneNumber); | 
		
	
	
		
			
				
					|  |  |  | @ -469,68 +466,6 @@ class _OTPVerificationScreenState extends State<OTPVerificationScreen> { | 
		
	
		
			
				|  |  |  |  |     return phone.length > 4 ? '05xxxxxx${phone.substring(phone.length - 2)}' : phone; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   /// Extract OTP from text using multiple patterns | 
		
	
		
			
				|  |  |  |  |   String? _extractOtpFromText(String text) { | 
		
	
		
			
				|  |  |  |  |     // Pattern 1: Find 4-6 consecutive digits | 
		
	
		
			
				|  |  |  |  |     RegExp digitPattern = RegExp(r'\b\d{4,6}\b'); | 
		
	
		
			
				|  |  |  |  |     Match? match = digitPattern.firstMatch(text); | 
		
	
		
			
				|  |  |  |  |      | 
		
	
		
			
				|  |  |  |  |     if (match != null) { | 
		
	
		
			
				|  |  |  |  |       String digits = match.group(0)!; | 
		
	
		
			
				|  |  |  |  |       if (digits.length >= _otpLength) { | 
		
	
		
			
				|  |  |  |  |         return digits.substring(0, _otpLength); | 
		
	
		
			
				|  |  |  |  |       } | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |      | 
		
	
		
			
				|  |  |  |  |     // Pattern 2: Find digits separated by spaces or special characters | 
		
	
		
			
				|  |  |  |  |     String cleanedText = text.replaceAll(RegExp(r'[^\d]'), ''); | 
		
	
		
			
				|  |  |  |  |     if (cleanedText.length >= _otpLength) { | 
		
	
		
			
				|  |  |  |  |       return cleanedText.substring(0, _otpLength); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |      | 
		
	
		
			
				|  |  |  |  |     return null; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   /// Paste OTP from clipboard | 
		
	
		
			
				|  |  |  |  |   Future<void> _pasteFromClipboard() async { | 
		
	
		
			
				|  |  |  |  |     try { | 
		
	
		
			
				|  |  |  |  |       ClipboardData? data = await Clipboard.getData(Clipboard.kTextPlain); | 
		
	
		
			
				|  |  |  |  |       if (data != null && data.text != null) { | 
		
	
		
			
				|  |  |  |  |         String clipboardText = data.text!; | 
		
	
		
			
				|  |  |  |  |         String? otp = _extractOtpFromText(clipboardText); | 
		
	
		
			
				|  |  |  |  |          | 
		
	
		
			
				|  |  |  |  |         if (otp != null) { | 
		
	
		
			
				|  |  |  |  |           autoFillOtp(otp); | 
		
	
		
			
				|  |  |  |  |            | 
		
	
		
			
				|  |  |  |  |           // Show feedback to user | 
		
	
		
			
				|  |  |  |  |           ScaffoldMessenger.of(context).showSnackBar( | 
		
	
		
			
				|  |  |  |  |             SnackBar( | 
		
	
		
			
				|  |  |  |  |               content: Text('OTP pasted: $otp'), | 
		
	
		
			
				|  |  |  |  |               duration: const Duration(seconds: 2), | 
		
	
		
			
				|  |  |  |  |               backgroundColor: AppColors.successColor, | 
		
	
		
			
				|  |  |  |  |             ), | 
		
	
		
			
				|  |  |  |  |           ); | 
		
	
		
			
				|  |  |  |  |         } else { | 
		
	
		
			
				|  |  |  |  |           // Show error if no valid OTP found | 
		
	
		
			
				|  |  |  |  |           ScaffoldMessenger.of(context).showSnackBar( | 
		
	
		
			
				|  |  |  |  |             const SnackBar( | 
		
	
		
			
				|  |  |  |  |               content: Text('No valid OTP found in clipboard'), | 
		
	
		
			
				|  |  |  |  |               duration: Duration(seconds: 2), | 
		
	
		
			
				|  |  |  |  |             ), | 
		
	
		
			
				|  |  |  |  |           ); | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |       } | 
		
	
		
			
				|  |  |  |  |     } catch (e) { | 
		
	
		
			
				|  |  |  |  |       debugPrint('Error pasting from clipboard: $e'); | 
		
	
		
			
				|  |  |  |  |       ScaffoldMessenger.of(context).showSnackBar( | 
		
	
		
			
				|  |  |  |  |         const SnackBar( | 
		
	
		
			
				|  |  |  |  |           content: Text('Failed to paste from clipboard'), | 
		
	
		
			
				|  |  |  |  |           duration: Duration(seconds: 2), | 
		
	
		
			
				|  |  |  |  |         ), | 
		
	
		
			
				|  |  |  |  |       ); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   @override | 
		
	
		
			
				|  |  |  |  |   Widget build(BuildContext context) { | 
		
	
		
			
				|  |  |  |  |     return Scaffold( | 
		
	
	
		
			
				
					|  |  |  | @ -562,33 +497,28 @@ class _OTPVerificationScreenState extends State<OTPVerificationScreen> { | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |               // OTP Input Fields using new OTP Widget | 
		
	
		
			
				|  |  |  |  |               Center( | 
		
	
		
			
				|  |  |  |  |                 child: AutofillGroup( | 
		
	
		
			
				|  |  |  |  |                 child: OTPWidget( | 
		
	
		
			
				|  |  |  |  |                   maxLength: _otpLength, | 
		
	
		
			
				|  |  |  |  |                   controller: _otpController, | 
		
	
		
			
				|  |  |  |  |                     pinBoxWidth: 75.h, | 
		
	
		
			
				|  |  |  |  |                     pinBoxHeight: 100.h, | 
		
	
		
			
				|  |  |  |  |                     autoFocus: true, | 
		
	
		
			
				|  |  |  |  |                   pinBoxWidth: 70.h, | 
		
	
		
			
				|  |  |  |  |                   pinBoxHeight: 100, | 
		
	
		
			
				|  |  |  |  |                   pinBoxRadius: 16, | 
		
	
		
			
				|  |  |  |  |                   pinBoxBorderWidth: 0, | 
		
	
		
			
				|  |  |  |  |                   pinBoxOuterPadding: EdgeInsets.symmetric(horizontal: 4.h), | 
		
	
		
			
				|  |  |  |  |                   defaultBorderColor: Colors.transparent, | 
		
	
		
			
				|  |  |  |  |                   textBorderColor: Colors.transparent, | 
		
	
		
			
				|  |  |  |  |                     errorBorderColor: AppColors.primaryRedColor, | 
		
	
		
			
				|  |  |  |  |                   pinBoxColor: AppColors.whiteColor, | 
		
	
		
			
				|  |  |  |  |                   autoFocus: true, | 
		
	
		
			
				|  |  |  |  |                   onTextChanged: _onOtpChanged, | 
		
	
		
			
				|  |  |  |  |                   pinTextStyle: TextStyle( | 
		
	
		
			
				|  |  |  |  |                       fontSize: 50.fSize, | 
		
	
		
			
				|  |  |  |  |                     fontSize: 40.fSize, | 
		
	
		
			
				|  |  |  |  |                     fontWeight: FontWeight.bold, | 
		
	
		
			
				|  |  |  |  |                     color: AppColors.whiteColor, | 
		
	
		
			
				|  |  |  |  |                   ), | 
		
	
		
			
				|  |  |  |  |                     onTextChanged: _onOtpChanged, | 
		
	
		
			
				|  |  |  |  |                     onDone: _onOtpCompleted, | 
		
	
		
			
				|  |  |  |  |                   ), | 
		
	
		
			
				|  |  |  |  |                 ), | 
		
	
		
			
				|  |  |  |  |               ), | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |               const SizedBox(height: 16), | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |               const SizedBox(height: 32), | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |               // Resend OTP | 
		
	
		
			
				|  |  |  |  |               Row( | 
		
	
	
		
			
				
					|  |  |  | @ -620,50 +550,15 @@ class _OTPVerificationScreenState extends State<OTPVerificationScreen> { | 
		
	
		
			
				|  |  |  |  |     ); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   void _verifyOtp(String otp) { | 
		
	
		
			
				|  |  |  |  |     debugPrint('Verifying OTP: $otp'); | 
		
	
		
			
				|  |  |  |  |     widget.checkActivationCode(int.parse(otp)); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   /// Auto fill OTP into text fields | 
		
	
		
			
				|  |  |  |  |   void autoFillOtp(String otp) { | 
		
	
		
			
				|  |  |  |  |     if (otp.length != _otpLength) return; | 
		
	
		
			
				|  |  |  |  |      | 
		
	
		
			
				|  |  |  |  |     // Clear any existing text first | 
		
	
		
			
				|  |  |  |  |     _otpController.clear(); | 
		
	
		
			
				|  |  |  |  |      | 
		
	
		
			
				|  |  |  |  |     // Add a small delay to ensure the UI is updated | 
		
	
		
			
				|  |  |  |  |     Future.delayed(const Duration(milliseconds: 50), () { | 
		
	
		
			
				|  |  |  |  |     _isVerifying = false; // Reset flag before setting new OTP | 
		
	
		
			
				|  |  |  |  |     _otpController.text = otp; | 
		
	
		
			
				|  |  |  |  |       // Move cursor to the end | 
		
	
		
			
				|  |  |  |  |       _otpController.selection = TextSelection.fromPosition( | 
		
	
		
			
				|  |  |  |  |         TextPosition(offset: otp.length), | 
		
	
		
			
				|  |  |  |  |       ); | 
		
	
		
			
				|  |  |  |  |     }); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   /// Clear OTP fields | 
		
	
		
			
				|  |  |  |  |   void clearOtp() { | 
		
	
		
			
				|  |  |  |  |     _otpController.clear(); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   /// Get current OTP value | 
		
	
		
			
				|  |  |  |  |   String getCurrentOtp() { | 
		
	
		
			
				|  |  |  |  |     return _otpController.text; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   /// Check if OTP is complete | 
		
	
		
			
				|  |  |  |  |   bool isOtpComplete() { | 
		
	
		
			
				|  |  |  |  |     return _otpController.text.length == _otpLength; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   /// Simulate SMS received with OTP (for testing purposes) | 
		
	
		
			
				|  |  |  |  |   void simulateSMSReceived(String otp) { | 
		
	
		
			
				|  |  |  |  |     if (otp.length == _otpLength && RegExp(r'^\d+$').hasMatch(otp)) { | 
		
	
		
			
				|  |  |  |  |       autoFillOtp(otp); | 
		
	
		
			
				|  |  |  |  |       // Show a brief indicator that SMS was detected | 
		
	
		
			
				|  |  |  |  |       ScaffoldMessenger.of(context).showSnackBar( | 
		
	
		
			
				|  |  |  |  |         SnackBar( | 
		
	
		
			
				|  |  |  |  |           content: Text('OTP detected from SMS: $otp'), | 
		
	
		
			
				|  |  |  |  |           duration: const Duration(seconds: 2), | 
		
	
		
			
				|  |  |  |  |           backgroundColor: AppColors.successColor, | 
		
	
		
			
				|  |  |  |  |         ), | 
		
	
		
			
				|  |  |  |  |       ); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
	
		
			
				
					|  |  |  | 
 |