|  |  | @ -6,6 +6,7 @@ import 'package:flutter/material.dart'; | 
			
		
	
		
		
			
				
					
					|  |  |  | import 'package:flutter/rendering.dart'; |  |  |  | import 'package:flutter/rendering.dart'; | 
			
		
	
		
		
			
				
					
					|  |  |  | import 'package:flutter/services.dart'; |  |  |  | import 'package:flutter/services.dart'; | 
			
		
	
		
		
			
				
					
					|  |  |  | import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; |  |  |  | import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; | 
			
		
	
		
		
			
				
					
					|  |  |  | import 'package:hmg_patient_app_new/theme/colors.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/appbar/app_bar_widget.dart'; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -50,7 +51,7 @@ class OTPWidget extends StatefulWidget { | 
			
		
	
		
		
			
				
					
					|  |  |  |   final TextInputType keyboardType; |  |  |  |   final TextInputType keyboardType; | 
			
		
	
		
		
			
				
					
					|  |  |  |   final EdgeInsets pinBoxOuterPadding; |  |  |  |   final EdgeInsets pinBoxOuterPadding; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   OTPWidget({ |  |  |  |   const OTPWidget({ | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     Key? key, |  |  |  |     Key? key, | 
			
		
	
		
		
			
				
					
					|  |  |  |     this.maxLength = 4, |  |  |  |     this.maxLength = 4, | 
			
		
	
		
		
			
				
					
					|  |  |  |     this.controller, |  |  |  |     this.controller, | 
			
		
	
	
		
		
			
				
					|  |  | @ -101,7 +102,7 @@ class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixi | 
			
		
	
		
		
			
				
					
					|  |  |  |       }); |  |  |  |       }); | 
			
		
	
		
		
			
				
					
					|  |  |  |       widget.controller?.text = text; |  |  |  |       widget.controller?.text = text; | 
			
		
	
		
		
			
				
					
					|  |  |  |       widget.controller?.selection = TextSelection.collapsed(offset: text.length); |  |  |  |       widget.controller?.selection = TextSelection.collapsed(offset: text.length); | 
			
		
	
		
		
			
				
					
					|  |  |  |     } else if (oldWidget.maxLength > widget.maxLength && widget.maxLength > 0 && text.length > 0 && text.length > widget.maxLength) { |  |  |  |     } else if (oldWidget.maxLength > widget.maxLength && widget.maxLength > 0 && text.isNotEmpty && text.length > widget.maxLength) { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |       setState(() { |  |  |  |       setState(() { | 
			
		
	
		
		
			
				
					
					|  |  |  |         text = text.substring(0, widget.maxLength); |  |  |  |         text = text.substring(0, widget.maxLength); | 
			
		
	
		
		
			
				
					
					|  |  |  |         currentIndex = text.length; |  |  |  |         currentIndex = text.length; | 
			
		
	
	
		
		
			
				
					|  |  | @ -127,7 +128,9 @@ class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixi | 
			
		
	
		
		
			
				
					
					|  |  |  |     _highlightAnimationController = AnimationController(vsync: this); |  |  |  |     _highlightAnimationController = AnimationController(vsync: this); | 
			
		
	
		
		
			
				
					
					|  |  |  |     _initTextController(); |  |  |  |     _initTextController(); | 
			
		
	
		
		
			
				
					
					|  |  |  |     _calculateStrList(); |  |  |  |     _calculateStrList(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     if (widget.controller != null) { | 
			
		
	
		
		
			
				
					
					|  |  |  |       widget.controller!.addListener(_controllerListener); |  |  |  |       widget.controller!.addListener(_controllerListener); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |     focusNode.addListener(_focusListener); |  |  |  |     focusNode.addListener(_focusListener); | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -190,7 +193,9 @@ class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixi | 
			
		
	
		
		
			
				
					
					|  |  |  |       focusNode.removeListener(_focusListener); |  |  |  |       focusNode.removeListener(_focusListener); | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |     _highlightAnimationController.dispose(); |  |  |  |     _highlightAnimationController.dispose(); | 
			
		
	
		
		
			
				
					
					|  |  |  |     widget.controller?.removeListener(_controllerListener); |  |  |  |     if (widget.controller != null) { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       widget.controller!.removeListener(_controllerListener); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     super.dispose(); |  |  |  |     super.dispose(); | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
	
		
		
			
				
					|  |  | @ -241,12 +246,7 @@ class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixi | 
			
		
	
		
		
			
				
					
					|  |  |  |         controller: widget.controller, |  |  |  |         controller: widget.controller, | 
			
		
	
		
		
			
				
					
					|  |  |  |         keyboardType: widget.keyboardType, |  |  |  |         keyboardType: widget.keyboardType, | 
			
		
	
		
		
			
				
					
					|  |  |  |         inputFormatters: widget.keyboardType == TextInputType.number ? <TextInputFormatter>[FilteringTextInputFormatter.digitsOnly] : null, |  |  |  |         inputFormatters: widget.keyboardType == TextInputType.number ? <TextInputFormatter>[FilteringTextInputFormatter.digitsOnly] : null, | 
			
		
	
		
		
			
				
					
					|  |  |  |         // Enable SMS autofill |  |  |  |         style: TextStyle(height: 0.1, color: Colors.transparent), | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         autofillHints: const [AutofillHints.oneTimeCode], |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         style: TextStyle( |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |           height: 0.1, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |           color: Colors.transparent, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         ), |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         decoration: InputDecoration( |  |  |  |         decoration: InputDecoration( | 
			
		
	
		
		
			
				
					
					|  |  |  |           contentPadding: EdgeInsets.all(0), |  |  |  |           contentPadding: EdgeInsets.all(0), | 
			
		
	
		
		
			
				
					
					|  |  |  |           focusedErrorBorder: transparentBorder, |  |  |  |           focusedErrorBorder: transparentBorder, | 
			
		
	
	
		
		
			
				
					|  |  | @ -256,10 +256,7 @@ class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixi | 
			
		
	
		
		
			
				
					
					|  |  |  |           focusedBorder: transparentBorder, |  |  |  |           focusedBorder: transparentBorder, | 
			
		
	
		
		
			
				
					
					|  |  |  |           counterText: null, |  |  |  |           counterText: null, | 
			
		
	
		
		
			
				
					
					|  |  |  |           counterStyle: null, |  |  |  |           counterStyle: null, | 
			
		
	
		
		
			
				
					
					|  |  |  |           helperStyle: TextStyle( |  |  |  |           helperStyle: TextStyle(height: 0.0, color: Colors.transparent), | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |             height: 0.0, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             color: Colors.transparent, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |           ), |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |           labelStyle: TextStyle(height: 0.1), |  |  |  |           labelStyle: TextStyle(height: 0.1), | 
			
		
	
		
		
			
				
					
					|  |  |  |           fillColor: Colors.transparent, |  |  |  |           fillColor: Colors.transparent, | 
			
		
	
		
		
			
				
					
					|  |  |  |           border: InputBorder.none, |  |  |  |           border: InputBorder.none, | 
			
		
	
	
		
		
			
				
					|  |  | @ -307,25 +304,19 @@ class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixi | 
			
		
	
		
		
			
				
					
					|  |  |  |     ); |  |  |  |     ); | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   Widget _buildPinCode(int i, BuildContext context) { |  |  |  |   Widget _buildPinCode(int i, BuildContext context) { | 
			
		
	
		
		
			
				
					
					|  |  |  |     Color borderColor; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     Color pinBoxColor; |  |  |  |     Color pinBoxColor; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     // Determine if OTP is complete |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     bool isComplete = text.length == widget.maxLength; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (widget.hasError) { |  |  |  |     if (widget.hasError) { | 
			
		
	
		
		
			
				
					
					|  |  |  |       borderColor = widget.errorBorderColor; |  |  |  |       pinBoxColor = widget.errorBorderColor; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |       pinBoxColor = widget.pinBoxColor; |  |  |  |     } else if (text.length == widget.maxLength) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     } else if (isComplete) { |  |  |  |       // Check for completion first, before individual box logic | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |       borderColor = Colors.transparent; |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |       pinBoxColor = AppColors.successColor; |  |  |  |       pinBoxColor = AppColors.successColor; | 
			
		
	
		
		
			
				
					
					|  |  |  |     } else if (i < text.length) { |  |  |  |     } else if (i < text.length) { | 
			
		
	
		
		
			
				
					
					|  |  |  |       borderColor = Colors.transparent; |  |  |  |       pinBoxColor = AppColors.blackBgColor; // Custom color for filled boxes | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |       pinBoxColor = AppColors.blackBgColor; |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     } else { |  |  |  |     } else { | 
			
		
	
		
		
			
				
					
					|  |  |  |       borderColor = Colors.transparent; |  |  |  |       pinBoxColor = widget.pinBoxColor; // Default white color | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |       pinBoxColor = widget.pinBoxColor; |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     EdgeInsets insets; |  |  |  |     EdgeInsets insets; | 
			
		
	
	
		
		
			
				
					|  |  | @ -346,18 +337,17 @@ class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixi | 
			
		
	
		
		
			
				
					
					|  |  |  |     } else { |  |  |  |     } else { | 
			
		
	
		
		
			
				
					
					|  |  |  |       insets = widget.pinBoxOuterPadding; |  |  |  |       insets = widget.pinBoxOuterPadding; | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |     return Container( |  |  |  | 
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     return AnimatedContainer( | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       duration: const Duration(milliseconds: 200), | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       curve: Curves.easeInOut, | 
			
		
	
		
		
			
				
					
					|  |  |  |       key: ValueKey<String>("container$i"), |  |  |  |       key: ValueKey<String>("container$i"), | 
			
		
	
		
		
			
				
					
					|  |  |  |       alignment: Alignment.center, |  |  |  |       alignment: Alignment.center, | 
			
		
	
		
		
			
				
					
					|  |  |  |       padding: EdgeInsets.symmetric(vertical: 4.0, horizontal: 1.0), |  |  |  |       padding: EdgeInsets.symmetric(vertical: 4.0, horizontal: 1.0), | 
			
		
	
		
		
			
				
					
					|  |  |  |       margin: insets, |  |  |  |       margin: insets, | 
			
		
	
		
		
			
				
					
					|  |  |  |       decoration: BoxDecoration( |  |  |  |       decoration: RoundedRectangleBorder().toSmoothCornerDecoration( | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         border: Border.all( |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |           color: borderColor, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |           width: widget.pinBoxBorderWidth, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         ), |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         color: pinBoxColor, |  |  |  |         color: pinBoxColor, | 
			
		
	
		
		
			
				
					
					|  |  |  |         borderRadius: BorderRadius.circular(widget.pinBoxRadius), |  |  |  |         borderRadius: widget.pinBoxRadius, | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |       ), |  |  |  |       ), | 
			
		
	
		
		
			
				
					
					|  |  |  |       width: widget.pinBoxWidth, |  |  |  |       width: widget.pinBoxWidth, | 
			
		
	
		
		
			
				
					
					|  |  |  |       height: widget.pinBoxHeight, |  |  |  |       height: widget.pinBoxHeight, | 
			
		
	
	
		
		
			
				
					|  |  | @ -365,6 +355,59 @@ class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixi | 
			
		
	
		
		
			
				
					
					|  |  |  |     ); |  |  |  |     ); | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   // Widget _buildPinCode(int i, BuildContext context) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   //   Color pinBoxColor = widget.pinBoxColor; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   // | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   //   if (widget.hasError) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   //     pinBoxColor = widget.errorBorderColor; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   //   } else if (i < text.length) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   //     pinBoxColor = AppColors.blackBgColor; // Custom color for filled boxes | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   //   } else { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   //     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( | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   //       left: 0, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   //       top: widget.pinBoxOuterPadding.top, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   //       right: widget.pinBoxOuterPadding.right, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   //       bottom: widget.pinBoxOuterPadding.bottom, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   //     ); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   //   } else if (i == strList.length - 1) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   //     insets = EdgeInsets.only( | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   //       left: widget.pinBoxOuterPadding.left, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   //       top: widget.pinBoxOuterPadding.top, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   //       right: 0, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   //       bottom: widget.pinBoxOuterPadding.bottom, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   //     ); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   //   } else { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   //     insets = widget.pinBoxOuterPadding; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   //   } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   // | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   //   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: RoundedRectangleBorder().toSmoothCornerDecoration( | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   //       color: pinBoxColor, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   //       borderRadius: widget.pinBoxRadius, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   //     ), | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   //     width: widget.pinBoxWidth, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   //     height: widget.pinBoxHeight, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   //     child: _animatedTextBox(strList[i], i), | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   //   ); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   // } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   Widget _animatedTextBox(String text, int i) { |  |  |  |   Widget _animatedTextBox(String text, int i) { | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (widget.pinTextAnimatedSwitcherTransition != null) { |  |  |  |     if (widget.pinTextAnimatedSwitcherTransition != null) { | 
			
		
	
		
		
			
				
					
					|  |  |  |       return AnimatedSwitcher( |  |  |  |       return AnimatedSwitcher( | 
			
		
	
	
		
		
			
				
					|  |  | @ -407,10 +450,12 @@ class OTPVerificationScreen extends StatefulWidget { | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | class _OTPVerificationScreenState extends State<OTPVerificationScreen> { |  |  |  | class _OTPVerificationScreenState extends State<OTPVerificationScreen> { | 
			
		
	
		
		
			
				
					
					|  |  |  |   final int _otpLength = 4; |  |  |  |   final int _otpLength = 4; | 
			
		
	
		
		
			
				
					
					|  |  |  |   late TextEditingController _otpController; |  |  |  |   late final TextEditingController _otpController; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   Timer? _resendTimer; |  |  |  |   Timer? _resendTimer; | 
			
		
	
		
		
			
				
					
					|  |  |  |   int _resendTime = 60; |  |  |  |   int _resendTime = 120; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   bool _isOtpComplete = false; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   bool _isVerifying = false; // Flag to prevent multiple verification calls | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   @override |  |  |  |   @override | 
			
		
	
		
		
			
				
					
					|  |  |  |   void initState() { |  |  |  |   void initState() { | 
			
		
	
	
		
		
			
				
					|  |  | @ -437,30 +482,29 @@ class _OTPVerificationScreenState extends State<OTPVerificationScreen> { | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   void _onOtpChanged(String value) { |  |  |  |   void _onOtpChanged(String value) { | 
			
		
	
		
		
			
				
					
					|  |  |  |     // Handle clipboard paste or programmatic input |  |  |  |     setState(() { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     if (value.length >= 4) { |  |  |  |       _isOtpComplete = value.length == _otpLength; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |       _onOtpCompleted(value); |  |  |  |     }); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |       // String? otp = _extractOtpFromText(value); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       // if (otp != null) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       //   autoFillOtp(otp); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       //   return; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       // } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     // The OTPWidget will automatically call onDone when complete |  |  |  |     if (_isOtpComplete && !_isVerifying) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     // This method can be used for any additional logic on text change |  |  |  |       _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() { |  |  |  |   void _resendOtp() { | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (_resendTime == 0) { |  |  |  |     if (_resendTime == 0) { | 
			
		
	
		
		
			
				
					
					|  |  |  |       setState(() => _resendTime = 60); |  |  |  |       setState(() { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         _resendTime = 120; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         _isVerifying = false; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         _isOtpComplete = false; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       }); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       _otpController.clear(); | 
			
		
	
		
		
			
				
					
					|  |  |  |       _startResendTimer(); |  |  |  |       _startResendTimer(); | 
			
		
	
		
		
			
				
					
					|  |  |  |       autoFillOtp("1234"); |  |  |  |       // autoFillOtp("1234"); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |       widget.onResendOTPPressed(widget.phoneNumber); |  |  |  |       widget.onResendOTPPressed(widget.phoneNumber); | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
	
		
		
			
				
					|  |  | @ -470,68 +514,6 @@ class _OTPVerificationScreenState extends State<OTPVerificationScreen> { | 
			
		
	
		
		
			
				
					
					|  |  |  |     return phone.length > 4 ? '05xxxxxx${phone.substring(phone.length - 2)}' : phone; |  |  |  |     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 |  |  |  |   @override | 
			
		
	
		
		
			
				
					
					|  |  |  |   Widget build(BuildContext context) { |  |  |  |   Widget build(BuildContext context) { | 
			
		
	
		
		
			
				
					
					|  |  |  |     return Scaffold( |  |  |  |     return Scaffold( | 
			
		
	
	
		
		
			
				
					|  |  | @ -561,35 +543,30 @@ class _OTPVerificationScreenState extends State<OTPVerificationScreen> { | 
			
		
	
		
		
			
				
					
					|  |  |  |               ), |  |  |  |               ), | 
			
		
	
		
		
			
				
					
					|  |  |  |               SizedBox(height: 40.h), |  |  |  |               SizedBox(height: 40.h), | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |               // OTP Input Fields using new OTPWidget |  |  |  |               // OTP Input Fields using new OTP Widget | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |               Center( |  |  |  |               Center( | 
			
		
	
		
		
			
				
					
					|  |  |  |                 child: AutofillGroup( |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 child: OTPWidget( |  |  |  |                 child: OTPWidget( | 
			
		
	
		
		
			
				
					
					|  |  |  |                   maxLength: _otpLength, |  |  |  |                   maxLength: _otpLength, | 
			
		
	
		
		
			
				
					
					|  |  |  |                   controller: _otpController, |  |  |  |                   controller: _otpController, | 
			
		
	
		
		
			
				
					
					|  |  |  |                     pinBoxWidth: 75.h, |  |  |  |                   pinBoxWidth: 70.h, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     pinBoxHeight: 100.h, |  |  |  |                   pinBoxHeight: 100, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     autoFocus: true, |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |                   pinBoxRadius: 16, |  |  |  |                   pinBoxRadius: 16, | 
			
		
	
		
		
			
				
					
					|  |  |  |                   pinBoxBorderWidth: 0, |  |  |  |                   pinBoxBorderWidth: 0, | 
			
		
	
		
		
			
				
					
					|  |  |  |                   pinBoxOuterPadding: EdgeInsets.symmetric(horizontal: 4.h), |  |  |  |                   pinBoxOuterPadding: EdgeInsets.symmetric(horizontal: 4.h), | 
			
		
	
		
		
			
				
					
					|  |  |  |                   defaultBorderColor: Colors.transparent, |  |  |  |                   defaultBorderColor: Colors.transparent, | 
			
		
	
		
		
			
				
					
					|  |  |  |                   textBorderColor: Colors.transparent, |  |  |  |                   textBorderColor: Colors.transparent, | 
			
		
	
		
		
			
				
					
					|  |  |  |                     errorBorderColor: AppColors.primaryRedColor, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                   pinBoxColor: AppColors.whiteColor, |  |  |  |                   pinBoxColor: AppColors.whiteColor, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                   autoFocus: true, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                   onTextChanged: _onOtpChanged, | 
			
		
	
		
		
			
				
					
					|  |  |  |                   pinTextStyle: TextStyle( |  |  |  |                   pinTextStyle: TextStyle( | 
			
		
	
		
		
			
				
					
					|  |  |  |                       fontSize: 50.fSize, |  |  |  |                     fontSize: 40.fSize, | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |                     fontWeight: FontWeight.bold, |  |  |  |                     fontWeight: FontWeight.bold, | 
			
		
	
		
		
			
				
					
					|  |  |  |                     color: AppColors.whiteColor, |  |  |  |                     color: AppColors.whiteColor, | 
			
		
	
		
		
			
				
					
					|  |  |  |                   ), |  |  |  |                   ), | 
			
		
	
		
		
			
				
					
					|  |  |  |                     onTextChanged: _onOtpChanged, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                     onDone: _onOtpCompleted, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                   ), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 ), |  |  |  |                 ), | 
			
		
	
		
		
			
				
					
					|  |  |  |               ), |  |  |  |               ), | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |               const SizedBox(height: 16), |  |  |  |               const SizedBox(height: 32), | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |               // Resend OTP |  |  |  |               // Resend OTP | 
			
		
	
		
		
			
				
					
					|  |  |  |               Row( |  |  |  |               Row( | 
			
		
	
	
		
		
			
				
					|  |  | @ -597,9 +574,18 @@ class _OTPVerificationScreenState extends State<OTPVerificationScreen> { | 
			
		
	
		
		
			
				
					
					|  |  |  |                 children: [ |  |  |  |                 children: [ | 
			
		
	
		
		
			
				
					
					|  |  |  |                   const Text("Didn't receive it? "), |  |  |  |                   const Text("Didn't receive it? "), | 
			
		
	
		
		
			
				
					
					|  |  |  |                   if (_resendTime > 0) |  |  |  |                   if (_resendTime > 0) | 
			
		
	
		
		
			
				
					
					|  |  |  |                     Text( |  |  |  |                     Builder( | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                       'resend in (${_resendTime.toString().padLeft(2, '0')}:00). ', |  |  |  |                       // Use a Builder to easily calculate minutes and seconds inline | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                       builder: (context) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                         final minutes = (_resendTime ~/ 60) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             .toString() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             .padLeft(2, '0'); // Integer division for minutes          final seconds = (_resendTime % 60).toString().padLeft(2, '0'); // Modulo for remaining seconds | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                         final seconds = (_resendTime % 60).toString().padLeft(2, '0'); // Modulo for remaining seconds // <--- HERE IT IS | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                         return Text( | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                           'resend in ($minutes:$seconds). ', | 
			
		
	
		
		
			
				
					
					|  |  |  |                           style: const TextStyle(color: Colors.grey), |  |  |  |                           style: const TextStyle(color: Colors.grey), | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                         ); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                       }, | 
			
		
	
		
		
			
				
					
					|  |  |  |                     ) |  |  |  |                     ) | 
			
		
	
		
		
			
				
					
					|  |  |  |                   else |  |  |  |                   else | 
			
		
	
		
		
			
				
					
					|  |  |  |                     GestureDetector( |  |  |  |                     GestureDetector( | 
			
		
	
	
		
		
			
				
					|  |  | @ -621,84 +607,16 @@ class _OTPVerificationScreenState extends State<OTPVerificationScreen> { | 
			
		
	
		
		
			
				
					
					|  |  |  |     ); |  |  |  |     ); | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   void _verifyOtp(String otp) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     debugPrint('Verifying OTP: $otp'); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     widget.checkActivationCode(int.parse(otp)); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   /// Auto fill OTP into text fields |  |  |  |   /// Auto fill OTP into text fields | 
			
		
	
		
		
			
				
					
					|  |  |  |   void autoFillOtp(String otp) { |  |  |  |   void autoFillOtp(String otp) { | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (!mounted) return; |  |  |  |     if (!mounted) return; | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (otp.length != _otpLength) return; |  |  |  |     if (otp.length != _otpLength) return; | 
			
		
	
		
		
			
				
					
					|  |  |  |      |  |  |  |     _isVerifying = false; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     try { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       // Clear any existing text first |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       _otpController.clear(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       // Use WidgetsBinding to ensure the widget tree is ready |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       WidgetsBinding.instance.addPostFrameCallback((_) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         if (!mounted) return; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         try { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |           // Set the text first |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     _otpController.text = otp; |  |  |  |     _otpController.text = otp; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |           // Use a longer delay for iOS and add validation |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |           Future.delayed(const Duration(milliseconds: 300), () { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             if (!mounted) return; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             try { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |               // Only attempt to set selection if conditions are met |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |               if (_otpController.text == otp && |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                   _otpController.text.length == _otpLength && |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                   _otpController.text.length <= _otpController.text.length) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 final newSelection = TextSelection.fromPosition( |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                   TextPosition(offset: _otpController.text.length), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 ); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 // Validate selection before setting |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 if (newSelection.baseOffset <= _otpController.text.length && |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                     newSelection.extentOffset <= _otpController.text.length) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                   _otpController.selection = newSelection; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |               } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             } catch (selectionError) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |               // Silently fail on selection - text is already set correctly |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |               debugPrint('Selection error (non-critical): $selectionError'); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |           }); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         } catch (textError) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |           debugPrint('Error setting OTP text: $textError'); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       }); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     } catch (e) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       debugPrint('Error in autoFillOtp: $e'); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   /// 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, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         ), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       ); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
	
		
		
			
				
					|  |  | 
 |