import 'package:eatvio_app/core/utils/image_constant.dart'; import 'package:eatvio_app/core/widgets/loader.dart'; import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart'; import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_state.dart'; import 'package:eatvio_app/features/registration/presentation/pages/additional_information_screen.dart'; import 'package:eatvio_app/features/registration/presentation/pages/allergies_screen.dart'; import 'package:eatvio_app/features/registration/presentation/pages/blood_pressure_screen.dart'; import 'package:eatvio_app/features/registration/presentation/pages/body_circumferences_screen.dart'; import 'package:eatvio_app/features/registration/presentation/pages/city_of_living_screen.dart'; import 'package:eatvio_app/features/registration/presentation/pages/credentials_screen.dart'; import 'package:eatvio_app/features/registration/presentation/pages/date_of_birth_screen.dart'; import 'package:eatvio_app/features/registration/presentation/pages/favorite_foods_screen.dart'; import 'package:eatvio_app/features/registration/presentation/pages/favorite_sports_screen.dart'; import 'package:eatvio_app/features/registration/presentation/pages/gender_screen.dart'; import 'package:eatvio_app/features/registration/presentation/pages/height_screen.dart'; import 'package:eatvio_app/features/registration/presentation/pages/medicine_intake_screen.dart'; import 'package:eatvio_app/features/registration/presentation/pages/name_screen.dart'; import 'package:eatvio_app/features/registration/presentation/pages/phone_screen.dart'; import 'package:eatvio_app/features/registration/presentation/pages/weight_screen.dart'; import 'package:eatvio_app/generated/l10n.dart'; import 'package:eatvio_app/core/locator_service.dart'; import 'package:eatvio_app/core/theme/theme_helper.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:go_router/go_router.dart'; import 'package:validators/validators.dart'; class RegistrationScreen extends StatefulWidget { const RegistrationScreen({super.key}); @override State createState() => _RegistrationScreenState(); } class _RegistrationScreenState extends State { double progressValue = 1 / 15; int step = 1; final pageController = PageController(); final RegistrationCubit registrationCubit = sl(); @override Widget build(BuildContext context) { return BlocProvider( create: (BuildContext context) => registrationCubit, child: BlocBuilder( builder: (BuildContext context, RegistrationState state) { return Scaffold( floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, floatingActionButton: Row( children: [ Container( height: 48, width: MediaQuery.of(context).size.width * 0.2, padding: EdgeInsets.only(left: 16, right: 4), child: FloatingActionButton.extended( heroTag: 'backButtonRegistration', highlightElevation: 0, focusElevation: 0, elevation: 0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20), ), backgroundColor: Color(0xFFEAF2FD), onPressed: () async { setState(() { pageController.previousPage( duration: const Duration(milliseconds: 350), curve: Curves.easeInOut, ); }); }, label: Icon( Icons.arrow_back_ios_new_rounded, color: appTheme.blueA400, ), ), ), Container( height: 48, width: MediaQuery.of(context).size.width * 0.8, padding: EdgeInsets.only(left: 4, right: 16), child: FloatingActionButton.extended( heroTag: 'nextButtonRegistration', highlightElevation: 0, elevation: 0, focusElevation: 0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20), ), backgroundColor: appTheme.blueA400, onPressed: () async { if (await canGoNext(state)) { setState(() { pageController.nextPage( duration: const Duration(milliseconds: 350), curve: Curves.easeInOut, ); }); } }, label: Text( 'Продолжить', style: theme.textTheme.titleSmall!.copyWith(color: Colors.white), ), ), ), ], ), appBar: AppBar( automaticallyImplyLeading: false, leading: Builder( builder: (context) => IconButton( icon: Icon(Icons.close_rounded), onPressed: () => GoRouter.of(context).pop(), ), ), centerTitle: true, title: SvgPicture.asset( ImageConstant.imgLogoEatvio, height: 48, fit: BoxFit.contain, ), actions: [ Padding( padding: const EdgeInsets.only(right: 16), child: Text('шаг $step из 15'), ), ], bottom: PreferredSize( preferredSize: Size(MediaQuery.of(context).size.width, 32), child: Padding( padding: const EdgeInsets.all(16), child: TweenAnimationBuilder( duration: const Duration(milliseconds: 350), curve: Curves.easeInOut, tween: Tween( begin: 1 / 15, end: progressValue, ), builder: (context, value, _) => LinearProgressIndicator( value: value, borderRadius: BorderRadius.circular(16), minHeight: 8, backgroundColor: Colors.grey.shade100, valueColor: AlwaysStoppedAnimation(appTheme.blueA400), ), ), ), ), ), body: PageView( physics: NeverScrollableScrollPhysics(), controller: pageController, onPageChanged: (index) { setState(() { step = index + 1; progressValue = step / 15; }); }, children: [ // LanguageSelectScreen(sheet: state.sheet), PhoneScreen(sheet: state.sheet), CredentialsScreen(sheet: state.sheet), NameScreen(sheet: state.sheet), GenderScreen(sheet: state.sheet), DateOfBirthScreen(sheet: state.sheet), CityOfLivingScreen(sheet: state.sheet), BodyCircumferencesScreen(sheet: state.sheet), WeightScreen(sheet: state.sheet), HeightScreen(sheet: state.sheet), BloodPressureScreen(sheet: state.sheet), AllergiesScreen(sheet: state.sheet), MedicineIntakeScreen(sheet: state.sheet), FavoriteSportsScreen(sheet: state.sheet), FavoriteFoodsScreen(sheet: state.sheet), AdditionalInformationScreen(sheet: state.sheet), ], ), ); }, ), ); } Future canGoNext(RegistrationState state) async { switch (step) { case 1: if (state.sheet.phone.length != 18) { showDialog( context: context, builder: (context) => AlertDialog( title: Text('Ошибка'), content: Text('Введите корректный номер телефона'), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: Text('OK'), ), ], ), ); return false; } else { return true; } case 2: List errors = validateCredentialsFields( state.sheet.email, state.sheet.password, state.sheet.passwordConfirmation, context, ); if (errors.isEmpty) { return true; } else { String errorMessage = ''; for (var error in errors) { errorMessage += error + '\n\n'; } showDialog( context: context, builder: (context) => AlertDialog( title: Text('Ошибка'), content: Text(errorMessage), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: Text('OK'), ), ], ), ); return false; } case 3: List errors = validateNameFields( state.sheet.firstName.toString(), state.sheet.lastName.toString(), context, ); if (errors.isEmpty) { return true; } else { String errorMessage = ''; for (var error in errors) { errorMessage += error + '\n\n'; } showDialog( context: context, builder: (context) => AlertDialog( title: Text('Ошибка'), content: Text(errorMessage), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: Text('OK'), ), ], ), ); return false; } case 4: if (state.sheet.gender.isNotEmpty) return true; else { showDialog( context: context, builder: (context) => AlertDialog( title: Text('Ошибка'), content: Text('Выберете пол'), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: Text('OK'), ), ], ), ); return false; } case 6: if (state.sheet.location.isNotEmpty) return true; else { showDialog( context: context, builder: (context) => AlertDialog( title: Text('Ошибка'), content: Text('Заполните все поля'), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: Text('OK'), ), ], ), ); return false; } case 7: List errors = validateCircumferencesFields( state.sheet.chestCircumference.toString(), state.sheet.waistCircumference.toString(), state.sheet.hipCircumference.toString(), context, ); if (errors.isEmpty) { return true; } else { String errorMessage = ''; for (var error in errors) { errorMessage += error + '\n\n'; } showDialog( context: context, builder: (context) => AlertDialog( title: Text('Ошибка'), content: Text(errorMessage), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: Text('OK'), ), ], ), ); return false; } case 15: try { showDialog( barrierDismissible: false, useSafeArea: false, context: context, builder: (context) => PopScope( canPop: false, child: const Loader(), ), ); await registrationCubit.tryRegistration(); Navigator.pop(context); } catch (e) { Navigator.pop(context); showDialog( context: context, builder: (context) => AlertDialog( title: Text('Ошибка при попытке регистрации'), ), ); } return false; default: return true; } } List validateCircumferencesFields( String chestCircumference, String waistCircumference, String hipCircumference, BuildContext context, ) { final s = S.of(context); List errors = []; if (chestCircumference.isEmpty | waistCircumference.isEmpty | hipCircumference.isEmpty) { errors.add(s.circumference_empty); } if (![chestCircumference, waistCircumference, hipCircumference].every((circumference) => int.tryParse(circumference) != null)) { errors.add(s.circumference_is_not_a_number); } return errors; } List validateCredentialsFields( String email, String password, String passwordConfirmation, BuildContext context, ) { final s = S.of(context); List errors = []; if (!isEmail(email)) { errors.add(s.email_invalid); } if (email.isEmpty) { errors.add(s.email_empty); } if (password.length < 6) { errors.add(s.password_short); } if (password != passwordConfirmation) { errors.add(s.password_confirmation_mismatch); } return errors; } List validateNameFields( String firstName, String lastName, BuildContext context, ) { List errors = []; if (firstName.isEmpty) { errors.add('First name cannot be empty'); } if (firstName.length < 1) { errors.add('First name is too short'); } if (lastName.isEmpty) { errors.add('Last name cannot be empty'); } if (lastName.length < 1) { errors.add('Last name is too short'); } return errors; } }