Merge pull request 'feature/consultant' (#134) from mso7nueh/eatvio_app:feature/consultant into main

Reviewed-on: eatvio/eatvio_app#134
This commit is contained in:
mso7nueh
2024-10-09 13:32:32 +00:00
56 changed files with 3413 additions and 542 deletions

View File

@@ -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 = "../.."
}

View File

@@ -1,3 +1,3 @@
org.gradle.jvmargs=-Xmx1536M
org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError
android.useAndroidX=true
android.enableJetifier=true

View File

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

View File

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

View File

@@ -0,0 +1,3 @@
<svg width="24" height="20" viewBox="0 0 24 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M22.3836 0.295837C21.1711 0.493883 16.5808 2.33657 6.46472 6.69359C3.42471 8.00242 0.791764 9.16486 0.601222 9.28541C-0.0570137 9.69873 -0.178268 10.1379 0.254782 10.534C0.523273 10.7837 2.23815 11.395 4.0483 11.8858C5.25218 12.2131 6.50802 12.2217 7.18358 11.9031C7.44341 11.7825 9.70393 10.3273 12.207 8.66544C16.6068 5.74641 17.6114 5.10922 17.8193 5.10922C17.9665 5.10922 18.1831 5.35893 18.1831 5.53115C18.1831 5.76363 17.3516 6.61609 14.9958 8.82905C12.1463 11.4811 11.0291 12.5747 10.7259 12.9794C10.3275 13.5133 10.4141 14.0816 10.9684 14.5896C11.3235 14.9168 18.0878 19.4374 18.6248 19.713C19.1704 19.9885 19.9586 20.0832 20.357 19.9196C20.7294 19.7646 21.1018 19.2308 21.301 18.5505C21.6561 17.3623 23.2584 7.86465 23.8127 3.6454C24.0466 1.88882 24.0552 1.10524 23.8733 0.752205C23.6655 0.347502 23.1112 0.175287 22.3836 0.295837Z" fill="#323F4B"/>
</svg>

After

Width:  |  Height:  |  Size: 971 B

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

@@ -0,0 +1,3 @@
<svg width="24" height="16" viewBox="0 0 24 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.0718 15.2C4.87192 15.2 0.19489 9.49429 0 0H4.10744C4.24236 6.96856 7.2704 9.9203 9.66887 10.5289V0H13.5366V6.00996C15.9051 5.75131 18.3932 3.01261 19.2327 0H23.1004C22.4558 3.71252 19.7575 6.45123 17.8387 7.57714C19.7575 8.49005 22.8307 10.8789 24 15.2H19.7425C18.8281 12.3091 16.5497 10.0725 13.5366 9.76813V15.2H13.0718Z" fill="#323F4B"/>
</svg>

After

Width:  |  Height:  |  Size: 457 B

11
assets/icons/web.svg Normal file
View File

