feat(registration): added base layout for new registration page, and a bit of state managment

This commit is contained in:
misha
2025-10-20 17:55:56 +03:00
parent bb68ea963c
commit 2440204294
23 changed files with 1072 additions and 226 deletions

3
assets/icons/sucess.svg Normal file
View File

@@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.33333 16C3.85185 16 2.59259 15.4815 1.55556 14.4444C0.518519 13.4074 0 12.1481 0 10.6667V5.33333C0 3.85185 0.518519 2.59259 1.55556 1.55556C2.59259 0.518519 3.85185 0 5.33333 0H10.6667C12.1481 0 13.4074 0.518519 14.4444 1.55556C15.4815 2.59259 16 3.85185 16 5.33333V10.6667C16 12.1481 15.4815 13.4074 14.4444 14.4444C13.4074 15.4815 12.1481 16 10.6667 16H5.33333ZM7.11111 9.06667L5.77778 7.73333C5.61481 7.57037 5.40741 7.48889 5.15556 7.48889C4.9037 7.48889 4.6963 7.57037 4.53333 7.73333C4.37037 7.8963 4.28889 8.1037 4.28889 8.35556C4.28889 8.60741 4.37037 8.81481 4.53333 8.97778L6.48889 10.9333C6.66667 11.1111 6.87407 11.2 7.11111 11.2C7.34815 11.2 7.55556 11.1111 7.73333 10.9333L11.8222 6.84444C11.9852 6.68148 12.0667 6.47407 12.0667 6.22222C12.0667 5.97037 11.9852 5.76296 11.8222 5.6C11.6593 5.43704 11.4519 5.35556 11.2 5.35556C10.9481 5.35556 10.7407 5.43704 10.5778 5.6L7.11111 9.06667ZM5.33333 14.2222H10.6667C11.6444 14.2222 12.4815 13.8741 13.1778 13.1778C13.8741 12.4815 14.2222 11.6444 14.2222 10.6667V5.33333C14.2222 4.35556 13.8741 3.51852 13.1778 2.82222C12.4815 2.12593 11.6444 1.77778 10.6667 1.77778H5.33333C4.35556 1.77778 3.51852 2.12593 2.82222 2.82222C2.12593 3.51852 1.77778 4.35556 1.77778 5.33333V10.6667C1.77778 11.6444 2.12593 12.4815 2.82222 13.1778C3.51852 13.8741 4.35556 14.2222 5.33333 14.2222Z" fill="#16A249"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -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>(() => ResetPasswordCubit(resetPasswordRepository: sl()));
sl.registerFactory<VerifyEmailCubit>(() => VerifyEmailCubit(profileRepository: sl()));
sl.registerFactory<OAuthCubit>(() => OAuthCubit(authRepository: sl()));
sl.registerFactory<RegistrationCubitV2>(() => RegistrationCubitV2());
// Feed related cubits
sl.registerFactory<FeedCubit>(() => FeedCubit(feedRepository: sl()));
sl.registerFactory<RecipesCubit>(() => RecipesCubit(feedRepository: sl(), recipeRepository: sl(), aboutRecipeRepository: sl()));

View File

@@ -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',

View File

@@ -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';

View File

@@ -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);
}

View File

@@ -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<String, PrimaryColors> _supportedCustomColor = {
'primary': PrimaryColors(),
};
// A map of custom color themes supported by the app
final Map<String, PrimaryColors> _supportedCustomColor = {'primary': PrimaryColors()};
// A map of color schemes supported by the app
final Map<String, ColorScheme> _supportedColorScheme = {
'primary': ColorSchemes.primaryColorScheme,
};
// A map of color schemes supported by the app
final Map<String, ColorScheme> _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();

View File

@@ -3,16 +3,28 @@ import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
class CustomDropDownButton<T> 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<DropdownMenuItem<T>> items;
final void Function(T?)? onChanged;
final Widget? hint;
final bool hasError;
final List<Widget> 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<T> extends StatelessWidget {
initialValue: value,
items: items,
onChanged: onChanged,
selectedItemBuilder: selectedItemBuilder,
);
}
}

View File

@@ -337,7 +337,7 @@ class _AuthScreenState extends State<AuthScreen> {
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),

View File

@@ -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<RegistrationStateV2> {
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));
}
}

View File

@@ -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;
}

View File

@@ -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<RegistrationCubitV2>(), 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<RegistrationCubitV2, RegistrationStateV2>(
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()),
],
);
},
),
),
);
}
}

View File

@@ -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<RegistrationCubitV2>().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),
],
);
}
}

View File

@@ -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<PasswordField> createState() => _PasswordFieldState();
}
class _PasswordFieldState extends State<PasswordField> {
@override
Widget build(BuildContext context) {
return BlocBuilder<RegistrationCubitV2, RegistrationStateV2>(
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)),
],
),
),
],
);
},
);
}
}

View File

@@ -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<PhisicalActivity> createState() => _PhisicalActivityState();
}
class _PhisicalActivityState extends State<PhisicalActivity> {
final List<String> 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<RegistrationCubitV2, RegistrationStateV2>(
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 ?? '')],
],
);
},
);
}
}

View File

@@ -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<RegistrationCubitV2>().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<RegistrationCubitV2>());
// 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<AppConfig>().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<AppConfig>().baseUrl}/docs/privacy.pdf')),
),
],
),
),
),
const SizedBox(height: 30),
],
);
}
}

View File

@@ -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<RegistrationCubitV2, RegistrationStateV2>(
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<RegistrationCubitV2>().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<RegistrationCubitV2>().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,
),
),
),
),
),
),
],
);
},
);
}
}

View File

@@ -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
],
),
);
}
}

View File

@@ -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<RegistrationCubitV2, RegistrationStateV2>(
builder: (context, state) {
return GestureDetector(
onTap: () {
context.read<RegistrationCubitV2>().nextStep();
},
child: LinearProgressIndicator(
value: state.step == 0 ? 0.5 : 1,
borderRadius: BorderRadius.circular(6),
color: appTheme.blueA400,
backgroundColor: appTheme.greyD9,
minHeight: 8,
),
);
},
);
}
}

View File

@@ -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<RegistrationCubitV2, RegistrationStateV2>(
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)),
);
},
);
}
}

View File

@@ -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<String, Function> _notInlinedMessages(_) => <String, Function>{
@@ -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("Ваш вес:"),

View File

@@ -28,10 +28,9 @@ class S {
static const AppLocalizationDelegate delegate = AppLocalizationDelegate();
static Future<S> 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<S> {

View File

@@ -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": "Войти в аккаунт"
}