diff --git a/lib/data/models/userRegistrationModel/user_registration_model.dart b/lib/data/models/userRegistrationModel/user_registration_model.dart new file mode 100644 index 00000000..e69de29b diff --git a/lib/localization/ru/ru_translations.dart b/lib/localization/ru/ru_translations.dart index 83806f19..012f1bda 100644 --- a/lib/localization/ru/ru_translations.dart +++ b/lib/localization/ru/ru_translations.dart @@ -1,10 +1,17 @@ final Map ru = { + "user_registration": "Регистрация пользователя", + "email": "Элетронная почта", + "password": "Пароль", + "password_confirmation": "Подтвердите пароль", + "first_name": "Имя", + "last_name": "Фамилия", + // date_of_birth Screen "date_of_birth": "Дата рождения", - // city_of_living Screen "country": "Страна", "Russia": "Россия", "city": "Город", "Moscow": "Москва", "place_of_living": "Место проживания", + "what_is_your_name": "Как вас зовут?", // body_circumferences Screen "hip_circumference": "Обхват бедр", "chest_circumference": "Обхват груди", diff --git a/lib/presentation/credentials_screen/bloc/credentials_bloc.dart b/lib/presentation/credentials_screen/bloc/credentials_bloc.dart new file mode 100644 index 00000000..fe83f536 --- /dev/null +++ b/lib/presentation/credentials_screen/bloc/credentials_bloc.dart @@ -0,0 +1,23 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; +import '/core/app_export.dart'; +import 'package:eatvio_app/presentation/credentials_screen/models/credentials_model.dart'; +part 'credentials_event.dart'; +part 'credentials_state.dart'; + +/// A bloc that manages the state of a Credentials according to the event that is dispatched to it. +class CredentialsBloc extends Bloc { + CredentialsBloc(CredentialsState initialState) : super(initialState) { + on(_onInitialize); + } + + _onInitialize( + CredentialsInitialEvent event, + Emitter emit, + ) async { + emit(state.copyWith( + valueController: TextEditingController(), + valueController1: TextEditingController(), + valueController2: TextEditingController())); + } +} diff --git a/lib/presentation/credentials_screen/bloc/credentials_event.dart b/lib/presentation/credentials_screen/bloc/credentials_event.dart new file mode 100644 index 00000000..3001076a --- /dev/null +++ b/lib/presentation/credentials_screen/bloc/credentials_event.dart @@ -0,0 +1,16 @@ +// ignore_for_file: must_be_immutable + +part of 'credentials_bloc.dart'; + +/// Abstract class for all events that can be dispatched from the +///Credentials widget. +/// +/// Events must be immutable and implement the [Equatable] interface. +@immutable +abstract class CredentialsEvent extends Equatable {} + +/// Event that is dispatched when the Credentials widget is first created. +class CredentialsInitialEvent extends CredentialsEvent { + @override + List get props => []; +} diff --git a/lib/presentation/credentials_screen/bloc/credentials_state.dart b/lib/presentation/credentials_screen/bloc/credentials_state.dart new file mode 100644 index 00000000..c59dec31 --- /dev/null +++ b/lib/presentation/credentials_screen/bloc/credentials_state.dart @@ -0,0 +1,42 @@ +// ignore_for_file: must_be_immutable + +part of 'credentials_bloc.dart'; + +/// Represents the state of Credentials in the application. +class CredentialsState extends Equatable { + CredentialsState({ + this.valueController, + this.valueController1, + this.valueController2, + this.credentialsModelObj, + }); + + TextEditingController? valueController; + + TextEditingController? valueController1; + + TextEditingController? valueController2; + + CredentialsModel? credentialsModelObj; + + @override + List get props => [ + valueController, + valueController1, + valueController2, + credentialsModelObj, + ]; + CredentialsState copyWith({ + TextEditingController? valueController, + TextEditingController? valueController1, + TextEditingController? valueController2, + CredentialsModel? credentialsModelObj, + }) { + return CredentialsState( + valueController: valueController ?? this.valueController, + valueController1: valueController1 ?? this.valueController1, + valueController2: valueController2 ?? this.valueController2, + credentialsModelObj: credentialsModelObj ?? this.credentialsModelObj, + ); + } +} diff --git a/lib/presentation/credentials_screen/credentials_screen.dart b/lib/presentation/credentials_screen/credentials_screen.dart new file mode 100644 index 00000000..091f5b29 --- /dev/null +++ b/lib/presentation/credentials_screen/credentials_screen.dart @@ -0,0 +1,130 @@ +import 'bloc/credentials_bloc.dart'; +import 'models/credentials_model.dart'; +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/widgets/app_bar/appbar_leading_image.dart'; +import 'package:eatvio_app/widgets/app_bar/appbar_title_image.dart'; +import 'package:eatvio_app/widgets/app_bar/custom_app_bar.dart'; +import 'package:eatvio_app/widgets/custom_outlined_button.dart'; +import 'package:eatvio_app/widgets/custom_text_form_field.dart'; +import 'package:flutter/material.dart'; + +class CredentialsScreen extends StatefulWidget { + const CredentialsScreen({Key? key}) : super(key: key); + + static Widget builder(BuildContext context) { + return BlocProvider( + create: (context) => CredentialsBloc( + CredentialsState(credentialsModelObj: CredentialsModel())) + ..add(CredentialsInitialEvent()), + child: CredentialsScreen()); + } + + @override + State createState() => _CredentialsScreenState(); +} + +class _CredentialsScreenState extends State { + @override + Widget build(BuildContext context) { + mediaQueryData = MediaQuery.of(context); + return SafeArea( + child: Scaffold( + resizeToAvoidBottomInset: false, + appBar: _buildAppBar(context), + body: Container( + width: double.maxFinite, + padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 9.v), + child: Column(children: [ + SizedBox(height: 7.v), + Container( + height: 16.v, + width: 343.h, + decoration: BoxDecoration( + color: theme.colorScheme.onPrimary, + borderRadius: BorderRadius.circular(8.h), + border: Border.all( + color: theme.colorScheme.primary, width: 1.h)), + child: ClipRRect( + borderRadius: BorderRadius.circular(8.h), + child: LinearProgressIndicator( + value: 0.05, + backgroundColor: theme.colorScheme.onPrimary, + valueColor: AlwaysStoppedAnimation( + appTheme.blueA400)))), + SizedBox(height: 39.v), + Text("user_registration".tr, + style: theme.textTheme.headlineSmall), + SizedBox(height: 93.v), + Text("email".tr, style: theme.textTheme.bodyLarge), + SizedBox(height: 3.v), + BlocSelector( + selector: (state) => state.valueController1, + builder: (context, valueController1) { + return CustomTextFormField( + controller: valueController1, + textInputAction: TextInputAction.done); + }), + SizedBox(height: 19.v), + Text("password".tr, style: theme.textTheme.bodyLarge), + SizedBox(height: 5.v), + BlocSelector( + selector: (state) => state.valueController2, + builder: (context, valueController2) { + return CustomTextFormField( + obscureText: true, + controller: valueController2, + ); + }), + SizedBox(height: 21.v), + Text("password_confirmation".tr, + style: theme.textTheme.bodyLarge), + SizedBox(height: 3.v), + BlocSelector( + selector: (state) => state.valueController, + builder: (context, valueController3) { + return CustomTextFormField( + obscureText: true, + controller: valueController3, + textInputAction: TextInputAction.done); + }), + Spacer(), + CustomOutlinedButton( + text: "continue".tr.toUpperCase(), + buttonStyle: CustomButtonStyles.outlinePrimaryTL15, + onPressed: () { + navigateToName(context); + }), + SizedBox(height: 17.v), + Text("skip".tr, style: theme.textTheme.bodyLarge) + ])))); + } + + /// Section Widget + PreferredSizeWidget _buildAppBar(BuildContext context) { + return CustomAppBar( + leadingWidth: 29.h, + leading: AppbarLeadingImage( + imagePath: ImageConstant.imgArrowLeft, + margin: EdgeInsets.only(left: 16.h, top: 15.v, bottom: 15.v), + onTap: () { + onTapArrowLeft(context); + }), + centerTitle: true, + title: AppbarTitleImage(imagePath: ImageConstant.imgLogoEatvio)); + } + + /// Navigates to the previous screen. + onTapArrowLeft(BuildContext context) { + NavigatorService.goBack(); + } + + /// Navigates to the weightScreen when the action is triggered. + navigateToName(BuildContext context) { + NavigatorService.pushNamed( + AppRoutes.nameScreen, + ); + } +} diff --git a/lib/presentation/credentials_screen/models/credentials_model.dart b/lib/presentation/credentials_screen/models/credentials_model.dart new file mode 100644 index 00000000..57ae6d7c --- /dev/null +++ b/lib/presentation/credentials_screen/models/credentials_model.dart @@ -0,0 +1,16 @@ +// ignore_for_file: must_be_immutable + +import 'package:equatable/equatable.dart'; + +/// This class defines the variables used in the [credentials_screen], +/// and is typically used to hold data that is passed between different parts of the application. +class CredentialsModel extends Equatable { + CredentialsModel() {} + + CredentialsModel copyWith() { + return CredentialsModel(); + } + + @override + List get props => []; +} diff --git a/lib/presentation/date_of_birth_screen/date_of_birth_screen.dart b/lib/presentation/date_of_birth_screen/date_of_birth_screen.dart index 1d0037fb..b9325910 100644 --- a/lib/presentation/date_of_birth_screen/date_of_birth_screen.dart +++ b/lib/presentation/date_of_birth_screen/date_of_birth_screen.dart @@ -148,7 +148,7 @@ class _DateOfBirthScreenState extends State { DateTime? dateTime = await showDatePicker( context: context, initialDate: DateTime.now(), - firstDate: DateTime(1970), + firstDate: DateTime(1924), lastDate: DateTime( DateTime.now().year, DateTime.now().month, DateTime.now().day)); if (dateTime != null) { diff --git a/lib/presentation/language_select_screen/language_select_screen.dart b/lib/presentation/language_select_screen/language_select_screen.dart index c947456e..d3683263 100644 --- a/lib/presentation/language_select_screen/language_select_screen.dart +++ b/lib/presentation/language_select_screen/language_select_screen.dart @@ -46,7 +46,7 @@ class _LanguageSelectScreenState extends State { child: ClipRRect( borderRadius: BorderRadius.circular(8.h), child: LinearProgressIndicator( - value: 0.08, + value: 0, backgroundColor: theme.colorScheme.onPrimary, valueColor: AlwaysStoppedAnimation( appTheme.blueA400)))), @@ -112,14 +112,14 @@ class _LanguageSelectScreenState extends State { margin: EdgeInsets.only(left: 16.h, right: 16.h, bottom: 50.v), buttonStyle: CustomButtonStyles.outlinePrimaryTL15, onPressed: () { - navigteToGender(context); + navigteToCredentials(context); }); } /// Navigates to the genderScreen when the action is triggered. - navigteToGender(BuildContext context) { + navigteToCredentials(BuildContext context) { NavigatorService.pushNamed( - AppRoutes.genderScreen, + AppRoutes.credentialsScreen, ); } } diff --git a/lib/presentation/name_screen/bloc/name_bloc.dart b/lib/presentation/name_screen/bloc/name_bloc.dart new file mode 100644 index 00000000..7611e222 --- /dev/null +++ b/lib/presentation/name_screen/bloc/name_bloc.dart @@ -0,0 +1,23 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; +import '/core/app_export.dart'; +import 'package:eatvio_app/presentation/name_screen/models/name_model.dart'; +part 'name_event.dart'; +part 'name_state.dart'; + +/// A bloc that manages the state of a Name according to the event that is dispatched to it. +class NameBloc extends Bloc { + NameBloc(NameState initialState) : super(initialState) { + on(_onInitialize); + } + + _onInitialize( + NameInitialEvent event, + Emitter emit, + ) async { + emit(state.copyWith( + valueController: TextEditingController(), + valueController1: TextEditingController(), + valueController2: TextEditingController())); + } +} diff --git a/lib/presentation/name_screen/bloc/name_event.dart b/lib/presentation/name_screen/bloc/name_event.dart new file mode 100644 index 00000000..7e102994 --- /dev/null +++ b/lib/presentation/name_screen/bloc/name_event.dart @@ -0,0 +1,16 @@ +// ignore_for_file: must_be_immutable + +part of 'name_bloc.dart'; + +/// Abstract class for all events that can be dispatched from the +///Name widget. +/// +/// Events must be immutable and implement the [Equatable] interface. +@immutable +abstract class NameEvent extends Equatable {} + +/// Event that is dispatched when the Name widget is first created. +class NameInitialEvent extends NameEvent { + @override + List get props => []; +} diff --git a/lib/presentation/name_screen/bloc/name_state.dart b/lib/presentation/name_screen/bloc/name_state.dart new file mode 100644 index 00000000..d729b067 --- /dev/null +++ b/lib/presentation/name_screen/bloc/name_state.dart @@ -0,0 +1,42 @@ +// ignore_for_file: must_be_immutable + +part of 'name_bloc.dart'; + +/// Represents the state of Name in the application. +class NameState extends Equatable { + NameState({ + this.valueController, + this.valueController1, + this.valueController2, + this.nameModelObj, + }); + + TextEditingController? valueController; + + TextEditingController? valueController1; + + TextEditingController? valueController2; + + NameModel? nameModelObj; + + @override + List get props => [ + valueController, + valueController1, + valueController2, + nameModelObj, + ]; + NameState copyWith({ + TextEditingController? valueController, + TextEditingController? valueController1, + TextEditingController? valueController2, + NameModel? nameModelObj, + }) { + return NameState( + valueController: valueController ?? this.valueController, + valueController1: valueController1 ?? this.valueController1, + valueController2: valueController2 ?? this.valueController2, + nameModelObj: nameModelObj ?? this.nameModelObj, + ); + } +} diff --git a/lib/presentation/name_screen/models/name_model.dart b/lib/presentation/name_screen/models/name_model.dart new file mode 100644 index 00000000..22b22839 --- /dev/null +++ b/lib/presentation/name_screen/models/name_model.dart @@ -0,0 +1,16 @@ +// ignore_for_file: must_be_immutable + +import 'package:equatable/equatable.dart'; + +/// This class defines the variables used in the [name_screen], +/// and is typically used to hold data that is passed between different parts of the application. +class NameModel extends Equatable { + NameModel() {} + + NameModel copyWith() { + return NameModel(); + } + + @override + List get props => []; +} diff --git a/lib/presentation/name_screen/name_screen.dart b/lib/presentation/name_screen/name_screen.dart new file mode 100644 index 00000000..203513d6 --- /dev/null +++ b/lib/presentation/name_screen/name_screen.dart @@ -0,0 +1,114 @@ +import 'bloc/name_bloc.dart'; +import 'models/name_model.dart'; +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/widgets/app_bar/appbar_leading_image.dart'; +import 'package:eatvio_app/widgets/app_bar/appbar_title_image.dart'; +import 'package:eatvio_app/widgets/app_bar/custom_app_bar.dart'; +import 'package:eatvio_app/widgets/custom_outlined_button.dart'; +import 'package:eatvio_app/widgets/custom_text_form_field.dart'; +import 'package:flutter/material.dart'; + +class NameScreen extends StatefulWidget { + const NameScreen({Key? key}) : super(key: key); + + static Widget builder(BuildContext context) { + return BlocProvider( + create: (context) => NameBloc(NameState(nameModelObj: NameModel())) + ..add(NameInitialEvent()), + child: NameScreen()); + } + + @override + State createState() => _NameScreenState(); +} + +class _NameScreenState extends State { + @override + Widget build(BuildContext context) { + mediaQueryData = MediaQuery.of(context); + return SafeArea( + child: Scaffold( + resizeToAvoidBottomInset: false, + appBar: _buildAppBar(context), + body: Container( + width: double.maxFinite, + padding: EdgeInsets.symmetric(horizontal: 16.h, vertical: 9.v), + child: Column(children: [ + SizedBox(height: 7.v), + Container( + height: 16.v, + width: 343.h, + decoration: BoxDecoration( + color: theme.colorScheme.onPrimary, + borderRadius: BorderRadius.circular(8.h), + border: Border.all( + color: theme.colorScheme.primary, width: 1.h)), + child: ClipRRect( + borderRadius: BorderRadius.circular(8.h), + child: LinearProgressIndicator( + value: 0.1, + backgroundColor: theme.colorScheme.onPrimary, + valueColor: AlwaysStoppedAnimation( + appTheme.blueA400)))), + SizedBox(height: 39.v), + Text("what_is_your_name".tr, + style: theme.textTheme.headlineSmall), + SizedBox(height: 93.v), + Text("first_name".tr, style: theme.textTheme.bodyLarge), + SizedBox(height: 3.v), + BlocSelector( + selector: (state) => state.valueController, + builder: (context, valueController) { + return CustomTextFormField( + controller: valueController, + textInputAction: TextInputAction.done); + }), + SizedBox(height: 19.v), + Text("last_name".tr, style: theme.textTheme.bodyLarge), + SizedBox(height: 5.v), + BlocSelector( + selector: (state) => state.valueController1, + builder: (context, valueController1) { + return CustomTextFormField( + controller: valueController1, + ); + }), + SizedBox(height: 21.v), + Spacer(), + CustomOutlinedButton( + text: "continue".tr.toUpperCase(), + buttonStyle: CustomButtonStyles.outlinePrimaryTL15, + onPressed: () { + navigateToGender(context); + }), + SizedBox(height: 17.v), + Text("skip".tr, style: theme.textTheme.bodyLarge) + ])))); + } + + /// Section Widget + PreferredSizeWidget _buildAppBar(BuildContext context) { + return CustomAppBar( + leadingWidth: 29.h, + leading: AppbarLeadingImage( + imagePath: ImageConstant.imgArrowLeft, + margin: EdgeInsets.only(left: 16.h, top: 15.v, bottom: 15.v), + onTap: () { + onTapArrowLeft(context); + }), + centerTitle: true, + title: AppbarTitleImage(imagePath: ImageConstant.imgLogoEatvio)); + } + + /// Navigates to the previous screen. + onTapArrowLeft(BuildContext context) { + NavigatorService.goBack(); + } + + /// Navigates to the weightScreen when the action is triggered. + navigateToGender(BuildContext context) { + NavigatorService.pushNamed( + AppRoutes.genderScreen, + ); + } +} diff --git a/lib/routes/app_routes.dart b/lib/routes/app_routes.dart index 50e3bdfd..a9adebc0 100644 --- a/lib/routes/app_routes.dart +++ b/lib/routes/app_routes.dart @@ -1,3 +1,4 @@ +import 'package:eatvio_app/presentation/credentials_screen/models/credentials_model.dart'; import 'package:flutter/material.dart'; import 'package:eatvio_app/presentation/date_of_birth_screen/date_of_birth_screen.dart'; import 'package:eatvio_app/presentation/city_of_living_screen/city_of_living_screen.dart'; @@ -14,6 +15,8 @@ import 'package:eatvio_app/presentation/schedule_screen/schedule_screen.dart'; import 'package:eatvio_app/presentation/additional_information_screen/additional_information_screen.dart'; import 'package:eatvio_app/presentation/language_select_screen/language_select_screen.dart'; import 'package:eatvio_app/presentation/height_screen/height_screen.dart'; +import 'package:eatvio_app/presentation/credentials_screen/credentials_screen.dart'; +import 'package:eatvio_app/presentation/name_screen/name_screen.dart'; import 'package:eatvio_app/presentation/app_navigation_screen/app_navigation_screen.dart'; class AppRoutes { @@ -50,6 +53,10 @@ class AppRoutes { static const String languageSelectScreen = '/language_select_screen'; + static const String nameScreen = '/name_screen'; + + static const String credentialsScreen = '/credentials_screen'; + static const String appNavigationScreen = '/app_navigation_screen'; static const String initialRoute = '/initialRoute'; @@ -60,6 +67,8 @@ class AppRoutes { bodyCircumferencesScreen: BodyCircumferencesScreen.builder, weightScreen: WeightScreen.builder, heightScreen: HeightScreen.builder, + nameScreen: NameScreen.builder, + credentialsScreen: CredentialsScreen.builder, allergiesScreen: AllergiesScreen.builder, medicineIntakeScreen: MedicineIntakeScreen.builder, splashScreen: SplashScreen.builder,