@@ -0,0 +1,11 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_942_11290)">
<path d="M10.6171 0.0515556C8.33433 0.332806 6.30933 1.17656 4.47651 2.61562C4.04526 2.95781 2.94839 4.05468 2.59683 4.49999C1.30308 6.14062 0.431201 8.12343 0.107764 10.1719C-0.0141113 10.9406 -0.0141113 13.0594 0.107764 13.8281C0.492139 16.2609 1.60308 18.5062 3.29526 20.2781C5.14214 22.2094 7.37808 23.4 10.05 23.8687C10.8234 24.0047 13.3781 24.0516 13.6546 23.9344C14.3343 23.6531 14.6156 22.8609 14.2687 22.2234C13.9968 21.7125 13.6218 21.5625 12.6515 21.5625H12.0093L11.7937 21.1969C11.1609 20.1141 10.4718 18.3422 10.1812 17.0297L10.1343 16.8328L11.2453 16.8187C12.2765 16.8047 12.3656 16.7953 12.539 16.7016C13.4062 16.2328 13.4484 15.0328 12.6187 14.5453L12.3984 14.4141L11.0625 14.3906L9.72651 14.3672L9.6937 14.0625C9.62339 13.3219 9.59995 11.475 9.65151 10.6406C9.68433 10.1625 9.71714 9.73593 9.7312 9.68906C9.75464 9.61406 9.90464 9.60937 12 9.60937H14.2406L14.2734 9.82968C14.2875 9.95624 14.3296 10.5844 14.3578 11.2312C14.4187 12.375 14.4187 12.4078 14.5453 12.6234C15.0328 13.4484 16.2374 13.4062 16.7015 12.5391C16.7906 12.375 16.8046 12.2766 16.8046 11.7187C16.8046 11.3719 16.7859 10.7531 16.7671 10.3453L16.7296 9.60937H18.9984H21.2671L21.3234 9.85312C21.5203 10.7625 21.5343 10.8844 21.5343 12.2391L21.539 13.5797L21.6796 13.8094C21.9281 14.2031 22.4578 14.4469 22.9078 14.3625C23.3812 14.2781 23.7515 13.9594 23.8874 13.5234C24.0046 13.1531 24.0328 11.3578 23.9343 10.5516C23.6765 8.44218 22.889 6.48749 21.5953 4.75781C21.0984 4.08749 19.9031 2.89218 19.2421 2.39999C17.5218 1.12499 15.5578 0.328119 13.5 0.0703068C12.8671 -0.00469398 11.189 -0.0187569 10.6171 0.0515556ZM12.3421 3.11718C12.8343 4.03124 13.2515 5.06249 13.5656 6.15937C13.6781 6.54843 13.7859 6.93749 13.8046 7.01718L13.8375 7.17187H12.0046C10.2468 7.17187 10.1718 7.16718 10.1718 7.08281C10.1718 6.93749 10.5328 5.70937 10.7578 5.09062C11.0203 4.35937 11.4234 3.47343 11.7281 2.93906C11.925 2.59687 11.9765 2.53593 12.0234 2.58749C12.0562 2.62031 12.2015 2.85937 12.3421 3.11718ZM16.1484 3.39843C17.7609 4.18124 19.1343 5.39999 20.0812 6.89999L20.2546 7.17187H18.3046H16.3593L16.3359 7.06406C16.0312 5.69531 15.7406 4.73437 15.3281 3.72656C15.1734 3.33749 15.0328 2.99531 15.014 2.96249C14.9765 2.87343 15.4312 3.05156 16.1484 3.39843ZM8.93901 3.00937C8.92495 3.04218 8.83589 3.24843 8.74214 3.46874C8.4562 4.13906 8.0437 5.41406 7.82339 6.31406L7.61714 7.17187H5.6812H3.74526L3.9187 6.89999C4.9687 5.24062 6.5812 3.88593 8.41401 3.13124C8.8687 2.94374 8.97651 2.92031 8.93901 3.00937ZM7.23276 10.1344C7.20933 10.425 7.19526 11.2641 7.19526 12C7.19526 12.7359 7.20933 13.575 7.23276 13.8609L7.26558 14.3906H4.99683H2.73276L2.62964 13.9078C2.48901 13.2094 2.43745 12.7172 2.43745 12C2.43745 11.2828 2.48901 10.7906 2.62964 10.0875L2.73276 9.60937H4.99683H7.26558L7.23276 10.1344ZM7.71089 17.2359C7.89839 18.1453 8.36714 19.6359 8.76558 20.5922C8.86401 20.8266 8.92964 21.0281 8.91089 21.0375C8.84995 21.0609 8.04839 20.7187 7.5562 20.4609C6.09839 19.6875 4.79058 18.4828 3.9187 17.0953L3.74526 16.8281H5.68589H7.62651L7.71089 17.2359Z" fill="#323F4B"/>
<path d="M15.3234 15.3234C14.9953 15.6469 14.939 15.4828 16.7249 19.4109C18.1406 22.5187 18.3281 22.9078 18.4687 23.0016C18.6515 23.1281 18.8859 23.1375 19.1109 23.0344C19.2562 22.9641 19.3265 22.8422 19.8515 21.8016C20.1843 21.1359 20.4843 20.5969 20.5593 20.5219C20.6343 20.4562 21.2015 20.1469 21.8249 19.8375C22.8468 19.3266 22.964 19.2562 23.0343 19.1109C23.1374 18.8859 23.1281 18.6516 23.0062 18.4687C22.9078 18.3281 22.5187 18.1406 19.4109 16.725C15.4828 14.9391 15.6468 14.9953 15.3234 15.3234Z" fill="#323F4B"/>
</g>
<defs>
<clipPath id="clip0_942_11290">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

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

View File

