diff --git a/android/app/build.gradle b/android/app/build.gradle index bc059244..81f74f06 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -1,53 +1,33 @@ plugins { id "com.android.application" id "kotlin-android" - // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. id "dev.flutter.flutter-gradle-plugin" } -def localProperties = new Properties() -def localPropertiesFile = rootProject.file("local.properties") -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader("UTF-8") { reader -> - localProperties.load(reader) - } -} - -def flutterVersionCode = localProperties.getProperty("flutter.versionCode") -if (flutterVersionCode == null) { - flutterVersionCode = "1" -} - -def flutterVersionName = localProperties.getProperty("flutter.versionName") -if (flutterVersionName == null) { - flutterVersionName = "1.0" -} - android { namespace = "com.eatvioapp.app" compileSdk = flutter.compileSdkVersion - ndkVersion = "25.1.8937393" + ndkVersion = flutter.ndkVersion compileOptions { sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 } + kotlinOptions { + jvmTarget = JavaVersion.VERSION_1_8 + } + defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId = "com.eatvioapp.app" - // You can update the following values to match your application needs. - // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. - minSdk = 23 + minSdk = flutter.minSdkVersion targetSdk = flutter.targetSdkVersion - versionCode = flutterVersionCode.toInteger() - versionName = flutterVersionName + versionCode = flutter.versionCode + versionName = flutter.versionName } buildTypes { release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. signingConfig = signingConfigs.debug } } @@ -56,4 +36,3 @@ android { flutter { source = "../.." } - diff --git a/android/gradle.properties b/android/gradle.properties index 94adc3a3..25971708 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index aeaff6f8..e6b38c2d 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip diff --git a/android/settings.gradle b/android/settings.gradle index 5a6de5ce..ff583230 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -18,7 +18,7 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "7.3.1" apply false + id "com.android.application" version "8.1.4" apply false id "org.jetbrains.kotlin.android" version "2.0.20" apply false } diff --git a/assets/icons/telegram.svg b/assets/icons/telegram.svg new file mode 100644 index 00000000..3ec45ee8 --- /dev/null +++ b/assets/icons/telegram.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/vk.svg b/assets/icons/vk.svg new file mode 100644 index 00000000..4f20c777 --- /dev/null +++ b/assets/icons/vk.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/web.svg b/assets/icons/web.svg new file mode 100644 index 00000000..a3fc538c --- /dev/null +++ b/assets/icons/web.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/lib/app_router.dart b/lib/app_router.dart index e54fe2da..2f1f53e4 100644 --- a/lib/app_router.dart +++ b/lib/app_router.dart @@ -7,6 +7,8 @@ import 'package:eatvio_app/features/calendar/presentation/pages/calendar_screen. import 'package:eatvio_app/features/chat/presentation/pages/chat_screen.dart'; import 'package:eatvio_app/features/chat/presentation/pages/chat_select_screen.dart'; import 'package:eatvio_app/features/chat/presentation/pages/photo_view_screen.dart'; +import 'package:eatvio_app/features/consultant/become_consultant/presentation/pages/become_consultant_screen.dart'; +import 'package:eatvio_app/features/consultant/become_consultant/presentation/pages/stepper_become_consultant_screen.dart'; import 'package:eatvio_app/features/diary/presentation/pages/diary_screen.dart'; import 'package:eatvio_app/features/diets/presentation/pages/about_diet_screen.dart'; import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart'; @@ -23,6 +25,7 @@ import 'package:eatvio_app/features/recipes/presentation/pages/recipe_create_scr import 'package:eatvio_app/features/recipes/presentation/pages/recipe_edit_screen.dart'; import 'package:eatvio_app/features/registration/presentation/pages/registration_screen.dart'; import 'package:eatvio_app/features/settings/entities/settings_entity.dart'; +import 'package:eatvio_app/features/settings/presentation/pages/change_email_screen.dart'; import 'package:eatvio_app/features/settings/presentation/pages/change_password_screen.dart'; import 'package:eatvio_app/features/settings/presentation/pages/general_info_screen.dart'; import 'package:eatvio_app/features/settings/presentation/pages/other_info_screen.dart'; @@ -214,6 +217,13 @@ class AppRouter { settingsEntity: state.extra as SettingsEntity, ), ), + GoRoute( + path: 'change-email-screen', + name: 'changeEmailScreen', + builder: (context, state) => ChangeEmailScreen( + settingsEntity: state.extra as SettingsEntity, + ), + ), ], ), GoRoute( @@ -221,6 +231,16 @@ class AppRouter { name: 'mySettingsScreen', builder: (context, state) => MySettingsScreen.builder(context), ), + GoRoute( + path: '/become-consultant-screen', + name: 'becomeConsultantScreen', + builder: (context, state) => BecomeConsultantScreen(), + ), + GoRoute( + path: '/stepper-become-consultant-screen', + name: 'stepperBecomeConsultantScreen', + builder: (context, state) => StepperBecomeConsultantScreen(), + ), GoRoute( path: '/recipe-select-screen', name: 'recipeSelectScreen', diff --git a/lib/features/blog_post_create/presentation/pages/blog_post_create_screen.dart b/lib/features/blog_post_create/presentation/pages/blog_post_create_screen.dart index baf87e0f..d76b7bd4 100644 --- a/lib/features/blog_post_create/presentation/pages/blog_post_create_screen.dart +++ b/lib/features/blog_post_create/presentation/pages/blog_post_create_screen.dart @@ -85,15 +85,13 @@ class _BlogPostCreateScreenState extends State { shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), ), - backgroundColor: state.image != null || state.title!.text.isNotEmpty || state.description!.text.isNotEmpty || state.youtubeURL!.text.isNotEmpty - ? appTheme.blueA400 - : Colors.grey, - onPressed: state.image != null || state.title!.text.isNotEmpty || state.description!.text.isNotEmpty || state.youtubeURL!.text.isNotEmpty - ? () => _submitForm(context, state.title!.text, state.description!.text, state.youtubeURL!.text) - : null, + backgroundColor: appTheme.blueA400, + onPressed: () => _submitForm(context, state.title!.text, state.description!.text, state.youtubeURL!.text), label: Text( 'Создать', - style: theme.textTheme.titleSmall, + style: TextStyle( + color: Colors.white, + ), ), ), ), @@ -102,9 +100,6 @@ class _BlogPostCreateScreenState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - if (state.youtubeURL!.text.isEmpty) Text('Изображение поста'), - if (state.youtubeURL!.text.isEmpty) SizedBox(height: 8), - if (state.youtubeURL!.text.isEmpty) _buildAddPhoto(state), SizedBox(height: 16), Text('Заголовок'), SizedBox(height: 8), @@ -117,9 +112,13 @@ class _BlogPostCreateScreenState extends State { CustomTextFormField( controller: state.description, maxLines: 6, - minLines: 1, + minLines: 4, ), SizedBox(height: 16), + if (state.youtubeURL!.text.isEmpty) Text('Изображение поста'), + if (state.youtubeURL!.text.isEmpty) SizedBox(height: 8), + if (state.youtubeURL!.text.isEmpty) _buildAddPhoto(state), + SizedBox(height: 16), if (state.image == null) Text('Ссылка на видео'), if (state.image == null) SizedBox(height: 8), if (state.image == null) @@ -184,7 +183,12 @@ class _BlogPostCreateScreenState extends State { } } -_submitForm(BuildContext context, String title, String description, String youtubeURL) async { +_submitForm( + BuildContext context, + String title, + String description, + String youtubeURL, +) async { context.read().add(CreateBlogPost()); } diff --git a/lib/features/blog_post_create/services/blog_post_service.dart b/lib/features/blog_post_create/services/blog_post_service.dart new file mode 100644 index 00000000..33524124 --- /dev/null +++ b/lib/features/blog_post_create/services/blog_post_service.dart @@ -0,0 +1,19 @@ +import 'package:dio/dio.dart'; +import 'package:retrofit/retrofit.dart'; + +part 'blog_post_service.g.dart'; + +@RestApi() +abstract class BlogPostService { + factory BlogPostService(Dio dio, {String baseUrl}) = _BlogPostService; + + @POST('/api/blogPosts/create') + @MultiPart() + Future sendMessage({ + @Path() String? title, + @Path() required String state, + @Path() String? description, + @Part() String? youtube_url, + @Part(name: 'image', contentType: 'multipart/form-data') List? media_data, + }); +} diff --git a/lib/features/blog_post_create/services/blog_post_service.g.dart b/lib/features/blog_post_create/services/blog_post_service.g.dart new file mode 100644 index 00000000..fab2c34d --- /dev/null +++ b/lib/features/blog_post_create/services/blog_post_service.g.dart @@ -0,0 +1,95 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'blog_post_service.dart'; + +// ************************************************************************** +// RetrofitGenerator +// ************************************************************************** + +// ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element + +class _BlogPostService implements BlogPostService { + _BlogPostService( + this._dio, { + this.baseUrl, + this.errorLogger, + }); + + final Dio _dio; + + String? baseUrl; + + final ParseErrorLogger? errorLogger; + + @override + Future sendMessage({ + String? title, + required String state, + String? description, + String? youtube_url, + List? media_data, + }) async { + final _extra = {}; + final queryParameters = {}; + queryParameters.removeWhere((k, v) => v == null); + final _headers = {}; + final _data = FormData(); + if (youtube_url != null) { + _data.fields.add(MapEntry( + 'youtube_url', + youtube_url, + )); + } + if (media_data != null) { + _data.files.addAll(media_data.map((i) => MapEntry('image', i))); + } + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + contentType: 'multipart/form-data', + ) + .compose( + _dio.options, + '/api/blogPosts/create', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); + await _dio.fetch(_options); + } + + RequestOptions _setStreamType(RequestOptions requestOptions) { + if (T != dynamic && + !(requestOptions.responseType == ResponseType.bytes || + requestOptions.responseType == ResponseType.stream)) { + if (T == String) { + requestOptions.responseType = ResponseType.plain; + } else { + requestOptions.responseType = ResponseType.json; + } + } + return requestOptions; + } + + String _combineBaseUrls( + String dioBaseUrl, + String? baseUrl, + ) { + if (baseUrl == null || baseUrl.trim().isEmpty) { + return dioBaseUrl; + } + + final url = Uri.parse(baseUrl); + + if (url.isAbsolute) { + return url.toString(); + } + + return Uri.parse(dioBaseUrl).resolveUri(url).toString(); + } +} diff --git a/lib/features/chat/presentation/pages/chat_screen.dart b/lib/features/chat/presentation/pages/chat_screen.dart index 2e96d007..ee50e04d 100644 --- a/lib/features/chat/presentation/pages/chat_screen.dart +++ b/lib/features/chat/presentation/pages/chat_screen.dart @@ -27,16 +27,18 @@ class ChatScreen extends StatefulWidget { class _ChatScreenState extends State { final scrollController = ScrollController(); final TextEditingController textEditingController = TextEditingController(); + final ChatRoomCubit chatRoomCubit = sl(); @override void initState() { - scrollController.addListener(_onScroll); super.initState(); + scrollController.addListener(_onScroll); + chatRoomCubit.initChat(widget.chatId); } _onScroll() { if (scrollController.offset >= scrollController.position.maxScrollExtent && !scrollController.position.outOfRange) { - context.read().loadNextPage(widget.chatId); + chatRoomCubit.loadNextPage(widget.chatId); } } @@ -48,8 +50,9 @@ class _ChatScreenState extends State { Widget build(BuildContext context) { return BlocProvider( - create: (BuildContext context) => sl()..initChat(widget.chatId), + create: (BuildContext context) => chatRoomCubit, child: BlocBuilder( + bloc: chatRoomCubit, builder: (context, state) { if (state is ChatRoomStateLoaded) { return _buildChat(context, state); @@ -234,10 +237,10 @@ class _ChatScreenState extends State { if (result != null) { List files = result.paths.map((path) => File(path!)).toList(); - context.read().sendMessage( - chatId: widget.chatId, - files: files, - ); + chatRoomCubit.sendMessage( + chatId: widget.chatId, + files: files, + ); } else { // User canceled the picker } @@ -305,10 +308,10 @@ class _ChatScreenState extends State { customBorder: CircleBorder(), onTap: () { if (textEditingController.text.isNotEmpty) { - context.read().sendMessage( - chatId: widget.chatId, - data: textEditingController.text.trim(), - ); + chatRoomCubit.sendMessage( + chatId: widget.chatId, + data: textEditingController.text.trim(), + ); setState(() { textEditingController.clear(); }); diff --git a/lib/features/chat/services/chat_service.dart b/lib/features/chat/services/chat_service.dart index 3bbb74ff..f572b117 100644 --- a/lib/features/chat/services/chat_service.dart +++ b/lib/features/chat/services/chat_service.dart @@ -37,4 +37,9 @@ abstract class ChatService { @GET('/api/profile/ws/params') Future getWebsocket(); + + @GET('/api/chat/get_by_user/{user}') + Future getChatRoomIdByUserSlug({ + @Path() required String user, + }); } diff --git a/lib/features/chat/services/chat_service.g.dart b/lib/features/chat/services/chat_service.g.dart index 4e84a7b3..77366053 100644 --- a/lib/features/chat/services/chat_service.g.dart +++ b/lib/features/chat/services/chat_service.g.dart @@ -198,6 +198,39 @@ class _ChatService implements ChatService { return _value; } + @override + Future getChatRoomIdByUserSlug({required String user}) async { + final _extra = {}; + final queryParameters = {}; + final _headers = {}; + const Map? _data = null; + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/chat/get_by_user/${user}', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); + final _result = await _dio.fetch>(_options); + late ChatRoomModel _value; + try { + _value = ChatRoomModel.fromJson(_result.data!); + } on Object catch (e, s) { + errorLogger?.logError(e, s, _options); + rethrow; + } + return _value; + } + RequestOptions _setStreamType(RequestOptions requestOptions) { if (T != dynamic && !(requestOptions.responseType == ResponseType.bytes || diff --git a/lib/features/consultant/become_consultant/entities/diploma_entity.dart b/lib/features/consultant/become_consultant/entities/diploma_entity.dart new file mode 100644 index 00000000..0194a811 --- /dev/null +++ b/lib/features/consultant/become_consultant/entities/diploma_entity.dart @@ -0,0 +1,13 @@ +import 'package:flutter/material.dart'; + +class DiplomaEntity { + TextEditingController textEditingController; + DateTime? date; + bool enableDeleteButton; + + DiplomaEntity({ + this.date, + required this.textEditingController, + required this.enableDeleteButton, + }); +} diff --git a/lib/features/consultant/become_consultant/models/consultant_profile_model.dart b/lib/features/consultant/become_consultant/models/consultant_profile_model.dart new file mode 100644 index 00000000..4cbde94f --- /dev/null +++ b/lib/features/consultant/become_consultant/models/consultant_profile_model.dart @@ -0,0 +1,40 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'consultant_profile_model.freezed.dart'; + +part 'consultant_profile_model.g.dart'; + +@freezed +class ConsultantProfileModel with _$ConsultantProfileModel { + const factory ConsultantProfileModel({ + @JsonKey(name: 'has_medical_education') bool? hasMedicalEducation, + @JsonKey(name: 'social_links') SocialLinksModel? socialLinks, + @JsonKey(name: 'cert_photos') List? photos, + @JsonKey(name: 'completed_courses') List? certificates, + }) = _ConsultantProfileModel; + + factory ConsultantProfileModel.fromJson(Map json) => _$ConsultantProfileModelFromJson(json); +} + +@freezed +class SocialLinksModel with _$SocialLinksModel { + const factory SocialLinksModel({ + @JsonKey(name: 'vk_link') String? vkLink, + @JsonKey(name: 'tg_link') String? tgLink, + @JsonKey(name: 'fb_link') String? fbLink, + @JsonKey(name: 'insta_link') String? instaLink, + @JsonKey(name: 'personal_site_link') String? personalSiteLink, + }) = _SocialLinksModel; + + factory SocialLinksModel.fromJson(Map json) => _$SocialLinksModelFromJson(json); +} + +@freezed +class CertificatesModel with _$CertificatesModel { + const factory CertificatesModel({ + required String title, + required String date, + }) = _CertificatesModel; + + factory CertificatesModel.fromJson(Map json) => _$CertificatesModelFromJson(json); +} diff --git a/lib/features/consultant/become_consultant/models/consultant_profile_model.freezed.dart b/lib/features/consultant/become_consultant/models/consultant_profile_model.freezed.dart new file mode 100644 index 00000000..3abdd043 --- /dev/null +++ b/lib/features/consultant/become_consultant/models/consultant_profile_model.freezed.dart @@ -0,0 +1,717 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'consultant_profile_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +ConsultantProfileModel _$ConsultantProfileModelFromJson( + Map json) { + return _ConsultantProfileModel.fromJson(json); +} + +/// @nodoc +mixin _$ConsultantProfileModel { + @JsonKey(name: 'has_medical_education') + bool? get hasMedicalEducation => throw _privateConstructorUsedError; + @JsonKey(name: 'social_links') + SocialLinksModel? get socialLinks => throw _privateConstructorUsedError; + @JsonKey(name: 'cert_photos') + List? get photos => throw _privateConstructorUsedError; + @JsonKey(name: 'completed_courses') + List? get certificates => + throw _privateConstructorUsedError; + + /// Serializes this ConsultantProfileModel to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of ConsultantProfileModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $ConsultantProfileModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ConsultantProfileModelCopyWith<$Res> { + factory $ConsultantProfileModelCopyWith(ConsultantProfileModel value, + $Res Function(ConsultantProfileModel) then) = + _$ConsultantProfileModelCopyWithImpl<$Res, ConsultantProfileModel>; + @useResult + $Res call( + {@JsonKey(name: 'has_medical_education') bool? hasMedicalEducation, + @JsonKey(name: 'social_links') SocialLinksModel? socialLinks, + @JsonKey(name: 'cert_photos') List? photos, + @JsonKey(name: 'completed_courses') + List? certificates}); + + $SocialLinksModelCopyWith<$Res>? get socialLinks; +} + +/// @nodoc +class _$ConsultantProfileModelCopyWithImpl<$Res, + $Val extends ConsultantProfileModel> + implements $ConsultantProfileModelCopyWith<$Res> { + _$ConsultantProfileModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of ConsultantProfileModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? hasMedicalEducation = freezed, + Object? socialLinks = freezed, + Object? photos = freezed, + Object? certificates = freezed, + }) { + return _then(_value.copyWith( + hasMedicalEducation: freezed == hasMedicalEducation + ? _value.hasMedicalEducation + : hasMedicalEducation // ignore: cast_nullable_to_non_nullable + as bool?, + socialLinks: freezed == socialLinks + ? _value.socialLinks + : socialLinks // ignore: cast_nullable_to_non_nullable + as SocialLinksModel?, + photos: freezed == photos + ? _value.photos + : photos // ignore: cast_nullable_to_non_nullable + as List?, + certificates: freezed == certificates + ? _value.certificates + : certificates // ignore: cast_nullable_to_non_nullable + as List?, + ) as $Val); + } + + /// Create a copy of ConsultantProfileModel + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $SocialLinksModelCopyWith<$Res>? get socialLinks { + if (_value.socialLinks == null) { + return null; + } + + return $SocialLinksModelCopyWith<$Res>(_value.socialLinks!, (value) { + return _then(_value.copyWith(socialLinks: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$ConsultantProfileModelImplCopyWith<$Res> + implements $ConsultantProfileModelCopyWith<$Res> { + factory _$$ConsultantProfileModelImplCopyWith( + _$ConsultantProfileModelImpl value, + $Res Function(_$ConsultantProfileModelImpl) then) = + __$$ConsultantProfileModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {@JsonKey(name: 'has_medical_education') bool? hasMedicalEducation, + @JsonKey(name: 'social_links') SocialLinksModel? socialLinks, + @JsonKey(name: 'cert_photos') List? photos, + @JsonKey(name: 'completed_courses') + List? certificates}); + + @override + $SocialLinksModelCopyWith<$Res>? get socialLinks; +} + +/// @nodoc +class __$$ConsultantProfileModelImplCopyWithImpl<$Res> + extends _$ConsultantProfileModelCopyWithImpl<$Res, + _$ConsultantProfileModelImpl> + implements _$$ConsultantProfileModelImplCopyWith<$Res> { + __$$ConsultantProfileModelImplCopyWithImpl( + _$ConsultantProfileModelImpl _value, + $Res Function(_$ConsultantProfileModelImpl) _then) + : super(_value, _then); + + /// Create a copy of ConsultantProfileModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? hasMedicalEducation = freezed, + Object? socialLinks = freezed, + Object? photos = freezed, + Object? certificates = freezed, + }) { + return _then(_$ConsultantProfileModelImpl( + hasMedicalEducation: freezed == hasMedicalEducation + ? _value.hasMedicalEducation + : hasMedicalEducation // ignore: cast_nullable_to_non_nullable + as bool?, + socialLinks: freezed == socialLinks + ? _value.socialLinks + : socialLinks // ignore: cast_nullable_to_non_nullable + as SocialLinksModel?, + photos: freezed == photos + ? _value._photos + : photos // ignore: cast_nullable_to_non_nullable + as List?, + certificates: freezed == certificates + ? _value._certificates + : certificates // ignore: cast_nullable_to_non_nullable + as List?, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$ConsultantProfileModelImpl implements _ConsultantProfileModel { + const _$ConsultantProfileModelImpl( + {@JsonKey(name: 'has_medical_education') this.hasMedicalEducation, + @JsonKey(name: 'social_links') this.socialLinks, + @JsonKey(name: 'cert_photos') final List? photos, + @JsonKey(name: 'completed_courses') + final List? certificates}) + : _photos = photos, + _certificates = certificates; + + factory _$ConsultantProfileModelImpl.fromJson(Map json) => + _$$ConsultantProfileModelImplFromJson(json); + + @override + @JsonKey(name: 'has_medical_education') + final bool? hasMedicalEducation; + @override + @JsonKey(name: 'social_links') + final SocialLinksModel? socialLinks; + final List? _photos; + @override + @JsonKey(name: 'cert_photos') + List? get photos { + final value = _photos; + if (value == null) return null; + if (_photos is EqualUnmodifiableListView) return _photos; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + + final List? _certificates; + @override + @JsonKey(name: 'completed_courses') + List? get certificates { + final value = _certificates; + if (value == null) return null; + if (_certificates is EqualUnmodifiableListView) return _certificates; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + + @override + String toString() { + return 'ConsultantProfileModel(hasMedicalEducation: $hasMedicalEducation, socialLinks: $socialLinks, photos: $photos, certificates: $certificates)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ConsultantProfileModelImpl && + (identical(other.hasMedicalEducation, hasMedicalEducation) || + other.hasMedicalEducation == hasMedicalEducation) && + (identical(other.socialLinks, socialLinks) || + other.socialLinks == socialLinks) && + const DeepCollectionEquality().equals(other._photos, _photos) && + const DeepCollectionEquality() + .equals(other._certificates, _certificates)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash( + runtimeType, + hasMedicalEducation, + socialLinks, + const DeepCollectionEquality().hash(_photos), + const DeepCollectionEquality().hash(_certificates)); + + /// Create a copy of ConsultantProfileModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$ConsultantProfileModelImplCopyWith<_$ConsultantProfileModelImpl> + get copyWith => __$$ConsultantProfileModelImplCopyWithImpl< + _$ConsultantProfileModelImpl>(this, _$identity); + + @override + Map toJson() { + return _$$ConsultantProfileModelImplToJson( + this, + ); + } +} + +abstract class _ConsultantProfileModel implements ConsultantProfileModel { + const factory _ConsultantProfileModel( + {@JsonKey(name: 'has_medical_education') final bool? hasMedicalEducation, + @JsonKey(name: 'social_links') final SocialLinksModel? socialLinks, + @JsonKey(name: 'cert_photos') final List? photos, + @JsonKey(name: 'completed_courses') + final List? + certificates}) = _$ConsultantProfileModelImpl; + + factory _ConsultantProfileModel.fromJson(Map json) = + _$ConsultantProfileModelImpl.fromJson; + + @override + @JsonKey(name: 'has_medical_education') + bool? get hasMedicalEducation; + @override + @JsonKey(name: 'social_links') + SocialLinksModel? get socialLinks; + @override + @JsonKey(name: 'cert_photos') + List? get photos; + @override + @JsonKey(name: 'completed_courses') + List? get certificates; + + /// Create a copy of ConsultantProfileModel + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$ConsultantProfileModelImplCopyWith<_$ConsultantProfileModelImpl> + get copyWith => throw _privateConstructorUsedError; +} + +SocialLinksModel _$SocialLinksModelFromJson(Map json) { + return _SocialLinksModel.fromJson(json); +} + +/// @nodoc +mixin _$SocialLinksModel { + @JsonKey(name: 'vk_link') + String? get vkLink => throw _privateConstructorUsedError; + @JsonKey(name: 'tg_link') + String? get tgLink => throw _privateConstructorUsedError; + @JsonKey(name: 'fb_link') + String? get fbLink => throw _privateConstructorUsedError; + @JsonKey(name: 'insta_link') + String? get instaLink => throw _privateConstructorUsedError; + @JsonKey(name: 'personal_site_link') + String? get personalSiteLink => throw _privateConstructorUsedError; + + /// Serializes this SocialLinksModel to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of SocialLinksModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $SocialLinksModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $SocialLinksModelCopyWith<$Res> { + factory $SocialLinksModelCopyWith( + SocialLinksModel value, $Res Function(SocialLinksModel) then) = + _$SocialLinksModelCopyWithImpl<$Res, SocialLinksModel>; + @useResult + $Res call( + {@JsonKey(name: 'vk_link') String? vkLink, + @JsonKey(name: 'tg_link') String? tgLink, + @JsonKey(name: 'fb_link') String? fbLink, + @JsonKey(name: 'insta_link') String? instaLink, + @JsonKey(name: 'personal_site_link') String? personalSiteLink}); +} + +/// @nodoc +class _$SocialLinksModelCopyWithImpl<$Res, $Val extends SocialLinksModel> + implements $SocialLinksModelCopyWith<$Res> { + _$SocialLinksModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of SocialLinksModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? vkLink = freezed, + Object? tgLink = freezed, + Object? fbLink = freezed, + Object? instaLink = freezed, + Object? personalSiteLink = freezed, + }) { + return _then(_value.copyWith( + vkLink: freezed == vkLink + ? _value.vkLink + : vkLink // ignore: cast_nullable_to_non_nullable + as String?, + tgLink: freezed == tgLink + ? _value.tgLink + : tgLink // ignore: cast_nullable_to_non_nullable + as String?, + fbLink: freezed == fbLink + ? _value.fbLink + : fbLink // ignore: cast_nullable_to_non_nullable + as String?, + instaLink: freezed == instaLink + ? _value.instaLink + : instaLink // ignore: cast_nullable_to_non_nullable + as String?, + personalSiteLink: freezed == personalSiteLink + ? _value.personalSiteLink + : personalSiteLink // ignore: cast_nullable_to_non_nullable + as String?, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$SocialLinksModelImplCopyWith<$Res> + implements $SocialLinksModelCopyWith<$Res> { + factory _$$SocialLinksModelImplCopyWith(_$SocialLinksModelImpl value, + $Res Function(_$SocialLinksModelImpl) then) = + __$$SocialLinksModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {@JsonKey(name: 'vk_link') String? vkLink, + @JsonKey(name: 'tg_link') String? tgLink, + @JsonKey(name: 'fb_link') String? fbLink, + @JsonKey(name: 'insta_link') String? instaLink, + @JsonKey(name: 'personal_site_link') String? personalSiteLink}); +} + +/// @nodoc +class __$$SocialLinksModelImplCopyWithImpl<$Res> + extends _$SocialLinksModelCopyWithImpl<$Res, _$SocialLinksModelImpl> + implements _$$SocialLinksModelImplCopyWith<$Res> { + __$$SocialLinksModelImplCopyWithImpl(_$SocialLinksModelImpl _value, + $Res Function(_$SocialLinksModelImpl) _then) + : super(_value, _then); + + /// Create a copy of SocialLinksModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? vkLink = freezed, + Object? tgLink = freezed, + Object? fbLink = freezed, + Object? instaLink = freezed, + Object? personalSiteLink = freezed, + }) { + return _then(_$SocialLinksModelImpl( + vkLink: freezed == vkLink + ? _value.vkLink + : vkLink // ignore: cast_nullable_to_non_nullable + as String?, + tgLink: freezed == tgLink + ? _value.tgLink + : tgLink // ignore: cast_nullable_to_non_nullable + as String?, + fbLink: freezed == fbLink + ? _value.fbLink + : fbLink // ignore: cast_nullable_to_non_nullable + as String?, + instaLink: freezed == instaLink + ? _value.instaLink + : instaLink // ignore: cast_nullable_to_non_nullable + as String?, + personalSiteLink: freezed == personalSiteLink + ? _value.personalSiteLink + : personalSiteLink // ignore: cast_nullable_to_non_nullable + as String?, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$SocialLinksModelImpl implements _SocialLinksModel { + const _$SocialLinksModelImpl( + {@JsonKey(name: 'vk_link') this.vkLink, + @JsonKey(name: 'tg_link') this.tgLink, + @JsonKey(name: 'fb_link') this.fbLink, + @JsonKey(name: 'insta_link') this.instaLink, + @JsonKey(name: 'personal_site_link') this.personalSiteLink}); + + factory _$SocialLinksModelImpl.fromJson(Map json) => + _$$SocialLinksModelImplFromJson(json); + + @override + @JsonKey(name: 'vk_link') + final String? vkLink; + @override + @JsonKey(name: 'tg_link') + final String? tgLink; + @override + @JsonKey(name: 'fb_link') + final String? fbLink; + @override + @JsonKey(name: 'insta_link') + final String? instaLink; + @override + @JsonKey(name: 'personal_site_link') + final String? personalSiteLink; + + @override + String toString() { + return 'SocialLinksModel(vkLink: $vkLink, tgLink: $tgLink, fbLink: $fbLink, instaLink: $instaLink, personalSiteLink: $personalSiteLink)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$SocialLinksModelImpl && + (identical(other.vkLink, vkLink) || other.vkLink == vkLink) && + (identical(other.tgLink, tgLink) || other.tgLink == tgLink) && + (identical(other.fbLink, fbLink) || other.fbLink == fbLink) && + (identical(other.instaLink, instaLink) || + other.instaLink == instaLink) && + (identical(other.personalSiteLink, personalSiteLink) || + other.personalSiteLink == personalSiteLink)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash( + runtimeType, vkLink, tgLink, fbLink, instaLink, personalSiteLink); + + /// Create a copy of SocialLinksModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$SocialLinksModelImplCopyWith<_$SocialLinksModelImpl> get copyWith => + __$$SocialLinksModelImplCopyWithImpl<_$SocialLinksModelImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$SocialLinksModelImplToJson( + this, + ); + } +} + +abstract class _SocialLinksModel implements SocialLinksModel { + const factory _SocialLinksModel( + {@JsonKey(name: 'vk_link') final String? vkLink, + @JsonKey(name: 'tg_link') final String? tgLink, + @JsonKey(name: 'fb_link') final String? fbLink, + @JsonKey(name: 'insta_link') final String? instaLink, + @JsonKey(name: 'personal_site_link') + final String? personalSiteLink}) = _$SocialLinksModelImpl; + + factory _SocialLinksModel.fromJson(Map json) = + _$SocialLinksModelImpl.fromJson; + + @override + @JsonKey(name: 'vk_link') + String? get vkLink; + @override + @JsonKey(name: 'tg_link') + String? get tgLink; + @override + @JsonKey(name: 'fb_link') + String? get fbLink; + @override + @JsonKey(name: 'insta_link') + String? get instaLink; + @override + @JsonKey(name: 'personal_site_link') + String? get personalSiteLink; + + /// Create a copy of SocialLinksModel + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$SocialLinksModelImplCopyWith<_$SocialLinksModelImpl> get copyWith => + throw _privateConstructorUsedError; +} + +CertificatesModel _$CertificatesModelFromJson(Map json) { + return _CertificatesModel.fromJson(json); +} + +/// @nodoc +mixin _$CertificatesModel { + String get title => throw _privateConstructorUsedError; + String get date => throw _privateConstructorUsedError; + + /// Serializes this CertificatesModel to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of CertificatesModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $CertificatesModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $CertificatesModelCopyWith<$Res> { + factory $CertificatesModelCopyWith( + CertificatesModel value, $Res Function(CertificatesModel) then) = + _$CertificatesModelCopyWithImpl<$Res, CertificatesModel>; + @useResult + $Res call({String title, String date}); +} + +/// @nodoc +class _$CertificatesModelCopyWithImpl<$Res, $Val extends CertificatesModel> + implements $CertificatesModelCopyWith<$Res> { + _$CertificatesModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of CertificatesModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? title = null, + Object? date = null, + }) { + return _then(_value.copyWith( + title: null == title + ? _value.title + : title // ignore: cast_nullable_to_non_nullable + as String, + date: null == date + ? _value.date + : date // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$CertificatesModelImplCopyWith<$Res> + implements $CertificatesModelCopyWith<$Res> { + factory _$$CertificatesModelImplCopyWith(_$CertificatesModelImpl value, + $Res Function(_$CertificatesModelImpl) then) = + __$$CertificatesModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({String title, String date}); +} + +/// @nodoc +class __$$CertificatesModelImplCopyWithImpl<$Res> + extends _$CertificatesModelCopyWithImpl<$Res, _$CertificatesModelImpl> + implements _$$CertificatesModelImplCopyWith<$Res> { + __$$CertificatesModelImplCopyWithImpl(_$CertificatesModelImpl _value, + $Res Function(_$CertificatesModelImpl) _then) + : super(_value, _then); + + /// Create a copy of CertificatesModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? title = null, + Object? date = null, + }) { + return _then(_$CertificatesModelImpl( + title: null == title + ? _value.title + : title // ignore: cast_nullable_to_non_nullable + as String, + date: null == date + ? _value.date + : date // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$CertificatesModelImpl implements _CertificatesModel { + const _$CertificatesModelImpl({required this.title, required this.date}); + + factory _$CertificatesModelImpl.fromJson(Map json) => + _$$CertificatesModelImplFromJson(json); + + @override + final String title; + @override + final String date; + + @override + String toString() { + return 'CertificatesModel(title: $title, date: $date)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$CertificatesModelImpl && + (identical(other.title, title) || other.title == title) && + (identical(other.date, date) || other.date == date)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash(runtimeType, title, date); + + /// Create a copy of CertificatesModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$CertificatesModelImplCopyWith<_$CertificatesModelImpl> get copyWith => + __$$CertificatesModelImplCopyWithImpl<_$CertificatesModelImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$CertificatesModelImplToJson( + this, + ); + } +} + +abstract class _CertificatesModel implements CertificatesModel { + const factory _CertificatesModel( + {required final String title, + required final String date}) = _$CertificatesModelImpl; + + factory _CertificatesModel.fromJson(Map json) = + _$CertificatesModelImpl.fromJson; + + @override + String get title; + @override + String get date; + + /// Create a copy of CertificatesModel + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$CertificatesModelImplCopyWith<_$CertificatesModelImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/features/consultant/become_consultant/models/consultant_profile_model.g.dart b/lib/features/consultant/become_consultant/models/consultant_profile_model.g.dart new file mode 100644 index 00000000..ab86917a --- /dev/null +++ b/lib/features/consultant/become_consultant/models/consultant_profile_model.g.dart @@ -0,0 +1,66 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'consultant_profile_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$ConsultantProfileModelImpl _$$ConsultantProfileModelImplFromJson( + Map json) => + _$ConsultantProfileModelImpl( + hasMedicalEducation: json['has_medical_education'] as bool?, + socialLinks: json['social_links'] == null + ? null + : SocialLinksModel.fromJson( + json['social_links'] as Map), + photos: (json['cert_photos'] as List?) + ?.map((e) => e as String) + .toList(), + certificates: (json['completed_courses'] as List?) + ?.map((e) => CertificatesModel.fromJson(e as Map)) + .toList(), + ); + +Map _$$ConsultantProfileModelImplToJson( + _$ConsultantProfileModelImpl instance) => + { + 'has_medical_education': instance.hasMedicalEducation, + 'social_links': instance.socialLinks, + 'cert_photos': instance.photos, + 'completed_courses': instance.certificates, + }; + +_$SocialLinksModelImpl _$$SocialLinksModelImplFromJson( + Map json) => + _$SocialLinksModelImpl( + vkLink: json['vk_link'] as String?, + tgLink: json['tg_link'] as String?, + fbLink: json['fb_link'] as String?, + instaLink: json['insta_link'] as String?, + personalSiteLink: json['personal_site_link'] as String?, + ); + +Map _$$SocialLinksModelImplToJson( + _$SocialLinksModelImpl instance) => + { + 'vk_link': instance.vkLink, + 'tg_link': instance.tgLink, + 'fb_link': instance.fbLink, + 'insta_link': instance.instaLink, + 'personal_site_link': instance.personalSiteLink, + }; + +_$CertificatesModelImpl _$$CertificatesModelImplFromJson( + Map json) => + _$CertificatesModelImpl( + title: json['title'] as String, + date: json['date'] as String, + ); + +Map _$$CertificatesModelImplToJson( + _$CertificatesModelImpl instance) => + { + 'title': instance.title, + 'date': instance.date, + }; diff --git a/lib/features/consultant/become_consultant/presentation/bloc/register_consultant_cubit/register_consultant_cubit.dart b/lib/features/consultant/become_consultant/presentation/bloc/register_consultant_cubit/register_consultant_cubit.dart new file mode 100644 index 00000000..b60cab68 --- /dev/null +++ b/lib/features/consultant/become_consultant/presentation/bloc/register_consultant_cubit/register_consultant_cubit.dart @@ -0,0 +1,30 @@ +import 'dart:io'; + +import 'package:eatvio_app/features/consultant/become_consultant/models/consultant_profile_model.dart'; +import 'package:eatvio_app/features/consultant/become_consultant/presentation/bloc/register_consultant_cubit/register_consultant_state.dart'; +import 'package:eatvio_app/features/consultant/become_consultant/repositories/consultant_repository.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +class RegisterConsultantCubit extends Cubit { + final ConsultantRepository consultantRepository; + + RegisterConsultantCubit({ + required this.consultantRepository, + }) : super( + RegisterConsultantState( + consultant: ConsultantProfileModel(), + ), + ); + + updateConsultantProfileModel(ConsultantProfileModel consultant) { + emit(RegisterConsultantState(consultant: consultant)); + } + + registerConsultant() async { + await consultantRepository.registerConsultant(consultant: state.consultant); + } + + uploadPhotos(List files) async { + await consultantRepository.uploadPhotos(files: files); + } +} diff --git a/lib/features/consultant/become_consultant/presentation/bloc/register_consultant_cubit/register_consultant_state.dart b/lib/features/consultant/become_consultant/presentation/bloc/register_consultant_cubit/register_consultant_state.dart new file mode 100644 index 00000000..cb8cafe6 --- /dev/null +++ b/lib/features/consultant/become_consultant/presentation/bloc/register_consultant_cubit/register_consultant_state.dart @@ -0,0 +1,11 @@ +import 'package:eatvio_app/features/consultant/become_consultant/models/consultant_profile_model.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'register_consultant_state.freezed.dart'; + +@freezed +abstract class RegisterConsultantState with _$RegisterConsultantState { + const factory RegisterConsultantState({ + required ConsultantProfileModel consultant, + }) = _RegisterConsultantState; +} diff --git a/lib/features/consultant/become_consultant/presentation/bloc/register_consultant_cubit/register_consultant_state.freezed.dart b/lib/features/consultant/become_consultant/presentation/bloc/register_consultant_cubit/register_consultant_state.freezed.dart new file mode 100644 index 00000000..f516e7bf --- /dev/null +++ b/lib/features/consultant/become_consultant/presentation/bloc/register_consultant_cubit/register_consultant_state.freezed.dart @@ -0,0 +1,166 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'register_consultant_state.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$RegisterConsultantState { + ConsultantProfileModel get consultant => throw _privateConstructorUsedError; + + /// Create a copy of RegisterConsultantState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $RegisterConsultantStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $RegisterConsultantStateCopyWith<$Res> { + factory $RegisterConsultantStateCopyWith(RegisterConsultantState value, + $Res Function(RegisterConsultantState) then) = + _$RegisterConsultantStateCopyWithImpl<$Res, RegisterConsultantState>; + @useResult + $Res call({ConsultantProfileModel consultant}); + + $ConsultantProfileModelCopyWith<$Res> get consultant; +} + +/// @nodoc +class _$RegisterConsultantStateCopyWithImpl<$Res, + $Val extends RegisterConsultantState> + implements $RegisterConsultantStateCopyWith<$Res> { + _$RegisterConsultantStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of RegisterConsultantState + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? consultant = null, + }) { + return _then(_value.copyWith( + consultant: null == consultant + ? _value.consultant + : consultant // ignore: cast_nullable_to_non_nullable + as ConsultantProfileModel, + ) as $Val); + } + + /// Create a copy of RegisterConsultantState + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $ConsultantProfileModelCopyWith<$Res> get consultant { + return $ConsultantProfileModelCopyWith<$Res>(_value.consultant, (value) { + return _then(_value.copyWith(consultant: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$RegisterConsultantStateImplCopyWith<$Res> + implements $RegisterConsultantStateCopyWith<$Res> { + factory _$$RegisterConsultantStateImplCopyWith( + _$RegisterConsultantStateImpl value, + $Res Function(_$RegisterConsultantStateImpl) then) = + __$$RegisterConsultantStateImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({ConsultantProfileModel consultant}); + + @override + $ConsultantProfileModelCopyWith<$Res> get consultant; +} + +/// @nodoc +class __$$RegisterConsultantStateImplCopyWithImpl<$Res> + extends _$RegisterConsultantStateCopyWithImpl<$Res, + _$RegisterConsultantStateImpl> + implements _$$RegisterConsultantStateImplCopyWith<$Res> { + __$$RegisterConsultantStateImplCopyWithImpl( + _$RegisterConsultantStateImpl _value, + $Res Function(_$RegisterConsultantStateImpl) _then) + : super(_value, _then); + + /// Create a copy of RegisterConsultantState + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? consultant = null, + }) { + return _then(_$RegisterConsultantStateImpl( + consultant: null == consultant + ? _value.consultant + : consultant // ignore: cast_nullable_to_non_nullable + as ConsultantProfileModel, + )); + } +} + +/// @nodoc + +class _$RegisterConsultantStateImpl implements _RegisterConsultantState { + const _$RegisterConsultantStateImpl({required this.consultant}); + + @override + final ConsultantProfileModel consultant; + + @override + String toString() { + return 'RegisterConsultantState(consultant: $consultant)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$RegisterConsultantStateImpl && + (identical(other.consultant, consultant) || + other.consultant == consultant)); + } + + @override + int get hashCode => Object.hash(runtimeType, consultant); + + /// Create a copy of RegisterConsultantState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$RegisterConsultantStateImplCopyWith<_$RegisterConsultantStateImpl> + get copyWith => __$$RegisterConsultantStateImplCopyWithImpl< + _$RegisterConsultantStateImpl>(this, _$identity); +} + +abstract class _RegisterConsultantState implements RegisterConsultantState { + const factory _RegisterConsultantState( + {required final ConsultantProfileModel consultant}) = + _$RegisterConsultantStateImpl; + + @override + ConsultantProfileModel get consultant; + + /// Create a copy of RegisterConsultantState + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$RegisterConsultantStateImplCopyWith<_$RegisterConsultantStateImpl> + get copyWith => throw _privateConstructorUsedError; +} diff --git a/lib/features/consultant/become_consultant/presentation/pages/additional_settings_screen.dart b/lib/features/consultant/become_consultant/presentation/pages/additional_settings_screen.dart new file mode 100644 index 00000000..ac8b4e11 --- /dev/null +++ b/lib/features/consultant/become_consultant/presentation/pages/additional_settings_screen.dart @@ -0,0 +1,98 @@ +import 'package:eatvio_app/theme/theme_helper.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class AdditionalSettingsScreen extends StatefulWidget { + const AdditionalSettingsScreen({super.key}); + + @override + State createState() => _AdditionalSettingsScreenState(); +} + +class _AdditionalSettingsScreenState extends State { + bool publishDiplomasAndCertificatesInProfile = true; + bool haveMedicalDegree = true; + + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + padding: EdgeInsets.only(bottom: 80, top: 16), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Text( + 'Дополнительные настройки', + style: TextStyle( + fontSize: 24, + fontWeight: FontWeight.w700, + height: 1.1, + ), + ), + ), + const SizedBox(height: 16), + _tile( + title: 'Опубликовать дипломы\nи сертификаты в профиле', + value: publishDiplomasAndCertificatesInProfile, + onTap: () { + setState(() { + publishDiplomasAndCertificatesInProfile = !publishDiplomasAndCertificatesInProfile; + }); + }, + ), + _divider(context), + _tile( + title: 'У меня есть медицинское образование ', + value: haveMedicalDegree, + onTap: () { + setState(() { + haveMedicalDegree = !haveMedicalDegree; + }); + }, + ), + ], + ), + ); + } + + _tile({ + required String title, + required Function() onTap, + required bool value, + }) { + return ListTile( + contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 4), + onTap: onTap, + title: Text( + title, + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.w400, + height: 1, + ), + ), + trailing: CupertinoSwitch( + value: value, + activeColor: appTheme.blueA400, + onChanged: (_) { + onTap(); + }, + ), + ); + } + + _divider(BuildContext context) { + return Center( + child: Container( + height: 0.4, + width: MediaQuery.of(context).size.width - 32, + decoration: BoxDecoration( + color: Colors.black26, + borderRadius: BorderRadius.circular(16), + ), + ), + ); + } +} diff --git a/lib/features/consultant/become_consultant/presentation/pages/become_consultant_screen.dart b/lib/features/consultant/become_consultant/presentation/pages/become_consultant_screen.dart new file mode 100644 index 00000000..bf7ec475 --- /dev/null +++ b/lib/features/consultant/become_consultant/presentation/pages/become_consultant_screen.dart @@ -0,0 +1,58 @@ +import 'package:eatvio_app/theme/theme_helper.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; + +class BecomeConsultantScreen extends StatefulWidget { + const BecomeConsultantScreen({super.key}); + + @override + State createState() => _BecomeConsultantScreenState(); +} + +class _BecomeConsultantScreenState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('Стать консультантом'), + automaticallyImplyLeading: false, + centerTitle: false, + leading: IconButton( + onPressed: () => GoRouter.of(context).pop(), + icon: Icon(Icons.close), + ), + ), + body: Padding( + padding: const EdgeInsets.all(16), + child: Text('Для регистрации потребуется следующий список документов, подготовьте их заранее'), + ), + bottomSheet: _startRegistrationButton(), + ); + } + + _startRegistrationButton() { + return InkWell( + onTap: () => GoRouter.of(context).pushReplacementNamed('stepperBecomeConsultantScreen'), + borderRadius: BorderRadius.circular(20), + child: Ink( + height: 52, + width: MediaQuery.of(context).size.width - 32, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: appTheme.blueA400, + ), + child: Center( + child: Text( + 'Начать регистрацию', + style: TextStyle( + color: Colors.white, + height: 1, + fontWeight: FontWeight.w600, + fontSize: 18, + ), + ), + ), + ), + ); + } +} diff --git a/lib/features/consultant/become_consultant/presentation/pages/certificates_and_diplomas_screen.dart b/lib/features/consultant/become_consultant/presentation/pages/certificates_and_diplomas_screen.dart new file mode 100644 index 00000000..1eb412f7 --- /dev/null +++ b/lib/features/consultant/become_consultant/presentation/pages/certificates_and_diplomas_screen.dart @@ -0,0 +1,230 @@ +import 'package:eatvio_app/features/consultant/become_consultant/entities/diploma_entity.dart'; +import 'package:eatvio_app/theme/theme_helper.dart'; +import 'package:eatvio_app/widgets/custom_text_form_field.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:eatvio_app/core/utils/date_time_utils.dart'; +import 'package:flutter/scheduler.dart'; + +class CertificatesAndDiplomasScreen extends StatefulWidget { + const CertificatesAndDiplomasScreen({super.key}); + + @override + State createState() => _CertificatesAndDiplomasScreenState(); +} + +class _CertificatesAndDiplomasScreenState extends State { + final scrollController = ScrollController(); + + List diplomasList = [ + DiplomaEntity( + textEditingController: TextEditingController(), + enableDeleteButton: false, + date: null, + ), + ]; + + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + physics: const BouncingScrollPhysics(), + controller: scrollController, + padding: EdgeInsets.only(bottom: 80, right: 16, left: 16, top: 16), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Добавьте дипломы\nи сертификаты', + style: TextStyle( + fontSize: 24, + fontWeight: FontWeight.w700, + height: 1.1, + ), + ), + const SizedBox(height: 16), + ListView.separated( + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemBuilder: (context, index) => _diplomaInfo(diploma: diplomasList[index]), + separatorBuilder: (context, index) => Padding( + padding: const EdgeInsets.symmetric(vertical: 16), + child: _divider(context), + ), + itemCount: diplomasList.length, + ), + ], + ), + ); + } + + _divider(BuildContext context) { + return Container( + height: 0.4, + width: MediaQuery.of(context).size.width - 32, + decoration: BoxDecoration( + color: Colors.black26, + borderRadius: BorderRadius.circular(16), + ), + ); + } + + _diplomaInfo({ + required DiplomaEntity diploma, + }) { + return Column( + children: [ + CustomTextFormField( + controller: diploma.textEditingController, + onChanged: (value) { + checkLast(); + enableDeleteButton(diploma); + }, + hintText: 'Наименование', + ), + const SizedBox(height: 8), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + width: MediaQuery.of(context).size.width - (diploma.enableDeleteButton ? 92 : 32), + child: ListTile( + onTap: onTapCalendar(context, diploma), + trailing: Icon( + Icons.keyboard_arrow_down_rounded, + color: Colors.grey.shade700, + ), + contentPadding: EdgeInsets.symmetric(horizontal: 12), + title: Text( + diploma.date?.format('dd MMMM yyyy', 'ru') ?? 'Дата выдачи', + style: TextStyle( + color: diploma.date == null ? Colors.grey.shade400 : Colors.black, + ), + ), + tileColor: Color(0xFFF6F6F6), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20), + ), + ), + ), + if (diploma.enableDeleteButton) const SizedBox(width: 8), + if (diploma.enableDeleteButton) + InkWell( + onTap: () { + setState(() { + diplomasList.remove(diploma); + }); + }, + borderRadius: BorderRadius.circular(20), + child: Ink( + height: 52, + width: 52, + decoration: BoxDecoration( + color: Color(0xFFF6F6F6), + borderRadius: BorderRadius.circular(20), + ), + child: Icon( + Icons.delete_outline_rounded, + ), + ), + ), + ], + ), + ], + ); + } + + onTapCalendar(BuildContext context, DiplomaEntity diploma) { + return () { + _showDialog( + CupertinoDatePicker( + initialDateTime: DateTime.now(), + maximumDate: DateTime.now(), + minimumDate: DateTime(1900), + mode: CupertinoDatePickerMode.date, + onDateTimeChanged: (DateTime newDateTime) { + setState(() { + diplomasList[diplomasList.indexOf(diploma)].date = newDateTime; + }); + checkLast(); + enableDeleteButton(diploma); + }, + ), + ); + }; + } + + void _showDialog(Widget child) { + showCupertinoModalPopup( + context: context, + builder: (BuildContext context) => Container( + height: 216, + padding: const EdgeInsets.only(top: 6), + margin: EdgeInsets.only( + bottom: MediaQuery.of(context).viewInsets.bottom, + ), + color: CupertinoColors.systemBackground.resolveFrom(context), + child: SafeArea( + top: false, + child: Column( + children: [ + child, + InkWell( + onTap: () { + Navigator.of(context).pop(); + }, + child: Ink( + width: MediaQuery.of(context).size.width - 32, + height: 52, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: appTheme.blueA400, + ), + child: Center( + child: Text( + 'Закрыть', + style: TextStyle( + color: Colors.white, + fontSize: 18, + fontWeight: FontWeight.w600, + ), + ), + ), + ), + ), + ], + ), + ), + ), + ); + } + + checkLast() { + if (diplomasList.last.textEditingController.text.isNotEmpty || diplomasList.last.date != null) { + setState(() { + diplomasList.add( + DiplomaEntity( + textEditingController: TextEditingController(), + enableDeleteButton: false, + date: null, + ), + ); + SchedulerBinding.instance.addPostFrameCallback((_) { + scrollController.animateTo( + scrollController.position.maxScrollExtent, + duration: const Duration(milliseconds: 250), + curve: Curves.fastOutSlowIn, + ); + }); + }); + } + } + + enableDeleteButton(DiplomaEntity diploma) { + if (diploma.textEditingController.text.isNotEmpty || diploma.date != null) { + setState(() { + diplomasList[diplomasList.indexOf(diploma)].enableDeleteButton = true; + }); + } + } +} diff --git a/lib/features/consultant/become_consultant/presentation/pages/last_step_screen.dart b/lib/features/consultant/become_consultant/presentation/pages/last_step_screen.dart new file mode 100644 index 00000000..89e3e2d4 --- /dev/null +++ b/lib/features/consultant/become_consultant/presentation/pages/last_step_screen.dart @@ -0,0 +1,90 @@ +import 'package:eatvio_app/core/const.dart'; +import 'package:eatvio_app/theme/theme_helper.dart'; +import 'package:flutter/material.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class LastStepScreen extends StatefulWidget { + const LastStepScreen({super.key}); + + @override + State createState() => _LastStepScreenState(); +} + +class _LastStepScreenState extends State { + bool checkboxState = false; + + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + padding: EdgeInsets.only(bottom: 80, top: 16), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Text( + 'Последний шаг', + style: TextStyle( + fontSize: 24, + fontWeight: FontWeight.w700, + height: 1.1, + ), + ), + ), + const SizedBox(height: 16), + CheckboxListTile( + value: checkboxState, + title: Text( + 'Я ознакомлен и принимаю договор публичной офёрты', + style: TextStyle( + fontSize: 18, + height: 1, + ), + ), + onChanged: (_) { + setState(() { + checkboxState = !checkboxState; + }); + }, + activeColor: appTheme.blueA400, + contentPadding: const EdgeInsets.symmetric(horizontal: 16), + ), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 16, + ), + child: _divider(context), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 4), + child: TextButton( + onPressed: () async => await launchUrl(Uri.parse(baseUrl + '/oferta_bs.pdf')), + child: Text( + 'Договор офёрты', + style: TextStyle( + height: 1, + fontSize: 16, + color: Color(0xFF323F4B), + decoration: TextDecoration.underline, + ), + ), + ), + ), + ], + ), + ); + } + + _divider(BuildContext context) { + return Container( + height: 0.4, + width: MediaQuery.of(context).size.width - 32, + decoration: BoxDecoration( + color: Colors.black26, + borderRadius: BorderRadius.circular(16), + ), + ); + } +} diff --git a/lib/features/consultant/become_consultant/presentation/pages/photo_or_scans_screen.dart b/lib/features/consultant/become_consultant/presentation/pages/photo_or_scans_screen.dart new file mode 100644 index 00000000..5f7abbef --- /dev/null +++ b/lib/features/consultant/become_consultant/presentation/pages/photo_or_scans_screen.dart @@ -0,0 +1,121 @@ +import 'dart:io'; + +import 'package:eatvio_app/theme/theme_helper.dart'; +import 'package:flutter/material.dart'; +import 'package:image_picker/image_picker.dart'; + +class PhotoOrScansScreen extends StatefulWidget { + const PhotoOrScansScreen({super.key}); + + @override + State createState() => _PhotoOrScansScreenState(); +} + +class _PhotoOrScansScreenState extends State { + List images = []; + + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + physics: const BouncingScrollPhysics(), + padding: EdgeInsets.only(bottom: 80, right: 16, left: 16, top: 16), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Загрузите фото или сканы дипломов и сертификатов', + style: TextStyle( + fontSize: 24, + fontWeight: FontWeight.w700, + height: 1.1, + ), + ), + const SizedBox(height: 16), + GridView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 3, + childAspectRatio: 3 / 4, + crossAxisSpacing: 8, + mainAxisSpacing: 8, + ), + itemBuilder: (BuildContext context, int index) { + if (index == images.length) { + return InkWell( + borderRadius: BorderRadius.circular(20), + onTap: () async { + final picker = ImagePicker(); + List? newImages = await picker.pickMultiImage(); + setState(() { + images = [...images, ...newImages]; + }); + }, + child: Ink( + decoration: BoxDecoration( + color: Color(0xFFF6F6F6), + borderRadius: BorderRadius.circular(20), + ), + child: Icon( + Icons.add, + color: appTheme.blueA400, + ), + ), + ); + } else { + return InkWell( + onTap: () {}, + borderRadius: BorderRadius.circular(20), + child: Stack( + clipBehavior: Clip.none, + children: [ + Ink( + decoration: BoxDecoration( + borderRadius: BorderRadius.all( + Radius.circular(20), + ), + image: DecorationImage( + fit: BoxFit.fitHeight, + image: FileImage( + File(images[index].path), + ), + ), + ), + ), + Positioned( + right: -12, + top: -12, + child: InkWell( + onTap: () { + setState(() { + images.removeAt(index); + }); + }, + customBorder: CircleBorder(), + child: Ink( + padding: EdgeInsets.all(4), + decoration: BoxDecoration( + color: Color(0xFFF1F2F6), + shape: BoxShape.circle, + ), + child: Icon( + size: 20, + Icons.close, + color: Colors.black, + ), + ), + ), + ), + ], + ), + ); + } + }, + itemCount: images.length + 1, + ), + ], + ), + ); + } +} diff --git a/lib/features/consultant/become_consultant/presentation/pages/registration_as_screen.dart b/lib/features/consultant/become_consultant/presentation/pages/registration_as_screen.dart new file mode 100644 index 00000000..9f6ee8e3 --- /dev/null +++ b/lib/features/consultant/become_consultant/presentation/pages/registration_as_screen.dart @@ -0,0 +1,115 @@ +import 'package:flutter/material.dart'; + +class RegistrationAsScreen extends StatefulWidget { + const RegistrationAsScreen({super.key}); + + @override + State createState() => _RegistrationAsScreenState(); +} + +enum RegistrationAsType { Physical, SelfBusy, IP, OOO } + +class _RegistrationAsScreenState extends State { + RegistrationAsType registrationAsType = RegistrationAsType.Physical; + + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + padding: EdgeInsets.only(bottom: 80, top: 16), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Text( + 'Регистрация в качестве', + style: TextStyle( + fontSize: 24, + fontWeight: FontWeight.w700, + height: 1.1, + ), + ), + ), + const SizedBox(height: 16), + RadioListTile( + value: RegistrationAsType.Physical, + groupValue: registrationAsType, + title: Text( + 'Физического лица', + style: TextStyle( + fontSize: 18, + height: 1, + ), + ), + onChanged: (value) {}, + contentPadding: EdgeInsets.symmetric(horizontal: 8), + ), + RadioListTile( + value: RegistrationAsType.SelfBusy, + groupValue: registrationAsType, + title: Text( + 'Самозанятого', + style: TextStyle( + fontSize: 18, + height: 1, + ), + ), + onChanged: null, + contentPadding: EdgeInsets.symmetric(horizontal: 8), + ), + RadioListTile( + value: RegistrationAsType.IP, + groupValue: registrationAsType, + title: Text( + 'Индивидуального предпринимателя', + style: TextStyle( + fontSize: 18, + height: 1, + ), + ), + onChanged: null, + contentPadding: EdgeInsets.symmetric(horizontal: 8), + ), + RadioListTile( + value: RegistrationAsType.OOO, + groupValue: registrationAsType, + title: Text( + 'Общества с ограниченной ответственностью', + style: TextStyle( + fontSize: 18, + height: 1, + ), + ), + onChanged: null, + contentPadding: EdgeInsets.symmetric(horizontal: 8), + ), + Padding( + padding: EdgeInsets.symmetric( + horizontal: 16, + vertical: 16, + ), + child: _divider(context), + ), + Padding( + padding: EdgeInsets.symmetric(horizontal: 16), + child: Text( + '* На данный момент регистрация доступна только в качестве физического лица. Остальные варианты скоро появятся', + ), + ), + ], + ), + ); + } + + _divider(BuildContext context) { + return Container( + height: 0.4, + width: MediaQuery.of(context).size.width - 32, + decoration: BoxDecoration( + color: Colors.black26, + borderRadius: BorderRadius.circular(16), + ), + ); + } +} diff --git a/lib/features/consultant/become_consultant/presentation/pages/social_networks_screen.dart b/lib/features/consultant/become_consultant/presentation/pages/social_networks_screen.dart new file mode 100644 index 00000000..0de6e609 --- /dev/null +++ b/lib/features/consultant/become_consultant/presentation/pages/social_networks_screen.dart @@ -0,0 +1,108 @@ +import 'package:eatvio_app/widgets/custom_text_form_field.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; + +class SocialNetworksScreen extends StatefulWidget { + const SocialNetworksScreen({super.key}); + + @override + State createState() => _SocialNetworksScreenState(); +} + +class _SocialNetworksScreenState extends State { + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + padding: EdgeInsets.only(bottom: 80, right: 16, left: 16, top: 16), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Социальные сети', + style: TextStyle( + fontSize: 24, + fontWeight: FontWeight.w700, + height: 1.1, + ), + ), + const SizedBox(height: 24), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + height: 52, + width: 52, + padding: EdgeInsets.all(12), + decoration: BoxDecoration( + color: Color(0xFFF6F6F6), + borderRadius: BorderRadius.circular(20), + ), + child: SvgPicture.asset( + 'assets/icons/vk.svg', + ), + ), + const SizedBox(width: 8), + SizedBox( + width: MediaQuery.of(context).size.width - 92, + child: CustomTextFormField( + hintText: 'ВКонтакте', + ), + ), + ], + ), + const SizedBox(height: 12), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + height: 52, + width: 52, + padding: EdgeInsets.all(12), + decoration: BoxDecoration( + color: Color(0xFFF6F6F6), + borderRadius: BorderRadius.circular(20), + ), + child: SvgPicture.asset( + 'assets/icons/telegram.svg', + ), + ), + const SizedBox(width: 8), + SizedBox( + width: MediaQuery.of(context).size.width - 92, + child: CustomTextFormField( + hintText: 'Telegram', + ), + ), + ], + ), + const SizedBox(height: 12), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + height: 52, + width: 52, + padding: EdgeInsets.all(12), + decoration: BoxDecoration( + color: Color(0xFFF6F6F6), + borderRadius: BorderRadius.circular(20), + ), + child: SvgPicture.asset( + 'assets/icons/web.svg', + ), + ), + const SizedBox(width: 8), + SizedBox( + width: MediaQuery.of(context).size.width - 92, + child: CustomTextFormField( + hintText: 'Личный сайт', + ), + ), + ], + ), + ], + ), + ); + } +} diff --git a/lib/features/consultant/become_consultant/presentation/pages/stepper_become_consultant_screen.dart b/lib/features/consultant/become_consultant/presentation/pages/stepper_become_consultant_screen.dart new file mode 100644 index 00000000..bd2f3d0b --- /dev/null +++ b/lib/features/consultant/become_consultant/presentation/pages/stepper_become_consultant_screen.dart @@ -0,0 +1,218 @@ +import 'package:eatvio_app/core/utils/image_constant.dart'; +import 'package:eatvio_app/features/consultant/become_consultant/presentation/pages/additional_settings_screen.dart'; +import 'package:eatvio_app/features/consultant/become_consultant/presentation/pages/certificates_and_diplomas_screen.dart'; +import 'package:eatvio_app/features/consultant/become_consultant/presentation/pages/last_step_screen.dart'; +import 'package:eatvio_app/features/consultant/become_consultant/presentation/pages/photo_or_scans_screen.dart'; +import 'package:eatvio_app/features/consultant/become_consultant/presentation/pages/registration_as_screen.dart'; +import 'package:eatvio_app/features/consultant/become_consultant/presentation/pages/social_networks_screen.dart'; +import 'package:eatvio_app/theme/theme_helper.dart'; +import 'package:eatvio_app/widgets/app_bar/appbar_title_image.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; + +class StepperBecomeConsultantScreen extends StatefulWidget { + const StepperBecomeConsultantScreen({super.key}); + + @override + State createState() => _StepperBecomeConsultantScreenState(); +} + +class _StepperBecomeConsultantScreenState extends State { + double progressValue = 1 / 6; + int step = 1; + final pageController = PageController(); + + @override + Widget build(BuildContext context) { + return Scaffold( + floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, + floatingActionButton: Row( + children: [ + Container( + height: 48, + width: MediaQuery.of(context).size.width * 0.2, + padding: EdgeInsets.only(left: 16, right: 4), + child: FloatingActionButton.extended( + heroTag: 'backButtonRegistration', + highlightElevation: 0, + focusElevation: 0, + elevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20), + ), + backgroundColor: Color(0xFFEAF2FD), + onPressed: () async { + setState(() { + pageController.previousPage( + duration: const Duration(milliseconds: 350), + curve: Curves.easeInOut, + ); + }); + }, + label: Icon( + Icons.arrow_back_ios_new_rounded, + color: appTheme.blueA400, + ), + ), + ), + Container( + height: 48, + width: MediaQuery.of(context).size.width * 0.8, + padding: EdgeInsets.only(left: 4, right: 16), + child: FloatingActionButton.extended( + heroTag: 'nextButtonRegistration', + highlightElevation: 0, + elevation: 0, + focusElevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20), + ), + backgroundColor: appTheme.blueA400, + onPressed: () async { + if (step == 6) { + await showModalBottomSheet( + useRootNavigator: true, + showDragHandle: true, + context: context, + builder: (context) => Container( + padding: EdgeInsets.all(16), + width: MediaQuery.of(context).size.width, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + 'Спасибо!\nВаши данные отправлены на модерацию', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 20, + height: 1, + fontWeight: FontWeight.w600, + ), + ), + const SizedBox(height: 16), + Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: appTheme.blueA400, + shape: BoxShape.circle, + ), + child: Icon( + size: 32, + Icons.done, + color: Colors.white, + ), + ), + const SizedBox(height: 16), + Text( + 'В течении трех рабочих дней Вам придет уведомление о смене статуса', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 16, + height: 1, + fontWeight: FontWeight.w500, + ), + ), + const SizedBox(height: 16), + InkWell( + onTap: () { + Navigator.of(context).pop(); + }, + child: Ink( + width: MediaQuery.of(context).size.width - 32, + height: 52, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: appTheme.blueA400, + ), + child: Center( + child: Text( + 'Закрыть', + style: TextStyle( + color: Colors.white, + fontSize: 18, + fontWeight: FontWeight.w600, + ), + ), + ), + ), + ), + ], + ), + ), + ); + } else { + setState(() { + pageController.nextPage( + duration: const Duration(milliseconds: 350), + curve: Curves.easeInOut, + ); + }); + } + }, + label: Text( + 'Продолжить', + style: theme.textTheme.titleSmall!.copyWith(color: Colors.white), + ), + ), + ), + ], + ), + appBar: AppBar( + automaticallyImplyLeading: false, + leading: Builder( + builder: (context) => IconButton( + icon: Icon(Icons.close_rounded), + onPressed: () => GoRouter.of(context).pop(), + ), + ), + centerTitle: true, + title: AppbarTitleImage(imagePath: ImageConstant.imgLogoEatvio), + actions: [ + Padding( + padding: const EdgeInsets.only(right: 16), + child: Text('шаг $step из 6'), + ), + ], + bottom: PreferredSize( + preferredSize: Size(MediaQuery.of(context).size.width, 32), + child: Padding( + padding: const EdgeInsets.all(16), + child: TweenAnimationBuilder( + duration: const Duration(milliseconds: 350), + curve: Curves.easeInOut, + tween: Tween( + begin: 1 / 6, + end: progressValue, + ), + builder: (context, value, _) => LinearProgressIndicator( + value: value, + borderRadius: BorderRadius.circular(16), + minHeight: 8, + backgroundColor: Colors.grey.shade100, + valueColor: AlwaysStoppedAnimation(appTheme.blueA400), + ), + ), + ), + ), + ), + body: PageView( + physics: NeverScrollableScrollPhysics(), + controller: pageController, + onPageChanged: (index) { + setState(() { + step = index + 1; + progressValue = step / 6; + }); + }, + children: [ + CertificatesAndDiplomasScreen(), + PhotoOrScansScreen(), + AdditionalSettingsScreen(), + SocialNetworksScreen(), + RegistrationAsScreen(), + LastStepScreen(), + ], + ), + ); + } +} diff --git a/lib/features/consultant/become_consultant/repositories/consultant_repository.dart b/lib/features/consultant/become_consultant/repositories/consultant_repository.dart new file mode 100644 index 00000000..35594b96 --- /dev/null +++ b/lib/features/consultant/become_consultant/repositories/consultant_repository.dart @@ -0,0 +1,51 @@ +import 'dart:io'; +import 'package:eatvio_app/features/consultant/become_consultant/models/consultant_profile_model.dart'; +import 'package:eatvio_app/features/consultant/become_consultant/services/consultant_service.dart'; +import 'package:http_parser/http_parser.dart'; +import 'package:dio/dio.dart'; + +class ConsultantRepository { + final ConsultantService consultantService; + + const ConsultantRepository({ + required this.consultantService, + }); + + Future registerConsultant({ + required ConsultantProfileModel consultant, + }) async { + try { + return await consultantService.consultantRegistration( + consultantModel: consultant.toJson(), + ); + } catch (e) { + print(e); + rethrow; + } + } + + Future> uploadPhotos({ + required List files, + }) async { + try { + final multipartFiles = []; + + for (final file in files) { + final fileBytes = await file.readAsBytes(); + final multipartFile = MultipartFile.fromBytes( + fileBytes, + filename: file.path.split('/').last, + contentType: MediaType('application', 'octet-stream'), + ); + multipartFiles.add(multipartFile); + } + + return await consultantService.uploadPhotos( + photos: multipartFiles.isEmpty ? null : multipartFiles, + ); + } catch (e) { + print(e); + rethrow; + } + } +} diff --git a/lib/features/consultant/become_consultant/services/consultant_service.dart b/lib/features/consultant/become_consultant/services/consultant_service.dart new file mode 100644 index 00000000..ecfe5e14 --- /dev/null +++ b/lib/features/consultant/become_consultant/services/consultant_service.dart @@ -0,0 +1,20 @@ +import 'package:dio/dio.dart'; +import 'package:retrofit/retrofit.dart'; + +part 'consultant_service.g.dart'; + +@RestApi() +abstract class ConsultantService { + factory ConsultantService(Dio dio, {String baseUrl}) = _ConsultantService; + + @POST('/api/consultant_request/registration') + Future consultantRegistration({ + @Body() required Map consultantModel, + }); + + @POST('/api/consultant_request/photos/upload') + @MultiPart() + Future> uploadPhotos({ + @Part(name: 'photos[]', contentType: 'multipart/form-data') List? photos, + }); +} diff --git a/lib/features/consultant/become_consultant/services/consultant_service.g.dart b/lib/features/consultant/become_consultant/services/consultant_service.g.dart new file mode 100644 index 00000000..41bc384c --- /dev/null +++ b/lib/features/consultant/become_consultant/services/consultant_service.g.dart @@ -0,0 +1,118 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'consultant_service.dart'; + +// ************************************************************************** +// RetrofitGenerator +// ************************************************************************** + +// ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element + +class _ConsultantService implements ConsultantService { + _ConsultantService( + this._dio, { + this.baseUrl, + this.errorLogger, + }); + + final Dio _dio; + + String? baseUrl; + + final ParseErrorLogger? errorLogger; + + @override + Future consultantRegistration( + {required Map consultantModel}) async { + final _extra = {}; + final queryParameters = {}; + final _headers = {}; + final _data = {}; + _data.addAll(consultantModel); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/consultant_request/registration', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); + await _dio.fetch(_options); + } + + @override + Future> uploadPhotos({List? photos}) async { + final _extra = {}; + final queryParameters = {}; + queryParameters.removeWhere((k, v) => v == null); + final _headers = {}; + final _data = FormData(); + if (photos != null) { + _data.files.addAll(photos.map((i) => MapEntry('photos[]', i))); + } + final _options = _setStreamType>(Options( + method: 'POST', + headers: _headers, + extra: _extra, + contentType: 'multipart/form-data', + ) + .compose( + _dio.options, + '/api/consultant_request/photos/upload', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); + final _result = await _dio.fetch>(_options); + late List _value; + try { + _value = _result.data!.cast(); + } on Object catch (e, s) { + errorLogger?.logError(e, s, _options); + rethrow; + } + return _value; + } + + RequestOptions _setStreamType(RequestOptions requestOptions) { + if (T != dynamic && + !(requestOptions.responseType == ResponseType.bytes || + requestOptions.responseType == ResponseType.stream)) { + if (T == String) { + requestOptions.responseType = ResponseType.plain; + } else { + requestOptions.responseType = ResponseType.json; + } + } + return requestOptions; + } + + String _combineBaseUrls( + String dioBaseUrl, + String? baseUrl, + ) { + if (baseUrl == null || baseUrl.trim().isEmpty) { + return dioBaseUrl; + } + + final url = Uri.parse(baseUrl); + + if (url.isAbsolute) { + return url.toString(); + } + + return Uri.parse(dioBaseUrl).resolveUri(url).toString(); + } +} diff --git a/lib/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart b/lib/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart index 858bbe9e..fa44eafb 100644 --- a/lib/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart +++ b/lib/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart @@ -4,15 +4,60 @@ import 'package:flutter_bloc/flutter_bloc.dart'; class DietsCubit extends Cubit { final FeedRepository feedRepository; + int currentPage = 1; + late int lastPage; + bool isLoading = false; + String? _query; DietsCubit({required this.feedRepository}) : super(const DietsState.loading()); - loadDiets() async { + loadDiets({ + String? query, + }) async { try { - final diets = await feedRepository.getDiets(); - emit(DietsState.loaded(diets: diets)); + _query = query; + final dietsPagination = await feedRepository.getDiets( + query: query, + ); + lastPage = dietsPagination.meta.lastPage; + emit(DietsState.loaded( + dietsList: dietsPagination.data, + isLoading: isLoading, + )); } catch (e) { - emit(DietsState.error(errorMessage: e.toString())); + emit(DietsState.error( + errorMessage: e.toString(), + )); + } + } + + loadNextPage() async { + if (currentPage < lastPage && !isLoading) { + isLoading = true; + + emit((state as DietsStateLoaded).copyWith(isLoading: isLoading)); + + try { + if (currentPage < lastPage) { + currentPage++; + final dietPagination = await feedRepository.getDiets( + page: currentPage, + query: _query, + ); + isLoading = false; + emit( + DietsState.loaded( + dietsList: [ + ...(state as DietsStateLoaded).dietsList, + ...dietPagination.data, + ], + isLoading: isLoading, + ), + ); + } + } catch (e) { + emit(DietsState.error(errorMessage: e.toString())); + } } } } diff --git a/lib/features/feed/presentation/bloc/diets_cubit/diets_state.dart b/lib/features/feed/presentation/bloc/diets_cubit/diets_state.dart index 3cd342e8..bc5bbba1 100644 --- a/lib/features/feed/presentation/bloc/diets_cubit/diets_state.dart +++ b/lib/features/feed/presentation/bloc/diets_cubit/diets_state.dart @@ -10,7 +10,8 @@ abstract class DietsState with _$DietsState { const factory DietsState.loading() = DietsStateLoading; const factory DietsState.loaded({ - required DietsPagination diets, + required List dietsList, + required bool isLoading, }) = DietsStateLoaded; const factory DietsState.error({ diff --git a/lib/features/feed/presentation/bloc/diets_cubit/diets_state.freezed.dart b/lib/features/feed/presentation/bloc/diets_cubit/diets_state.freezed.dart index dd30f73d..8edde15b 100644 --- a/lib/features/feed/presentation/bloc/diets_cubit/diets_state.freezed.dart +++ b/lib/features/feed/presentation/bloc/diets_cubit/diets_state.freezed.dart @@ -20,7 +20,7 @@ mixin _$DietsState { TResult when( TResult Function() $default, { required TResult Function() loading, - required TResult Function(DietsPagination diets) loaded, + required TResult Function(List dietsList, bool isLoading) loaded, required TResult Function(String errorMessage) error, }) => throw _privateConstructorUsedError; @@ -28,7 +28,7 @@ mixin _$DietsState { TResult? whenOrNull( TResult? Function()? $default, { TResult? Function()? loading, - TResult? Function(DietsPagination diets)? loaded, + TResult? Function(List dietsList, bool isLoading)? loaded, TResult? Function(String errorMessage)? error, }) => throw _privateConstructorUsedError; @@ -36,7 +36,7 @@ mixin _$DietsState { TResult maybeWhen( TResult Function()? $default, { TResult Function()? loading, - TResult Function(DietsPagination diets)? loaded, + TResult Function(List dietsList, bool isLoading)? loaded, TResult Function(String errorMessage)? error, required TResult orElse(), }) => @@ -132,7 +132,7 @@ class _$DietsStateImpl implements _DietsState { TResult when( TResult Function() $default, { required TResult Function() loading, - required TResult Function(DietsPagination diets) loaded, + required TResult Function(List dietsList, bool isLoading) loaded, required TResult Function(String errorMessage) error, }) { return $default(); @@ -143,7 +143,7 @@ class _$DietsStateImpl implements _DietsState { TResult? whenOrNull( TResult? Function()? $default, { TResult? Function()? loading, - TResult? Function(DietsPagination diets)? loaded, + TResult? Function(List dietsList, bool isLoading)? loaded, TResult? Function(String errorMessage)? error, }) { return $default?.call(); @@ -154,7 +154,7 @@ class _$DietsStateImpl implements _DietsState { TResult maybeWhen( TResult Function()? $default, { TResult Function()? loading, - TResult Function(DietsPagination diets)? loaded, + TResult Function(List dietsList, bool isLoading)? loaded, TResult Function(String errorMessage)? error, required TResult orElse(), }) { @@ -249,7 +249,7 @@ class _$DietsStateLoadingImpl implements DietsStateLoading { TResult when( TResult Function() $default, { required TResult Function() loading, - required TResult Function(DietsPagination diets) loaded, + required TResult Function(List dietsList, bool isLoading) loaded, required TResult Function(String errorMessage) error, }) { return loading(); @@ -260,7 +260,7 @@ class _$DietsStateLoadingImpl implements DietsStateLoading { TResult? whenOrNull( TResult? Function()? $default, { TResult? Function()? loading, - TResult? Function(DietsPagination diets)? loaded, + TResult? Function(List dietsList, bool isLoading)? loaded, TResult? Function(String errorMessage)? error, }) { return loading?.call(); @@ -271,7 +271,7 @@ class _$DietsStateLoadingImpl implements DietsStateLoading { TResult maybeWhen( TResult Function()? $default, { TResult Function()? loading, - TResult Function(DietsPagination diets)? loaded, + TResult Function(List dietsList, bool isLoading)? loaded, TResult Function(String errorMessage)? error, required TResult orElse(), }) { @@ -329,9 +329,7 @@ abstract class _$$DietsStateLoadedImplCopyWith<$Res> { $Res Function(_$DietsStateLoadedImpl) then) = __$$DietsStateLoadedImplCopyWithImpl<$Res>; @useResult - $Res call({DietsPagination diets}); - - $DietsPaginationCopyWith<$Res> get diets; + $Res call({List dietsList, bool isLoading}); } /// @nodoc @@ -347,38 +345,43 @@ class __$$DietsStateLoadedImplCopyWithImpl<$Res> @pragma('vm:prefer-inline') @override $Res call({ - Object? diets = null, + Object? dietsList = null, + Object? isLoading = null, }) { return _then(_$DietsStateLoadedImpl( - diets: null == diets - ? _value.diets - : diets // ignore: cast_nullable_to_non_nullable - as DietsPagination, + dietsList: null == dietsList + ? _value._dietsList + : dietsList // ignore: cast_nullable_to_non_nullable + as List, + isLoading: null == isLoading + ? _value.isLoading + : isLoading // ignore: cast_nullable_to_non_nullable + as bool, )); } - - /// Create a copy of DietsState - /// with the given fields replaced by the non-null parameter values. - @override - @pragma('vm:prefer-inline') - $DietsPaginationCopyWith<$Res> get diets { - return $DietsPaginationCopyWith<$Res>(_value.diets, (value) { - return _then(_value.copyWith(diets: value)); - }); - } } /// @nodoc class _$DietsStateLoadedImpl implements DietsStateLoaded { - const _$DietsStateLoadedImpl({required this.diets}); + const _$DietsStateLoadedImpl( + {required final List dietsList, required this.isLoading}) + : _dietsList = dietsList; + + final List _dietsList; + @override + List get dietsList { + if (_dietsList is EqualUnmodifiableListView) return _dietsList; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_dietsList); + } @override - final DietsPagination diets; + final bool isLoading; @override String toString() { - return 'DietsState.loaded(diets: $diets)'; + return 'DietsState.loaded(dietsList: $dietsList, isLoading: $isLoading)'; } @override @@ -386,11 +389,15 @@ class _$DietsStateLoadedImpl implements DietsStateLoaded { return identical(this, other) || (other.runtimeType == runtimeType && other is _$DietsStateLoadedImpl && - (identical(other.diets, diets) || other.diets == diets)); + const DeepCollectionEquality() + .equals(other._dietsList, _dietsList) && + (identical(other.isLoading, isLoading) || + other.isLoading == isLoading)); } @override - int get hashCode => Object.hash(runtimeType, diets); + int get hashCode => Object.hash( + runtimeType, const DeepCollectionEquality().hash(_dietsList), isLoading); /// Create a copy of DietsState /// with the given fields replaced by the non-null parameter values. @@ -406,10 +413,10 @@ class _$DietsStateLoadedImpl implements DietsStateLoaded { TResult when( TResult Function() $default, { required TResult Function() loading, - required TResult Function(DietsPagination diets) loaded, + required TResult Function(List dietsList, bool isLoading) loaded, required TResult Function(String errorMessage) error, }) { - return loaded(diets); + return loaded(dietsList, isLoading); } @override @@ -417,10 +424,10 @@ class _$DietsStateLoadedImpl implements DietsStateLoaded { TResult? whenOrNull( TResult? Function()? $default, { TResult? Function()? loading, - TResult? Function(DietsPagination diets)? loaded, + TResult? Function(List dietsList, bool isLoading)? loaded, TResult? Function(String errorMessage)? error, }) { - return loaded?.call(diets); + return loaded?.call(dietsList, isLoading); } @override @@ -428,12 +435,12 @@ class _$DietsStateLoadedImpl implements DietsStateLoaded { TResult maybeWhen( TResult Function()? $default, { TResult Function()? loading, - TResult Function(DietsPagination diets)? loaded, + TResult Function(List dietsList, bool isLoading)? loaded, TResult Function(String errorMessage)? error, required TResult orElse(), }) { if (loaded != null) { - return loaded(diets); + return loaded(dietsList, isLoading); } return orElse(); } @@ -477,10 +484,12 @@ class _$DietsStateLoadedImpl implements DietsStateLoaded { } abstract class DietsStateLoaded implements DietsState { - const factory DietsStateLoaded({required final DietsPagination diets}) = - _$DietsStateLoadedImpl; + const factory DietsStateLoaded( + {required final List dietsList, + required final bool isLoading}) = _$DietsStateLoadedImpl; - DietsPagination get diets; + List get dietsList; + bool get isLoading; /// Create a copy of DietsState /// with the given fields replaced by the non-null parameter values. @@ -561,7 +570,7 @@ class _$DietsStateErrorImpl implements DietsStateError { TResult when( TResult Function() $default, { required TResult Function() loading, - required TResult Function(DietsPagination diets) loaded, + required TResult Function(List dietsList, bool isLoading) loaded, required TResult Function(String errorMessage) error, }) { return error(errorMessage); @@ -572,7 +581,7 @@ class _$DietsStateErrorImpl implements DietsStateError { TResult? whenOrNull( TResult? Function()? $default, { TResult? Function()? loading, - TResult? Function(DietsPagination diets)? loaded, + TResult? Function(List dietsList, bool isLoading)? loaded, TResult? Function(String errorMessage)? error, }) { return error?.call(errorMessage); @@ -583,7 +592,7 @@ class _$DietsStateErrorImpl implements DietsStateError { TResult maybeWhen( TResult Function()? $default, { TResult Function()? loading, - TResult Function(DietsPagination diets)? loaded, + TResult Function(List dietsList, bool isLoading)? loaded, TResult Function(String errorMessage)? error, required TResult orElse(), }) { diff --git a/lib/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart b/lib/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart index 83df5eb0..f387a4eb 100644 --- a/lib/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart +++ b/lib/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart @@ -37,7 +37,9 @@ class FeedCubit extends Cubit { try { if (currentPage < lastPage) { + print('before: $currentPage'); currentPage++; + print('after: $currentPage'); final feedBlogPosts = await feedRepository.getFeedBlogPosts( page: currentPage, query: _query, diff --git a/lib/features/feed/presentation/bloc/recipes_cubit/recipes_cubit.dart b/lib/features/feed/presentation/bloc/recipes_cubit/recipes_cubit.dart index 621880fe..93bcf399 100644 --- a/lib/features/feed/presentation/bloc/recipes_cubit/recipes_cubit.dart +++ b/lib/features/feed/presentation/bloc/recipes_cubit/recipes_cubit.dart @@ -13,6 +13,11 @@ class RecipesCubit extends Cubit { bool isLoading = false; String? _query; + RecipesCubit({ + required this.feedRepository, + required this.recipeRepository, + }) : super(const RecipesState.loading()); + loadRecipesList({ String? query, }) async { @@ -35,11 +40,6 @@ class RecipesCubit extends Cubit { } } - RecipesCubit({ - required this.feedRepository, - required this.recipeRepository, - }) : super(const RecipesState.loading()); - loadNextPage() async { if (currentPage < lastPage && !isLoading) { isLoading = true; diff --git a/lib/features/feed/presentation/pages/feed_screen.dart b/lib/features/feed/presentation/pages/feed_screen.dart index ab1c9768..0abbb6c2 100644 --- a/lib/features/feed/presentation/pages/feed_screen.dart +++ b/lib/features/feed/presentation/pages/feed_screen.dart @@ -57,11 +57,23 @@ class _FeedScreenState extends State { } } - _onScrollRecipes() {} + _onScrollRecipes() { + if (recipesScrollController.offset >= recipesScrollController.position.maxScrollExtent && !recipesScrollController.position.outOfRange) { + recipesCubit.loadNextPage(); + } + } - _onScrollDiets() {} + _onScrollDiets() { + if (dietsScrollController.offset >= dietsScrollController.position.maxScrollExtent && !dietsScrollController.position.outOfRange) { + dietsCubit.loadNextPage(); + } + } - _onScrollPlans() {} + _onScrollPlans() { + if (plansScrollController.offset >= plansScrollController.position.maxScrollExtent && !plansScrollController.position.outOfRange) { + // plansCubit.loadNextPage(); + } + } @override void dispose() { @@ -133,16 +145,17 @@ class _FeedScreenState extends State { }, body: Builder( builder: (BuildContext context) { - if (_selectedChipIndex == 0) + if (_selectedChipIndex == 0) { return _buildAllBlogPosts(); - else if (_selectedChipIndex == 1) + } else if (_selectedChipIndex == 1) { return _buildAllRecipes(); - else if (_selectedChipIndex == 2) + } else if (_selectedChipIndex == 2) { return _buildDiets(); - else if (_selectedChipIndex == 3) + } else if (_selectedChipIndex == 3) { return _buildPlans(); - else + } else { return Center(child: Text(chipsLabelList[_selectedChipIndex])); + } }, ), ), @@ -274,12 +287,12 @@ class _FeedScreenState extends State { shrinkWrap: true, physics: BouncingScrollPhysics(), itemBuilder: (context, index) { - return DietsWidget(diet: state.diets.data[index]); + return DietsWidget(diet: state.dietsList[index]); }, separatorBuilder: (context, index) { return SizedBox(height: 8); }, - itemCount: state.diets.data.length, + itemCount: state.dietsList.length, ); } else if (state is DietsStateError) { return Scaffold( @@ -428,6 +441,9 @@ class _FeedScreenState extends State { case 1: recipesCubit.loadRecipesList(query: query); break; + case 2: + dietsCubit.loadDiets(query: query); + break; } }, ); @@ -443,6 +459,9 @@ class _FeedScreenState extends State { case 1: recipesCubit.loadRecipesList(); break; + case 2: + dietsCubit.loadDiets(query: query); + break; } }, ); diff --git a/lib/features/feed/services/feed_service.dart b/lib/features/feed/services/feed_service.dart index 9d0cd1bd..1321fa6b 100644 --- a/lib/features/feed/services/feed_service.dart +++ b/lib/features/feed/services/feed_service.dart @@ -13,20 +13,20 @@ abstract class FeedService { @GET('/api/blogPosts/index') Future getBlogPostList({ - @Path() required int page, + @Query('page') required int page, @Query('query_search') String? query, }); @GET('/api/recipes/index') Future getRecipes({ - @Path() required int page, + @Query('page') required int page, @Query('filters[tags][tags.id][\$in][]') required List? tags, @Query('filters[title][\$contains]') required String? query, }); @GET('/api/diets/index') Future getDiets({ - @Path() required int page, + @Query('page') required int page, @Query('query_search') String? query, }); diff --git a/lib/features/feed/services/feed_service.g.dart b/lib/features/feed/services/feed_service.g.dart index d074b0a2..31b022c4 100644 --- a/lib/features/feed/services/feed_service.g.dart +++ b/lib/features/feed/services/feed_service.g.dart @@ -27,7 +27,10 @@ class _FeedService implements FeedService { String? query, }) async { final _extra = {}; - final queryParameters = {r'query_search': query}; + final queryParameters = { + r'page': page, + r'query_search': query, + }; queryParameters.removeWhere((k, v) => v == null); final _headers = {}; const Map? _data = null; @@ -66,6 +69,7 @@ class _FeedService implements FeedService { }) async { final _extra = {}; final queryParameters = { + r'page': page, r'filters[tags][tags.id][$in][]': tags, r'filters[title][$contains]': query, }; @@ -105,7 +109,10 @@ class _FeedService implements FeedService { String? query, }) async { final _extra = {}; - final queryParameters = {r'query_search': query}; + final queryParameters = { + r'page': page, + r'query_search': query, + }; queryParameters.removeWhere((k, v) => v == null); final _headers = {}; const Map? _data = null; diff --git a/lib/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart b/lib/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart index 89406741..52c1c039 100644 --- a/lib/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart +++ b/lib/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart @@ -10,8 +10,9 @@ import 'package:go_router/go_router.dart'; class RegistrationCubit extends Cubit { final RegistrationRepository registrationRepository; - RegistrationCubit({required this.registrationRepository}) - : super( + RegistrationCubit({ + required this.registrationRepository, + }) : super( RegistrationState( sheet: UserRegistrationSheet( firstName: '', diff --git a/lib/features/registration/presentation/pages/registration_screen.dart b/lib/features/registration/presentation/pages/registration_screen.dart index 7694582c..b47212ba 100644 --- a/lib/features/registration/presentation/pages/registration_screen.dart +++ b/lib/features/registration/presentation/pages/registration_screen.dart @@ -131,7 +131,7 @@ class _RegistrationScreenState extends State { duration: const Duration(milliseconds: 350), curve: Curves.easeInOut, tween: Tween( - begin: 0, + begin: 1 / 15, end: progressValue, ), builder: (context, value, _) => LinearProgressIndicator( diff --git a/lib/features/settings/presentation/pages/change_email_screen.dart b/lib/features/settings/presentation/pages/change_email_screen.dart new file mode 100644 index 00000000..b2637bb9 --- /dev/null +++ b/lib/features/settings/presentation/pages/change_email_screen.dart @@ -0,0 +1,28 @@ +import 'package:eatvio_app/features/settings/entities/settings_entity.dart'; +import 'package:flutter/material.dart'; + +class ChangeEmailScreen extends StatefulWidget { + final SettingsEntity settingsEntity; + + const ChangeEmailScreen({ + super.key, + required this.settingsEntity, + }); + + @override + State createState() => _ChangeEmailScreenState(); +} + +class _ChangeEmailScreenState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('Смена Email-a'), + ), + body: Center( + child: Text('Coming soon...'), + ), + ); + } +} diff --git a/lib/features/settings/presentation/pages/other_info_screen.dart b/lib/features/settings/presentation/pages/other_info_screen.dart index 2799b853..f9dfc9e1 100644 --- a/lib/features/settings/presentation/pages/other_info_screen.dart +++ b/lib/features/settings/presentation/pages/other_info_screen.dart @@ -128,13 +128,13 @@ class _OtherInfoScreenState extends State { onTap: () { widget.settingsEntity.settingsCubit.updateProfileDetails( profileDetailsModel: (widget.settingsEntity.settingsCubit.state as SettingsStateLoaded).profileDetails.copyWith( - aboutAlergy: aboutAllergyController.text, - aboutTakingPils: aboutTakingPillsController.text, - aboutSportHobbies: aboutSportHobbiesController.text, - favoriteFoods: favoriteFoodsController.text, - unfavoriteFoods: unFavouriteFoodsController.text, - additionalInfo: additionalInfoController.text, - ), + aboutAlergy: aboutAllergyController.text, + aboutTakingPils: aboutTakingPillsController.text, + aboutSportHobbies: aboutSportHobbiesController.text, + favoriteFoods: favoriteFoodsController.text, + unfavoriteFoods: unFavouriteFoodsController.text, + additionalInfo: additionalInfoController.text, + ), ); GoRouter.of(context).pop(); }, diff --git a/lib/features/settings/presentation/pages/settings_screen.dart b/lib/features/settings/presentation/pages/settings_screen.dart index 0a18843f..c0a8901b 100644 --- a/lib/features/settings/presentation/pages/settings_screen.dart +++ b/lib/features/settings/presentation/pages/settings_screen.dart @@ -175,6 +175,18 @@ class _SettingsScreenState extends State { ), title: 'Сменить пароль', ), + _divider(context), + _tile( + onTap: () => GoRouter.of(context).pushNamed( + 'changeEmailScreen', + extra: SettingsEntity( + profileSettingsModel: state.profileSettings, + profileDetailsModel: state.profileDetails, + settingsCubit: settingsCubit, + ), + ), + title: 'Сменить Email', + ), ], ); } @@ -345,7 +357,7 @@ class _SettingsScreenState extends State { return Padding( padding: EdgeInsets.symmetric(horizontal: 16), child: InkWell( - onTap: () {}, + onTap: () => GoRouter.of(context).pushNamed('becomeConsultantScreen'), borderRadius: BorderRadius.circular(20), child: Ink( height: 52, diff --git a/lib/generated/intl/messages_all.dart b/lib/generated/intl/messages_all.dart index 203415cc..abae25a5 100644 --- a/lib/generated/intl/messages_all.dart +++ b/lib/generated/intl/messages_all.dart @@ -17,16 +17,20 @@ import 'package:intl/message_lookup_by_library.dart'; import 'package:intl/src/intl_helpers.dart'; import 'messages_en.dart' as messages_en; +import 'messages_ru.dart' as messages_ru; typedef Future LibraryLoader(); Map _deferredLibraries = { 'en': () => new SynchronousFuture(null), + 'ru': () => new SynchronousFuture(null), }; MessageLookupByLibrary? _findExact(String localeName) { switch (localeName) { case 'en': return messages_en.messages; + case 'ru': + return messages_ru.messages; default: return null; } diff --git a/lib/generated/intl/messages_en.dart b/lib/generated/intl/messages_en.dart index 34f0eb48..3d320130 100644 --- a/lib/generated/intl/messages_en.dart +++ b/lib/generated/intl/messages_en.dart @@ -22,154 +22,157 @@ class MessageLookup extends MessageLookupByLibrary { final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { - "Moscow": MessageLookupByLibrary.simpleMessage("Москва"), - "Russia": MessageLookupByLibrary.simpleMessage("Россия"), - "active": MessageLookupByLibrary.simpleMessage("Активен"), - "add_measure": MessageLookupByLibrary.simpleMessage("Добавить замер"), + "Moscow": MessageLookupByLibrary.simpleMessage("Moscow"), + "Russia": MessageLookupByLibrary.simpleMessage("Russia"), + "active": MessageLookupByLibrary.simpleMessage("Active"), + "add_measure": MessageLookupByLibrary.simpleMessage("Add Measurement"), "additional_information": - MessageLookupByLibrary.simpleMessage("Дополнительная информация"), - "admin": MessageLookupByLibrary.simpleMessage("Админ"), + MessageLookupByLibrary.simpleMessage("Additional Information"), + "admin": MessageLookupByLibrary.simpleMessage("Admin"), "allergies_presence": - MessageLookupByLibrary.simpleMessage("Наличие аллергии"), - "archived": MessageLookupByLibrary.simpleMessage("В архиве"), - "authentificate": MessageLookupByLibrary.simpleMessage("Войти"), - "average_pressure": MessageLookupByLibrary.simpleMessage( - "Средние показатели давления:"), - "bodymass_chart": MessageLookupByLibrary.simpleMessage("График ИМТ"), - "chat": MessageLookupByLibrary.simpleMessage("Чат"), - "chest": MessageLookupByLibrary.simpleMessage("Грудь"), + MessageLookupByLibrary.simpleMessage("Presence of Allergies"), + "archived": MessageLookupByLibrary.simpleMessage("Archived"), + "authentificate": MessageLookupByLibrary.simpleMessage("Log In"), + "average_pressure": + MessageLookupByLibrary.simpleMessage("Average Pressure Readings:"), + "bodymass_chart": MessageLookupByLibrary.simpleMessage("BMI Chart"), + "chat": MessageLookupByLibrary.simpleMessage("Chat"), + "chest": MessageLookupByLibrary.simpleMessage("Chest"), "chest_circumference": - MessageLookupByLibrary.simpleMessage("Обхват груди"), + MessageLookupByLibrary.simpleMessage("Chest Circumference"), "circumference_empty": MessageLookupByLibrary.simpleMessage( - "Все замеры обязательны к заполнению"), + "All measurements are required"), "circumference_is_not_a_number": MessageLookupByLibrary.simpleMessage( - "Все замеры должны быть числами"), + "All measurements must be numbers"), "circumferences_chart": - MessageLookupByLibrary.simpleMessage("График обхватов"), - "city": MessageLookupByLibrary.simpleMessage("Город"), + MessageLookupByLibrary.simpleMessage("Circumference Chart"), + "city": MessageLookupByLibrary.simpleMessage("City"), "city_of_living": - MessageLookupByLibrary.simpleMessage("Город проживания"), - "continueButton": MessageLookupByLibrary.simpleMessage("Продолжить"), - "country": MessageLookupByLibrary.simpleMessage("Страна"), - "date_of_birth": MessageLookupByLibrary.simpleMessage("Дата рождения"), - "diary": MessageLookupByLibrary.simpleMessage("Дневник"), + MessageLookupByLibrary.simpleMessage("City of Residence"), + "continueButton": MessageLookupByLibrary.simpleMessage("Continue"), + "country": MessageLookupByLibrary.simpleMessage("Country"), + "date_of_birth": MessageLookupByLibrary.simpleMessage("Date of Birth"), + "diary": MessageLookupByLibrary.simpleMessage("Diary"), "do_you_have_hypertension_tendency": - MessageLookupByLibrary.simpleMessage("Есть ли у вас гипертония?"), + MessageLookupByLibrary.simpleMessage( + "Do you have a tendency for hypertension?"), "do_you_have_hypotension_tendency": - MessageLookupByLibrary.simpleMessage("Есть ли у вас гипотония?"), + MessageLookupByLibrary.simpleMessage( + "Do you have a tendency for hypotension?"), "do_you_take_pills": MessageLookupByLibrary.simpleMessage( - "Принимаете ли вы лекарства или бады?"), + "Do you take any medications or supplements?"), "down_pressure": - MessageLookupByLibrary.simpleMessage("Нижние показатели давления:"), - "draft": MessageLookupByLibrary.simpleMessage("Черновик"), - "email": MessageLookupByLibrary.simpleMessage("Элетронная почта"), - "email_empty": MessageLookupByLibrary.simpleMessage( - "Необходимо ввести адрес электронной почты"), - "email_invalid": MessageLookupByLibrary.simpleMessage( - "Некорректный адрес электронной почты"), + MessageLookupByLibrary.simpleMessage("Lower Pressure Readings:"), + "draft": MessageLookupByLibrary.simpleMessage("Draft"), + "email": MessageLookupByLibrary.simpleMessage("Email"), + "email_empty": + MessageLookupByLibrary.simpleMessage("Email address is required"), + "email_invalid": + MessageLookupByLibrary.simpleMessage("Invalid email address"), "enter_additional_information": MessageLookupByLibrary.simpleMessage( - "Введите любую дополнительную информацию на своё усмотрение:"), + "Enter any additional information at your discretion:"), "enter_information": - MessageLookupByLibrary.simpleMessage("Введите информацию..."), - "exit": MessageLookupByLibrary.simpleMessage("Выйти"), + MessageLookupByLibrary.simpleMessage("Enter information..."), + "exit": MessageLookupByLibrary.simpleMessage("Log Out"), "favorite_foods": - MessageLookupByLibrary.simpleMessage("Любимые продукты"), + MessageLookupByLibrary.simpleMessage("Favorite Foods"), "favorite_unfavorite_foods": MessageLookupByLibrary.simpleMessage( - "Ваши любимые/нелюбимые продукты питания?"), - "female": MessageLookupByLibrary.simpleMessage("Женский"), + "Your Favorite/Least Favorite Foods?"), + "female": MessageLookupByLibrary.simpleMessage("Female"), "fill_in_information": - MessageLookupByLibrary.simpleMessage("Заполните информацию:"), - "finish": MessageLookupByLibrary.simpleMessage("Завершить"), - "first_name": MessageLookupByLibrary.simpleMessage("Имя"), - "first_name_empty": MessageLookupByLibrary.simpleMessage( - "Имя обязательно для заполнения"), + MessageLookupByLibrary.simpleMessage("Fill in the information:"), + "finish": MessageLookupByLibrary.simpleMessage("Finish"), + "first_name": MessageLookupByLibrary.simpleMessage("First Name"), + "first_name_empty": + MessageLookupByLibrary.simpleMessage("First name is required"), "first_name_short": MessageLookupByLibrary.simpleMessage( - "В имени должен быть минимум 1 символ"), - "gr": MessageLookupByLibrary.simpleMessage("гр"), - "grams": MessageLookupByLibrary.simpleMessage("гр"), + "First name must be at least 1 character long"), + "gr": MessageLookupByLibrary.simpleMessage("g"), + "grams": MessageLookupByLibrary.simpleMessage("g"), "height_measurements": - MessageLookupByLibrary.simpleMessage("Замер роста"), + MessageLookupByLibrary.simpleMessage("Height Measurement"), "hip_circumference": - MessageLookupByLibrary.simpleMessage("Обхват бедер"), - "hips": MessageLookupByLibrary.simpleMessage("Бедра"), - "in_progress": MessageLookupByLibrary.simpleMessage("В процессе"), + MessageLookupByLibrary.simpleMessage("Hip Circumference"), + "hips": MessageLookupByLibrary.simpleMessage("Hips"), + "in_progress": MessageLookupByLibrary.simpleMessage("In Progress"), "initial_measurements": - MessageLookupByLibrary.simpleMessage("Первичные замеры"), - "language": MessageLookupByLibrary.simpleMessage("Язык"), - "last_name": MessageLookupByLibrary.simpleMessage("Фамилия"), - "last_name_empty": MessageLookupByLibrary.simpleMessage( - "Фамилия обязательна для заполнения"), + MessageLookupByLibrary.simpleMessage("Initial Measurements"), + "language": MessageLookupByLibrary.simpleMessage("Language"), + "last_name": MessageLookupByLibrary.simpleMessage("Last Name"), + "last_name_empty": + MessageLookupByLibrary.simpleMessage("Last name is required"), "last_name_short": MessageLookupByLibrary.simpleMessage( - "В фамилии должен быть минимум 6 символов"), + "Last name must be at least 6 characters long"), "lbl_english": MessageLookupByLibrary.simpleMessage("English"), - "loading": MessageLookupByLibrary.simpleMessage("Загрузка..."), - "male": MessageLookupByLibrary.simpleMessage("Мужской"), + "loading": MessageLookupByLibrary.simpleMessage("Loading..."), + "male": MessageLookupByLibrary.simpleMessage("Male"), "msg_network_err": - MessageLookupByLibrary.simpleMessage("Сетевая ошибка!"), + MessageLookupByLibrary.simpleMessage("Network error!"), "msg_something_went_wrong": - MessageLookupByLibrary.simpleMessage("Что то пошло не так!"), - "my_blog": MessageLookupByLibrary.simpleMessage("Мой блог"), - "my_settings": MessageLookupByLibrary.simpleMessage("Мои настройки"), - "name_empty": MessageLookupByLibrary.simpleMessage( - "Имя пользователя обязательно для заполнения"), + MessageLookupByLibrary.simpleMessage("Something went wrong!"), + "my_blog": MessageLookupByLibrary.simpleMessage("My Blog"), + "my_settings": MessageLookupByLibrary.simpleMessage("My Settings"), + "name_empty": + MessageLookupByLibrary.simpleMessage("Username is required"), "name_short": MessageLookupByLibrary.simpleMessage( - "В имени пользователя должно быть минимум 6 символов"), - "no": MessageLookupByLibrary.simpleMessage("Нет"), + "Username must be at least 6 characters long"), + "no": MessageLookupByLibrary.simpleMessage("No"), "no_account": - MessageLookupByLibrary.simpleMessage("У меня нет аккаунта"), - "password": MessageLookupByLibrary.simpleMessage("Пароль"), + MessageLookupByLibrary.simpleMessage("I do not have an account"), + "password": MessageLookupByLibrary.simpleMessage("Password"), "password_confirmation": - MessageLookupByLibrary.simpleMessage("Подтвердите пароль"), + MessageLookupByLibrary.simpleMessage("Confirm Password"), "password_confirmation_mismatch": - MessageLookupByLibrary.simpleMessage("Пароли не совпадают"), - "password_empty": MessageLookupByLibrary.simpleMessage( - "Пароль обязателен для заполнения"), + MessageLookupByLibrary.simpleMessage("Passwords do not match"), + "password_empty": + MessageLookupByLibrary.simpleMessage("Password is required"), "password_short": MessageLookupByLibrary.simpleMessage( - "В пароле должно быть минимум 6 символов"), - "pcs": MessageLookupByLibrary.simpleMessage("шт"), + "Password must be at least 6 characters long"), + "pcs": MessageLookupByLibrary.simpleMessage("pcs"), "place_of_living": - MessageLookupByLibrary.simpleMessage("Место проживания"), + MessageLookupByLibrary.simpleMessage("Place of Residence"), "plans_complete": - MessageLookupByLibrary.simpleMessage("Пройденные планы"), - "preferred_language": - MessageLookupByLibrary.simpleMessage("Предпочитаемый язык общения"), + MessageLookupByLibrary.simpleMessage("Completed Plans"), + "preferred_language": MessageLookupByLibrary.simpleMessage( + "Preferred Language of Communication"), "pressure_empty": MessageLookupByLibrary.simpleMessage( - "Все показатели давления обязательны к заполнению"), + "All blood pressure readings are required"), "pressure_is_not_a_number": MessageLookupByLibrary.simpleMessage( - "Все показатели давления должны быть числами"), - "profile": MessageLookupByLibrary.simpleMessage("Профиль"), - "save": MessageLookupByLibrary.simpleMessage("Сохранить"), - "settings": MessageLookupByLibrary.simpleMessage("Настройки"), - "skip": MessageLookupByLibrary.simpleMessage("Пропустить"), + "All blood pressure readings must be numbers"), + "profile": MessageLookupByLibrary.simpleMessage("Profile"), + "save": MessageLookupByLibrary.simpleMessage("Save"), + "settings": MessageLookupByLibrary.simpleMessage("Settings"), + "skip": MessageLookupByLibrary.simpleMessage("Skip"), "tell_your_schedule": MessageLookupByLibrary.simpleMessage( - "Расскажите в свободной форме о том как просыпаетесь, когда едите, когда ложитесь спать:"), + "Describe your daily routine freely, such as when you wake up, eat, and go to bed:"), "unfavorite_foods": - MessageLookupByLibrary.simpleMessage("Нелюбимые продукты"), - "up_pressure": MessageLookupByLibrary.simpleMessage( - "Верхние показатели давления:"), + MessageLookupByLibrary.simpleMessage("Least Favorite Foods"), + "up_pressure": + MessageLookupByLibrary.simpleMessage("Upper Pressure Readings:"), "user_authorization": - MessageLookupByLibrary.simpleMessage("Аутентификация"), + MessageLookupByLibrary.simpleMessage("Authentication"), "user_registration": - MessageLookupByLibrary.simpleMessage("Регистрация пользователя"), - "username": MessageLookupByLibrary.simpleMessage("Имя пользователя"), - "waist": MessageLookupByLibrary.simpleMessage("Талия"), + MessageLookupByLibrary.simpleMessage("User Registration"), + "username": MessageLookupByLibrary.simpleMessage("Username"), + "waist": MessageLookupByLibrary.simpleMessage("Waist"), "waist_circumference": - MessageLookupByLibrary.simpleMessage("Обхват талии"), - "weight": MessageLookupByLibrary.simpleMessage("Вес"), - "weight_chart": MessageLookupByLibrary.simpleMessage("График веса"), + MessageLookupByLibrary.simpleMessage("Waist Circumference"), + "weight": MessageLookupByLibrary.simpleMessage("Weight"), + "weight_chart": MessageLookupByLibrary.simpleMessage("Weight Chart"), "weight_measurements": - MessageLookupByLibrary.simpleMessage("Замер веса"), + MessageLookupByLibrary.simpleMessage("Weight Measurement"), "what_is_your_name": - MessageLookupByLibrary.simpleMessage("Как вас зовут?"), - "wrong_credentials": MessageLookupByLibrary.simpleMessage( - "Неверные данные пользователя"), + MessageLookupByLibrary.simpleMessage("What is your name?"), + "wrong_credentials": + MessageLookupByLibrary.simpleMessage("Invalid user credentials"), "your_blood_pressure": - MessageLookupByLibrary.simpleMessage("Ваше артериальное давление?"), + MessageLookupByLibrary.simpleMessage("Your Blood Pressure?"), "your_favorite_sports": - MessageLookupByLibrary.simpleMessage("Ваши спортивные увлечения?"), - "your_gender": MessageLookupByLibrary.simpleMessage("Ваш пол?"), - "your_height": MessageLookupByLibrary.simpleMessage("Ваш рост:"), - "your_schedule": MessageLookupByLibrary.simpleMessage("Ваш режим дня?"), - "your_weight": MessageLookupByLibrary.simpleMessage("Ваш вес:") + MessageLookupByLibrary.simpleMessage("Your Favorite Sports?"), + "your_gender": MessageLookupByLibrary.simpleMessage("Your Gender?"), + "your_height": MessageLookupByLibrary.simpleMessage("Your Height:"), + "your_schedule": + MessageLookupByLibrary.simpleMessage("Your Daily Routine?"), + "your_weight": MessageLookupByLibrary.simpleMessage("Your Weight:") }; } diff --git a/lib/generated/intl/messages_ru.dart b/lib/generated/intl/messages_ru.dart new file mode 100644 index 00000000..9c4da5f8 --- /dev/null +++ b/lib/generated/intl/messages_ru.dart @@ -0,0 +1,175 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that provides messages for a ru locale. All the +// messages from the main program should be duplicated here with the same +// function name. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering +// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases +// ignore_for_file:unused_import, file_names, avoid_escaping_inner_quotes +// ignore_for_file:unnecessary_string_interpolations, unnecessary_string_escapes + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; + +final messages = new MessageLookup(); + +typedef String MessageIfAbsent(String messageStr, List args); + +class MessageLookup extends MessageLookupByLibrary { + String get localeName => 'ru'; + + final messages = _notInlinedMessages(_notInlinedMessages); + static Map _notInlinedMessages(_) => { + "Moscow": MessageLookupByLibrary.simpleMessage("Москва"), + "Russia": MessageLookupByLibrary.simpleMessage("Россия"), + "active": MessageLookupByLibrary.simpleMessage("Активен"), + "add_measure": MessageLookupByLibrary.simpleMessage("Добавить замер"), + "additional_information": + MessageLookupByLibrary.simpleMessage("Дополнительная информация"), + "admin": MessageLookupByLibrary.simpleMessage("Админ"), + "allergies_presence": + MessageLookupByLibrary.simpleMessage("Наличие аллергии"), + "archived": MessageLookupByLibrary.simpleMessage("В архиве"), + "authentificate": MessageLookupByLibrary.simpleMessage("Войти"), + "average_pressure": MessageLookupByLibrary.simpleMessage( + "Средние показатели давления:"), + "bodymass_chart": MessageLookupByLibrary.simpleMessage("График ИМТ"), + "chat": MessageLookupByLibrary.simpleMessage("Чат"), + "chest": MessageLookupByLibrary.simpleMessage("Грудь"), + "chest_circumference": + MessageLookupByLibrary.simpleMessage("Обхват груди"), + "circumference_empty": MessageLookupByLibrary.simpleMessage( + "Все замеры обязательны к заполнению"), + "circumference_is_not_a_number": MessageLookupByLibrary.simpleMessage( + "Все замеры должны быть числами"), + "circumferences_chart": + MessageLookupByLibrary.simpleMessage("График обхватов"), + "city": MessageLookupByLibrary.simpleMessage("Город"), + "city_of_living": + MessageLookupByLibrary.simpleMessage("Город проживания"), + "continueButton": MessageLookupByLibrary.simpleMessage("Продолжить"), + "country": MessageLookupByLibrary.simpleMessage("Страна"), + "date_of_birth": MessageLookupByLibrary.simpleMessage("Дата рождения"), + "diary": MessageLookupByLibrary.simpleMessage("Дневник"), + "do_you_have_hypertension_tendency": + MessageLookupByLibrary.simpleMessage("Есть ли у вас гипертония?"), + "do_you_have_hypotension_tendency": + MessageLookupByLibrary.simpleMessage("Есть ли у вас гипотония?"), + "do_you_take_pills": MessageLookupByLibrary.simpleMessage( + "Принимаете ли вы лекарства или бады?"), + "down_pressure": + MessageLookupByLibrary.simpleMessage("Нижние показатели давления:"), + "draft": MessageLookupByLibrary.simpleMessage("Черновик"), + "email": MessageLookupByLibrary.simpleMessage("Элетронная почта"), + "email_empty": MessageLookupByLibrary.simpleMessage( + "Необходимо ввести адрес электронной почты"), + "email_invalid": MessageLookupByLibrary.simpleMessage( + "Некорректный адрес электронной почты"), + "enter_additional_information": MessageLookupByLibrary.simpleMessage( + "Введите любую дополнительную информацию на своё усмотрение:"), + "enter_information": + MessageLookupByLibrary.simpleMessage("Введите информацию..."), + "exit": MessageLookupByLibrary.simpleMessage("Выйти"), + "favorite_foods": + MessageLookupByLibrary.simpleMessage("Любимые продукты"), + "favorite_unfavorite_foods": MessageLookupByLibrary.simpleMessage( + "Ваши любимые/нелюбимые продукты питания?"), + "female": MessageLookupByLibrary.simpleMessage("Женский"), + "fill_in_information": + MessageLookupByLibrary.simpleMessage("Заполните информацию:"), + "finish": MessageLookupByLibrary.simpleMessage("Завершить"), + "first_name": MessageLookupByLibrary.simpleMessage("Имя"), + "first_name_empty": MessageLookupByLibrary.simpleMessage( + "Имя обязательно для заполнения"), + "first_name_short": MessageLookupByLibrary.simpleMessage( + "В имени должен быть минимум 1 символ"), + "gr": MessageLookupByLibrary.simpleMessage("гр"), + "grams": MessageLookupByLibrary.simpleMessage("гр"), + "height_measurements": + MessageLookupByLibrary.simpleMessage("Замер роста"), + "hip_circumference": + MessageLookupByLibrary.simpleMessage("Обхват бедер"), + "hips": MessageLookupByLibrary.simpleMessage("Бедра"), + "in_progress": MessageLookupByLibrary.simpleMessage("В процессе"), + "initial_measurements": + MessageLookupByLibrary.simpleMessage("Первичные замеры"), + "language": MessageLookupByLibrary.simpleMessage("Язык"), + "last_name": MessageLookupByLibrary.simpleMessage("Фамилия"), + "last_name_empty": MessageLookupByLibrary.simpleMessage( + "Фамилия обязательна для заполнения"), + "last_name_short": MessageLookupByLibrary.simpleMessage( + "В фамилии должен быть минимум 6 символов"), + "lbl_english": MessageLookupByLibrary.simpleMessage("English"), + "loading": MessageLookupByLibrary.simpleMessage("Загрузка..."), + "male": MessageLookupByLibrary.simpleMessage("Мужской"), + "msg_network_err": + MessageLookupByLibrary.simpleMessage("Сетевая ошибка!"), + "msg_something_went_wrong": + MessageLookupByLibrary.simpleMessage("Что то пошло не так!"), + "my_blog": MessageLookupByLibrary.simpleMessage("Мой блог"), + "my_settings": MessageLookupByLibrary.simpleMessage("Мои настройки"), + "name_empty": MessageLookupByLibrary.simpleMessage( + "Имя пользователя обязательно для заполнения"), + "name_short": MessageLookupByLibrary.simpleMessage( + "В имени пользователя должно быть минимум 6 символов"), + "no": MessageLookupByLibrary.simpleMessage("Нет"), + "no_account": + MessageLookupByLibrary.simpleMessage("У меня нет аккаунта"), + "password": MessageLookupByLibrary.simpleMessage("Пароль"), + "password_confirmation": + MessageLookupByLibrary.simpleMessage("Подтвердите пароль"), + "password_confirmation_mismatch": + MessageLookupByLibrary.simpleMessage("Пароли не совпадают"), + "password_empty": MessageLookupByLibrary.simpleMessage( + "Пароль обязателен для заполнения"), + "password_short": MessageLookupByLibrary.simpleMessage( + "В пароле должно быть минимум 6 символов"), + "pcs": MessageLookupByLibrary.simpleMessage("шт"), + "place_of_living": + MessageLookupByLibrary.simpleMessage("Место проживания"), + "plans_complete": + MessageLookupByLibrary.simpleMessage("Пройденные планы"), + "preferred_language": + MessageLookupByLibrary.simpleMessage("Предпочитаемый язык общения"), + "pressure_empty": MessageLookupByLibrary.simpleMessage( + "Все показатели давления обязательны к заполнению"), + "pressure_is_not_a_number": MessageLookupByLibrary.simpleMessage( + "Все показатели давления должны быть числами"), + "profile": MessageLookupByLibrary.simpleMessage("Профиль"), + "save": MessageLookupByLibrary.simpleMessage("Сохранить"), + "settings": MessageLookupByLibrary.simpleMessage("Настройки"), + "skip": MessageLookupByLibrary.simpleMessage("Пропустить"), + "tell_your_schedule": MessageLookupByLibrary.simpleMessage( + "Расскажите в свободной форме о том как просыпаетесь, когда едите, когда ложитесь спать:"), + "unfavorite_foods": + MessageLookupByLibrary.simpleMessage("Нелюбимые продукты"), + "up_pressure": MessageLookupByLibrary.simpleMessage( + "Верхние показатели давления:"), + "user_authorization": + MessageLookupByLibrary.simpleMessage("Аутентификация"), + "user_registration": + MessageLookupByLibrary.simpleMessage("Регистрация пользователя"), + "username": MessageLookupByLibrary.simpleMessage("Имя пользователя"), + "waist": MessageLookupByLibrary.simpleMessage("Талия"), + "waist_circumference": + MessageLookupByLibrary.simpleMessage("Обхват талии"), + "weight": MessageLookupByLibrary.simpleMessage("Вес"), + "weight_chart": MessageLookupByLibrary.simpleMessage("График веса"), + "weight_measurements": + MessageLookupByLibrary.simpleMessage("Замер веса"), + "what_is_your_name": + MessageLookupByLibrary.simpleMessage("Как вас зовут?"), + "wrong_credentials": MessageLookupByLibrary.simpleMessage( + "Неверные данные пользователя"), + "your_blood_pressure": + MessageLookupByLibrary.simpleMessage("Ваше артериальное давление?"), + "your_favorite_sports": + MessageLookupByLibrary.simpleMessage("Ваши спортивные увлечения?"), + "your_gender": MessageLookupByLibrary.simpleMessage("Ваш пол?"), + "your_height": MessageLookupByLibrary.simpleMessage("Ваш рост:"), + "your_schedule": MessageLookupByLibrary.simpleMessage("Ваш режим дня?"), + "your_weight": MessageLookupByLibrary.simpleMessage("Ваш вес:") + }; +} diff --git a/lib/generated/l10n.dart b/lib/generated/l10n.dart index b54c60ae..1d48044a 100644 --- a/lib/generated/l10n.dart +++ b/lib/generated/l10n.dart @@ -50,430 +50,430 @@ class S { return Localizations.of(context, S); } - /// `Регистрация пользователя` + /// `User Registration` String get user_registration { return Intl.message( - 'Регистрация пользователя', + 'User Registration', name: 'user_registration', desc: '', args: [], ); } - /// `Элетронная почта` + /// `Email` String get email { return Intl.message( - 'Элетронная почта', + 'Email', name: 'email', desc: '', args: [], ); } - /// `Имя пользователя` + /// `Username` String get username { return Intl.message( - 'Имя пользователя', + 'Username', name: 'username', desc: '', args: [], ); } - /// `Пароль` + /// `Password` String get password { return Intl.message( - 'Пароль', + 'Password', name: 'password', desc: '', args: [], ); } - /// `Подтвердите пароль` + /// `Confirm Password` String get password_confirmation { return Intl.message( - 'Подтвердите пароль', + 'Confirm Password', name: 'password_confirmation', desc: '', args: [], ); } - /// `Неверные данные пользователя` + /// `Invalid user credentials` String get wrong_credentials { return Intl.message( - 'Неверные данные пользователя', + 'Invalid user credentials', name: 'wrong_credentials', desc: '', args: [], ); } - /// `Имя` + /// `First Name` String get first_name { return Intl.message( - 'Имя', + 'First Name', name: 'first_name', desc: '', args: [], ); } - /// `Фамилия` + /// `Last Name` String get last_name { return Intl.message( - 'Фамилия', + 'Last Name', name: 'last_name', desc: '', args: [], ); } - /// `Как вас зовут?` + /// `What is your name?` String get what_is_your_name { return Intl.message( - 'Как вас зовут?', + 'What is your name?', name: 'what_is_your_name', desc: '', args: [], ); } - /// `Дата рождения` + /// `Date of Birth` String get date_of_birth { return Intl.message( - 'Дата рождения', + 'Date of Birth', name: 'date_of_birth', desc: '', args: [], ); } - /// `Страна` + /// `Country` String get country { return Intl.message( - 'Страна', + 'Country', name: 'country', desc: '', args: [], ); } - /// `Россия` + /// `Russia` String get Russia { return Intl.message( - 'Россия', + 'Russia', name: 'Russia', desc: '', args: [], ); } - /// `Город` + /// `City` String get city { return Intl.message( - 'Город', + 'City', name: 'city', desc: '', args: [], ); } - /// `Москва` + /// `Moscow` String get Moscow { return Intl.message( - 'Москва', + 'Moscow', name: 'Moscow', desc: '', args: [], ); } - /// `Место проживания` + /// `Place of Residence` String get place_of_living { return Intl.message( - 'Место проживания', + 'Place of Residence', name: 'place_of_living', desc: '', args: [], ); } - /// `Обхват бедер` + /// `Hip Circumference` String get hip_circumference { return Intl.message( - 'Обхват бедер', + 'Hip Circumference', name: 'hip_circumference', desc: '', args: [], ); } - /// `Обхват груди` + /// `Chest Circumference` String get chest_circumference { return Intl.message( - 'Обхват груди', + 'Chest Circumference', name: 'chest_circumference', desc: '', args: [], ); } - /// `Обхват талии` + /// `Waist Circumference` String get waist_circumference { return Intl.message( - 'Обхват талии', + 'Waist Circumference', name: 'waist_circumference', desc: '', args: [], ); } - /// `Первичные замеры` + /// `Initial Measurements` String get initial_measurements { return Intl.message( - 'Первичные замеры', + 'Initial Measurements', name: 'initial_measurements', desc: '', args: [], ); } - /// `Мужской` + /// `Male` String get male { return Intl.message( - 'Мужской', + 'Male', name: 'male', desc: '', args: [], ); } - /// `Женский` + /// `Female` String get female { return Intl.message( - 'Женский', + 'Female', name: 'female', desc: '', args: [], ); } - /// `Замер веса` + /// `Weight Measurement` String get weight_measurements { return Intl.message( - 'Замер веса', + 'Weight Measurement', name: 'weight_measurements', desc: '', args: [], ); } - /// `Ваш вес:` + /// `Your Weight:` String get your_weight { return Intl.message( - 'Ваш вес:', + 'Your Weight:', name: 'your_weight', desc: '', args: [], ); } - /// `Замер роста` + /// `Height Measurement` String get height_measurements { return Intl.message( - 'Замер роста', + 'Height Measurement', name: 'height_measurements', desc: '', args: [], ); } - /// `Ваш рост:` + /// `Your Height:` String get your_height { return Intl.message( - 'Ваш рост:', + 'Your Height:', name: 'your_height', desc: '', args: [], ); } - /// `Наличие аллергии` + /// `Presence of Allergies` String get allergies_presence { return Intl.message( - 'Наличие аллергии', + 'Presence of Allergies', name: 'allergies_presence', desc: '', args: [], ); } - /// `Принимаете ли вы лекарства или бады?` + /// `Do you take any medications or supplements?` String get do_you_take_pills { return Intl.message( - 'Принимаете ли вы лекарства или бады?', + 'Do you take any medications or supplements?', name: 'do_you_take_pills', desc: '', args: [], ); } - /// `Ваш пол?` + /// `Your Gender?` String get your_gender { return Intl.message( - 'Ваш пол?', + 'Your Gender?', name: 'your_gender', desc: '', args: [], ); } - /// `Нет` + /// `No` String get no { return Intl.message( - 'Нет', + 'No', name: 'no', desc: '', args: [], ); } - /// `Есть ли у вас гипертония?` + /// `Do you have a tendency for hypertension?` String get do_you_have_hypertension_tendency { return Intl.message( - 'Есть ли у вас гипертония?', + 'Do you have a tendency for hypertension?', name: 'do_you_have_hypertension_tendency', desc: '', args: [], ); } - /// `Ваше артериальное давление?` + /// `Your Blood Pressure?` String get your_blood_pressure { return Intl.message( - 'Ваше артериальное давление?', + 'Your Blood Pressure?', name: 'your_blood_pressure', desc: '', args: [], ); } - /// `Средние показатели давления:` + /// `Average Pressure Readings:` String get average_pressure { return Intl.message( - 'Средние показатели давления:', + 'Average Pressure Readings:', name: 'average_pressure', desc: '', args: [], ); } - /// `Верхние показатели давления:` + /// `Upper Pressure Readings:` String get up_pressure { return Intl.message( - 'Верхние показатели давления:', + 'Upper Pressure Readings:', name: 'up_pressure', desc: '', args: [], ); } - /// `Нижние показатели давления:` + /// `Lower Pressure Readings:` String get down_pressure { return Intl.message( - 'Нижние показатели давления:', + 'Lower Pressure Readings:', name: 'down_pressure', desc: '', args: [], ); } - /// `Есть ли у вас гипотония?` + /// `Do you have a tendency for hypotension?` String get do_you_have_hypotension_tendency { return Intl.message( - 'Есть ли у вас гипотония?', + 'Do you have a tendency for hypotension?', name: 'do_you_have_hypotension_tendency', desc: '', args: [], ); } - /// `Ваши спортивные увлечения?` + /// `Your Favorite Sports?` String get your_favorite_sports { return Intl.message( - 'Ваши спортивные увлечения?', + 'Your Favorite Sports?', name: 'your_favorite_sports', desc: '', args: [], ); } - /// `Любимые продукты` + /// `Favorite Foods` String get favorite_foods { return Intl.message( - 'Любимые продукты', + 'Favorite Foods', name: 'favorite_foods', desc: '', args: [], ); } - /// `Ваши любимые/нелюбимые продукты питания?` + /// `Your Favorite/Least Favorite Foods?` String get favorite_unfavorite_foods { return Intl.message( - 'Ваши любимые/нелюбимые продукты питания?', + 'Your Favorite/Least Favorite Foods?', name: 'favorite_unfavorite_foods', desc: '', args: [], ); } - /// `Нелюбимые продукты` + /// `Least Favorite Foods` String get unfavorite_foods { return Intl.message( - 'Нелюбимые продукты', + 'Least Favorite Foods', name: 'unfavorite_foods', desc: '', args: [], ); } - /// `Ваш режим дня?` + /// `Your Daily Routine?` String get your_schedule { return Intl.message( - 'Ваш режим дня?', + 'Your Daily Routine?', name: 'your_schedule', desc: '', args: [], ); } - /// `Расскажите в свободной форме о том как просыпаетесь, когда едите, когда ложитесь спать:` + /// `Describe your daily routine freely, such as when you wake up, eat, and go to bed:` String get tell_your_schedule { return Intl.message( - 'Расскажите в свободной форме о том как просыпаетесь, когда едите, когда ложитесь спать:', + 'Describe your daily routine freely, such as when you wake up, eat, and go to bed:', name: 'tell_your_schedule', desc: '', args: [], ); } - /// `Дополнительная информация` + /// `Additional Information` String get additional_information { return Intl.message( - 'Дополнительная информация', + 'Additional Information', name: 'additional_information', desc: '', args: [], ); } - /// `Введите любую дополнительную информацию на своё усмотрение:` + /// `Enter any additional information at your discretion:` String get enter_additional_information { return Intl.message( - 'Введите любую дополнительную информацию на своё усмотрение:', + 'Enter any additional information at your discretion:', name: 'enter_additional_information', desc: '', args: [], @@ -490,540 +490,540 @@ class S { ); } - /// `Завершить` + /// `Finish` String get finish { return Intl.message( - 'Завершить', + 'Finish', name: 'finish', desc: '', args: [], ); } - /// `Предпочитаемый язык общения` + /// `Preferred Language of Communication` String get preferred_language { return Intl.message( - 'Предпочитаемый язык общения', + 'Preferred Language of Communication', name: 'preferred_language', desc: '', args: [], ); } - /// `Продолжить` + /// `Continue` String get continueButton { return Intl.message( - 'Продолжить', + 'Continue', name: 'continueButton', desc: '', args: [], ); } - /// `Пропустить` + /// `Skip` String get skip { return Intl.message( - 'Пропустить', + 'Skip', name: 'skip', desc: '', args: [], ); } - /// `Заполните информацию:` + /// `Fill in the information:` String get fill_in_information { return Intl.message( - 'Заполните информацию:', + 'Fill in the information:', name: 'fill_in_information', desc: '', args: [], ); } - /// `Введите информацию...` + /// `Enter information...` String get enter_information { return Intl.message( - 'Введите информацию...', + 'Enter information...', name: 'enter_information', desc: '', args: [], ); } - /// `Сетевая ошибка!` + /// `Network error!` String get msg_network_err { return Intl.message( - 'Сетевая ошибка!', + 'Network error!', name: 'msg_network_err', desc: '', args: [], ); } - /// `Что то пошло не так!` + /// `Something went wrong!` String get msg_something_went_wrong { return Intl.message( - 'Что то пошло не так!', + 'Something went wrong!', name: 'msg_something_went_wrong', desc: '', args: [], ); } - /// `Необходимо ввести адрес электронной почты` + /// `Email address is required` String get email_empty { return Intl.message( - 'Необходимо ввести адрес электронной почты', + 'Email address is required', name: 'email_empty', desc: '', args: [], ); } - /// `Некорректный адрес электронной почты` + /// `Invalid email address` String get email_invalid { return Intl.message( - 'Некорректный адрес электронной почты', + 'Invalid email address', name: 'email_invalid', desc: '', args: [], ); } - /// `Пароль обязателен для заполнения` + /// `Password is required` String get password_empty { return Intl.message( - 'Пароль обязателен для заполнения', + 'Password is required', name: 'password_empty', desc: '', args: [], ); } - /// `В пароле должно быть минимум 6 символов` + /// `Password must be at least 6 characters long` String get password_short { return Intl.message( - 'В пароле должно быть минимум 6 символов', + 'Password must be at least 6 characters long', name: 'password_short', desc: '', args: [], ); } - /// `Имя пользователя обязательно для заполнения` + /// `Username is required` String get name_empty { return Intl.message( - 'Имя пользователя обязательно для заполнения', + 'Username is required', name: 'name_empty', desc: '', args: [], ); } - /// `В имени пользователя должно быть минимум 6 символов` + /// `Username must be at least 6 characters long` String get name_short { return Intl.message( - 'В имени пользователя должно быть минимум 6 символов', + 'Username must be at least 6 characters long', name: 'name_short', desc: '', args: [], ); } - /// `Пароли не совпадают` + /// `Passwords do not match` String get password_confirmation_mismatch { return Intl.message( - 'Пароли не совпадают', + 'Passwords do not match', name: 'password_confirmation_mismatch', desc: '', args: [], ); } - /// `Имя обязательно для заполнения` + /// `First name is required` String get first_name_empty { return Intl.message( - 'Имя обязательно для заполнения', + 'First name is required', name: 'first_name_empty', desc: '', args: [], ); } - /// `В имени должен быть минимум 1 символ` + /// `First name must be at least 1 character long` String get first_name_short { return Intl.message( - 'В имени должен быть минимум 1 символ', + 'First name must be at least 1 character long', name: 'first_name_short', desc: '', args: [], ); } - /// `Фамилия обязательна для заполнения` + /// `Last name is required` String get last_name_empty { return Intl.message( - 'Фамилия обязательна для заполнения', + 'Last name is required', name: 'last_name_empty', desc: '', args: [], ); } - /// `В фамилии должен быть минимум 6 символов` + /// `Last name must be at least 6 characters long` String get last_name_short { return Intl.message( - 'В фамилии должен быть минимум 6 символов', + 'Last name must be at least 6 characters long', name: 'last_name_short', desc: '', args: [], ); } - /// `Все замеры обязательны к заполнению` + /// `All measurements are required` String get circumference_empty { return Intl.message( - 'Все замеры обязательны к заполнению', + 'All measurements are required', name: 'circumference_empty', desc: '', args: [], ); } - /// `Все замеры должны быть числами` + /// `All measurements must be numbers` String get circumference_is_not_a_number { return Intl.message( - 'Все замеры должны быть числами', + 'All measurements must be numbers', name: 'circumference_is_not_a_number', desc: '', args: [], ); } - /// `Все показатели давления обязательны к заполнению` + /// `All blood pressure readings are required` String get pressure_empty { return Intl.message( - 'Все показатели давления обязательны к заполнению', + 'All blood pressure readings are required', name: 'pressure_empty', desc: '', args: [], ); } - /// `Все показатели давления должны быть числами` + /// `All blood pressure readings must be numbers` String get pressure_is_not_a_number { return Intl.message( - 'Все показатели давления должны быть числами', + 'All blood pressure readings must be numbers', name: 'pressure_is_not_a_number', desc: '', args: [], ); } - /// `У меня нет аккаунта` + /// `I do not have an account` String get no_account { return Intl.message( - 'У меня нет аккаунта', + 'I do not have an account', name: 'no_account', desc: '', args: [], ); } - /// `Войти` + /// `Log In` String get authentificate { return Intl.message( - 'Войти', + 'Log In', name: 'authentificate', desc: '', args: [], ); } - /// `Аутентификация` + /// `Authentication` String get user_authorization { return Intl.message( - 'Аутентификация', + 'Authentication', name: 'user_authorization', desc: '', args: [], ); } - /// `Загрузка...` + /// `Loading...` String get loading { return Intl.message( - 'Загрузка...', + 'Loading...', name: 'loading', desc: '', args: [], ); } - /// `График веса` + /// `Weight Chart` String get weight_chart { return Intl.message( - 'График веса', + 'Weight Chart', name: 'weight_chart', desc: '', args: [], ); } - /// `График обхватов` + /// `Circumference Chart` String get circumferences_chart { return Intl.message( - 'График обхватов', + 'Circumference Chart', name: 'circumferences_chart', desc: '', args: [], ); } - /// `Город проживания` + /// `City of Residence` String get city_of_living { return Intl.message( - 'Город проживания', + 'City of Residence', name: 'city_of_living', desc: '', args: [], ); } - /// `График ИМТ` + /// `BMI Chart` String get bodymass_chart { return Intl.message( - 'График ИМТ', + 'BMI Chart', name: 'bodymass_chart', desc: '', args: [], ); } - /// `Грудь` + /// `Chest` String get chest { return Intl.message( - 'Грудь', + 'Chest', name: 'chest', desc: '', args: [], ); } - /// `Талия` + /// `Waist` String get waist { return Intl.message( - 'Талия', + 'Waist', name: 'waist', desc: '', args: [], ); } - /// `Бедра` + /// `Hips` String get hips { return Intl.message( - 'Бедра', + 'Hips', name: 'hips', desc: '', args: [], ); } - /// `Выйти` + /// `Log Out` String get exit { return Intl.message( - 'Выйти', + 'Log Out', name: 'exit', desc: '', args: [], ); } - /// `Активен` + /// `Active` String get active { return Intl.message( - 'Активен', + 'Active', name: 'active', desc: '', args: [], ); } - /// `В архиве` + /// `Archived` String get archived { return Intl.message( - 'В архиве', + 'Archived', name: 'archived', desc: '', args: [], ); } - /// `Черновик` + /// `Draft` String get draft { return Intl.message( - 'Черновик', + 'Draft', name: 'draft', desc: '', args: [], ); } - /// `Мой блог` + /// `My Blog` String get my_blog { return Intl.message( - 'Мой блог', + 'My Blog', name: 'my_blog', desc: '', args: [], ); } - /// `Язык` + /// `Language` String get language { return Intl.message( - 'Язык', + 'Language', name: 'language', desc: '', args: [], ); } - /// `В процессе` + /// `In Progress` String get in_progress { return Intl.message( - 'В процессе', + 'In Progress', name: 'in_progress', desc: '', args: [], ); } - /// `Добавить замер` + /// `Add Measurement` String get add_measure { return Intl.message( - 'Добавить замер', + 'Add Measurement', name: 'add_measure', desc: '', args: [], ); } - /// `Вес` + /// `Weight` String get weight { return Intl.message( - 'Вес', + 'Weight', name: 'weight', desc: '', args: [], ); } - /// `Пройденные планы` + /// `Completed Plans` String get plans_complete { return Intl.message( - 'Пройденные планы', + 'Completed Plans', name: 'plans_complete', desc: '', args: [], ); } - /// `Мои настройки` + /// `My Settings` String get my_settings { return Intl.message( - 'Мои настройки', + 'My Settings', name: 'my_settings', desc: '', args: [], ); } - /// `Настройки` + /// `Settings` String get settings { return Intl.message( - 'Настройки', + 'Settings', name: 'settings', desc: '', args: [], ); } - /// `Профиль` + /// `Profile` String get profile { return Intl.message( - 'Профиль', + 'Profile', name: 'profile', desc: '', args: [], ); } - /// `Чат` + /// `Chat` String get chat { return Intl.message( - 'Чат', + 'Chat', name: 'chat', desc: '', args: [], ); } - /// `Админ` + /// `Admin` String get admin { return Intl.message( - 'Админ', + 'Admin', name: 'admin', desc: '', args: [], ); } - /// `Дневник` + /// `Diary` String get diary { return Intl.message( - 'Дневник', + 'Diary', name: 'diary', desc: '', args: [], ); } - /// `Сохранить` + /// `Save` String get save { return Intl.message( - 'Сохранить', + 'Save', name: 'save', desc: '', args: [], ); } - /// `шт` + /// `pcs` String get pcs { return Intl.message( - 'шт', + 'pcs', name: 'pcs', desc: '', args: [], ); } - /// `гр` + /// `g` String get gr { return Intl.message( - 'гр', + 'g', name: 'gr', desc: '', args: [], ); } - /// `гр` + /// `g` String get grams { return Intl.message( - 'гр', + 'g', name: 'grams', desc: '', args: [], @@ -1037,6 +1037,7 @@ class AppLocalizationDelegate extends LocalizationsDelegate { List get supportedLocales { return const [ Locale.fromSubtags(languageCode: 'en'), + Locale.fromSubtags(languageCode: 'ru'), ]; } diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index 8d2d512c..a204a347 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -1,100 +1,100 @@ { - "user_registration": "Регистрация пользователя", - "email": "Элетронная почта", - "username": "Имя пользователя", - "password": "Пароль", - "password_confirmation": "Подтвердите пароль", - "wrong_credentials": "Неверные данные пользователя", - "first_name": "Имя", - "last_name": "Фамилия", - "what_is_your_name": "Как вас зовут?", - "date_of_birth": "Дата рождения", - "country": "Страна", - "Russia": "Россия", - "city": "Город", - "Moscow": "Москва", - "place_of_living": "Место проживания", - "hip_circumference": "Обхват бедер", - "chest_circumference": "Обхват груди", - "waist_circumference": "Обхват талии", - "initial_measurements": "Первичные замеры", - "male": "Мужской", - "female": "Женский", - "weight_measurements": "Замер веса", - "your_weight": "Ваш вес:", - "height_measurements": "Замер роста", - "your_height": "Ваш рост:", - "allergies_presence": "Наличие аллергии", - "do_you_take_pills": "Принимаете ли вы лекарства или бады?", - "your_gender": "Ваш пол?", - "no": "Нет", - "do_you_have_hypertension_tendency": "Есть ли у вас гипертония?", - "your_blood_pressure": "Ваше артериальное давление?", - "average_pressure": "Средние показатели давления:", - "up_pressure": "Верхние показатели давления:", - "down_pressure": "Нижние показатели давления:", - "do_you_have_hypotension_tendency": "Есть ли у вас гипотония?", - "your_favorite_sports": "Ваши спортивные увлечения?", - "favorite_foods": "Любимые продукты", - "favorite_unfavorite_foods": "Ваши любимые/нелюбимые продукты питания?", - "unfavorite_foods": "Нелюбимые продукты", - "your_schedule": "Ваш режим дня?", - "tell_your_schedule": "Расскажите в свободной форме о том как просыпаетесь, когда едите, когда ложитесь спать:", - "additional_information": "Дополнительная информация", - "enter_additional_information": "Введите любую дополнительную информацию на своё усмотрение:", + "user_registration": "User Registration", + "email": "Email", + "username": "Username", + "password": "Password", + "password_confirmation": "Confirm Password", + "wrong_credentials": "Invalid user credentials", + "first_name": "First Name", + "last_name": "Last Name", + "what_is_your_name": "What is your name?", + "date_of_birth": "Date of Birth", + "country": "Country", + "Russia": "Russia", + "city": "City", + "Moscow": "Moscow", + "place_of_living": "Place of Residence", + "hip_circumference": "Hip Circumference", + "chest_circumference": "Chest Circumference", + "waist_circumference": "Waist Circumference", + "initial_measurements": "Initial Measurements", + "male": "Male", + "female": "Female", + "weight_measurements": "Weight Measurement", + "your_weight": "Your Weight:", + "height_measurements": "Height Measurement", + "your_height": "Your Height:", + "allergies_presence": "Presence of Allergies", + "do_you_take_pills": "Do you take any medications or supplements?", + "your_gender": "Your Gender?", + "no": "No", + "do_you_have_hypertension_tendency": "Do you have a tendency for hypertension?", + "your_blood_pressure": "Your Blood Pressure?", + "average_pressure": "Average Pressure Readings:", + "up_pressure": "Upper Pressure Readings:", + "down_pressure": "Lower Pressure Readings:", + "do_you_have_hypotension_tendency": "Do you have a tendency for hypotension?", + "your_favorite_sports": "Your Favorite Sports?", + "favorite_foods": "Favorite Foods", + "favorite_unfavorite_foods": "Your Favorite/Least Favorite Foods?", + "unfavorite_foods": "Least Favorite Foods", + "your_schedule": "Your Daily Routine?", + "tell_your_schedule": "Describe your daily routine freely, such as when you wake up, eat, and go to bed:", + "additional_information": "Additional Information", + "enter_additional_information": "Enter any additional information at your discretion:", "lbl_english": "English", - "finish": "Завершить", - "preferred_language": "Предпочитаемый язык общения", - "continueButton": "Продолжить", - "skip": "Пропустить", - "fill_in_information": "Заполните информацию:", - "enter_information": "Введите информацию...", - "msg_network_err": "Сетевая ошибка!", - "msg_something_went_wrong": "Что то пошло не так!", - "email_empty": "Необходимо ввести адрес электронной почты", - "email_invalid": "Некорректный адрес электронной почты", - "password_empty": "Пароль обязателен для заполнения", - "password_short": "В пароле должно быть минимум 6 символов", - "name_empty": "Имя пользователя обязательно для заполнения", - "name_short": "В имени пользователя должно быть минимум 6 символов", - "password_confirmation_mismatch": "Пароли не совпадают", - "first_name_empty": "Имя обязательно для заполнения", - "first_name_short": "В имени должен быть минимум 1 символ", - "last_name_empty": "Фамилия обязательна для заполнения", - "last_name_short": "В фамилии должен быть минимум 6 символов", - "circumference_empty": "Все замеры обязательны к заполнению", - "circumference_is_not_a_number": "Все замеры должны быть числами", - "pressure_empty": "Все показатели давления обязательны к заполнению", - "pressure_is_not_a_number": "Все показатели давления должны быть числами", - "no_account": "У меня нет аккаунта", - "authentificate": "Войти", - "user_authorization": "Аутентификация", - "loading": "Загрузка...", - "weight_chart": "График веса", - "circumferences_chart": "График обхватов", - "city_of_living": "Город проживания", - "bodymass_chart": "График ИМТ", - "chest": "Грудь", - "waist": "Талия", - "hips": "Бедра", - "exit": "Выйти", - "active": "Активен", - "archived": "В архиве", - "draft": "Черновик", - "my_blog": "Мой блог", - "language": "Язык", - "in_progress": "В процессе", - "add_measure": "Добавить замер", - "weight": "Вес", - "plans_complete": "Пройденные планы", - "my_settings": "Мои настройки", - "settings": "Настройки", - "profile": "Профиль", - "chat": "Чат", - "admin": "Админ", - "diary": "Дневник", - "save": "Сохранить", - "pcs": "шт", - "gr": "гр", - "grams": "гр" -} \ No newline at end of file + "finish": "Finish", + "preferred_language": "Preferred Language of Communication", + "continueButton": "Continue", + "skip": "Skip", + "fill_in_information": "Fill in the information:", + "enter_information": "Enter information...", + "msg_network_err": "Network error!", + "msg_something_went_wrong": "Something went wrong!", + "email_empty": "Email address is required", + "email_invalid": "Invalid email address", + "password_empty": "Password is required", + "password_short": "Password must be at least 6 characters long", + "name_empty": "Username is required", + "name_short": "Username must be at least 6 characters long", + "password_confirmation_mismatch": "Passwords do not match", + "first_name_empty": "First name is required", + "first_name_short": "First name must be at least 1 character long", + "last_name_empty": "Last name is required", + "last_name_short": "Last name must be at least 6 characters long", + "circumference_empty": "All measurements are required", + "circumference_is_not_a_number": "All measurements must be numbers", + "pressure_empty": "All blood pressure readings are required", + "pressure_is_not_a_number": "All blood pressure readings must be numbers", + "no_account": "I do not have an account", + "authentificate": "Log In", + "user_authorization": "Authentication", + "loading": "Loading...", + "weight_chart": "Weight Chart", + "circumferences_chart": "Circumference Chart", + "city_of_living": "City of Residence", + "bodymass_chart": "BMI Chart", + "chest": "Chest", + "waist": "Waist", + "hips": "Hips", + "exit": "Log Out", + "active": "Active", + "archived": "Archived", + "draft": "Draft", + "my_blog": "My Blog", + "language": "Language", + "in_progress": "In Progress", + "add_measure": "Add Measurement", + "weight": "Weight", + "plans_complete": "Completed Plans", + "my_settings": "My Settings", + "settings": "Settings", + "profile": "Profile", + "chat": "Chat", + "admin": "Admin", + "diary": "Diary", + "save": "Save", + "pcs": "pcs", + "gr": "g", + "grams": "g" +} diff --git a/lib/l10n/intl_ru.arb b/lib/l10n/intl_ru.arb new file mode 100644 index 00000000..8d2d512c --- /dev/null +++ b/lib/l10n/intl_ru.arb @@ -0,0 +1,100 @@ +{ + "user_registration": "Регистрация пользователя", + "email": "Элетронная почта", + "username": "Имя пользователя", + "password": "Пароль", + "password_confirmation": "Подтвердите пароль", + "wrong_credentials": "Неверные данные пользователя", + "first_name": "Имя", + "last_name": "Фамилия", + "what_is_your_name": "Как вас зовут?", + "date_of_birth": "Дата рождения", + "country": "Страна", + "Russia": "Россия", + "city": "Город", + "Moscow": "Москва", + "place_of_living": "Место проживания", + "hip_circumference": "Обхват бедер", + "chest_circumference": "Обхват груди", + "waist_circumference": "Обхват талии", + "initial_measurements": "Первичные замеры", + "male": "Мужской", + "female": "Женский", + "weight_measurements": "Замер веса", + "your_weight": "Ваш вес:", + "height_measurements": "Замер роста", + "your_height": "Ваш рост:", + "allergies_presence": "Наличие аллергии", + "do_you_take_pills": "Принимаете ли вы лекарства или бады?", + "your_gender": "Ваш пол?", + "no": "Нет", + "do_you_have_hypertension_tendency": "Есть ли у вас гипертония?", + "your_blood_pressure": "Ваше артериальное давление?", + "average_pressure": "Средние показатели давления:", + "up_pressure": "Верхние показатели давления:", + "down_pressure": "Нижние показатели давления:", + "do_you_have_hypotension_tendency": "Есть ли у вас гипотония?", + "your_favorite_sports": "Ваши спортивные увлечения?", + "favorite_foods": "Любимые продукты", + "favorite_unfavorite_foods": "Ваши любимые/нелюбимые продукты питания?", + "unfavorite_foods": "Нелюбимые продукты", + "your_schedule": "Ваш режим дня?", + "tell_your_schedule": "Расскажите в свободной форме о том как просыпаетесь, когда едите, когда ложитесь спать:", + "additional_information": "Дополнительная информация", + "enter_additional_information": "Введите любую дополнительную информацию на своё усмотрение:", + "lbl_english": "English", + "finish": "Завершить", + "preferred_language": "Предпочитаемый язык общения", + "continueButton": "Продолжить", + "skip": "Пропустить", + "fill_in_information": "Заполните информацию:", + "enter_information": "Введите информацию...", + "msg_network_err": "Сетевая ошибка!", + "msg_something_went_wrong": "Что то пошло не так!", + "email_empty": "Необходимо ввести адрес электронной почты", + "email_invalid": "Некорректный адрес электронной почты", + "password_empty": "Пароль обязателен для заполнения", + "password_short": "В пароле должно быть минимум 6 символов", + "name_empty": "Имя пользователя обязательно для заполнения", + "name_short": "В имени пользователя должно быть минимум 6 символов", + "password_confirmation_mismatch": "Пароли не совпадают", + "first_name_empty": "Имя обязательно для заполнения", + "first_name_short": "В имени должен быть минимум 1 символ", + "last_name_empty": "Фамилия обязательна для заполнения", + "last_name_short": "В фамилии должен быть минимум 6 символов", + "circumference_empty": "Все замеры обязательны к заполнению", + "circumference_is_not_a_number": "Все замеры должны быть числами", + "pressure_empty": "Все показатели давления обязательны к заполнению", + "pressure_is_not_a_number": "Все показатели давления должны быть числами", + "no_account": "У меня нет аккаунта", + "authentificate": "Войти", + "user_authorization": "Аутентификация", + "loading": "Загрузка...", + "weight_chart": "График веса", + "circumferences_chart": "График обхватов", + "city_of_living": "Город проживания", + "bodymass_chart": "График ИМТ", + "chest": "Грудь", + "waist": "Талия", + "hips": "Бедра", + "exit": "Выйти", + "active": "Активен", + "archived": "В архиве", + "draft": "Черновик", + "my_blog": "Мой блог", + "language": "Язык", + "in_progress": "В процессе", + "add_measure": "Добавить замер", + "weight": "Вес", + "plans_complete": "Пройденные планы", + "my_settings": "Мои настройки", + "settings": "Настройки", + "profile": "Профиль", + "chat": "Чат", + "admin": "Админ", + "diary": "Дневник", + "save": "Сохранить", + "pcs": "шт", + "gr": "гр", + "grams": "гр" +} \ No newline at end of file diff --git a/lib/locator_service.dart b/lib/locator_service.dart index e51ccc7c..e64ee309 100644 --- a/lib/locator_service.dart +++ b/lib/locator_service.dart @@ -11,6 +11,9 @@ import 'package:eatvio_app/features/chat/presentation/bloc/chat_room_cubit/chat_ import 'package:eatvio_app/features/chat/presentation/bloc/chat_select_cubit/chat_select_cubit.dart'; import 'package:eatvio_app/features/chat/repositories/chat_repository.dart'; import 'package:eatvio_app/features/chat/services/chat_service.dart'; +import 'package:eatvio_app/features/consultant/become_consultant/presentation/bloc/register_consultant_cubit/register_consultant_cubit.dart'; +import 'package:eatvio_app/features/consultant/become_consultant/repositories/consultant_repository.dart'; +import 'package:eatvio_app/features/consultant/become_consultant/services/consultant_service.dart'; import 'package:eatvio_app/features/diary/presentation/bloc/diary_bloc.dart'; import 'package:eatvio_app/features/diary/repositories/diary_repository.dart'; import 'package:eatvio_app/features/diary/services/diary_service.dart'; @@ -60,6 +63,7 @@ Future init() async { sl.registerFactory(() => ChatSelectCubit(chatRepository: sl())); sl.registerFactory(() => PlansCubit(plansRepository: sl())); sl.registerFactory(() => SettingsCubit(profileRepository: sl(), settingsRepository: sl())); + sl.registerFactory(() => RegisterConsultantCubit(consultantRepository: sl())); // Repository sl.registerLazySingleton(() => ChatRepository(chatService: sl())); @@ -71,6 +75,7 @@ Future init() async { sl.registerLazySingleton(() => RecipeRepository(recipeService: sl())); sl.registerLazySingleton(() => PlansRepository(plansService: sl())); sl.registerLazySingleton(() => SettingsRepository(settingsService: sl())); + sl.registerLazySingleton(() => ConsultantRepository(consultantService: sl())); // Services sl.registerLazySingleton(() => ChatService(sl())); @@ -82,6 +87,7 @@ Future init() async { sl.registerLazySingleton(() => RecipeService(sl())); sl.registerLazySingleton(() => PlansService(sl())); sl.registerLazySingleton(() => SettingsService(sl())); + sl.registerLazySingleton(() => ConsultantService(sl())); // External sl.registerLazySingleton( diff --git a/lib/old/auth/auth_screen/auth_screen.dart b/lib/old/auth/auth_screen/auth_screen.dart index fc8cb13f..3850cacf 100644 --- a/lib/old/auth/auth_screen/auth_screen.dart +++ b/lib/old/auth/auth_screen/auth_screen.dart @@ -37,6 +37,7 @@ class AuthScreen extends StatefulWidget { class _AuthScreenState extends State { bool checkboxState = false; + bool hidePassword = true; @override Widget build(BuildContext context) { @@ -73,9 +74,20 @@ class _AuthScreenState extends State { selector: (state) => state.passwordController, builder: (context, passwordController) { return CustomTextFormField( - obscureText: true, + obscureText: hidePassword, controller: passwordController, hintText: 'Введите пароль', + suffix: IconButton( + onPressed: () { + setState(() { + hidePassword = !hidePassword; + }); + }, + icon: Icon( + hidePassword ? Icons.visibility_outlined : Icons.visibility_off_outlined, + color: Colors.grey, + ), + ), ); }, ), diff --git a/lib/old/feed/blog_post_create_screen/bloc/blog_post_create_bloc.dart b/lib/old/feed/blog_post_create_screen/bloc/blog_post_create_bloc.dart index 15e80977..05c02fbc 100644 --- a/lib/old/feed/blog_post_create_screen/bloc/blog_post_create_bloc.dart +++ b/lib/old/feed/blog_post_create_screen/bloc/blog_post_create_bloc.dart @@ -81,9 +81,9 @@ class BlogPostCreateBloc extends Bloc FormData formData = FormData.fromMap({ 'title': title, 'description': description, - 'youtube_url': youtubeURL, 'state': 'active', - 'image': await MultipartFile.fromFile(image!.path, filename: image.name), + 'youtube_url': youtubeURL, + 'image': image != null ? await MultipartFile.fromFile(image.path, filename: image.name) : null, }); final response = await sl().post( diff --git a/lib/widgets/custom_expandable_list.dart b/lib/widgets/custom_expandable_list.dart index dfda23f9..ff29bc86 100644 --- a/lib/widgets/custom_expandable_list.dart +++ b/lib/widgets/custom_expandable_list.dart @@ -1,5 +1,5 @@ import 'dart:convert'; -import 'package:rive/rive.dart' as rive; + import 'package:eatvio_app/core/const.dart'; import 'package:eatvio_app/core/token_storage.dart'; import 'package:eatvio_app/generated/l10n.dart'; @@ -14,6 +14,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; import 'package:http/http.dart' as http; import 'package:intl/intl.dart'; +import 'package:rive/rive.dart' as rive; class ExpandableList extends StatefulWidget { final String title; diff --git a/pubspec.yaml b/pubspec.yaml index 0b30677b..de3084db 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -26,10 +26,10 @@ dependencies: flutter_form_builder: ^9.4.1 image_picker: ^1.1.2 flutter_typeahead: ^5.2.0 - go_router: ^14.2.7 + go_router: ^14.2.9 keyboard_dismisser: ^3.0.0 retrofit: ^4.4.1 - get_it: ^7.7.0 + get_it: ^8.0.0 dio: ^5.7.0 dart_pusher_channels: ^1.2.3 photo_view: ^0.15.0 @@ -39,7 +39,7 @@ dependencies: badges: ^3.1.2 google_fonts: ^6.2.1 location: ^6.0.2 - syncfusion_flutter_charts: ^27.1.48 + syncfusion_flutter_charts: ^27.1.51 table_calendar: ^3.1.2 flutter_keyboard_visibility: ^6.0.0 share_plus: ^10.0.2 @@ -50,7 +50,7 @@ dependencies: rive: ^0.13.14 dev_dependencies: - build_runner: ^2.4.12 + build_runner: ^2.4.13 freezed: ^2.5.7 json_serializable: ^6.8.0 retrofit_generator: ^9.1.2