import 'dart:async'; import 'package:eatvio_app/core/locator_service.dart'; import 'package:eatvio_app/core/theme/custom_text_style.dart'; import 'package:eatvio_app/core/theme/theme_helper.dart'; import 'package:eatvio_app/core/utils/toasts.dart'; import 'package:eatvio_app/core/widgets/custom_outlined_button.dart'; import 'package:eatvio_app/features/registration/presentation/bloc/verify_email_cubit/verify_email_cubit.dart'; import 'package:eatvio_app/features/registration/presentation/bloc/verify_email_cubit/verify_email_state.dart'; import 'package:eatvio_app/features/registration/presentation/widgets/change_email_dialog.dart'; import 'package:eatvio_app/features/registration/presentation/widgets/code_not_received_dialog.dart'; import 'package:eatvio_app/features/registration/services/registration_analytics_service.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; class VerifyEmailScreen extends StatefulWidget { const VerifyEmailScreen({super.key}); @override State createState() => _VerifyEmailScreenState(); } class _VerifyEmailScreenState extends State { final List _focusNodes = List.generate(4, (_) => FocusNode()); final List _controllers = List.generate(4, (_) => TextEditingController()); String email = ''; late final GoRouter goRouter; late Timer _timer; int _secondsRemaining = 60; bool _canSendAgain = false; @override void initState() { super.initState(); goRouter = GoRouter.of(context); _startTimer(); // Report email verification screen opened RegistrationAnalyticsService.reportRegistrationStep(16); // Email verification step } @override void dispose() { for (var controller in _controllers) { controller.dispose(); } for (var node in _focusNodes) { node.dispose(); } super.dispose(); } void _startTimer() { setState(() { _canSendAgain = false; _secondsRemaining = 60; }); _timer = Timer.periodic(const Duration(seconds: 1), (timer) { setState(() { if (_secondsRemaining > 0) { _secondsRemaining--; } else { _canSendAgain = true; _timer.cancel(); } }); }); } void _checkAndSubmitCode(BuildContext context) { final code = _controllers.map((c) => c.text).join(); if (code.length == 4) { context.read().tryVerify(code); } } @override Widget build(BuildContext context) { return BlocProvider( create: (_) => sl()..sendEmailCode(), child: Builder( builder: (context) { return BlocConsumer( listener: (context, state) { if (state is VerifyEmailStateLoaded) { setState(() { email = state.email; }); _startTimer(); } else if (state is VerifyEmailStateVerifySuccess) { showSuccessToast('Почта успешно подтверждена'); goRouter.pushNamed('feedScreen'); } else if (state is VerifyEmailStateVerifyError) { showErrorToast("Неверный код. Попробуйте снова."); for (var controller in _controllers) { controller.clear(); } FocusScope.of(context).requestFocus(_focusNodes[0]); } else if (state is VerifyEmailStateChangeEmailSuccess) { showSuccessToast('Код подтверждения отправлен на новый email'); // Диалог закроется автоматически в ChangeEmailDialog при успешной смене } else if (state is VerifyEmailStateChangeEmailError) { showErrorToast('Ошибка при смене email. Попробуйте снова.'); } }, builder: (context, state) { return Scaffold( appBar: AppBar(title: const Text("Подтвердите почту")), body: Padding( padding: const EdgeInsets.all(24.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text("Код отправлен на почту\n$email", textAlign: TextAlign.center), const SizedBox(height: 20), Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: List.generate(4, (index) => _buildCodeField(context, index))), const SizedBox(height: 16), GestureDetector( onTap: () { final verifyEmailCubit = context.read(); showDialog(context: context, builder: (context) => CodeNotReceivedDialog( currentEmail: email, verifyEmailCubit: verifyEmailCubit, )); }, child: Text( 'Не приходит код?', style: TextStyles.textSMedium.copyWith(color: appTheme.blueA400, decoration: TextDecoration.underline), ), ), const SizedBox(height: 24), CustomOutlinedButton( text: 'Запросить код повторно', height: 52, isDisabled: !_canSendAgain, buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700), buttonStyle: ButtonStyle( side: const WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll(_canSendAgain ? appTheme.blueA400 : appTheme.gray), ), onPressed: () async { await context.read().sendEmailCode(); _startTimer(); }, ), const SizedBox(height: 8), if (!_canSendAgain) Text("Зпросить код повторно можно через $_secondsRemaining с.", style: TextStyles.textSMedium.copyWith(color: appTheme.gray)), const SizedBox(height: 16), CustomOutlinedButton( text: 'Сменить email', height: 52, buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.blueA400), buttonStyle: ButtonStyle( side: WidgetStatePropertyAll(BorderSide(color: appTheme.blueA400)), backgroundColor: const WidgetStatePropertyAll(Colors.transparent), ), onPressed: () { final verifyEmailCubit = context.read(); showDialog( context: context, builder: (context) => ChangeEmailDialog(currentEmail: email, verifyEmailCubit: verifyEmailCubit), ); }, ), ], ), ), ); }, ); }, ), ); } Widget _buildCodeField(BuildContext context, int index) { return SizedBox( width: 50, child: TextField( controller: _controllers[index], focusNode: _focusNodes[index], keyboardType: TextInputType.number, textAlign: TextAlign.center, maxLength: 1, style: const TextStyle(fontSize: 24), decoration: InputDecoration( counterText: "", border: OutlineInputBorder(borderRadius: BorderRadius.circular(8.0)), ), onChanged: (value) { if (value.isNotEmpty && index < 3) { FocusScope.of(context).requestFocus(_focusNodes[index + 1]); } if (value.isEmpty && index > 0) { FocusScope.of(context).requestFocus(_focusNodes[index - 1]); } _checkAndSubmitCode(context); }, ), ); } }