@@ -85,15 +85,13 @@ class _BlogPostCreateScreenState extends State<BlogPostCreateScreen> {
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<BlogPostCreateScreen> {
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<BlogPostCreateScreen> {
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<BlogPostCreateScreen> {
}
}
_submitForm(BuildContext context, String title, String description, String youtubeURL) async {
_submitForm(
BuildContext context,
String title,
String description,
String youtubeURL,
) async {
context.read<BlogPostCreateBloc>().add(CreateBlogPost());
}

View File

@@ -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<void> sendMessage({
@Path() String? title,
@Path() required String state,
@Path() String? description,
@Part() String? youtube_url,
@Part(name: 'image', contentType: 'multipart/form-data') List<MultipartFile>? media_data,
});
}

View File

@@ -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<void> sendMessage({
String? title,
required String state,
String? description,
String? youtube_url,
List<MultipartFile>? media_data,
}) async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
queryParameters.removeWhere((k, v) => v == null);
final _headers = <String, dynamic>{};
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<void>(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<void>(_options);
}
RequestOptions _setStreamType<T>(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();
}
}

View File

@@ -27,16 +27,18 @@ class ChatScreen extends StatefulWidget {
class _ChatScreenState extends State<ChatScreen> {
final scrollController = ScrollController();
final TextEditingController textEditingController = TextEditingController();
final ChatRoomCubit chatRoomCubit = sl<ChatRoomCubit>();
@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<ChatRoomCubit>().loadNextPage(widget.chatId);
chatRoomCubit.loadNextPage(widget.chatId);
}
}
@@ -48,8 +50,9 @@ class _ChatScreenState extends State<ChatScreen> {
Widget build(BuildContext context) {
return BlocProvider<ChatRoomCubit>(
create: (BuildContext context) => sl()..initChat(widget.chatId),
create: (BuildContext context) => chatRoomCubit,
child: BlocBuilder<ChatRoomCubit, ChatRoomState>(
bloc: chatRoomCubit,
builder: (context, state) {
if (state is ChatRoomStateLoaded) {
return _buildChat(context, state);
@@ -234,10 +237,10 @@ class _ChatScreenState extends State<ChatScreen> {
if (result != null) {
List<File> files = result.paths.map((path) => File(path!)).toList();
context.read<ChatRoomCubit>().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<ChatScreen> {
customBorder: CircleBorder(),
onTap: () {
if (textEditingController.text.isNotEmpty) {
context.read<ChatRoomCubit>().sendMessage(
chatId: widget.chatId,
data: textEditingController.text.trim(),
);
chatRoomCubit.sendMessage(
chatId: widget.chatId,
data: textEditingController.text.trim(),
);
setState(() {
textEditingController.clear();
});

View File

@@ -37,4 +37,9 @@ abstract class ChatService {
@GET('/api/profile/ws/params')
Future<WebsocketInfoModel> getWebsocket();
@GET('/api/chat/get_by_user/{user}')
Future<ChatRoomModel> getChatRoomIdByUserSlug({
@Path() required String user,
});
}

View File

@@ -198,6 +198,39 @@ class _ChatService implements ChatService {
return _value;
}
@override
Future<ChatRoomModel> getChatRoomIdByUserSlug({required String user}) async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<ChatRoomModel>(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<Map<String, dynamic>>(_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<T>(RequestOptions requestOptions) {
if (T != dynamic &&
!(requestOptions.responseType == ResponseType.bytes ||

View File

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

View File

@@ -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<String>? photos,
@JsonKey(name: 'completed_courses') List<CertificatesModel>? certificates,
}) = _ConsultantProfileModel;
factory ConsultantProfileModel.fromJson(Map<String, Object?> 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<String, Object?> json) => _$SocialLinksModelFromJson(json);
}
@freezed
class CertificatesModel with _$CertificatesModel {
const factory CertificatesModel({
required String title,
required String date,
}) = _CertificatesModel;
factory CertificatesModel.fromJson(Map<String, Object?> json) => _$CertificatesModelFromJson(json);
}

View File

@@ -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>(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<String, dynamic> 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<String>? get photos => throw _privateConstructorUsedError;
@JsonKey(name: 'completed_courses')
List<CertificatesModel>? get certificates =>
throw _privateConstructorUsedError;
/// Serializes this ConsultantProfileModel to a JSON map.
Map<String, dynamic> 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<ConsultantProfileModel> 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<String>? photos,
@JsonKey(name: 'completed_courses')
List<CertificatesModel>? 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<String>?,
certificates: freezed == certificates
? _value.certificates
: certificates // ignore: cast_nullable_to_non_nullable
as List<CertificatesModel>?,
) 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<String>? photos,
@JsonKey(name: 'completed_courses')
List<CertificatesModel>? 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<String>?,
certificates: freezed == certificates
? _value._certificates
: certificates // ignore: cast_nullable_to_non_nullable
as List<CertificatesModel>?,
));
}
}
/// @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<String>? photos,
@JsonKey(name: 'completed_courses')
final List<CertificatesModel>? certificates})
: _photos = photos,
_certificates = certificates;
factory _$ConsultantProfileModelImpl.fromJson(Map<String, dynamic> json) =>
_$$ConsultantProfileModelImplFromJson(json);
@override
@JsonKey(name: 'has_medical_education')
final bool? hasMedicalEducation;
@override
@JsonKey(name: 'social_links')
final SocialLinksModel? socialLinks;
final List<String>? _photos;
@override
@JsonKey(name: 'cert_photos')
List<String>? 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<CertificatesModel>? _certificates;
@override
@JsonKey(name: 'completed_courses')
List<CertificatesModel>? 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<String, dynamic> 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<String>? photos,
@JsonKey(name: 'completed_courses')
final List<CertificatesModel>?
certificates}) = _$ConsultantProfileModelImpl;
factory _ConsultantProfileModel.fromJson(Map<String, dynamic> 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<String>? get photos;
@override
@JsonKey(name: 'completed_courses')
List<CertificatesModel>? 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<String, dynamic> 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<String, dynamic> 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<SocialLinksModel> 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<String, dynamic> 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<String, dynamic> 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<String, dynamic> 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<String, dynamic> 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<String, dynamic> 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<CertificatesModel> 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<String, dynamic> 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<String, dynamic> 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<String, dynamic> 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;
}

View File

@@ -0,0 +1,66 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'consultant_profile_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$ConsultantProfileModelImpl _$$ConsultantProfileModelImplFromJson(
Map<String, dynamic> json) =>
_$ConsultantProfileModelImpl(
hasMedicalEducation: json['has_medical_education'] as bool?,
socialLinks: json['social_links'] == null
? null
: SocialLinksModel.fromJson(
json['social_links'] as Map<String, dynamic>),
photos: (json['cert_photos'] as List<dynamic>?)
?.map((e) => e as String)
.toList(),
certificates: (json['completed_courses'] as List<dynamic>?)
?.map((e) => CertificatesModel.fromJson(e as Map<String, dynamic>))
.toList(),
);
Map<String, dynamic> _$$ConsultantProfileModelImplToJson(
_$ConsultantProfileModelImpl instance) =>
<String, dynamic>{
'has_medical_education': instance.hasMedicalEducation,
'social_links': instance.socialLinks,
'cert_photos': instance.photos,
'completed_courses': instance.certificates,
};
_$SocialLinksModelImpl _$$SocialLinksModelImplFromJson(
Map<String, dynamic> 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<String, dynamic> _$$SocialLinksModelImplToJson(
_$SocialLinksModelImpl instance) =>
<String, dynamic>{
'vk_link': instance.vkLink,
'tg_link': instance.tgLink,
'fb_link': instance.fbLink,
'insta_link': instance.instaLink,
'personal_site_link': instance.personalSiteLink,
};
_$CertificatesModelImpl _$$CertificatesModelImplFromJson(
Map<String, dynamic> json) =>
_$CertificatesModelImpl(
title: json['title'] as String,
date: json['date'] as String,
);
Map<String, dynamic> _$$CertificatesModelImplToJson(
_$CertificatesModelImpl instance) =>
<String, dynamic>{
'title': instance.title,
'date': instance.date,
};

View File

@@ -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<RegisterConsultantState> {
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<File> files) async {
await consultantRepository.uploadPhotos(files: files);
}
}

View File

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

View File

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

View File

@@ -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<AdditionalSettingsScreen> createState() => _AdditionalSettingsScreenState();
}
class _AdditionalSettingsScreenState extends State<AdditionalSettingsScreen> {
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),
),
),
);
}
}

