diff --git a/assets/icons/sucess.svg b/assets/icons/sucess.svg
new file mode 100644
index 00000000..a4cf6d09
--- /dev/null
+++ b/assets/icons/sucess.svg
@@ -0,0 +1,3 @@
+
diff --git a/lib/core/di/cubit_registrations.dart b/lib/core/di/cubit_registrations.dart
index ca3ece97..36e9823d 100644
--- a/lib/core/di/cubit_registrations.dart
+++ b/lib/core/di/cubit_registrations.dart
@@ -46,6 +46,7 @@ import 'package:eatvio_app/features/recipe/presentation/cubit/about_recipe_cubit
import 'package:eatvio_app/features/recipe/presentation/cubit/my_recipes_cubit/my_recieps_cubit.dart';
import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart';
import 'package:eatvio_app/features/registration/presentation/bloc/verify_email_cubit/verify_email_cubit.dart';
+import 'package:eatvio_app/features/registration_v2/cubit/registration_cubit.dart';
import 'package:eatvio_app/features/settings/presentation/bloc/settings_cubit/settings_cubit.dart';
import 'package:eatvio_app/features/user_details/presentation/cubit/user_details_cubit.dart';
import 'package:eatvio_app/core/comments/comments_cubit/comments_cubit.dart';
@@ -78,6 +79,7 @@ class CubitRegistrations {
sl.registerFactory(() => ResetPasswordCubit(resetPasswordRepository: sl()));
sl.registerFactory(() => VerifyEmailCubit(profileRepository: sl()));
sl.registerFactory(() => OAuthCubit(authRepository: sl()));
+ sl.registerFactory(() => RegistrationCubitV2());
// Feed related cubits
sl.registerFactory(() => FeedCubit(feedRepository: sl()));
sl.registerFactory(() => RecipesCubit(feedRepository: sl(), recipeRepository: sl(), aboutRecipeRepository: sl()));
diff --git a/lib/core/routing/auth_routes.dart b/lib/core/routing/auth_routes.dart
index 39e7b2a9..2ac62618 100644
--- a/lib/core/routing/auth_routes.dart
+++ b/lib/core/routing/auth_routes.dart
@@ -9,6 +9,7 @@ import 'package:eatvio_app/features/auth/presentation/pages/scan_qr_code_screen.
import 'package:eatvio_app/features/registration/presentation/pages/registration_screen.dart';
import 'package:eatvio_app/features/registration/presentation/pages/verify_screen.dart';
import 'package:eatvio_app/features/registration/presentation/pages/verify_email_screen.dart';
+import 'package:eatvio_app/features/registration_v2/presentation/pages/registration_v2_page.dart';
import 'package:go_router/go_router.dart';
/// Маршруты для аутентификации
@@ -26,6 +27,7 @@ class AuthRoutes {
},
routes: [
GoRoute(path: RouteConstants.registrationScreen, name: 'registrationScreen', builder: (context, state) => const RegistrationScreen()),
+ GoRoute(path: RouteConstants.registrationScreenV2, name: 'registrationScreenV2', builder: (context, state) => const RegistrationV2Page()),
GoRoute(
path: RouteConstants.forgetPasswordScreen,
name: 'forgetPasswordScreen',
diff --git a/lib/core/routing/route_constants.dart b/lib/core/routing/route_constants.dart
index 1702b425..4ce78f4f 100644
--- a/lib/core/routing/route_constants.dart
+++ b/lib/core/routing/route_constants.dart
@@ -3,6 +3,7 @@ class RouteConstants {
// Auth routes
static const String authScreen = '/auth-screen';
static const String registrationScreen = 'registration-screen';
+ static const String registrationScreenV2 = 'registration-screen-v2';
static const String forgetPasswordScreen = 'forget-password-screen';
static const String scanQRCodeScreen = 'scan-qr-code-screen';
static const String verifyScreen = '/verify-screen';
diff --git a/lib/core/theme/custom_text_style.dart b/lib/core/theme/custom_text_style.dart
index 62544e86..b307ab81 100644
--- a/lib/core/theme/custom_text_style.dart
+++ b/lib/core/theme/custom_text_style.dart
@@ -10,161 +10,76 @@ class CustomTextStyles {
static TextStyle get headlineSmallMulish => theme.textTheme.headlineSmall!.mulish;
// Title text style
- static TextStyle get titleMediumSegoeUI => theme.textTheme.titleMedium!.segoeUI.copyWith(
- fontWeight: FontWeight.w600,
- );
+ static TextStyle get titleMediumSegoeUI => theme.textTheme.titleMedium!.segoeUI.copyWith(fontWeight: FontWeight.w600);
- static TextStyle get bodyMediumBlack900 => theme.textTheme.bodyMedium!.copyWith(
- color: appTheme.black900,
- );
+ static TextStyle get bodyMediumBlack900 => theme.textTheme.bodyMedium!.copyWith(color: appTheme.black900);
- static TextStyle get bodyMediumBlack90013 => theme.textTheme.bodyMedium!.copyWith(
- color: appTheme.black900,
- fontSize: 13,
- );
+ static TextStyle get bodyMediumBlack90013 => theme.textTheme.bodyMedium!.copyWith(color: appTheme.black900, fontSize: 13);
- static TextStyle get bodyMediumBluegray800 => theme.textTheme.bodyMedium!.copyWith(
- color: appTheme.black,
- );
+ static TextStyle get bodyMediumBluegray800 => theme.textTheme.bodyMedium!.copyWith(color: appTheme.black);
- static TextStyle get bodyMediumBluegray800_1 => theme.textTheme.bodyMedium!.copyWith(
- color: appTheme.black,
- );
+ static TextStyle get bodyMediumBluegray800_1 => theme.textTheme.bodyMedium!.copyWith(color: appTheme.black);
- static TextStyle get bodyMediumBluegray800_2 => theme.textTheme.bodyMedium!.copyWith(
- color: appTheme.black,
- );
+ static TextStyle get bodyMediumBluegray800_2 => theme.textTheme.bodyMedium!.copyWith(color: appTheme.black);
- static TextStyle get bodyMediumWhiteA700 => theme.textTheme.bodyMedium!.copyWith(
- color: appTheme.whiteA700,
- );
+ static TextStyle get bodyMediumWhiteA700 => theme.textTheme.bodyMedium!.copyWith(color: appTheme.whiteA700);
- static TextStyle get bodySmallMulishBlack900 => theme.textTheme.bodySmall!.mulish.copyWith(
- color: appTheme.black900,
- fontSize: 12,
- );
+ static TextStyle get bodySmallMulishBlack900 => theme.textTheme.bodySmall!.mulish.copyWith(color: appTheme.black900, fontSize: 12);
- static TextStyle get bodySmallMulishBluegray800 => theme.textTheme.bodySmall!.mulish.copyWith(
- color: appTheme.black,
- fontSize: 12,
- );
+ static TextStyle get bodySmallMulishBluegray800 => theme.textTheme.bodySmall!.mulish.copyWith(color: appTheme.black, fontSize: 12);
- static TextStyle get bodySmallMulishBluegray80012 => theme.textTheme.bodySmall!.mulish.copyWith(
- color: appTheme.black,
- fontSize: 12,
- );
+ static TextStyle get bodySmallMulishBluegray80012 => theme.textTheme.bodySmall!.mulish.copyWith(color: appTheme.black, fontSize: 12);
- static TextStyle get bodySmallMulishBluegray80012_1 => theme.textTheme.bodySmall!.mulish.copyWith(
- color: appTheme.black,
- fontSize: 12,
- );
+ static TextStyle get bodySmallMulishBluegray80012_1 => theme.textTheme.bodySmall!.mulish.copyWith(color: appTheme.black, fontSize: 12);
- static TextStyle get bodySmallMulishBluegray900 => theme.textTheme.bodySmall!.mulish.copyWith(
- color: appTheme.blueGray900,
- fontSize: 12,
- );
+ static TextStyle get bodySmallMulishBluegray900 => theme.textTheme.bodySmall!.mulish.copyWith(color: appTheme.blueGray900, fontSize: 12);
- static TextStyle get bodySmallMulishGray600 => theme.textTheme.bodySmall!.mulish.copyWith(
- color: appTheme.gray600,
- );
+ static TextStyle get bodySmallMulishGray600 => theme.textTheme.bodySmall!.mulish.copyWith(color: appTheme.gray600);
- static TextStyle get bodySmallMulishPrimary => theme.textTheme.bodySmall!.mulish.copyWith(
- color: theme.colorScheme.primary,
- fontSize: 12,
- );
+ static TextStyle get bodySmallMulishPrimary => theme.textTheme.bodySmall!.mulish.copyWith(color: theme.colorScheme.primary, fontSize: 12);
- static TextStyle get bodySmallSegoeUIBlack900 => theme.textTheme.bodySmall!.segoeUI.copyWith(
- color: appTheme.black900,
- fontSize: 12,
- );
+ static TextStyle get bodySmallSegoeUIBlack900 => theme.textTheme.bodySmall!.segoeUI.copyWith(color: appTheme.black900, fontSize: 12);
// Label text style
- static TextStyle get labelLargeGray60003 => theme.textTheme.labelLarge!.copyWith(
- color: appTheme.gray60003,
- );
+ static TextStyle get labelLargeGray60003 => theme.textTheme.labelLarge!.copyWith(color: appTheme.gray60003);
- static TextStyle get labelLargeWhiteA700 => theme.textTheme.labelLarge!.copyWith(
- color: appTheme.whiteA700,
- );
+ static TextStyle get labelLargeWhiteA700 => theme.textTheme.labelLarge!.copyWith(color: appTheme.whiteA700);
// Title text style
- static TextStyle get titleMedium16 => theme.textTheme.titleMedium!.copyWith(
- fontSize: 16,
- );
+ static TextStyle get titleMedium16 => theme.textTheme.titleMedium!.copyWith(fontSize: 16);
- static TextStyle get titleMediumBlack => theme.textTheme.titleMedium!.copyWith(
- fontSize: 17,
- fontWeight: FontWeight.w900,
- );
+ static TextStyle get titleMediumBlack => theme.textTheme.titleMedium!.copyWith(fontSize: 17, fontWeight: FontWeight.w900);
- static TextStyle get titleMediumBlack900 => theme.textTheme.titleMedium!.copyWith(
- color: appTheme.black900,
- );
+ static TextStyle get titleMediumBlack900 => theme.textTheme.titleMedium!.copyWith(color: appTheme.black900);
- static TextStyle get titleMediumSemiBold => theme.textTheme.titleMedium!.copyWith(
- fontWeight: FontWeight.w600,
- );
+ static TextStyle get titleMediumSemiBold => theme.textTheme.titleMedium!.copyWith(fontWeight: FontWeight.w600);
- static TextStyle get titleMediumWhiteA700 => theme.textTheme.titleMedium!.copyWith(
- color: appTheme.whiteA700,
- fontWeight: FontWeight.w600,
- );
+ static TextStyle get titleMediumWhiteA700 => theme.textTheme.titleMedium!.copyWith(color: appTheme.whiteA700, fontWeight: FontWeight.w600);
- static TextStyle get titleSmallBlue800 => theme.textTheme.titleSmall!.copyWith(
- color: appTheme.blue800,
- fontWeight: FontWeight.w800,
- );
+ static TextStyle get titleSmallBlue800 => theme.textTheme.titleSmall!.copyWith(color: appTheme.blue800, fontWeight: FontWeight.w800);
- static TextStyle get titleSmallBluegray800 => theme.textTheme.titleSmall!.copyWith(
- color: appTheme.black,
- );
+ static TextStyle get titleSmallBluegray800 => theme.textTheme.titleSmall!.copyWith(color: appTheme.black);
- static TextStyle get titleSmallBluegray800Bold => theme.textTheme.titleSmall!.copyWith(
- color: appTheme.black,
- fontWeight: FontWeight.w700,
- );
+ static TextStyle get titleSmallBluegray800Bold => theme.textTheme.titleSmall!.copyWith(color: appTheme.black, fontWeight: FontWeight.w700);
- static TextStyle get titleSmallBluegray800ExtraBold => theme.textTheme.titleSmall!.copyWith(
- color: appTheme.black,
- fontWeight: FontWeight.w800,
- );
+ static TextStyle get titleSmallBluegray800ExtraBold => theme.textTheme.titleSmall!.copyWith(color: appTheme.black, fontWeight: FontWeight.w800);
- static TextStyle get titleSmallBold => theme.textTheme.titleSmall!.copyWith(
- fontSize: 15,
- fontWeight: FontWeight.w700,
- );
+ static TextStyle get titleSmallBold => theme.textTheme.titleSmall!.copyWith(fontSize: 15, fontWeight: FontWeight.w700);
- static TextStyle get titleSmallGreenA70001 => theme.textTheme.titleSmall!.copyWith(
- color: appTheme.greenA70001,
- );
+ static TextStyle get titleSmallGreenA70001 => theme.textTheme.titleSmall!.copyWith(color: appTheme.greenA70001);
- static TextStyle get titleSmallGreenA70001ExtraBold => theme.textTheme.titleSmall!.copyWith(
- color: appTheme.greenA70001,
- fontWeight: FontWeight.w800,
- );
+ static TextStyle get titleSmallGreenA70001ExtraBold => theme.textTheme.titleSmall!.copyWith(color: appTheme.greenA70001, fontWeight: FontWeight.w800);
- static TextStyle get titleSmallLightgreen300 => theme.textTheme.titleSmall!.copyWith(
- color: appTheme.lightGreen300,
- fontWeight: FontWeight.w800,
- );
+ static TextStyle get titleSmallLightgreen300 => theme.textTheme.titleSmall!.copyWith(color: appTheme.lightGreen300, fontWeight: FontWeight.w800);
- static TextStyle get titleSmallRed200 => theme.textTheme.titleSmall!.copyWith(
- color: appTheme.red200,
- fontWeight: FontWeight.w800,
- );
+ static TextStyle get titleSmallRed200 => theme.textTheme.titleSmall!.copyWith(color: appTheme.red200, fontWeight: FontWeight.w800);
- static TextStyle get titleSmallSecondaryContainer => theme.textTheme.titleSmall!.copyWith(
- color: theme.colorScheme.secondaryContainer,
- fontWeight: FontWeight.w800,
- );
+ static TextStyle get titleSmallSecondaryContainer =>
+ theme.textTheme.titleSmall!.copyWith(color: theme.colorScheme.secondaryContainer, fontWeight: FontWeight.w800);
- static TextStyle get titleSmallSecondaryContainer_1 => theme.textTheme.titleSmall!.copyWith(
- color: theme.colorScheme.secondaryContainer,
- );
+ static TextStyle get titleSmallSecondaryContainer_1 => theme.textTheme.titleSmall!.copyWith(color: theme.colorScheme.secondaryContainer);
- static TextStyle get titleSmallSegoeUIOnPrimary => theme.textTheme.titleSmall!.segoeUI.copyWith(
- color: theme.colorScheme.onPrimary,
- );
+ static TextStyle get titleSmallSegoeUIOnPrimary => theme.textTheme.titleSmall!.segoeUI.copyWith(color: theme.colorScheme.onPrimary);
}
extension on TextStyle {
@@ -178,75 +93,31 @@ extension on TextStyle {
}
abstract class TextStyles {
- static const headingXLSemibold = TextStyle(
- fontSize: 20,
- fontWeight: FontWeight.w600,
- height: 1.255,
- );
+ static const headingXLSemibold = TextStyle(fontSize: 20, fontWeight: FontWeight.w600, height: 1.255);
- static const headingFS40FW600 = TextStyle(
- fontSize: 40,
- fontWeight: FontWeight.w600,
- height: 1.255,
- );
+ static const headingFS40FW600 = TextStyle(fontSize: 40, fontWeight: FontWeight.w600, height: 1.255);
- static const textLSemibold = TextStyle(
- fontSize: 18,
- fontWeight: FontWeight.w600,
- height: 1.255,
- );
+ static const textLSemibold = TextStyle(fontSize: 18, fontWeight: FontWeight.w600, height: 1.255);
- static const textLMedium = TextStyle(
- fontSize: 18,
- fontWeight: FontWeight.w500,
- height: 1.255,
- );
-
- static const textMSemibold = TextStyle(
- fontSize: 16,
- fontWeight: FontWeight.w600,
- height: 1.255,
- );
+ static const textLMedium = TextStyle(fontSize: 18, fontWeight: FontWeight.w500, height: 1.255);
- static const textMMedium = TextStyle(
- fontSize: 16,
- fontWeight: FontWeight.w500,
- height: 1,
- );
+ static const textMSemibold = TextStyle(fontSize: 16, fontWeight: FontWeight.w600, height: 1.255);
- static const textMMediumAuto = TextStyle(
- fontSize: 16,
- fontWeight: FontWeight.w500,
- height: 1.255,
- );
+ static const textMMedium = TextStyle(fontSize: 16, fontWeight: FontWeight.w500, height: 1);
- static const textSSemibold = TextStyle(
- fontSize: 14,
- fontWeight: FontWeight.w600,
- height: 1.255,
- );
+ static const textMMediumAuto = TextStyle(fontSize: 16, fontWeight: FontWeight.w500, height: 1.255);
- static const textSMedium = TextStyle(
- fontSize: 14,
- fontWeight: FontWeight.w500,
- height: 1.255,
- );
+ static const textSSemibold = TextStyle(fontSize: 14, fontWeight: FontWeight.w600, height: 1.255);
- static const textFS13FW400 = TextStyle(
- fontSize: 14,
- fontWeight: FontWeight.w400,
- height: 1.255,
- );
+ static const textSMedium = TextStyle(fontSize: 14, fontWeight: FontWeight.w500, height: 1.255);
- static const textXSSemibold = TextStyle(
- fontSize: 12,
- fontWeight: FontWeight.w500,
- height: 1.255,
- );
+ static const textFS13FW400 = TextStyle(fontSize: 14, fontWeight: FontWeight.w400, height: 1.255);
- static const textFS10FW500 = TextStyle(
- fontSize: 10,
- fontWeight: FontWeight.w500,
- height: 1.255,
- );
+ static const textXSSemibold = TextStyle(fontSize: 12, fontWeight: FontWeight.w500, height: 1.255);
+
+ static const textFS10FW500 = TextStyle(fontSize: 10, fontWeight: FontWeight.w500, height: 1.255);
+
+ static const textFS24FW700 = TextStyle(fontSize: 24, fontWeight: FontWeight.w700, height: 1.255);
+
+ static const textFS22FW600 = TextStyle(fontSize: 22, fontWeight: FontWeight.w600, height: 1.255);
}
diff --git a/lib/core/theme/theme_helper.dart b/lib/core/theme/theme_helper.dart
index c202129e..421247b6 100644
--- a/lib/core/theme/theme_helper.dart
+++ b/lib/core/theme/theme_helper.dart
@@ -7,23 +7,17 @@ class ThemeHelper {
// The current app theme
final _appTheme = 'primary';
-// A map of custom color themes supported by the app
- final Map _supportedCustomColor = {
- 'primary': PrimaryColors(),
- };
+ // A map of custom color themes supported by the app
+ final Map _supportedCustomColor = {'primary': PrimaryColors()};
-// A map of color schemes supported by the app
- final Map _supportedColorScheme = {
- 'primary': ColorSchemes.primaryColorScheme,
- };
+ // A map of color schemes supported by the app
+ final Map _supportedColorScheme = {'primary': ColorSchemes.primaryColorScheme};
/// Returns the primary colors for the current theme.
PrimaryColors _getThemeColors() {
//throw exception to notify given theme is not found or not generated by the generator
if (!_supportedCustomColor.containsKey(_appTheme)) {
- throw Exception(
- "$_appTheme is not found.Make sure you have added this theme class in JSON Try running flutter pub run build_runner",
- );
+ throw Exception("$_appTheme is not found.Make sure you have added this theme class in JSON Try running flutter pub run build_runner");
}
//return theme from map
@@ -34,9 +28,7 @@ class ThemeHelper {
ThemeData _getThemeData() {
//throw exception to notify given theme is not found or not generated by the generator
if (!_supportedColorScheme.containsKey(_appTheme)) {
- throw Exception(
- "$_appTheme is not found.Make sure you have added this theme class in JSON Try running flutter pub run build_runner",
- );
+ throw Exception("$_appTheme is not found.Make sure you have added this theme class in JSON Try running flutter pub run build_runner");
}
//return theme from map
@@ -60,17 +52,9 @@ class ThemeHelper {
outlinedButtonTheme: OutlinedButtonThemeData(
style: OutlinedButton.styleFrom(
backgroundColor: Colors.transparent,
- side: BorderSide(
- color: colorScheme.primary,
- width: 1,
- ),
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(20),
- ),
- visualDensity: const VisualDensity(
- vertical: -4,
- horizontal: -4,
- ),
+ side: BorderSide(color: colorScheme.primary, width: 1),
+ shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
+ visualDensity: const VisualDensity(vertical: -4, horizontal: -4),
padding: EdgeInsets.zero,
),
),
@@ -101,7 +85,7 @@ class PrimaryColors {
// Blue
Color get blue400 => const Color(0XFF43A6F2);
- Color get blueA400 => const Color(0XFF2F80ED);
+ Color get blueA400 => const Color(0XFF2F80ED);
// BlueGray
Color get blueGray400 => const Color(0XFF7B8794);
@@ -179,6 +163,8 @@ class PrimaryColors {
Color get transparentBlue => const Color(0xFF2F80ED).withValues(alpha: 0.1);
Color get lightGray0 => const Color(0xFFF6F6F6);
+
+ Color get darkGrey => const Color(0xFF5B656F);
Color get lightGray00 => const Color(0xFFE9E9EA);
@@ -206,6 +192,8 @@ class PrimaryColors {
Color get cardNotificationsBG => const Color(0xFFA4A4A4);
Color get grey7B => const Color(0xFF7B7B7B);
+
+ Color get greyD9 => const Color(0xFFD9D9D9);
}
PrimaryColors get appTheme => ThemeHelper().themeColor();
diff --git a/lib/core/widgets/custom_drop_down_button.dart b/lib/core/widgets/custom_drop_down_button.dart
index ac8f3c2b..d4c0e571 100644
--- a/lib/core/widgets/custom_drop_down_button.dart
+++ b/lib/core/widgets/custom_drop_down_button.dart
@@ -3,16 +3,28 @@ import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
class CustomDropDownButton extends StatelessWidget {
- const CustomDropDownButton({super.key, required this.items, required this.onChanged, this.value, this.hint, this.hasError = false});
+ const CustomDropDownButton({
+ super.key,
+ required this.items,
+ required this.onChanged,
+ this.value,
+ this.hint,
+ this.selectedItemBuilder,
+ this.hasError = false,
+ this.isExpanded = false,
+ });
final T? value;
final List> items;
final void Function(T?)? onChanged;
final Widget? hint;
final bool hasError;
+ final List Function(BuildContext)? selectedItemBuilder;
+ final bool isExpanded;
@override
Widget build(BuildContext context) {
return DropdownButtonFormField(
hint: hint,
+ isExpanded: isExpanded,
icon: SvgPicture.asset('assets/icons/arrow_down2.svg', width: 12, height: 8),
borderRadius: BorderRadius.circular(20),
dropdownColor: appTheme.lightGray0,
@@ -35,6 +47,7 @@ class CustomDropDownButton extends StatelessWidget {
initialValue: value,
items: items,
onChanged: onChanged,
+ selectedItemBuilder: selectedItemBuilder,
);
}
}
diff --git a/lib/features/auth/presentation/pages/auth_screen.dart b/lib/features/auth/presentation/pages/auth_screen.dart
index f7484a87..2a63de39 100644
--- a/lib/features/auth/presentation/pages/auth_screen.dart
+++ b/lib/features/auth/presentation/pages/auth_screen.dart
@@ -337,7 +337,7 @@ class _AuthScreenState extends State {
children: [
const Text('Нет аккаунта? '),
GestureDetector(
- onTap: () => GoRouter.of(context).goNamed('registrationScreen'),
+ onTap: () => GoRouter.of(context).pushNamed('registrationScreenV2'),
child: Text(
'Зарегистрироваться',
style: TextStyle(color: appTheme.blueA400, decorationColor: appTheme.blueA400, decoration: TextDecoration.underline),
diff --git a/lib/features/registration_v2/cubit/registration_cubit.dart b/lib/features/registration_v2/cubit/registration_cubit.dart
new file mode 100644
index 00000000..cb67bdf7
--- /dev/null
+++ b/lib/features/registration_v2/cubit/registration_cubit.dart
@@ -0,0 +1,117 @@
+import 'package:eatvio_app/features/registration_v2/cubit/registration_state.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+class RegistrationCubitV2 extends Cubit {
+ RegistrationCubitV2() : super(RegistrationStateV2());
+
+ void setFirstName(String firstName) {
+ emit(state.copyWith(firstName: firstName));
+ validateFirstName();
+ }
+
+ void setLastName(String lastName) {
+ emit(state.copyWith(lastName: lastName));
+ validateLastName();
+ }
+
+ void setEmail(String email) {
+ emit(state.copyWith(email: email));
+ validateEmail();
+ }
+
+ void setPhone(String phone) {
+ emit(state.copyWith(phone: phone));
+ validatePhone();
+ }
+
+ void setBirthday(DateTime birthday) {
+ emit(state.copyWith(birthday: birthday));
+ validateBirthday();
+ }
+
+ void setGender(String gender) {
+ emit(state.copyWith(gender: gender));
+ validateGender();
+ }
+
+ void setWeight(int weight) {
+ emit(state.copyWith(weight: weight));
+ validateWeight();
+ }
+
+ void setHeight(int height) {
+ emit(state.copyWith(height: height));
+ validateHeight();
+ }
+
+ void setActivityCoefficient(double activityCoefficient) {
+ emit(state.copyWith(activityCoefficient: activityCoefficient));
+ validateActivityCoefficient();
+ }
+
+ void setPassword(String password) {
+ emit(state.copyWith(password: password));
+ }
+
+ void validateFirstName() {
+ if (state.firstName.isEmpty) {
+ emit(state.copyWith(isFirstNameValid: false));
+ }
+ }
+
+ void validateLastName() {
+ if (state.lastName.isEmpty) {
+ emit(state.copyWith(isLastNameValid: false));
+ }
+ }
+
+ void validateEmail() {
+ if (state.email.isEmpty) {
+ emit(state.copyWith(isEmailValid: false));
+ }
+ }
+
+ void validatePhone() {
+ if (state.phone.isEmpty) {
+ emit(state.copyWith(isPhoneValid: false));
+ }
+ }
+
+ void validateGender() {
+ if (state.gender.isEmpty) {
+ emit(state.copyWith(isGenderValid: false));
+ }
+ }
+
+ void validateWeight() {
+ if (state.weight == 0) {
+ emit(state.copyWith(isWeightValid: false));
+ }
+ }
+
+ void validateHeight() {
+ if (state.height == 0) {
+ emit(state.copyWith(isHeightValid: false));
+ }
+ }
+
+ void validateActivityCoefficient() {
+ if (state.activityCoefficient == 0) {
+ emit(state.copyWith(isActivityCoefficientValid: false));
+ }
+ }
+
+ void validateBirthday() {
+ if (state.birthday == null) {
+ emit(state.copyWith(isBirthdayValid: false));
+ }
+ }
+
+ void nextStep() {
+ emit(state.copyWith(step: 1));
+ }
+
+ void prevStep() {
+ emit(state.copyWith(step: 0));
+ }
+}
diff --git a/lib/features/registration_v2/cubit/registration_state.dart b/lib/features/registration_v2/cubit/registration_state.dart
new file mode 100644
index 00000000..c91eb042
--- /dev/null
+++ b/lib/features/registration_v2/cubit/registration_state.dart
@@ -0,0 +1,29 @@
+import 'package:freezed_annotation/freezed_annotation.dart';
+
+part 'registration_state.freezed.dart';
+
+@freezed
+abstract class RegistrationStateV2 with _$RegistrationStateV2 {
+ factory RegistrationStateV2({
+ @Default('') String firstName,
+ @Default('') String lastName,
+ @Default('') String email,
+ @Default('') String phone,
+ @Default('') String gender,
+ @Default('') String password,
+ @Default(0) int weight,
+ @Default(0) int height,
+ @Default(1.2) double activityCoefficient,
+ DateTime? birthday,
+ @Default(true) bool isFirstNameValid,
+ @Default(true) bool isLastNameValid,
+ @Default(true) bool isEmailValid,
+ @Default(true) bool isPhoneValid,
+ @Default(true) bool isGenderValid,
+ @Default(true) bool isWeightValid,
+ @Default(true) bool isHeightValid,
+ @Default(true) bool isActivityCoefficientValid,
+ @Default(true) bool isBirthdayValid,
+ @Default(0) int step,
+ }) = _RegistrationStateV2;
+}
diff --git a/lib/features/registration_v2/models/registration_model.dart b/lib/features/registration_v2/models/registration_model.dart
new file mode 100644
index 00000000..e69de29b
diff --git a/lib/features/registration_v2/presentation/pages/registration_v2_page.dart b/lib/features/registration_v2/presentation/pages/registration_v2_page.dart
new file mode 100644
index 00000000..b9805d32
--- /dev/null
+++ b/lib/features/registration_v2/presentation/pages/registration_v2_page.dart
@@ -0,0 +1,47 @@
+import 'package:eatvio_app/core/locator_service.dart';
+import 'package:eatvio_app/core/utils/image_constant.dart';
+import 'package:eatvio_app/features/registration_v2/cubit/registration_cubit.dart';
+import 'package:eatvio_app/features/registration_v2/cubit/registration_state.dart';
+import 'package:eatvio_app/features/registration_v2/presentation/widgets/first_step_content.dart';
+import 'package:eatvio_app/features/registration_v2/presentation/widgets/second_step_content.dart';
+import 'package:eatvio_app/features/registration_v2/presentation/widgets/step_progress.dart';
+import 'package:eatvio_app/features/registration_v2/presentation/widgets/step_widget.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:flutter_svg/svg.dart';
+import 'package:mask_text_input_formatter/mask_text_input_formatter.dart';
+
+class RegistrationV2Page extends StatelessWidget {
+ const RegistrationV2Page({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return BlocProvider(create: (context) => sl(), child: RegistrationV2PageContent());
+ }
+}
+
+class RegistrationV2PageContent extends StatelessWidget {
+ RegistrationV2PageContent({super.key});
+ final maskFormatterForBirthday = MaskTextInputFormatter(mask: '##.##.####', filter: {"#": RegExp(r'[0-9]')}, type: MaskAutoCompletionType.lazy);
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(centerTitle: true, toolbarHeight: 45, title: SvgPicture.asset(ImageConstant.imgLogoEatvio, height: 45), actions: const [StepWidget()]),
+ body: Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 16),
+ child: BlocBuilder(
+ builder: (context, state) {
+ return Column(
+ children: [
+ const SizedBox(height: 4),
+ const StepProgress(),
+ const SizedBox(height: 20),
+ if (state.step == 0) Expanded(child: FirstStepContent()) else if (state.step == 1) const Expanded(child: SecondStepContent()),
+ ],
+ );
+ },
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/features/registration_v2/presentation/widgets/first_step_content.dart b/lib/features/registration_v2/presentation/widgets/first_step_content.dart
new file mode 100644
index 00000000..d87499c8
--- /dev/null
+++ b/lib/features/registration_v2/presentation/widgets/first_step_content.dart
@@ -0,0 +1,89 @@
+import 'package:eatvio_app/core/theme/custom_text_style.dart';
+import 'package:eatvio_app/core/theme/theme_helper.dart';
+import 'package:eatvio_app/core/widgets/custom_outlined_button.dart';
+import 'package:eatvio_app/core/widgets/custom_text_form_field.dart';
+import 'package:eatvio_app/features/registration_v2/cubit/registration_cubit.dart';
+import 'package:eatvio_app/features/registration_v2/presentation/widgets/sex_widget.dart';
+import 'package:eatvio_app/generated/l10n.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:mask_text_input_formatter/mask_text_input_formatter.dart';
+
+class FirstStepContent extends StatelessWidget {
+ FirstStepContent({super.key});
+ final maskFormatterForBirthday = MaskTextInputFormatter(mask: '##.##.####', filter: {"#": RegExp(r'[0-9]')}, type: MaskAutoCompletionType.lazy);
+ @override
+ Widget build(BuildContext context) {
+ final s = S.of(context);
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ children: [
+ Expanded(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(s.first_name, style: TextStyles.textSMedium.copyWith(color: appTheme.black)),
+ const SizedBox(height: 4),
+ CustomTextFormField(hintText: s.your_name),
+ ],
+ ),
+ ),
+ const SizedBox(width: 12),
+ Expanded(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(s.last_name, style: TextStyles.textSMedium.copyWith(color: appTheme.black)),
+ const SizedBox(height: 4),
+ CustomTextFormField(hintText: s.your_last_name),
+ ],
+ ),
+ ),
+ ],
+ ),
+ const SizedBox(height: 12),
+ Text(s.email, style: TextStyles.textSMedium.copyWith(color: appTheme.black)),
+ CustomTextFormField(hintText: s.type_email),
+ const SizedBox(height: 12),
+ Text(s.phone, style: TextStyles.textSMedium.copyWith(color: appTheme.black)),
+ const CustomTextFormField(hintText: '+7 (999) 999 99 99'),
+ const SizedBox(height: 12),
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.end,
+ children: [
+ Expanded(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(s.date_of_birth, style: TextStyles.textSMedium.copyWith(color: appTheme.black)),
+ const SizedBox(height: 4),
+ CustomTextFormField(
+ textInputAction: TextInputAction.done,
+ hintText: '01.01.2000',
+ keyboardType: TextInputType.number,
+ inputFormatters: [maskFormatterForBirthday],
+ ),
+ ],
+ ),
+ ),
+ const SizedBox(width: 12),
+ const Expanded(child: SexWidget()),
+ ],
+ ),
+ const Spacer(),
+ CustomOutlinedButton(
+ onPressed: () {
+ context.read().nextStep();
+ },
+ text: s.next,
+ height: 52,
+ buttonTextStyle: TextStyles.textSSemibold.copyWith(color: appTheme.whiteA700),
+ buttonStyle: ButtonStyle(side: const WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll(appTheme.blueA400)),
+ ),
+ const SizedBox(height: 20),
+ ],
+ );
+ }
+}
diff --git a/lib/features/registration_v2/presentation/widgets/password_field.dart b/lib/features/registration_v2/presentation/widgets/password_field.dart
new file mode 100644
index 00000000..cb0a7a0a
--- /dev/null
+++ b/lib/features/registration_v2/presentation/widgets/password_field.dart
@@ -0,0 +1,38 @@
+import 'package:eatvio_app/core/theme/custom_text_style.dart';
+import 'package:eatvio_app/core/theme/theme_helper.dart';
+import 'package:eatvio_app/features/registration_v2/cubit/registration_cubit.dart';
+import 'package:eatvio_app/features/registration_v2/cubit/registration_state.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+class PasswordField extends StatefulWidget {
+ const PasswordField({super.key, required this.cubit});
+ final RegistrationCubitV2 cubit;
+ @override
+ State createState() => _PasswordFieldState();
+}
+
+class _PasswordFieldState extends State {
+ @override
+ Widget build(BuildContext context) {
+ return BlocBuilder(
+ bloc: widget.cubit,
+ builder: (context, state) {
+ return Column(
+ children: [
+ Container(
+ decoration: BoxDecoration(color: appTheme.lightGray0, borderRadius: BorderRadius.circular(20)),
+ padding: const EdgeInsets.only(left: 24, right: 16, top: 16, bottom: 16),
+ width: double.infinity,
+ child: Row(
+ children: [
+ Text('Klknasd978!9', style: TextStyles.textMMediumAuto.copyWith(color: appTheme.black)),
+ ],
+ ),
+ ),
+ ],
+ );
+ },
+ );
+ }
+}
diff --git a/lib/features/registration_v2/presentation/widgets/phisical_activity.dart b/lib/features/registration_v2/presentation/widgets/phisical_activity.dart
new file mode 100644
index 00000000..59e65948
--- /dev/null
+++ b/lib/features/registration_v2/presentation/widgets/phisical_activity.dart
@@ -0,0 +1,83 @@
+import 'package:eatvio_app/core/theme/custom_text_style.dart';
+import 'package:eatvio_app/core/theme/theme_helper.dart';
+import 'package:eatvio_app/core/widgets/custom_drop_down_button.dart';
+import 'package:eatvio_app/features/registration_v2/cubit/registration_cubit.dart';
+import 'package:eatvio_app/features/registration_v2/cubit/registration_state.dart';
+import 'package:eatvio_app/generated/l10n.dart';
+import 'package:flutter/material.dart';
+import 'package:collection/collection.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+class PhisicalActivity extends StatefulWidget {
+ const PhisicalActivity({super.key});
+
+ @override
+ State createState() => _PhisicalActivityState();
+}
+
+class _PhisicalActivityState extends State {
+ final List activityDropDownTitles = [];
+
+ @override
+ void didChangeDependencies() {
+ super.didChangeDependencies();
+ final s = S.of(context);
+ if (activityDropDownTitles.isEmpty) {
+ activityDropDownTitles.add(s.activity_first_value);
+ activityDropDownTitles.add(s.activity_second_value);
+ activityDropDownTitles.add(s.activity_third_value);
+ activityDropDownTitles.add(s.activity_fourth_value);
+ activityDropDownTitles.add(s.activity_fifth_value);
+ }
+ }
+
+ String _getTitleFromValue(double value) {
+ switch (value) {
+ case 1.2:
+ return activityDropDownTitles[0];
+ case 1.375:
+ return activityDropDownTitles[1];
+ case 1.55:
+ return activityDropDownTitles[2];
+ case 1.7:
+ return activityDropDownTitles[3];
+ case 1.9:
+ return activityDropDownTitles[4];
+ default:
+ return activityDropDownTitles[5];
+ }
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return BlocBuilder(
+ builder: (context, state) {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ CustomDropDownButton(
+ // hasError: state.dietDurationError != null,
+ isExpanded: true,
+ onChanged: (value) {
+ if (value != null) {}
+ },
+ items: activityDropDownTitles
+ .mapIndexed(
+ (index, value) => DropdownMenuItem(
+ value: activityDropDownTitles[index],
+ child: Text(activityDropDownTitles[index], style: TextStyles.textMMedium.copyWith(color: appTheme.black)),
+ ),
+ )
+ .toList(),
+ value: state.activityCoefficient == 0 ? null : _getTitleFromValue(state.activityCoefficient),
+ selectedItemBuilder: (context) {
+ return activityDropDownTitles.mapIndexed((index, value) => Text(value, overflow: TextOverflow.clip, maxLines: 1)).toList();
+ },
+ ),
+ // if (state.dietDurationError != null) ...[const SizedBox(height: 4), ValidationErrorWidget(error: state.dietDurationError ?? '')],
+ ],
+ );
+ },
+ );
+ }
+}
diff --git a/lib/features/registration_v2/presentation/widgets/second_step_content.dart b/lib/features/registration_v2/presentation/widgets/second_step_content.dart
new file mode 100644
index 00000000..d20de147
--- /dev/null
+++ b/lib/features/registration_v2/presentation/widgets/second_step_content.dart
@@ -0,0 +1,120 @@
+import 'package:eatvio_app/core/app_config.dart';
+import 'package:eatvio_app/core/const.dart';
+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/widgets/custom_outlined_button.dart';
+import 'package:eatvio_app/core/widgets/custom_text_form_field.dart';
+import 'package:eatvio_app/core/widgets/show_error_dialog.dart';
+import 'package:eatvio_app/features/registration_v2/cubit/registration_cubit.dart';
+import 'package:eatvio_app/features/registration_v2/presentation/widgets/phisical_activity.dart';
+import 'package:eatvio_app/features/registration_v2/presentation/widgets/show_successful_registration_bottom_sheet.dart';
+import 'package:eatvio_app/generated/l10n.dart';
+import 'package:flutter/gestures.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import 'package:url_launcher/url_launcher.dart';
+
+class SecondStepContent extends StatelessWidget {
+ const SecondStepContent({super.key});
+ @override
+ Widget build(BuildContext context) {
+ final s = S.of(context);
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(s.last_step, style: TextStyles.textFS24FW700.copyWith(color: appTheme.black)),
+ const SizedBox(height: 12),
+ Text(s.user_data_desc, style: TextStyles.textSMedium.copyWith(color: appTheme.black)),
+ const SizedBox(height: 16),
+ Row(
+ children: [
+ Expanded(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(s.height, style: TextStyles.textSMedium.copyWith(color: appTheme.black)),
+ const SizedBox(height: 4),
+ CustomTextFormField(hintText: s.type_height),
+ ],
+ ),
+ ),
+ const SizedBox(width: 12),
+ Expanded(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(s.weight, style: TextStyles.textSMedium.copyWith(color: appTheme.black)),
+ const SizedBox(height: 4),
+ CustomTextFormField(hintText: s.type_weight),
+ ],
+ ),
+ ),
+ ],
+ ),
+ const SizedBox(height: 12),
+ Text(s.email, style: TextStyles.textSMedium.copyWith(color: appTheme.black)),
+ const PhisicalActivity(),
+ const SizedBox(height: 12),
+ const Spacer(),
+ Row(
+ children: [
+ InkWell(
+ onTap: () {
+ context.read().prevStep();
+ },
+ borderRadius: BorderRadius.circular(20),
+ child: Ink(
+ height: 52,
+ width: 52,
+ decoration: BoxDecoration(color: appTheme.gray50, borderRadius: BorderRadius.circular(20)),
+ child: Center(child: Icon(Icons.arrow_back_ios_new_rounded, color: appTheme.blueA400, size: 24)),
+ ),
+ ),
+ const SizedBox(width: 4),
+ Expanded(
+ child: CustomOutlinedButton(
+ onPressed: () {
+ showSuccessfulRegistrationBottomSheet(context, context.read());
+ // showErrorDialog(context);
+ },
+ text: s.register,
+ height: 52,
+ buttonTextStyle: TextStyles.textSSemibold.copyWith(color: appTheme.whiteA700),
+ buttonStyle: ButtonStyle(side: const WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll(appTheme.blueA400)),
+ ),
+ ),
+ ],
+ ),
+ const SizedBox(height: 12),
+ Center(
+ child: RichText(
+ textAlign: TextAlign.center,
+ text: TextSpan(
+ text: 'Нажимая “Зарегистрироваться”, Вы соглашаетесь \n',
+ style: const TextStyle(fontSize: 12, color: Colors.black),
+ children: [
+ const TextSpan(text: 'c '),
+ if (!hidePlans) ...[
+ TextSpan(
+ text: ' Публичной офертой',
+ style: TextStyle(fontSize: 12, color: appTheme.blueA400, decorationColor: appTheme.blueA400, decoration: TextDecoration.underline),
+ recognizer: TapGestureRecognizer()..onTap = () async => await launchUrl(Uri.parse('${sl().baseUrl}/oferta_bs.pdf')),
+ ),
+ const TextSpan(text: ' и '),
+ ],
+ TextSpan(
+ text: 'Политикой конфиденциальности\nи защитой персональных данных',
+ style: TextStyle(fontSize: 12, color: appTheme.blueA400, decorationColor: appTheme.blueA400, decoration: TextDecoration.underline),
+ recognizer: TapGestureRecognizer()..onTap = () async => await launchUrl(Uri.parse('${sl().baseUrl}/docs/privacy.pdf')),
+ ),
+ ],
+ ),
+ ),
+ ),
+ const SizedBox(height: 30),
+ ],
+ );
+ }
+}
diff --git a/lib/features/registration_v2/presentation/widgets/sex_widget.dart b/lib/features/registration_v2/presentation/widgets/sex_widget.dart
new file mode 100644
index 00000000..ccddcb17
--- /dev/null
+++ b/lib/features/registration_v2/presentation/widgets/sex_widget.dart
@@ -0,0 +1,84 @@
+import 'package:eatvio_app/core/theme/custom_text_style.dart';
+import 'package:eatvio_app/core/theme/theme_helper.dart';
+import 'package:eatvio_app/features/registration_v2/cubit/registration_cubit.dart';
+import 'package:eatvio_app/features/registration_v2/cubit/registration_state.dart';
+import 'package:eatvio_app/generated/l10n.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+class SexWidget extends StatelessWidget {
+ const SexWidget({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ final s = S.of(context);
+ return BlocBuilder(
+ builder: (context, state) {
+ return Row(
+ crossAxisAlignment: CrossAxisAlignment.end,
+ children: [
+ Expanded(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(s.sex, style: TextStyles.textSMedium.copyWith(color: appTheme.black)),
+ InkWell(
+ onTap: () {
+ context.read().setGender('male');
+ },
+ borderRadius: BorderRadius.circular(20),
+ child: Ink(
+ height: 52,
+ decoration: BoxDecoration(
+ color: const Color(0xFFF6F6F6),
+ borderRadius: BorderRadius.circular(20),
+ border: state.gender == 'male' ? Border.all(width: 2, color: appTheme.blueA400) : null,
+ ),
+ child: Center(
+ child: Text(
+ s.male_short,
+ style: TextStyle(
+ color: state.gender == 'male' ? appTheme.blueA400 : const Color(0xFF323F4B),
+ fontSize: 16,
+ fontWeight: FontWeight.w500,
+ ),
+ ),
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ const SizedBox(width: 4),
+ Expanded(
+ child: InkWell(
+ onTap: () {
+ context.read().setGender('female');
+ },
+ borderRadius: BorderRadius.circular(20),
+ child: Ink(
+ height: 52,
+ decoration: BoxDecoration(
+ color: const Color(0xFFF6F6F6),
+ borderRadius: BorderRadius.circular(20),
+ border: state.gender == 'female' ? Border.all(width: 2, color: appTheme.blueA400) : null,
+ ),
+ child: Center(
+ child: Text(
+ s.female_short,
+ style: TextStyle(
+ color: state.gender == 'female' ? appTheme.blueA400 : const Color(0xFF323F4B),
+ fontSize: 16,
+ fontWeight: FontWeight.w500,
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ],
+ );
+ },
+ );
+ }
+}
diff --git a/lib/features/registration_v2/presentation/widgets/show_successful_registration_bottom_sheet.dart b/lib/features/registration_v2/presentation/widgets/show_successful_registration_bottom_sheet.dart
new file mode 100644
index 00000000..132a0b33
--- /dev/null
+++ b/lib/features/registration_v2/presentation/widgets/show_successful_registration_bottom_sheet.dart
@@ -0,0 +1,56 @@
+import 'package:eatvio_app/core/theme/custom_text_style.dart';
+import 'package:eatvio_app/core/theme/theme_helper.dart';
+import 'package:eatvio_app/features/registration_v2/cubit/registration_cubit.dart';
+import 'package:eatvio_app/features/registration_v2/presentation/widgets/password_field.dart';
+import 'package:eatvio_app/generated/l10n.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/flutter_svg.dart';
+
+void showSuccessfulRegistrationBottomSheet(BuildContext context, RegistrationCubitV2 cubit) {
+ showModalBottomSheet(
+ context: context,
+ isScrollControlled: true,
+ backgroundColor: Colors.transparent,
+ builder: (context) => Container(
+ margin: EdgeInsets.only(left: 8, right: 8, bottom: MediaQuery.of(context).viewInsets.bottom + MediaQuery.of(context).padding.bottom),
+ decoration: BoxDecoration(borderRadius: BorderRadius.circular(12), color: appTheme.whiteA700),
+ child: SuccessfulBottomSheet(cubit: cubit),
+ ),
+ );
+}
+
+class SuccessfulBottomSheet extends StatelessWidget {
+ const SuccessfulBottomSheet({super.key, required this.cubit});
+ final RegistrationCubitV2 cubit;
+ @override
+ Widget build(BuildContext context) {
+ final s = S.of(context);
+ return Padding(
+ padding: const EdgeInsets.all(20),
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Padding(
+ padding: const EdgeInsets.only(bottom: 12.0),
+ child: Row(
+ children: [
+ SvgPicture.asset('assets/icons/sucess.svg', height: 16, width: 16),
+ const SizedBox(width: 8),
+ Text(s.registration_completed, style: TextStyles.textFS22FW600.copyWith(color: appTheme.black)),
+ ],
+ ),
+ ),
+
+ Padding(
+ padding: const EdgeInsets.only(bottom: 16.0),
+ child: Text(s.acc_has_been_created, style: TextStyles.textMMediumAuto.copyWith(color: appTheme.darkGrey)),
+ ),
+ PasswordField(cubit: cubit),
+ Text(s.password_desc, style: TextStyles.textSMedium.copyWith(color: appTheme.darkGrey)),
+ const SizedBox(width: 20),
+ //button
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/features/registration_v2/presentation/widgets/step_progress.dart b/lib/features/registration_v2/presentation/widgets/step_progress.dart
new file mode 100644
index 00000000..96d796ad
--- /dev/null
+++ b/lib/features/registration_v2/presentation/widgets/step_progress.dart
@@ -0,0 +1,29 @@
+import 'package:eatvio_app/core/theme/theme_helper.dart';
+import 'package:eatvio_app/features/registration_v2/cubit/registration_cubit.dart';
+import 'package:eatvio_app/features/registration_v2/cubit/registration_state.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+class StepProgress extends StatelessWidget {
+ const StepProgress({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return BlocBuilder(
+ builder: (context, state) {
+ return GestureDetector(
+ onTap: () {
+ context.read().nextStep();
+ },
+ child: LinearProgressIndicator(
+ value: state.step == 0 ? 0.5 : 1,
+ borderRadius: BorderRadius.circular(6),
+ color: appTheme.blueA400,
+ backgroundColor: appTheme.greyD9,
+ minHeight: 8,
+ ),
+ );
+ },
+ );
+ }
+}
diff --git a/lib/features/registration_v2/presentation/widgets/step_widget.dart b/lib/features/registration_v2/presentation/widgets/step_widget.dart
new file mode 100644
index 00000000..1176213a
--- /dev/null
+++ b/lib/features/registration_v2/presentation/widgets/step_widget.dart
@@ -0,0 +1,24 @@
+import 'package:eatvio_app/core/theme/custom_text_style.dart';
+import 'package:eatvio_app/core/theme/theme_helper.dart';
+import 'package:eatvio_app/features/registration_v2/cubit/registration_cubit.dart';
+import 'package:eatvio_app/features/registration_v2/cubit/registration_state.dart';
+import 'package:eatvio_app/generated/l10n.dart';
+import 'package:flutter/widgets.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+class StepWidget extends StatelessWidget {
+ const StepWidget({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ final s = S.of(context);
+ return BlocBuilder(
+ builder: (context, state) {
+ return Padding(
+ padding: const EdgeInsets.only(right: 16.0),
+ child: Text(s.step_widget(state.step + 1), style: TextStyles.textMMedium.copyWith(color: appTheme.black)),
+ );
+ },
+ );
+ }
+}
diff --git a/lib/generated/intl/messages_en.dart b/lib/generated/intl/messages_en.dart
index dc9e4c16..ed7ea1b8 100644
--- a/lib/generated/intl/messages_en.dart
+++ b/lib/generated/intl/messages_en.dart
@@ -27,22 +27,24 @@ class MessageLookup extends MessageLookupByLibrary {
static String m2(planName, name) =>
"План «${planName}» с пользователем ${name} начался";
- static String m3(planName, name) =>
+ static String m3(step) => "шаг ${step} из 2";
+
+ static String m4(planName, name) =>
"Завтра начинается план «${planName}» с пользователем ${name}";
- static String m4(planName) =>
+ static String m5(planName) =>
"Завтра начнется прохождение плана «${planName}»";
- static String m5(name, planName) =>
+ static String m6(name, planName) =>
"Пользователь ${name} отменил подписку на план «${planName}»";
- static String m6(name, planName) =>
+ static String m7(name, planName) =>
"Пользователь ${name} оплатил план «${planName}»";
- static String m7(name, planName) =>
+ static String m8(name, planName) =>
"Пользователь ${name} подписался на план «${planName}»";
- static String m8(planName) => "Вы отменили подписку на план «${planName}»";
+ static String m9(planName) => "Вы отменили подписку на план «${planName}»";
final messages = _notInlinedMessages(_notInlinedMessages);
static Map _notInlinedMessages(_) => {
@@ -51,6 +53,12 @@ class MessageLookup extends MessageLookupByLibrary {
"about_diet": MessageLookupByLibrary.simpleMessage("Об этой диете"),
"about_plan": MessageLookupByLibrary.simpleMessage("Об этом плане"),
"about_recipe": MessageLookupByLibrary.simpleMessage("Об этом рецепте"),
+ "acc_has_been_created": MessageLookupByLibrary.simpleMessage(
+ "Ваш аккаунт создан. Для входа используйте этот пароль:",
+ ),
+ "acc_has_been_created_btn": MessageLookupByLibrary.simpleMessage(
+ "Войти в аккаунт",
+ ),
"accountDeleting": MessageLookupByLibrary.simpleMessage(
"Удаление аккаунта",
),
@@ -59,6 +67,21 @@ class MessageLookup extends MessageLookupByLibrary {
"Кол-во активных консультаций",
),
"active_diet_state": MessageLookupByLibrary.simpleMessage("Активная"),
+ "activity_fifth_value": MessageLookupByLibrary.simpleMessage(
+ "1,9 — экстремальный (несколько интенсивных тренировок в день)",
+ ),
+ "activity_first_value": MessageLookupByLibrary.simpleMessage(
+ "1,2 — минимальный (сидячая работа, отсутствие физических нагрузок)",
+ ),
+ "activity_fourth_value": MessageLookupByLibrary.simpleMessage(
+ "1,7 — высокий (тренировки 30–60 мин 5–7 раза в неделю; тяжёлая физическая работа)",
+ ),
+ "activity_second_value": MessageLookupByLibrary.simpleMessage(
+ "1,375 — низкий (тренировки не менее 20 мин 1–3 раза в неделю)",
+ ),
+ "activity_third_value": MessageLookupByLibrary.simpleMessage(
+ "1,55 — умеренный (тренировки 30–60 мин 3–4 раза в неделю)",
+ ),
"add": MessageLookupByLibrary.simpleMessage("Добавить"),
"addAtLeastOneItem": MessageLookupByLibrary.simpleMessage(
"Добавьте хотя бы одину опцию",
@@ -353,6 +376,7 @@ class MessageLookup extends MessageLookupByLibrary {
"Ваши любимые/нелюбимые продукты питания?",
),
"female": MessageLookupByLibrary.simpleMessage("Женский"),
+ "female_short": MessageLookupByLibrary.simpleMessage("Ж"),
"fillYasterday": MessageLookupByLibrary.simpleMessage(
"Заполните вчерашний день",
),
@@ -433,6 +457,7 @@ class MessageLookup extends MessageLookupByLibrary {
"last_name_short": MessageLookupByLibrary.simpleMessage(
"В фамилии должен быть минимум 6 символов",
),
+ "last_step": MessageLookupByLibrary.simpleMessage("Последний шаг"),
"lawViolation": MessageLookupByLibrary.simpleMessage(
"Нарушение законодательства",
),
@@ -454,6 +479,7 @@ class MessageLookup extends MessageLookupByLibrary {
"Почта успешно скопирована",
),
"male": MessageLookupByLibrary.simpleMessage("Мужской"),
+ "male_short": MessageLookupByLibrary.simpleMessage("М"),
"markAsRead": MessageLookupByLibrary.simpleMessage(
"Отметить всё прочитанным",
),
@@ -505,6 +531,7 @@ class MessageLookup extends MessageLookupByLibrary {
"В имени пользователя должно быть минимум 6 символов",
),
"new_card": MessageLookupByLibrary.simpleMessage("Добавить карту"),
+ "next": MessageLookupByLibrary.simpleMessage("Далее"),
"nicotine": MessageLookupByLibrary.simpleMessage("Никотин"),
"no": MessageLookupByLibrary.simpleMessage("Нет"),
"no_account": MessageLookupByLibrary.simpleMessage("У меня нет аккаунта"),
@@ -549,6 +576,9 @@ class MessageLookup extends MessageLookupByLibrary {
"password_confirmation_mismatch": MessageLookupByLibrary.simpleMessage(
"Пароли не совпадают",
),
+ "password_desc": MessageLookupByLibrary.simpleMessage(
+ "Сохраните его в надежном месте! Вы сможете изменить пароль в настройках профиля",
+ ),
"password_empty": MessageLookupByLibrary.simpleMessage(
"Пароль обязателен для заполнения",
),
@@ -561,6 +591,7 @@ class MessageLookup extends MessageLookupByLibrary {
"pending_payment": MessageLookupByLibrary.simpleMessage("Ожидается оплата"),
"personal": MessageLookupByLibrary.simpleMessage("Персональные"),
"personal_diet_state": MessageLookupByLibrary.simpleMessage("Персональная"),
+ "phone": MessageLookupByLibrary.simpleMessage("Телефон"),
"photo": MessageLookupByLibrary.simpleMessage("Фото"),
"physical_fitness": MessageLookupByLibrary.simpleMessage(
"Физическая форма",
@@ -634,6 +665,10 @@ class MessageLookup extends MessageLookupByLibrary {
"refuse_order": MessageLookupByLibrary.simpleMessage(
"Отказаться от заказа",
),
+ "register": MessageLookupByLibrary.simpleMessage("Зарегистрироваться"),
+ "registration_completed": MessageLookupByLibrary.simpleMessage(
+ "Регистрация завершена!",
+ ),
"removeFromActive": MessageLookupByLibrary.simpleMessage(
"Снять с публикации",
),
@@ -686,6 +721,7 @@ class MessageLookup extends MessageLookupByLibrary {
"step_by_step_photo_recipe": MessageLookupByLibrary.simpleMessage(
"Пошаговый фоторецепт",
),
+ "step_widget": m3,
"successfully_published": MessageLookupByLibrary.simpleMessage(
"успешно опубликован",
),
@@ -709,8 +745,8 @@ class MessageLookup extends MessageLookupByLibrary {
"toOffer": MessageLookupByLibrary.simpleMessage("Предложить"),
"to_draft": MessageLookupByLibrary.simpleMessage("В черновик"),
"to_order": MessageLookupByLibrary.simpleMessage("Заказать"),
- "tommorowPlanWithUserWillStart": m3,
- "tomorrowYourPlanWillStart": m4,
+ "tommorowPlanWithUserWillStart": m4,
+ "tomorrowYourPlanWillStart": m5,
"try_again": MessageLookupByLibrary.simpleMessage("Попробовать снова"),
"try_again_2": MessageLookupByLibrary.simpleMessage("Попробуйте ещё раз"),
"typeAmoutOfReturn": MessageLookupByLibrary.simpleMessage(
@@ -725,9 +761,12 @@ class MessageLookup extends MessageLookupByLibrary {
"typePortionComment": MessageLookupByLibrary.simpleMessage(
"Прокомментируйте блюдо",
),
+ "type_email": MessageLookupByLibrary.simpleMessage("Введите email"),
+ "type_height": MessageLookupByLibrary.simpleMessage("Введите рост"),
"type_here_your_complaint": MessageLookupByLibrary.simpleMessage(
"Напишите здесь свою жалобу",
),
+ "type_weight": MessageLookupByLibrary.simpleMessage("Введите вес"),
"unfavorite_foods": MessageLookupByLibrary.simpleMessage(
"Нелюбимые продукты",
),
@@ -735,7 +774,7 @@ class MessageLookup extends MessageLookupByLibrary {
"Верхние показатели давления:",
),
"upper": MessageLookupByLibrary.simpleMessage("Верхнее"),
- "userCanceldThePlanSubscription": m5,
+ "userCanceldThePlanSubscription": m6,
"userConfirmedPlanCompletion": MessageLookupByLibrary.simpleMessage(
"Пользователь подтвердил прохождения плана. В ближайшее время Вы получите",
),
@@ -743,12 +782,15 @@ class MessageLookup extends MessageLookupByLibrary {
MessageLookupByLibrary.simpleMessage(
"Пользователь подтвердил прохождения плана.",
),
- "userPaidThePlan": m6,
- "userSubscribedToPlan": m7,
+ "userPaidThePlan": m7,
+ "userSubscribedToPlan": m8,
"user_authorization": MessageLookupByLibrary.simpleMessage(
"Аутентификация",
),
"user_data": MessageLookupByLibrary.simpleMessage("Данные пользователя"),
+ "user_data_desc": MessageLookupByLibrary.simpleMessage(
+ "Эти данные нужны для корректной работы дневника питания и расчета вашей дневной нормы потребления КБЖУ",
+ ),
"user_info": MessageLookupByLibrary.simpleMessage("Анкета пользователя"),
"user_registration": MessageLookupByLibrary.simpleMessage(
"Регистрация пользователя",
@@ -794,7 +836,7 @@ class MessageLookup extends MessageLookupByLibrary {
"youCanComplain": MessageLookupByLibrary.simpleMessage(
"Если вас что-то не устроило, вы можете подать жалобу",
),
- "youCanceledSubscriptionToPlan": m8,
+ "youCanceledSubscriptionToPlan": m9,
"youShureYouWantToCancelOrder": MessageLookupByLibrary.simpleMessage(
"Вы уверены, что хотите отменить заказ?",
),
@@ -817,6 +859,8 @@ class MessageLookup extends MessageLookupByLibrary {
),
"your_gender": MessageLookupByLibrary.simpleMessage("Ваш пол?"),
"your_height": MessageLookupByLibrary.simpleMessage("Ваш рост:"),
+ "your_last_name": MessageLookupByLibrary.simpleMessage("Ваша фамилия"),
+ "your_name": MessageLookupByLibrary.simpleMessage("Ваше имя"),
"your_rating": MessageLookupByLibrary.simpleMessage("Ваш рейтинг"),
"your_schedule": MessageLookupByLibrary.simpleMessage("Ваш режим дня?"),
"your_weight": MessageLookupByLibrary.simpleMessage("Ваш вес:"),
diff --git a/lib/generated/l10n.dart b/lib/generated/l10n.dart
index 1055e664..4c5fd8fb 100644
--- a/lib/generated/l10n.dart
+++ b/lib/generated/l10n.dart
@@ -28,10 +28,9 @@ class S {
static const AppLocalizationDelegate delegate = AppLocalizationDelegate();
static Future load(Locale locale) {
- final name =
- (locale.countryCode?.isEmpty ?? false)
- ? locale.languageCode
- : locale.toString();
+ final name = (locale.countryCode?.isEmpty ?? false)
+ ? locale.languageCode
+ : locale.toString();
final localeName = Intl.canonicalizedLocale(name);
return initializeMessages(localeName).then((_) {
Intl.defaultLocale = localeName;
@@ -3499,6 +3498,191 @@ class S {
args: [],
);
}
+
+ /// `шаг {step} из 2`
+ String step_widget(Object step) {
+ return Intl.message(
+ 'шаг $step из 2',
+ name: 'step_widget',
+ desc: '',
+ args: [step],
+ );
+ }
+
+ /// `Ваше имя`
+ String get your_name {
+ return Intl.message('Ваше имя', name: 'your_name', desc: '', args: []);
+ }
+
+ /// `Ваша фамилия`
+ String get your_last_name {
+ return Intl.message(
+ 'Ваша фамилия',
+ name: 'your_last_name',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Введите email`
+ String get type_email {
+ return Intl.message(
+ 'Введите email',
+ name: 'type_email',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Телефон`
+ String get phone {
+ return Intl.message('Телефон', name: 'phone', desc: '', args: []);
+ }
+
+ /// `М`
+ String get male_short {
+ return Intl.message('М', name: 'male_short', desc: '', args: []);
+ }
+
+ /// `Ж`
+ String get female_short {
+ return Intl.message('Ж', name: 'female_short', desc: '', args: []);
+ }
+
+ /// `Далее`
+ String get next {
+ return Intl.message('Далее', name: 'next', desc: '', args: []);
+ }
+
+ /// `Введите рост`
+ String get type_height {
+ return Intl.message(
+ 'Введите рост',
+ name: 'type_height',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Введите вес`
+ String get type_weight {
+ return Intl.message('Введите вес', name: 'type_weight', desc: '', args: []);
+ }
+
+ /// `Зарегистрироваться`
+ String get register {
+ return Intl.message(
+ 'Зарегистрироваться',
+ name: 'register',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Последний шаг`
+ String get last_step {
+ return Intl.message('Последний шаг', name: 'last_step', desc: '', args: []);
+ }
+
+ /// `Эти данные нужны для корректной работы дневника питания и расчета вашей дневной нормы потребления КБЖУ`
+ String get user_data_desc {
+ return Intl.message(
+ 'Эти данные нужны для корректной работы дневника питания и расчета вашей дневной нормы потребления КБЖУ',
+ name: 'user_data_desc',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `1,2 — минимальный (сидячая работа, отсутствие физических нагрузок)`
+ String get activity_first_value {
+ return Intl.message(
+ '1,2 — минимальный (сидячая работа, отсутствие физических нагрузок)',
+ name: 'activity_first_value',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `1,375 — низкий (тренировки не менее 20 мин 1–3 раза в неделю)`
+ String get activity_second_value {
+ return Intl.message(
+ '1,375 — низкий (тренировки не менее 20 мин 1–3 раза в неделю)',
+ name: 'activity_second_value',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `1,55 — умеренный (тренировки 30–60 мин 3–4 раза в неделю)`
+ String get activity_third_value {
+ return Intl.message(
+ '1,55 — умеренный (тренировки 30–60 мин 3–4 раза в неделю)',
+ name: 'activity_third_value',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `1,7 — высокий (тренировки 30–60 мин 5–7 раза в неделю; тяжёлая физическая работа)`
+ String get activity_fourth_value {
+ return Intl.message(
+ '1,7 — высокий (тренировки 30–60 мин 5–7 раза в неделю; тяжёлая физическая работа)',
+ name: 'activity_fourth_value',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `1,9 — экстремальный (несколько интенсивных тренировок в день)`
+ String get activity_fifth_value {
+ return Intl.message(
+ '1,9 — экстремальный (несколько интенсивных тренировок в день)',
+ name: 'activity_fifth_value',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Регистрация завершена!`
+ String get registration_completed {
+ return Intl.message(
+ 'Регистрация завершена!',
+ name: 'registration_completed',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Ваш аккаунт создан. Для входа используйте этот пароль:`
+ String get acc_has_been_created {
+ return Intl.message(
+ 'Ваш аккаунт создан. Для входа используйте этот пароль:',
+ name: 'acc_has_been_created',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Сохраните его в надежном месте! Вы сможете изменить пароль в настройках профиля`
+ String get password_desc {
+ return Intl.message(
+ 'Сохраните его в надежном месте! Вы сможете изменить пароль в настройках профиля',
+ name: 'password_desc',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Войти в аккаунт`
+ String get acc_has_been_created_btn {
+ return Intl.message(
+ 'Войти в аккаунт',
+ name: 'acc_has_been_created_btn',
+ desc: '',
+ args: [],
+ );
+ }
}
class AppLocalizationDelegate extends LocalizationsDelegate {
diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb
index 1fc575a8..6c9b22d2 100644
--- a/lib/l10n/intl_en.arb
+++ b/lib/l10n/intl_en.arb
@@ -414,6 +414,28 @@
"delete": "Удалить",
"cannotDeleteAccount": "Не получилось удалить ваш аккаунт",
"resend": "Отправить повторно",
- "notifications": "Уведомления"
+ "notifications": "Уведомления",
+ "step_widget": "шаг {step} из 2",
+ "your_name": "Ваше имя",
+ "your_last_name": "Ваша фамилия",
+ "type_email": "Введите email",
+ "phone": "Телефон",
+ "male_short": "М",
+ "female_short": "Ж",
+ "next": "Далее",
+ "type_height": "Введите рост",
+ "type_weight": "Введите вес",
+ "register": "Зарегистрироваться",
+ "last_step": "Последний шаг",
+ "user_data_desc": "Эти данные нужны для корректной работы дневника питания и расчета вашей дневной нормы потребления КБЖУ",
+ "activity_first_value": "1,2 — минимальный (сидячая работа, отсутствие физических нагрузок)",
+ "activity_second_value": "1,375 — низкий (тренировки не менее 20 мин 1–3 раза в неделю)",
+ "activity_third_value": "1,55 — умеренный (тренировки 30–60 мин 3–4 раза в неделю)",
+ "activity_fourth_value": "1,7 — высокий (тренировки 30–60 мин 5–7 раза в неделю; тяжёлая физическая работа)",
+ "activity_fifth_value": "1,9 — экстремальный (несколько интенсивных тренировок в день)",
+ "registration_completed": "Регистрация завершена!",
+ "acc_has_been_created": "Ваш аккаунт создан. Для входа используйте этот пароль:",
+ "password_desc": "Сохраните его в надежном месте! Вы сможете изменить пароль в настройках профиля",
+ "acc_has_been_created_btn": "Войти в аккаунт"
}