import 'dart:async'; // For Timer import 'dart:developer'; import 'package:animated_text_kit/animated_text_kit.dart'; import 'package:wanisclient/config/AppSnackbar.dart'; import 'package:wanisclient/screens/login_screnn.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get.dart'; import 'package:pin_code_fields/pin_code_fields.dart'; import 'package:provider/provider.dart'; import '../config/custom_text.dart'; import '../config/language/language_enum.dart'; import '../providers/authentification_provider.dart'; import '../providers/language_provider.dart'; import '../providers/utils_singleton.dart'; import '../services/Sockets/PubNubManager.dart'; import '../utils/colors.dart'; import '../widgets/custom_button.dart'; import 'NewUiScreen/CreatePasswordScreen.dart'; import 'NewUiScreen/PermissionModals/ProfileCompletedModal.dart'; import 'NewUiScreen/RegistrationScreen.dart'; import 'NewUiScreen/Selfi/AddProfilePicture.dart'; import 'allow_location_screen.dart'; import 'package:beemwidget/text_styles/beem_text_styles.dart'; class OtpVerificationScreen extends StatefulWidget { final String phoneNumber; final bool isForgetPassword; final bool? isupdatephonenumber; final bool? isLogin; OtpVerificationScreen({ super.key, required this.phoneNumber, required this.isForgetPassword, this.isLogin, this.isupdatephonenumber, }); @override _OtpVerificationScreenState createState() => _OtpVerificationScreenState(); } class _OtpVerificationScreenState extends State { final TextEditingController _otpController = TextEditingController(); Timer? _timer; int _secondsRemaining = 30; bool _isButtonDisabled = true; bool _isDisposed = false; // Add this flag int currentPermissionStep = 0; // 0: location, 1: contacts, 2: notifications bool showRegistration = true; @override void initState() { super.initState(); _startCountdown(); // Start countdown when the screen is first loaded } @override void dispose() { _isDisposed = true; _timer?.cancel(); // Detach controller from the widget tree before disposing it // WidgetsBinding.instance.addPostFrameCallback((_) { // if (mounted) setState(() {}); // }); _otpController.dispose(); super.dispose(); } void _startCountdown() { _timer?.cancel(); _secondsRemaining = 30; _isButtonDisabled = true; _timer = Timer.periodic(const Duration(seconds: 1), (timer) { if (_isDisposed) { timer.cancel(); return; } if (_secondsRemaining > 0) { if (!_isDisposed) { setState(() { _secondsRemaining--; }); } } else { timer.cancel(); if (!_isDisposed) { setState(() { _isButtonDisabled = false; }); } } }); } void _resendCode() async { final signUpProvider = Provider.of(context, listen: false); if (_isButtonDisabled) return; // Button should only work if it's enabled // Simulate resend code action var res = await signUpProvider.phoneTextLogin(widget.phoneNumber); if (res) { AppSnackbar.showInfo("Info","the code has been sent to you again"); _startCountdown(); } } @override Widget build(BuildContext context) { final languageProvider = context.watch(); // Watch for changes bool isArabic = languageProvider.currentLangCode == Language.ar; bool isFrench = languageProvider.currentLangCode == Language.fr; final signUpProvider = Provider.of(context, listen: false); return SafeArea( child: Scaffold( backgroundColor: Colors.white, resizeToAvoidBottomInset: false, appBar: AppBar( backgroundColor: Colors.white, elevation: 0, leading: Container( margin: const EdgeInsets.all(8), decoration: ShapeDecoration( color: const Color(0xFFF5F5F5), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), ), shadows: const [ BoxShadow( color: Color(0x07000000), blurRadius: 6, offset: Offset(0, 3), spreadRadius: -1.50, ), ], ), child: IconButton( icon: const Icon(Icons.arrow_back, color: Colors.black, size: 20), onPressed: () => Navigator.pop(context), ), ), ), body: Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 20), // Header Section SizedBox( width: double.infinity, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Txt( text: 'Phone Number Verification', style: TextStyle( color: AppNewColors.titleTextColor, fontSize: 26, fontFamily: isArabic ? "Readex_Pro" : 'Inter', fontWeight: FontWeight.w600, height: 1.23, ), ), const SizedBox(height: 4), Txt( text: isArabic ? ' تم إرسال رمز إلى رقم هاتفك +${widget.phoneNumber}' : isFrench ? 'Un code a été envoyé à votre numéro. +${widget.phoneNumber}' : 'A code has been sent to your number +${widget.phoneNumber}', style: TextStyle( color: AppNewColors.grayTxtColor, fontSize: 18, fontFamily: isArabic ? "Readex_Pro" : 'Inter', fontWeight: FontWeight.w500, height: 1.33, ), ), ], ), ), const SizedBox(height: 32), // PIN Code Section _pinCodeSection(context), const SizedBox(height: 4), // Resend Code Section _resentCodeSection(), const SizedBox(height: 24), CustomButton( onClick: signUpProvider.loader || _otpController.text.length < 4 ? null : () async { if (!mounted) return; log('OTP is ------------------ : ${_otpController.text}'); try { var isValid = false; if(widget.isupdatephonenumber!=null && widget.isupdatephonenumber==true){ bool isValid = await context.read().verifyphonenumber(widget.phoneNumber,_otpController.text); if (isValid && mounted) { // Cancel the timer BEFORE navigating _timer?.cancel(); Navigator.push(context, MaterialPageRoute(builder: (context)=> RegistrationScreen( onRegistrationComplete: () { _showProfileCompletedModal(context, isArabic); }, ),),); } } else if(widget.isForgetPassword){ isValid = await signUpProvider.validateResetPasswordOTP( widget.phoneNumber, _otpController.text, context); if (isValid && mounted) { // Cancel the timer BEFORE navigating _timer?.cancel(); Navigator.push( context, MaterialPageRoute( builder: (context) => CreatePasswordScreen(isForgetPassword:true,phonenumber:widget.phoneNumber ,code: _otpController.text,), ), ); } } else if(widget.isLogin !=null && widget.isLogin ==true){ isValid = await signUpProvider.validateOTPAuth( widget.phoneNumber, _otpController.text, context); if (isValid && mounted) { _timer?.cancel(); await signUpProvider.fetchProfile(); final userContext = UserContext(username: utils.user!.username!); context.read().init(userContext); if (mounted) { Get.offAll(() => const AllowLocationScreen(showRegistration: false)); } } } else{ isValid = await signUpProvider.validateOTP( widget.phoneNumber, _otpController.text, context); if (isValid && mounted) { // Cancel the timer BEFORE navigating _timer?.cancel(); Navigator.push( context, MaterialPageRoute( builder: (context) => CreatePasswordScreen(isForgetPassword:false,phonenumber:"" ,code: "",), ), ); // Get.offAll(() => const CreatePasswordScreen()); // await signUpProvider.fetchProfile(); // final userContext = UserContext(username: utils.user!.username!); // context.read().init(userContext); // if (mounted) { // Get.offAll(() => const AllowLocationScreen()); // } } } } finally { if (mounted && Navigator.canPop(context)) { //Navigator.of(context).pop(); } } }, fontSize: 18, width: double.infinity, height: 40, borderRadius: 10, txtColor: !_isDisposed &&_otpController.text.length >= 4 && !signUpProvider.loader ? AppNewColors.white : AppNewColors.nullBtnColor, title: 'Verify the code', backgroundColor: !_isDisposed &&_otpController.text.length >= 4 && !signUpProvider.loader ? AppNewColors.primaryBtnColor : AppNewColors.inputColor, borderColor: !_isDisposed &&_otpController.text.length >= 4 && !signUpProvider.loader ? AppNewColors.primaryBtnColor : AppNewColors.inputColor, isloading: signUpProvider.loader, loadercolor: AppNewColors.inputColor, ), const Spacer(), ], ), ), ), ); } void _showProfileCompletedModal(BuildContext context, bool isArabic) { showDialog( context: context, barrierDismissible: false, builder: (context) => Dialog( backgroundColor: Colors.transparent, child: ProfileCompletedModal( isArabic: isArabic, onContinue: () { Navigator.push( context, MaterialPageRoute( builder: (context) => const AddProfilePicture())); setState(() { showRegistration = false; currentPermissionStep = 0; }); }, ), ), ); } Widget _pinCodeSection(BuildContext context) { bool isArabic = languageSingleton.currentLangCode == Language.ar; String _otpValue = ''; return Directionality( textDirection: TextDirection.ltr, child: PinCodeTextField( mainAxisAlignment: MainAxisAlignment.spaceAround, appContext: context, controller: _isDisposed ? null : _otpController, length: 4, blinkWhenObscuring: true, enableActiveFill: true, animationType: AnimationType.fade, cursorColor: AppNewColors.primaryColor, validator: (val) { return null; }, onChanged: (value) { if (mounted && !_isDisposed) { setState(() { _otpValue = value; }); } }, separatorBuilder: (context, index) { // Add dash separator between 2nd and 3rd box if (index == 1) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 20.0), child: Text( '-', style: TextStyle( color: const Color(0xFF8C929C), fontSize: 22, fontFamily: isArabic ? "Readex_Pro" : 'Inter', fontWeight: FontWeight.w500, height: 1.45, ), ), ); } return const SizedBox(width: 8); }, pinTheme: PinTheme( shape: PinCodeFieldShape.box, borderRadius: BorderRadius.circular(10), fieldHeight: 53, fieldWidth: 70, borderWidth: 0, activeColor: AppNewColors.primaryColor, selectedColor: AppNewColors.primaryColor, inactiveColor: Colors.transparent, disabledColor: Colors.transparent, activeFillColor: const Color(0xFFF2F2F4), selectedFillColor: const Color(0xFFF2F2F4), inactiveFillColor: const Color(0xFFF2F2F4), errorBorderColor: Colors.redAccent, ), keyboardType: TextInputType.number, animationDuration: const Duration(milliseconds: 300), textStyle: TextStyle( fontFamily: isArabic ? "Readex_Pro" : 'Inter', fontSize: 22, fontWeight: FontWeight.w600, color: AppNewColors.titleTextColor, height: 1.45, ), ), ); } Widget _resentCodeSection() { final languageProvider = context.watch(); // Watch for changes bool isArabic = languageProvider.currentLangCode == Language.ar; bool isFrench = languageProvider.currentLangCode == Language.fr; final signUpProvider = Provider.of(context, listen: false); return Row( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.center, children: [ if (_isButtonDisabled) Text( isArabic ? 'إعادة الإرسال بعد ${_secondsRemaining}s' : isFrench ? 'Renvoyer le code dans ${_secondsRemaining}s' : 'Resend code in ${_secondsRemaining}s', style: TextStyle( color: AppNewColors.grayTxtColor, fontSize: 14, fontFamily: isArabic ? "Readex_Pro" : 'Inter', fontWeight: FontWeight.w500, height: 1.71, ), ), if (!_isButtonDisabled) GestureDetector( onTap: _isButtonDisabled || signUpProvider.loader ? null : _resendCode, child: Txt( text: 'Resend code', style: TextStyle( color: AppNewColors.grayTxtColor, fontSize: 14, fontFamily: isArabic ? "Readex_Pro" : 'Inter', fontWeight: FontWeight.w500, height: 1.71, decoration: TextDecoration.underline, ), ), ), ], ); } }