View File

@@ -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<BecomeConsultantScreen> createState() => _BecomeConsultantScreenState();
}
class _BecomeConsultantScreenState extends State<BecomeConsultantScreen> {
@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,
),
),
),
),
);
}
}

View File

@@ -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<CertificatesAndDiplomasScreen> createState() => _CertificatesAndDiplomasScreenState();
}
class _CertificatesAndDiplomasScreenState extends State<CertificatesAndDiplomasScreen> {
final scrollController = ScrollController();
List<DiplomaEntity> 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<void>(
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;
});
}
}
}

View File

@@ -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<LastStepScreen> createState() => _LastStepScreenState();
}
class _LastStepScreenState extends State<LastStepScreen> {
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),
),
);
}
}

View File

@@ -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<PhotoOrScansScreen> createState() => _PhotoOrScansScreenState();
}
class _PhotoOrScansScreenState extends State<PhotoOrScansScreen> {
List<XFile> 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<XFile>? 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,
),
],
),
);
}
}

View File

@@ -0,0 +1,115 @@
import 'package:flutter/material.dart';
class RegistrationAsScreen extends StatefulWidget {
const RegistrationAsScreen({super.key});
@override
State<RegistrationAsScreen> createState() => _RegistrationAsScreenState();
}
enum RegistrationAsType { Physical, SelfBusy, IP, OOO }
class _RegistrationAsScreenState extends State<RegistrationAsScreen> {
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<RegistrationAsType>(
value: RegistrationAsType.Physical,
groupValue: registrationAsType,
title: Text(
'Физического лица',
style: TextStyle(
fontSize: 18,
height: 1,
),
),
onChanged: (value) {},
contentPadding: EdgeInsets.symmetric(horizontal: 8),
),
RadioListTile<RegistrationAsType>(
value: RegistrationAsType.SelfBusy,
groupValue: registrationAsType,
title: Text(
'Самозанятого',
style: TextStyle(
fontSize: 18,
height: 1,
),
),
onChanged: null,
contentPadding: EdgeInsets.symmetric(horizontal: 8),
),
RadioListTile<RegistrationAsType>(
value: RegistrationAsType.IP,
groupValue: registrationAsType,
title: Text(
'Индивидуального предпринимателя',
style: TextStyle(
fontSize: 18,
height: 1,
),
),
onChanged: null,
contentPadding: EdgeInsets.symmetric(horizontal: 8),
),
RadioListTile<RegistrationAsType>(
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),
),
);
}
}

