@ -1,15 +1,21 @@
import ' dart:async ' ;
import ' dart:async ' ;
import ' package:easy_localization/easy_localization.dart ' ;
import ' package:flutter/animation.dart ' ;
import ' package:flutter/animation.dart ' ;
import ' package:flutter/foundation.dart ' ;
import ' package:flutter/foundation.dart ' ;
import ' package:flutter/material.dart ' ;
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:get_it/get_it.dart ' ;
import ' package:get_it/get_it.dart ' ;
import ' package:hmg_patient_app_new/core/app_state.dart ' ;
import ' package:hmg_patient_app_new/core/cache_consts.dart ' ;
import ' package:hmg_patient_app_new/core/cache_consts.dart ' ;
import ' package:hmg_patient_app_new/core/dependencies.dart ' ;
import ' package:hmg_patient_app_new/core/enums.dart ' ;
import ' package:hmg_patient_app_new/core/utils/size_utils.dart ' ;
import ' package:hmg_patient_app_new/core/utils/size_utils.dart ' ;
import ' package:hmg_patient_app_new/extensions/string_extensions.dart ' ;
import ' package:hmg_patient_app_new/extensions/widget_extensions.dart ' ;
import ' package:hmg_patient_app_new/extensions/widget_extensions.dart ' ;
import ' package:hmg_patient_app_new/features/authentication/authentication_view_model.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/services/cache_service.dart ' ;
import ' package:hmg_patient_app_new/services/cache_service.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 ' ;
@ -53,7 +59,8 @@ class OTPWidget extends StatefulWidget {
final FocusNode ? focusNode ;
final FocusNode ? focusNode ;
final AnimatedSwitcherTransitionBuilder ? pinTextAnimatedSwitcherTransition ;
final AnimatedSwitcherTransitionBuilder ? pinTextAnimatedSwitcherTransition ;
final Duration pinTextAnimatedSwitcherDuration ;
final Duration pinTextAnimatedSwitcherDuration ;
final TextDirection textDirection ;
/ / final TextDirection textDirection ;
final TextInputType keyboardType ;
final TextInputType keyboardType ;
final EdgeInsets pinBoxOuterPadding ;
final EdgeInsets pinBoxOuterPadding ;
@ -74,7 +81,6 @@ class OTPWidget extends StatefulWidget {
this . onTextChanged ,
this . onTextChanged ,
this . autoFocus = false ,
this . autoFocus = false ,
this . focusNode ,
this . focusNode ,
this . textDirection = TextDirection . ltr ,
this . keyboardType = TextInputType . number ,
this . keyboardType = TextInputType . number ,
this . pinBoxOuterPadding = const EdgeInsets . symmetric ( horizontal: 4.0 ) ,
this . pinBoxOuterPadding = const EdgeInsets . symmetric ( horizontal: 4.0 ) ,
this . pinBoxColor = Colors . white ,
this . pinBoxColor = Colors . white ,
@ -182,17 +188,9 @@ class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixi
widget . controller ! . clear ( ) ;
widget . controller ! . clear ( ) ;
}
}
/ / Remove focus from the input
if ( focusNode . hasFocus ) {
if ( focusNode . hasFocus ) {
focusNode . unfocus ( ) ;
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 ) ;
}
} ) ;
}
}
}
}
@ -402,58 +400,6 @@ 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 (
@ -586,6 +532,7 @@ class _OTPVerificationScreenState extends State<OTPVerificationScreen> {
@ override
@ override
Widget build ( BuildContext context ) {
Widget build ( BuildContext context ) {
AuthenticationViewModel authVM = context . read < AuthenticationViewModel > ( ) ;
return Scaffold (
return Scaffold (
backgroundColor: AppColors . scaffoldBgColor ,
backgroundColor: AppColors . scaffoldBgColor ,
appBar: CustomAppBar (
appBar: CustomAppBar (
@ -601,19 +548,22 @@ class _OTPVerificationScreenState extends State<OTPVerificationScreen> {
child: Column (
child: Column (
crossAxisAlignment: CrossAxisAlignment . start ,
crossAxisAlignment: CrossAxisAlignment . start ,
children: [
children: [
SizedBox ( height: 40. h ) ,
SizedBox ( height: 10. h ) ,
Text (
LocaleKeys . otpVerification . tr ( ) . toText24 ( isBold: true ) ,
' OTP Verification ' ,
SizedBox ( height: 20. h ) ,
style: TextStyle ( fontSize: 24. fSize , fontWeight: FontWeight . bold ) ,
Wrap (
) ,
spacing: 4. h ,
SizedBox ( height: 16. h ) ,
runSpacing: 8.0 ,
Text (
children: [
' We have sent you the OTP code on ${ _getMaskedPhoneNumber ( ) } via SMS for registration verification ' ,
LocaleKeys . weHaveSendOTP . tr ( ) . toText16 ( color: AppColors . inputLabelTextColor ) ,
style: TextStyle ( fontSize: 16. fSize , color: Colors . grey ) ,
_getMaskedPhoneNumber ( ) . toText16 ( color: AppColors . inputLabelTextColor , isBold: true ) ,
LocaleKeys . via . tr ( ) . toText16 ( color: AppColors . inputLabelTextColor ) ,
authVM . loginTypeEnum . displayName . toText16 ( color: AppColors . inputLabelTextColor ) ,
LocaleKeys . forRegistrationVerification . tr ( ) . toText16 ( color: AppColors . inputLabelTextColor ) ,
] ,
) ,
) ,
SizedBox ( height: 40. h ) ,
/ / OTP Input Fields using new OTP Widget
SizedBox ( height: 16. h ) ,
Center (
Center (
child: OTPWidget (
child: OTPWidget (
maxLength: _otpLength ,
maxLength: _otpLength ,
@ -635,38 +585,32 @@ class _OTPVerificationScreenState extends State<OTPVerificationScreen> {
) ,
) ,
) ,
) ,
) ,
) ,
SizedBox ( height: 32. h ) ,
const SizedBox ( height: 32 ) ,
/ / Resend OTP
/ / Resend OTP
Row (
Row (
mainAxisAlignment: MainAxisAlignment . center ,
mainAxisAlignment: MainAxisAlignment . center ,
children: [
children: [
const Text ( " Didn't receive it? " ) ,
LocaleKeys . didntReceiveIt . tr ( ) . toText16 ( color: AppColors . inputLabelTextColor ) ,
SizedBox ( width: 5. h ) ,
if ( _resendTime > 0 )
if ( _resendTime > 0 )
Builder (
Builder (
/ / Use a Builder to easily calculate minutes and seconds inline
builder: ( context ) {
builder: ( context ) {
final minutes = ( _resendTime ~ / 60 )
final minutes = ( _resendTime ~ / 60 ) . toString ( ) . padLeft ( 2 , ' 0 ' ) ;
. toString ( )
final seconds = ( _resendTime % 60 ) . toString ( ) . padLeft ( 2 , ' 0 ' ) ;
. padLeft ( 2 , ' 0 ' ) ; / / Integer division for minutes final seconds = ( _resendTime % 60 ) . toString ( ) . padLeft ( 2 , ' 0 ' ) ; / / Modulo for remaining seconds
return Row (
final seconds = ( _resendTime % 60 ) . toString ( ) . padLeft ( 2 , ' 0 ' ) ; / / Modulo for remaining seconds / / < - - - HERE IT IS
children: [
return Text (
LocaleKeys . resendIn . tr ( ) . toText16 ( color: AppColors . inputLabelTextColor ) ,
' resend in ( $ minutes : $ seconds ). ' ,
SizedBox ( width: 2. h ) ,
style: const TextStyle ( color: Colors . grey ) ,
' ( $ minutes : $ seconds ). ' . toText16 ( color: AppColors . inputLabelTextColor )
] ,
) ;
) ;
} ,
} ,
)
)
else
else
GestureDetector (
GestureDetector (
onTap: _resendOtp ,
onTap: _resendOtp ,
child: const Text (
child: LocaleKeys . resendOTP . tr ( ) . toText16 ( color: AppColors . primaryRedColor ) ,
' Resend ' ,
style: TextStyle (
color: AppColors . primaryRedColor ,
fontWeight: FontWeight . bold ,
) ,
) ,
) ,
) ,
] ,
] ,
) ,
) ,
@ -678,7 +622,6 @@ class _OTPVerificationScreenState extends State<OTPVerificationScreen> {
}
}
void _verifyOtp ( String otp ) {
void _verifyOtp ( String otp ) {
debugPrint ( ' Verifying OTP: $ otp ' ) ;
widget . checkActivationCode ( int . parse ( otp ) ) ;
widget . checkActivationCode ( int . parse ( otp ) ) ;
}
}
@ -689,6 +632,6 @@ class _OTPVerificationScreenState extends State<OTPVerificationScreen> {
_isVerifying = false ;
_isVerifying = false ;
_otpController . text = otp ;
_otpController . text = otp ;
setState ( ( ) { } ) ;
setState ( ( ) { } ) ;
_onOtpChanged ( otp ) ; / / Ensure verification and color update
_onOtpChanged ( otp ) ;
}
}
}
}