import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/flutter_svg.dart'; import '../../../../gen/assets.gen.dart'; import '../../../../widgets/button.dart'; import '../../../../widgets/remainingTime.dart'; import '../bloc/auth_bloc.dart'; import 'user_info_page.dart'; class OTPVerificationPage extends StatefulWidget { final String phoneNumber; final String timeDue; const OTPVerificationPage({ super.key, required this.phoneNumber, required this.timeDue, }); @override State createState() => _OTPVerificationPageState(); } class _OTPVerificationPageState extends State { final List _focusNodes = List.generate(5, (_) => FocusNode()); final List _controllers = List.generate(5, (_) => TextEditingController()); late RemainingTime _otpTimer; @override void initState() { super.initState(); _otpTimer = RemainingTime(); _initializeTimer(); } void _initializeTimer() { _otpTimer.initializeFromExpiry(expiryTimeString: widget.timeDue); } void _resendOTP() { if (_otpTimer.canResend.value) { context .read() .add(SendOTPEvent(phoneNumber: widget.phoneNumber)); } } @override void dispose() { for (final node in _focusNodes) { node.dispose(); } for (final controller in _controllers) { controller.dispose(); } _otpTimer.dispose(); super.dispose(); } Widget _buildOTPFields() { return Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: List.generate(5, (index) { return SizedBox( width: 60, child: TextField( controller: _controllers[index], focusNode: _focusNodes[index], keyboardType: TextInputType.number, textAlign: TextAlign.center, maxLength: 1, style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), decoration: InputDecoration( counterText: '', hintText: "0", enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: const BorderSide(color: Colors.grey), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: const BorderSide(color: Color.fromARGB(255, 14, 63, 102)), ), ), onChanged: (value) { if (value.length == 1 && index < 4) { FocusScope.of(context).requestFocus(_focusNodes[index + 1]); } }, ), ); }), ); } @override Widget build(BuildContext context) { final height = MediaQuery.of(context).size.height; return BlocListener( listener: (context, state) { if (state is AuthSuccess) { _otpTimer.initializeFromExpiry(expiryTimeString: state.timeDue); } }, child: Scaffold( body: SafeArea( child: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ IconButton( icon: SvgPicture.asset(Assets.icons.back.path), onPressed: () => Navigator.pop(context), ), ], ), Padding( padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 24), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Center( child: Padding( padding: const EdgeInsets.only(top: 0), child: SvgPicture.asset(Assets.images.logo.path, height: height / 5.2), ), ), SizedBox(height: height / 20), const Text("OTP Verification", style: TextStyle( fontSize: 33, fontWeight: FontWeight.bold)), const SizedBox(height: 8), const Text( "Enter the verification code we just sent to your device.", style: TextStyle( fontSize: 17, fontWeight: FontWeight.w500), ), const SizedBox(height: 25), _buildOTPFields(), SizedBox(height: height / 7), BlocConsumer( listener: (context, state) { if (state is OTPVerified) { Navigator.push( context, MaterialPageRoute( builder: (context) => const UserInfoPage()), ); } if (state is AuthError) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( duration: const Duration(seconds: 2), backgroundColor: Colors.red, content: Text(state.message), ), ); } }, builder: (context, state) { if (state is AuthLoading) { return const Center( child: CircularProgressIndicator()); } return SizedBox( width: double.infinity, height: 48, child: Button( text: "Verify", onPressed: () { final otpCode = _controllers.map((c) => c.text).join(); if (otpCode.length >= 4) { context.read().add(VerifyOTPEvent( otpCode: otpCode, phoneNumber: widget.phoneNumber, )); } else { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( backgroundColor: Colors.red, content: Text( 'لطفاً کد OTP را کامل وارد کنید'), ), ); } }, color: const Color.fromARGB(255, 30, 137, 221), ), ); }, ), SizedBox(height: height / 25), Center( child: Column( children: [ Row( children: [ const Expanded( child: Divider( thickness: 1, color: Colors.grey), ), ValueListenableBuilder( valueListenable: _otpTimer.remainingSeconds, builder: (context, seconds, _) { return Padding( padding: const EdgeInsets.symmetric( horizontal: 8.0), child: Text( "Resend OTP in ${_otpTimer.formatTime()}", style: const TextStyle( fontWeight: FontWeight.w500, fontSize: 18), ), ); }, ), const Expanded( child: Divider( thickness: 1, color: Colors.grey), ), ], ), const SizedBox(height: 8), ValueListenableBuilder( valueListenable: _otpTimer.canResend, builder: (context, canResend, _) { return GestureDetector( onTap: canResend ? _resendOTP : null, child: Text( "Resend OTP", style: TextStyle( fontSize: 16, color: canResend ? const Color.fromARGB( 255, 0, 0, 0) : Colors.grey, ), ), ); }, ), ], ), ), ], ), ), ], ), ), ), ), ); } }