View File

@@ -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<SocialNetworksScreen> createState() => _SocialNetworksScreenState();
}
class _SocialNetworksScreenState extends State<SocialNetworksScreen> {
@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: 'Личный сайт',
),
),
],
),
],
),
);
}
}

View File

@@ -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<StepperBecomeConsultantScreen> createState() => _StepperBecomeConsultantScreenState();
}
class _StepperBecomeConsultantScreenState extends State<StepperBecomeConsultantScreen> {
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<double>(
duration: const Duration(milliseconds: 350),
curve: Curves.easeInOut,
tween: Tween<double>(
begin: 1 / 6,
end: progressValue,
),
builder: (context, value, _) => LinearProgressIndicator(
value: value,
borderRadius: BorderRadius.circular(16),
minHeight: 8,
backgroundColor: Colors.grey.shade100,
valueColor: AlwaysStoppedAnimation<Color>(appTheme.blueA400),
),
),
),
),
),
body: PageView(
physics: NeverScrollableScrollPhysics(),
controller: pageController,
onPageChanged: (index) {
setState(() {
step = index + 1;
progressValue = step / 6;
});
},
children: [
CertificatesAndDiplomasScreen(),
PhotoOrScansScreen(),
AdditionalSettingsScreen(),
SocialNetworksScreen(),
RegistrationAsScreen(),
LastStepScreen(),
],
),
);
}
}

View File

@@ -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<void> registerConsultant({
required ConsultantProfileModel consultant,
}) async {
try {
return await consultantService.consultantRegistration(
consultantModel: consultant.toJson(),
);
} catch (e) {
print(e);
rethrow;
}
}
Future<List<String>> uploadPhotos({
required List<File> files,
}) async {
try {
final multipartFiles = <MultipartFile>[];
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;
}
}
}

View File

@@ -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<void> consultantRegistration({
@Body() required Map<String, dynamic> consultantModel,
});
@POST('/api/consultant_request/photos/upload')
@MultiPart()
Future<List<String>> uploadPhotos({
@Part(name: 'photos[]', contentType: 'multipart/form-data') List<MultipartFile>? photos,
});
}

View File

@@ -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<void> consultantRegistration(
{required Map<String, dynamic> consultantModel}) async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
final _data = <String, dynamic>{};
_data.addAll(consultantModel);
final _options = _setStreamType<void>(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<void>(_options);
}
@override
Future<List<String>> uploadPhotos({List<MultipartFile>? photos}) async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
queryParameters.removeWhere((k, v) => v == null);
final _headers = <String, dynamic>{};
final _data = FormData();
if (photos != null) {
_data.files.addAll(photos.map((i) => MapEntry('photos[]', i)));
}
final _options = _setStreamType<List<String>>(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<List<dynamic>>(_options);
late List<String> _value;
try {
_value = _result.data!.cast<String>();
} on Object catch (e, s) {
errorLogger?.logError(e, s, _options);
rethrow;
}
return _value;
}
RequestOptions _setStreamType<T>(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();
}
}

View File

@@ -4,15 +4,60 @@ import 'package:flutter_bloc/flutter_bloc.dart';
class DietsCubit extends Cubit<DietsState> {
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()));
}
}
}
}

View File

@@ -10,7 +10,8 @@ abstract class DietsState with _$DietsState {
const factory DietsState.loading() = DietsStateLoading;
const factory DietsState.loaded({
required DietsPagination diets,
required List<Diet> dietsList,
required bool isLoading,
}) = DietsStateLoaded;
const factory DietsState.error({

View File

@@ -20,7 +20,7 @@ mixin _$DietsState {
TResult when<TResult extends Object?>(
TResult Function() $default, {
required TResult Function() loading,
required TResult Function(DietsPagination diets) loaded,
required TResult Function(List<Diet> dietsList, bool isLoading) loaded,
required TResult Function(String errorMessage) error,
}) =>
throw _privateConstructorUsedError;
@@ -28,7 +28,7 @@ mixin _$DietsState {
TResult? whenOrNull<TResult extends Object?>(
TResult? Function()? $default, {
TResult? Function()? loading,
TResult? Function(DietsPagination diets)? loaded,
TResult? Function(List<Diet> dietsList, bool isLoading)? loaded,
TResult? Function(String errorMessage)? error,
}) =>
throw _privateConstructorUsedError;
@@ -36,7 +36,7 @@ mixin _$DietsState {
TResult maybeWhen<TResult extends Object?>(
TResult Function()? $default, {
TResult Function()? loading,
TResult Function(DietsPagination diets)? loaded,
TResult Function(List<Diet> dietsList, bool isLoading)? loaded,
TResult Function(String errorMessage)? error,
required TResult orElse(),
}) =>
@@ -132,7 +132,7 @@ class _$DietsStateImpl implements _DietsState {
TResult when<TResult extends Object?>(
TResult Function() $default, {
required TResult Function() loading,
required TResult Function(DietsPagination diets) loaded,
required TResult Function(List<Diet> dietsList, bool isLoading) loaded,
required TResult Function(String errorMessage) error,
}) {
return $default();
@@ -143,7 +143,7 @@ class _$DietsStateImpl implements _DietsState {
TResult? whenOrNull<TResult extends Object?>(
TResult? Function()? $default, {
TResult? Function()? loading,
TResult? Function(DietsPagination diets)? loaded,
TResult? Function(List<Diet> dietsList, bool isLoading)? loaded,
TResult? Function(String errorMessage)? error,
}) {
return $default?.call();
@@ -154,7 +154,7 @@ class _$DietsStateImpl implements _DietsState {
TResult maybeWhen<TResult extends Object?>(
TResult Function()? $default, {
TResult Function()? loading,
TResult Function(DietsPagination diets)? loaded,
TResult Function(List<Diet> dietsList, bool isLoading)? loaded,
TResult Function(String errorMessage)? error,
required TResult orElse(),
}) {
@@ -249,7 +249,7 @@ class _$DietsStateLoadingImpl implements DietsStateLoading {
TResult when<TResult extends Object?>(
TResult Function() $default, {
required TResult Function() loading,
required TResult Function(DietsPagination diets) loaded,
required TResult Function(List<Diet> dietsList, bool isLoading) loaded,
required TResult Function(String errorMessage) error,
}) {
return loading();
@@ -260,7 +260,7 @@ class _$DietsStateLoadingImpl implements DietsStateLoading {
TResult? whenOrNull<TResult extends Object?>(
TResult? Function()? $default, {
TResult? Function()? loading,
TResult? Function(DietsPagination diets)? loaded,
TResult? Function(List<Diet> dietsList, bool isLoading)? loaded,
TResult? Function(String errorMessage)? error,
}) {
return loading?.call();
@@ -271,7 +271,7 @@ class _$DietsStateLoadingImpl implements DietsStateLoading {
TResult maybeWhen<TResult extends Object?>(
TResult Function()? $default, {
TResult Function()? loading,
TResult Function(DietsPagination diets)? loaded,
TResult Function(List<Diet> 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<Diet> 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<Diet>,
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<Diet> dietsList, required this.isLoading})
: _dietsList = dietsList;
final List<Diet> _dietsList;
@override
List<Diet> 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 extends Object?>(
TResult Function() $default, {
required TResult Function() loading,
required TResult Function(DietsPagination diets) loaded,
required TResult Function(List<Diet> 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 extends Object?>(
TResult? Function()? $default, {
TResult? Function()? loading,
TResult? Function(DietsPagination diets)? loaded,
TResult? Function(List<Diet> 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 extends Object?>(
TResult Function()? $default, {
TResult Function()? loading,
TResult Function(DietsPagination diets)? loaded,
TResult Function(List<Diet> 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<Diet> dietsList,
required final bool isLoading}) = _$DietsStateLoadedImpl;
DietsPagination get diets;
List<Diet> 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 extends Object?>(
TResult Function() $default, {
required TResult Function() loading,
required TResult Function(DietsPagination diets) loaded,
required TResult Function(List<Diet> dietsList, bool isLoading) loaded,
required TResult Function(String errorMessage) error,
}) {
return error(errorMessage);
@@ -572,7 +581,7 @@ class _$DietsStateErrorImpl implements DietsStateError {
TResult? whenOrNull<TResult extends Object?>(
TResult? Function()? $default, {
TResult? Function()? loading,
TResult? Function(DietsPagination diets)? loaded,
TResult? Function(List<Diet> dietsList, bool isLoading)? loaded,
TResult? Function(String errorMessage)? error,
}) {
return error?.call(errorMessage);
@@ -583,7 +592,7 @@ class _$DietsStateErrorImpl implements DietsStateError {
TResult maybeWhen<TResult extends Object?>(
TResult Function()? $default, {
TResult Function()? loading,
TResult Function(DietsPagination diets)? loaded,
TResult Function(List<Diet> dietsList, bool isLoading)? loaded,
TResult Function(String errorMessage)? error,
required TResult orElse(),
}) {

View File

@@ -37,7 +37,9 @@ class FeedCubit extends Cubit<FeedState> {
try {
if (currentPage < lastPage) {
print('before: $currentPage');
currentPage++;
print('after: $currentPage');
final feedBlogPosts = await feedRepository.getFeedBlogPosts(
page: currentPage,
query: _query,

View File

@@ -13,6 +13,11 @@ class RecipesCubit extends Cubit<RecipesState> {
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<RecipesState> {
}
}
RecipesCubit({
required this.feedRepository,
required this.recipeRepository,
}) : super(const RecipesState.loading());
loadNextPage() async {
if (currentPage < lastPage && !isLoading) {
isLoading = true;

View File

@@ -57,11 +57,23 @@ class _FeedScreenState extends State<FeedScreen> {
}
}
_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<FeedScreen> {
},
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<FeedScreen> {
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<FeedScreen> {
case 1:
recipesCubit.loadRecipesList(query: query);
break;
case 2:
dietsCubit.loadDiets(query: query);
break;
}
},
);
@@ -443,6 +459,9 @@ class _FeedScreenState extends State<FeedScreen> {
case 1:
recipesCubit.loadRecipesList();
break;
case 2:
dietsCubit.loadDiets(query: query);
break;
}
},
);

View File

@@ -13,20 +13,20 @@ abstract class FeedService {
@GET('/api/blogPosts/index')
Future<FeedBlogPostSettingsModel> getBlogPostList({
@Path() required int page,
@Query('page') required int page,
@Query('query_search') String? query,
});
@GET('/api/recipes/index')
Future<RecipesPagination> getRecipes({
@Path() required int page,
@Query('page') required int page,
@Query('filters[tags][tags.id][\$in][]') required List<int>? tags,
@Query('filters[title][\$contains]') required String? query,
});
@GET('/api/diets/index')
Future<DietsPagination> getDiets({
@Path() required int page,
@Query('page') required int page,
@Query('query_search') String? query,
});

View File

@@ -27,7 +27,10 @@ class _FeedService implements FeedService {
String? query,
}) async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{r'query_search': query};
final queryParameters = <String, dynamic>{
r'page': page,
r'query_search': query,
};
queryParameters.removeWhere((k, v) => v == null);
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
@@ -66,6 +69,7 @@ class _FeedService implements FeedService {
}) async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{
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 = <String, dynamic>{};
final queryParameters = <String, dynamic>{r'query_search': query};
final queryParameters = <String, dynamic>{
r'page': page,
r'query_search': query,
};
queryParameters.removeWhere((k, v) => v == null);
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;

View File

@@ -10,8 +10,9 @@ import 'package:go_router/go_router.dart';
class RegistrationCubit extends Cubit<RegistrationState> {
final RegistrationRepository registrationRepository;
RegistrationCubit({required this.registrationRepository})
: super(
RegistrationCubit({
required this.registrationRepository,
}) : super(
RegistrationState(
sheet: UserRegistrationSheet(
firstName: '',

View File

@@ -131,7 +131,7 @@ class _RegistrationScreenState extends State<RegistrationScreen> {
duration: const Duration(milliseconds: 350),
curve: Curves.easeInOut,
tween: Tween<double>(
begin: 0,
begin: 1 / 15,
end: progressValue,
),
builder: (context, value, _) => LinearProgressIndicator(

View File

@@ -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<ChangeEmailScreen> createState() => _ChangeEmailScreenState();
}
class _ChangeEmailScreenState extends State<ChangeEmailScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Смена Email-a'),
),
body: Center(
child: Text('Coming soon...'),
),
);
}
}

View File

@@ -128,13 +128,13 @@ class _OtherInfoScreenState extends State<OtherInfoScreen> {
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();
},

View File

@@ -175,6 +175,18 @@ class _SettingsScreenState extends State<SettingsScreen> {
),
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<SettingsScreen> {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 16),
child: InkWell(
onTap: () {},
onTap: () => GoRouter.of(context).pushNamed('becomeConsultantScreen'),
borderRadius: BorderRadius.circular(20),
child: Ink(
height: 52,

View File

@@ -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<dynamic> LibraryLoader();
Map<String, LibraryLoader> _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;
}

View File

@@ -22,154 +22,157 @@ class MessageLookup extends MessageLookupByLibrary {
final messages = _notInlinedMessages(_notInlinedMessages);
static Map<String, Function> _notInlinedMessages(_) => <String, Function>{
"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:")
};
}

View File

@@ -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<dynamic> args);
class MessageLookup extends MessageLookupByLibrary {
String get localeName => 'ru';
final messages = _notInlinedMessages(_notInlinedMessages);
static Map<String, Function> _notInlinedMessages(_) => <String, Function>{
"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("Ваш вес:")
};
}

File diff suppressed because it is too large Load Diff

View File

@@ -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": "гр"
}
"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"
}

100
lib/l10n/intl_ru.arb Normal file
View File

@@ -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": "гр"
}

View File

@@ -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<void> init() async {
sl.registerFactory<ChatSelectCubit>(() => ChatSelectCubit(chatRepository: sl()));
sl.registerFactory<PlansCubit>(() => PlansCubit(plansRepository: sl()));
sl.registerFactory<SettingsCubit>(() => SettingsCubit(profileRepository: sl(), settingsRepository: sl()));
sl.registerFactory<RegisterConsultantCubit>(() => RegisterConsultantCubit(consultantRepository: sl()));
// Repository
sl.registerLazySingleton<ChatRepository>(() => ChatRepository(chatService: sl()));
@@ -71,6 +75,7 @@ Future<void> init() async {
sl.registerLazySingleton<RecipeRepository>(() => RecipeRepository(recipeService: sl()));
sl.registerLazySingleton<PlansRepository>(() => PlansRepository(plansService: sl()));
sl.registerLazySingleton<SettingsRepository>(() => SettingsRepository(settingsService: sl()));
sl.registerLazySingleton<ConsultantRepository>(() => ConsultantRepository(consultantService: sl()));
// Services
sl.registerLazySingleton<ChatService>(() => ChatService(sl()));
@@ -82,6 +87,7 @@ Future<void> init() async {
sl.registerLazySingleton<RecipeService>(() => RecipeService(sl()));
sl.registerLazySingleton<PlansService>(() => PlansService(sl()));
sl.registerLazySingleton<SettingsService>(() => SettingsService(sl()));
sl.registerLazySingleton<ConsultantService>(() => ConsultantService(sl()));
// External
sl.registerLazySingleton(

View File

@@ -37,6 +37,7 @@ class AuthScreen extends StatefulWidget {
class _AuthScreenState extends State<AuthScreen> {
bool checkboxState = false;
bool hidePassword = true;
@override
Widget build(BuildContext context) {
@@ -73,9 +74,20 @@ class _AuthScreenState extends State<AuthScreen> {
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,
),
),
);
},
),

View File

@@ -81,9 +81,9 @@ class BlogPostCreateBloc extends Bloc<BlogPostCreateEvent, BlogPostCreateState>
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<Dio>().post(

View File

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

View File

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