From 070d7e1047eb48ae471fde4c20b79c79c3289735 Mon Sep 17 00:00:00 2001 From: Username1548 Date: Mon, 10 Feb 2025 21:50:13 +0700 Subject: [PATCH] fixed profile, recipeis and diets --- lib/core/app_router.dart | 8 +- lib/core/widgets/bottom_sheet_with_blur.dart | 70 +-- .../services/blog_post_service.g.dart | 101 ++-- .../calendar/services/calendar_service.g.dart | 41 +- .../services/consultant_service.g.dart | 74 ++- .../create_diet/models/create_diet_model.dart | 5 +- .../models/create_diet_model.freezed.dart | 48 +- .../presentation/create_diet_screen.dart | 143 +++--- .../presentation/cubit/create_diet_cubit.dart | 120 +++-- .../presentation/cubit/create_diet_state.dart | 7 +- .../cubit/create_diet_state.freezed.dart | 80 ++- .../presentation/diet_preview_screen.dart | 11 +- .../presentation/widgets/add_meal_widget.dart | 4 +- .../presentation/widgets/day_widget.dart | 7 +- .../widgets/diet_image_picker_widget.dart | 19 +- .../widgets/diet_type_choice_widget.dart | 3 +- .../widgets/status_drop_down_widget.dart | 21 +- .../repositories/create_diet_repository.dart | 80 +-- .../services/create_diet_service.dart | 30 +- .../services/create_diet_service.g.dart | 198 +++----- .../services/create_plan_service.g.dart | 95 ++-- .../diary/services/diary_service.g.dart | 460 +++++++----------- .../presentation/pages/about_diet_screen.dart | 11 +- .../feed/models/diets_pagination_model.dart | 43 +- .../diets_pagination_model.freezed.dart | 83 ++-- .../feed/models/diets_pagination_model.g.dart | 39 +- .../consultants_cubit/consultants_cubit.dart | 5 +- .../bloc/diets_cubit/diets_cubit.dart | 10 +- .../feed/presentation/pages/feed_screen.dart | 20 +- .../feed/presentation/widgets/diets.dart | 2 +- .../success_published_diet_bottom_sheet.dart | 54 ++ .../glossary/services/glossary_service.g.dart | 42 +- .../presentation/cubit/my_diets_cubit.dart | 58 ++- .../presentation/my_diets_screen.dart | 6 +- .../presentation/widgets/my_diet_widget.dart | 98 ++-- .../repositories/my_diets_repository.dart | 2 + .../my_diets/services/my_diets_service.dart | 5 +- .../my_diets/services/my_diets_service.g.dart | 4 +- .../profile/models/profile_model.dart | 2 +- .../profile/models/profile_model.freezed.dart | 55 ++- .../profile/models/profile_model.g.dart | 4 +- .../presentation/pages/profile_screen.dart | 28 +- .../entities/recipe_create_entity.dart | 10 +- .../recipe_create_entity.freezed.dart | 128 +++-- .../create_recipe_cubit.dart | 20 +- .../widgets/time_of_cook_widget.dart | 32 +- .../recipes/services/recipe_service.g.dart | 159 +++--- .../services/registration_service.g.dart | 94 ++-- .../presentation/pages/settings_screen.dart | 2 +- .../settings/services/settings_service.g.dart | 99 ++-- .../services/profile_service_test.dart | 2 +- 51 files changed, 1382 insertions(+), 1360 deletions(-) create mode 100644 lib/features/feed/presentation/widgets/success_published_diet_bottom_sheet.dart diff --git a/lib/core/app_router.dart b/lib/core/app_router.dart index b7239f07..646293d0 100644 --- a/lib/core/app_router.dart +++ b/lib/core/app_router.dart @@ -54,11 +54,10 @@ class AppRouter { initialLocation: '/auth-screen', navigatorKey: navigatorKey, routes: [ - GoRoute( + GoRoute( path: '/auth-screen', name: 'authScreen', redirect: (context, state) async { - // TokenStorage.removeTokenInStorage(); if (await TokenStorage.haveTokenInStorage()) { return '/my-profile-screen'; } @@ -276,7 +275,10 @@ class AppRouter { GoRoute( path: CreateDietScreen.path, name: CreateDietScreen.name, - builder: (context, state) => CreateDietScreen(), + builder: (context, state) { + final diet = state.extra as Diet?; + return CreateDietScreen(diet: diet); + }, ), GoRoute( path: DietPreviewScreen.path, diff --git a/lib/core/widgets/bottom_sheet_with_blur.dart b/lib/core/widgets/bottom_sheet_with_blur.dart index 303170c4..d6c1b61f 100644 --- a/lib/core/widgets/bottom_sheet_with_blur.dart +++ b/lib/core/widgets/bottom_sheet_with_blur.dart @@ -4,42 +4,44 @@ import 'package:eatvio_app/core/theme/theme_helper.dart'; import 'package:flutter/material.dart'; Future showBottomSheetWithBlur({ - required BuildContext context, - required Widget child, - double height = 200, - bool hasBlur = true, - bool enableDrag = true, - }) { - return showModalBottomSheet( - context: context, - isScrollControlled: true, - barrierColor: appTheme.transparentBlack, - backgroundColor: Colors.transparent, - elevation: 0, - useSafeArea: true, - enableDrag: enableDrag, - builder: (context) => GestureDetector( - behavior: HitTestBehavior.opaque, - child: BackdropFilter( - filter: ImageFilter.blur( - sigmaX: hasBlur ? 24 : 0, - sigmaY: hasBlur ? 24 : 0, - tileMode: TileMode.mirror, - ), - child: SizedBox( - child: Container( - height: height, - decoration: BoxDecoration( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(20), - topRight: Radius.circular(20), - ), - color: appTheme.whiteA700, + required BuildContext context, + required Widget child, + double height = 200, + bool hasBlur = true, + bool enableDrag = true, + bool userRootNavigator = false, +}) { + return showModalBottomSheet( + context: context, + isScrollControlled: true, + barrierColor: appTheme.transparentBlack, + backgroundColor: Colors.transparent, + useRootNavigator: userRootNavigator, + elevation: 0, + useSafeArea: true, + enableDrag: enableDrag, + builder: (context) => GestureDetector( + behavior: HitTestBehavior.opaque, + child: BackdropFilter( + filter: ImageFilter.blur( + sigmaX: hasBlur ? 24 : 0, + sigmaY: hasBlur ? 24 : 0, + tileMode: TileMode.mirror, + ), + child: SizedBox( + child: Container( + height: height, + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(20), + topRight: Radius.circular(20), ), - child: child, + color: appTheme.whiteA700, ), + child: child, ), ), ), - ); - } \ No newline at end of file + ), + ); +} diff --git a/lib/features/blog_post_create/services/blog_post_service.g.dart b/lib/features/blog_post_create/services/blog_post_service.g.dart index 33f4251a..1f338526 100644 --- a/lib/features/blog_post_create/services/blog_post_service.g.dart +++ b/lib/features/blog_post_create/services/blog_post_service.g.dart @@ -9,11 +9,7 @@ part of 'blog_post_service.dart'; // ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element,unnecessary_string_interpolations class _BlogPostService implements BlogPostService { - _BlogPostService( - this._dio, { - this.baseUrl, - this.errorLogger, - }); + _BlogPostService(this._dio, {this.baseUrl, this.errorLogger}); final Dio _dio; @@ -27,23 +23,21 @@ class _BlogPostService implements BlogPostService { final queryParameters = {}; final _headers = {}; final _data = formData; - final _options = _setStreamType(Options( - method: 'POST', - headers: _headers, - extra: _extra, - contentType: 'multipart/form-data', - ) - .compose( - _dio.options, - '/api/blogPosts/create', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + final _options = _setStreamType( + Options( + method: 'POST', + headers: _headers, + extra: _extra, + contentType: 'multipart/form-data', + ) + .compose( + _dio.options, + '/api/blogPosts/create', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); await _dio.fetch(_options); } @@ -56,23 +50,21 @@ class _BlogPostService implements BlogPostService { final queryParameters = {}; final _headers = {}; final _data = formData; - final _options = _setStreamType(Options( - method: 'POST', - headers: _headers, - extra: _extra, - contentType: 'multipart/form-data', - ) - .compose( - _dio.options, - '/api/blogPosts/update/${id}', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + final _options = _setStreamType( + Options( + method: 'POST', + headers: _headers, + extra: _extra, + contentType: 'multipart/form-data', + ) + .compose( + _dio.options, + '/api/blogPosts/update/${id}', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); await _dio.fetch(_options); } @@ -82,22 +74,16 @@ class _BlogPostService implements BlogPostService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType(Options( - method: 'POST', - headers: _headers, - extra: _extra, - ) - .compose( - _dio.options, - '/api/blogPosts/delete/${id}', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + final _options = _setStreamType( + Options(method: 'POST', headers: _headers, extra: _extra) + .compose( + _dio.options, + '/api/blogPosts/delete/${id}', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); await _dio.fetch(_options); } @@ -114,10 +100,7 @@ class _BlogPostService implements BlogPostService { return requestOptions; } - String _combineBaseUrls( - String dioBaseUrl, - String? baseUrl, - ) { + String _combineBaseUrls(String dioBaseUrl, String? baseUrl) { if (baseUrl == null || baseUrl.trim().isEmpty) { return dioBaseUrl; } diff --git a/lib/features/calendar/services/calendar_service.g.dart b/lib/features/calendar/services/calendar_service.g.dart index 787983c8..5055d002 100644 --- a/lib/features/calendar/services/calendar_service.g.dart +++ b/lib/features/calendar/services/calendar_service.g.dart @@ -9,11 +9,7 @@ part of 'calendar_service.dart'; // ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element,unnecessary_string_interpolations class _CalendarService implements CalendarService { - _CalendarService( - this._dio, { - this.baseUrl, - this.errorLogger, - }); + _CalendarService(this._dio, {this.baseUrl, this.errorLogger}); final Dio _dio; @@ -27,27 +23,23 @@ class _CalendarService implements CalendarService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType>(Options( - method: 'GET', - headers: _headers, - extra: _extra, - ) - .compose( - _dio.options, - '/api/calendar/index', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + final _options = _setStreamType>( + Options(method: 'GET', headers: _headers, extra: _extra) + .compose( + _dio.options, + '/api/calendar/index', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); final _result = await _dio.fetch>(_options); late List _value; try { _value = _result.data! - .map((dynamic i) => CalendarModel.fromJson(i as Map)) + .map( + (dynamic i) => CalendarModel.fromJson(i as Map), + ) .toList(); } on Object catch (e, s) { errorLogger?.logError(e, s, _options); @@ -69,10 +61,7 @@ class _CalendarService implements CalendarService { return requestOptions; } - String _combineBaseUrls( - String dioBaseUrl, - String? baseUrl, - ) { + String _combineBaseUrls(String dioBaseUrl, String? baseUrl) { if (baseUrl == null || baseUrl.trim().isEmpty) { return dioBaseUrl; } diff --git a/lib/features/consultant/become_consultant/services/consultant_service.g.dart b/lib/features/consultant/become_consultant/services/consultant_service.g.dart index d895b861..79dd924e 100644 --- a/lib/features/consultant/become_consultant/services/consultant_service.g.dart +++ b/lib/features/consultant/become_consultant/services/consultant_service.g.dart @@ -9,11 +9,7 @@ part of 'consultant_service.dart'; // ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element,unnecessary_string_interpolations class _ConsultantService implements ConsultantService { - _ConsultantService( - this._dio, { - this.baseUrl, - this.errorLogger, - }); + _ConsultantService(this._dio, {this.baseUrl, this.errorLogger}); final Dio _dio; @@ -22,28 +18,23 @@ class _ConsultantService implements ConsultantService { final ParseErrorLogger? errorLogger; @override - Future consultantRegistration( - {required ConsultantProfileModel consultantModel}) async { + Future consultantRegistration({ + required ConsultantProfileModel consultantModel, + }) async { final _extra = {}; final queryParameters = {}; final _headers = {}; final _data = consultantModel; - final _options = _setStreamType(Options( - method: 'POST', - headers: _headers, - extra: _extra, - ) - .compose( - _dio.options, - '/api/consultant_request/registration', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + final _options = _setStreamType( + Options(method: 'POST', headers: _headers, extra: _extra) + .compose( + _dio.options, + '/api/consultant_request/registration', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); await _dio.fetch(_options); } @@ -57,23 +48,21 @@ class _ConsultantService implements ConsultantService { if (photos != null) { _data.files.addAll(photos.map((i) => MapEntry('photos[]', i))); } - final _options = _setStreamType>(Options( - method: 'POST', - headers: _headers, - extra: _extra, - contentType: 'multipart/form-data', - ) - .compose( - _dio.options, - '/api/consultant_request/photos/upload', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + final _options = _setStreamType>( + Options( + method: 'POST', + headers: _headers, + extra: _extra, + contentType: 'multipart/form-data', + ) + .compose( + _dio.options, + '/api/consultant_request/photos/upload', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); final _result = await _dio.fetch>(_options); late List _value; try { @@ -98,10 +87,7 @@ class _ConsultantService implements ConsultantService { return requestOptions; } - String _combineBaseUrls( - String dioBaseUrl, - String? baseUrl, - ) { + String _combineBaseUrls(String dioBaseUrl, String? baseUrl) { if (baseUrl == null || baseUrl.trim().isEmpty) { return dioBaseUrl; } diff --git a/lib/features/create_diet/models/create_diet_model.dart b/lib/features/create_diet/models/create_diet_model.dart index f089ff92..84639c77 100644 --- a/lib/features/create_diet/models/create_diet_model.dart +++ b/lib/features/create_diet/models/create_diet_model.dart @@ -9,12 +9,15 @@ class CreateDietModel with _$CreateDietModel { const CreateDietModel._(); const factory CreateDietModel({ + String? imageUrl, String? name, String? details, - String? state, + DietState? state, int? duration, required Map type, XFile? image, List>>? dailySchedule, }) = _CreateDietModel; } + + diff --git a/lib/features/create_diet/models/create_diet_model.freezed.dart b/lib/features/create_diet/models/create_diet_model.freezed.dart index 199f8e49..1effb5c0 100644 --- a/lib/features/create_diet/models/create_diet_model.freezed.dart +++ b/lib/features/create_diet/models/create_diet_model.freezed.dart @@ -16,9 +16,10 @@ final _privateConstructorUsedError = UnsupportedError( /// @nodoc mixin _$CreateDietModel { + String? get imageUrl => throw _privateConstructorUsedError; String? get name => throw _privateConstructorUsedError; String? get details => throw _privateConstructorUsedError; - String? get state => throw _privateConstructorUsedError; + DietState? get state => throw _privateConstructorUsedError; int? get duration => throw _privateConstructorUsedError; Map get type => throw _privateConstructorUsedError; XFile? get image => throw _privateConstructorUsedError; @@ -39,9 +40,10 @@ abstract class $CreateDietModelCopyWith<$Res> { _$CreateDietModelCopyWithImpl<$Res, CreateDietModel>; @useResult $Res call( - {String? name, + {String? imageUrl, + String? name, String? details, - String? state, + DietState? state, int? duration, Map type, XFile? image, @@ -63,6 +65,7 @@ class _$CreateDietModelCopyWithImpl<$Res, $Val extends CreateDietModel> @pragma('vm:prefer-inline') @override $Res call({ + Object? imageUrl = freezed, Object? name = freezed, Object? details = freezed, Object? state = freezed, @@ -72,6 +75,10 @@ class _$CreateDietModelCopyWithImpl<$Res, $Val extends CreateDietModel> Object? dailySchedule = freezed, }) { return _then(_value.copyWith( + imageUrl: freezed == imageUrl + ? _value.imageUrl + : imageUrl // ignore: cast_nullable_to_non_nullable + as String?, name: freezed == name ? _value.name : name // ignore: cast_nullable_to_non_nullable @@ -83,7 +90,7 @@ class _$CreateDietModelCopyWithImpl<$Res, $Val extends CreateDietModel> state: freezed == state ? _value.state : state // ignore: cast_nullable_to_non_nullable - as String?, + as DietState?, duration: freezed == duration ? _value.duration : duration // ignore: cast_nullable_to_non_nullable @@ -113,9 +120,10 @@ abstract class _$$CreateDietModelImplCopyWith<$Res> @override @useResult $Res call( - {String? name, + {String? imageUrl, + String? name, String? details, - String? state, + DietState? state, int? duration, Map type, XFile? image, @@ -135,6 +143,7 @@ class __$$CreateDietModelImplCopyWithImpl<$Res> @pragma('vm:prefer-inline') @override $Res call({ + Object? imageUrl = freezed, Object? name = freezed, Object? details = freezed, Object? state = freezed, @@ -144,6 +153,10 @@ class __$$CreateDietModelImplCopyWithImpl<$Res> Object? dailySchedule = freezed, }) { return _then(_$CreateDietModelImpl( + imageUrl: freezed == imageUrl + ? _value.imageUrl + : imageUrl // ignore: cast_nullable_to_non_nullable + as String?, name: freezed == name ? _value.name : name // ignore: cast_nullable_to_non_nullable @@ -155,7 +168,7 @@ class __$$CreateDietModelImplCopyWithImpl<$Res> state: freezed == state ? _value.state : state // ignore: cast_nullable_to_non_nullable - as String?, + as DietState?, duration: freezed == duration ? _value.duration : duration // ignore: cast_nullable_to_non_nullable @@ -180,7 +193,8 @@ class __$$CreateDietModelImplCopyWithImpl<$Res> class _$CreateDietModelImpl extends _CreateDietModel { const _$CreateDietModelImpl( - {this.name, + {this.imageUrl, + this.name, this.details, this.state, this.duration, @@ -191,12 +205,14 @@ class _$CreateDietModelImpl extends _CreateDietModel { _dailySchedule = dailySchedule, super._(); + @override + final String? imageUrl; @override final String? name; @override final String? details; @override - final String? state; + final DietState? state; @override final int? duration; final Map _type; @@ -221,7 +237,7 @@ class _$CreateDietModelImpl extends _CreateDietModel { @override String toString() { - return 'CreateDietModel(name: $name, details: $details, state: $state, duration: $duration, type: $type, image: $image, dailySchedule: $dailySchedule)'; + return 'CreateDietModel(imageUrl: $imageUrl, name: $name, details: $details, state: $state, duration: $duration, type: $type, image: $image, dailySchedule: $dailySchedule)'; } @override @@ -229,6 +245,8 @@ class _$CreateDietModelImpl extends _CreateDietModel { return identical(this, other) || (other.runtimeType == runtimeType && other is _$CreateDietModelImpl && + (identical(other.imageUrl, imageUrl) || + other.imageUrl == imageUrl) && (identical(other.name, name) || other.name == name) && (identical(other.details, details) || other.details == details) && (identical(other.state, state) || other.state == state) && @@ -243,6 +261,7 @@ class _$CreateDietModelImpl extends _CreateDietModel { @override int get hashCode => Object.hash( runtimeType, + imageUrl, name, details, state, @@ -263,9 +282,10 @@ class _$CreateDietModelImpl extends _CreateDietModel { abstract class _CreateDietModel extends CreateDietModel { const factory _CreateDietModel( - {final String? name, + {final String? imageUrl, + final String? name, final String? details, - final String? state, + final DietState? state, final int? duration, required final Map type, final XFile? image, @@ -273,12 +293,14 @@ abstract class _CreateDietModel extends CreateDietModel { _$CreateDietModelImpl; const _CreateDietModel._() : super._(); + @override + String? get imageUrl; @override String? get name; @override String? get details; @override - String? get state; + DietState? get state; @override int? get duration; @override diff --git a/lib/features/create_diet/presentation/create_diet_screen.dart b/lib/features/create_diet/presentation/create_diet_screen.dart index 49b23577..cb1cd953 100644 --- a/lib/features/create_diet/presentation/create_diet_screen.dart +++ b/lib/features/create_diet/presentation/create_diet_screen.dart @@ -6,6 +6,7 @@ import 'package:eatvio_app/core/widgets/bottom_sheet_handler_bar.dart'; import 'package:eatvio_app/core/widgets/bottom_sheet_with_blur.dart'; import 'package:eatvio_app/core/widgets/custom_outlined_button.dart'; import 'package:eatvio_app/core/widgets/custom_text_form_field.dart'; +import 'package:eatvio_app/core/widgets/loader.dart'; import 'package:eatvio_app/core/widgets/main_background_bouble.dart'; import 'package:eatvio_app/features/create_diet/presentation/cubit/create_diet_cubit.dart'; import 'package:eatvio_app/features/create_diet/presentation/cubit/create_diet_state.dart'; @@ -16,6 +17,7 @@ import 'package:eatvio_app/features/create_diet/presentation/widgets/diet_image_ import 'package:eatvio_app/features/create_diet/presentation/widgets/error_widget.dart'; import 'package:eatvio_app/features/create_diet/presentation/widgets/status_drop_down_widget.dart'; import 'package:eatvio_app/features/create_diet/presentation/widgets/diet_type_choice_widget.dart'; +import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart'; import 'package:eatvio_app/generated/l10n.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -24,19 +26,37 @@ import 'package:go_router/go_router.dart'; class CreateDietScreen extends StatelessWidget { static const name = 'createDietScreen'; static const path = '/create-diet-screen'; - const CreateDietScreen({super.key}); - + const CreateDietScreen({super.key, this.diet}); + final Diet? diet; @override Widget build(BuildContext context) { return BlocProvider( - create: (context) => sl(), - child: const CreateDietScreenContent(), + create: (context) => sl()..setInitialData(diet), + child: CreateDietScreenContent(diet: diet), ); } } -class CreateDietScreenContent extends StatelessWidget { - const CreateDietScreenContent({super.key}); +class CreateDietScreenContent extends StatefulWidget { + CreateDietScreenContent({super.key, this.diet}); + final Diet? diet; + + @override + State createState() => _CreateDietScreenContentState(); +} + +class _CreateDietScreenContentState extends State { + final nameController = TextEditingController(); + final descriptionController = TextEditingController(); + + @override + void initState() { + super.initState(); + if (widget.diet != null) { + nameController.text = widget.diet?.name ?? ''; + descriptionController.text = widget.diet?.details ?? ''; + } + } @override Widget build(BuildContext context) { @@ -44,55 +64,12 @@ class CreateDietScreenContent extends StatelessWidget { return BlocBuilder( builder: (context, state) { if (state.published) { - WidgetsBinding.instance.addPostFrameCallback((_) { - context.pop(); - showBottomSheetWithBlur( - context: context, - child: Column( - children: [ - SizedBox( - height: 20, - ), - BottomSheetHandlerBar(), - SizedBox( - height: 20, - ), - Text( - '${state.dietData.name ?? 'Диета'}', - style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black), - ), - Text( - 'опубликованна', - style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black), - ), - SizedBox( - height: 20, - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: CustomOutlinedButton( - onPressed: () { - context.pop(); - }, - text: 'Хорошо', - height: 52, - buttonTextStyle: TextStyles.textSSemibold.copyWith(color: appTheme.whiteA700), - buttonStyle: ButtonStyle( - side: WidgetStatePropertyAll(BorderSide.none), - backgroundColor: WidgetStatePropertyAll(appTheme.blueA400), - ), - ), - ), - SizedBox( - height: 20, - ), - ], - ), - ); + Future.delayed(Duration(milliseconds: 500), () { + context.pop('${state.dietData.name ?? 'Диета'}'); }); } else if (state.drafted) { - WidgetsBinding.instance.addPostFrameCallback((_) { - context.pop(); + Future.delayed(Duration(milliseconds: 500), () { + context.pop('${state.dietData.name ?? 'Диета'}'); showBottomSheetWithBlur( context: context, child: Column( @@ -116,7 +93,7 @@ class CreateDietScreenContent extends StatelessWidget { padding: const EdgeInsets.symmetric(horizontal: 20), child: CustomOutlinedButton( onPressed: () { - context.pop(); + Navigator.of(context, rootNavigator: true).pop(); }, text: 'Хорошо', height: 52, @@ -141,7 +118,7 @@ class CreateDietScreenContent extends StatelessWidget { appBar: AppBar( centerTitle: true, title: Text( - s.create_diet, + widget.diet != null ? 'Редактирование диеты' : s.create_diet, textAlign: TextAlign.center, overflow: TextOverflow.ellipsis, softWrap: true, @@ -160,6 +137,7 @@ class CreateDietScreenContent extends StatelessWidget { SizedBox(height: 16), CustomTextFormField( hintText: s.enter_diet_name, + controller: nameController, hasError: state.dietNameError != null, onChanged: (value) { context.read().setName(value); @@ -176,6 +154,7 @@ class CreateDietScreenContent extends StatelessWidget { height: 132, child: CustomTextFormField( hasError: state.dietDescriptionError != null, + controller: descriptionController, textAlignVertical: TextAlignVertical.top, maxLines: null, minLines: null, @@ -227,30 +206,19 @@ class CreateDietScreenContent extends StatelessWidget { physics: NeverScrollableScrollPhysics(), separatorBuilder: (context, index) => SizedBox(height: 8), ), - SizedBox(height: 20), + SizedBox(height: 12), Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), child: Column( children: [ CustomOutlinedButton( - onPressed: () async { - await context.read().publishDiet(toDraft: true); - }, - text: s.to_draft, - height: 52, - buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.gray), - buttonStyle: ButtonStyle( - side: WidgetStatePropertyAll(BorderSide.none), - backgroundColor: WidgetStatePropertyAll(appTheme.dottedBorder), - ), - ), - SizedBox(height: 12), - CustomOutlinedButton( - onPressed: () async { - final diet = await context.read().getDietForPreview(); - if (diet == null) return; - GoRouter.of(context).pushNamed(DietPreviewScreen.name, extra: diet); - }, + onPressed: state.isDietPublishing + ? () {} + : () async { + final diet = await context.read().getDietForPreview(); + if (diet == null) return; + GoRouter.of(context).pushNamed(DietPreviewScreen.name, extra: diet); + }, text: s.preview, height: 52, buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.gray), @@ -260,18 +228,21 @@ class CreateDietScreenContent extends StatelessWidget { ), ), SizedBox(height: 12), - CustomOutlinedButton( - onPressed: () { - context.read().publishDiet(); - }, - text: s.publish, - height: 52, - buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700), - buttonStyle: ButtonStyle( - side: WidgetStatePropertyAll(BorderSide.none), - backgroundColor: WidgetStatePropertyAll(appTheme.blueA400), + if (state.isDietPublishing) + Loader() + else + CustomOutlinedButton( + onPressed: () { + context.read().publishDiet(); + }, + text: widget.diet != null ? s.save : s.publish, + height: 52, + buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700), + buttonStyle: ButtonStyle( + side: WidgetStatePropertyAll(BorderSide.none), + backgroundColor: WidgetStatePropertyAll(appTheme.blueA400), + ), ), - ), ], ), ), @@ -282,5 +253,5 @@ class CreateDietScreenContent extends StatelessWidget { ); }, ); - } + } } diff --git a/lib/features/create_diet/presentation/cubit/create_diet_cubit.dart b/lib/features/create_diet/presentation/cubit/create_diet_cubit.dart index 67107cea..771e2531 100644 --- a/lib/features/create_diet/presentation/cubit/create_diet_cubit.dart +++ b/lib/features/create_diet/presentation/cubit/create_diet_cubit.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'dart:io'; import 'dart:developer'; +import 'package:dio/dio.dart'; import 'package:eatvio_app/core/const.dart'; import 'package:eatvio_app/core/image_compressing/image_compress_utility.dart'; import 'package:eatvio_app/features/create_diet/presentation/cubit/create_diet_state.dart'; @@ -16,10 +17,46 @@ class CreateDietCubit extends Cubit { final CreateDietRepository createDietRepository; final ProfileRepository profileRepository; final GlossaryRepository glossaryRepository; - static const _dietStateValues = ['active', 'personal', 'draft']; + String? tempImagePath; + static const _dietStateValues = DietState.values; CreateDietCubit({required this.profileRepository, required this.createDietRepository, required this.glossaryRepository}) : super(CreateDietState.initial()); + Future setInitialData(Diet? diet) async { + if (diet == null) return; + emit(state.copyWith(isLoading: true, isDietBeingEdited: true)); + final countOfDays = diet.dailySchedule.length; + final List>> dailySchedule = List.generate(countOfDays, (index) => [[], [], [], [], []]); + + for (final dayEntry in diet.dailySchedule.entries) { + for (final mealEntry in dayEntry.value.entries) { + for (final product in mealEntry.value.values) { + dailySchedule[dayEntry.key - 1][mealEntry.key - 1].add(product); + } + } + } + + final dietStateIndex = _dietStateValues.indexOf(diet.state); + final type = Map.fromIterable(dietTypeValues, value: (element) => false); + type['meat'] = diet.type.meat ?? false; + type['veg'] = diet.type.veg ?? false; + type['carb'] = diet.type.carb ?? false; + type['light'] = diet.type.light ?? false; + emit( + state.copyWith.dietData( + dailySchedule: dailySchedule, + details: diet.details, + state: diet.state, + name: diet.name, + duration: diet.duration, + type: type, + imageUrl: baseUrl + '/storage/' + diet.image, + ), + ); + emit(state.copyWith(dietStateIndex: dietStateIndex, durationIndex: durationValues.indexOf(diet.duration))); + emit(state.copyWith(isLoading: true)); + } + void setDetails(String text) { emit(state.copyWith(dietData: state.dietData.copyWith(details: text), dietDescriptionError: null)); } @@ -82,16 +119,16 @@ class CreateDietCubit extends Cubit { return await glossaryRepository.getGlossaryListByQuery(query); } - void setImage(XFile? image) { - emit(state.copyWith(dietData: state.dietData.copyWith(image: image), dietImageError: null)); + void setImage(XFile? image, {String? imageUrl}) { + emit(state.copyWith(dietData: state.dietData.copyWith(image: image, imageUrl: imageUrl), dietImageError: null)); } void setDailySchedule(List>> dailySchedule) { emit(state.copyWith(dietData: state.dietData.copyWith(dailySchedule: dailySchedule), dietDurationError: null)); } - void setDietState(int index) { - emit(state.copyWith(dietStateIndex: index, dietData: state.dietData.copyWith(state: _dietStateValues[index]), dietStateError: null)); + void setDietState(DietState dietState, int index) { + emit(state.copyWith(dietData: state.dietData.copyWith(state: dietState), dietStateIndex: index, dietStateError: null)); } void setDietType({required String key, required bool value}) { @@ -236,12 +273,26 @@ class CreateDietCubit extends Cubit { ); } } + final dailySchedule = >>{}; + + for (final (dayIndex, day) in state.dietData.dailySchedule!.indexed) { + final mappedDay = >{}; + for (final (mealIndex, meal) in day.indexed) { + final mappedMeal = {}; + for (final (productIndex, product) in meal.indexed) { + mappedMeal[productIndex + 1] = product; + } + mappedDay[mealIndex + 1] = mappedMeal; + } + dailySchedule[dayIndex + 1] = mappedDay; + } + final diet = Diet( id: 0, name: state.dietData.name ?? '', image: imageInBase64, duration: state.dietData.duration ?? 0, - state: state.dietData.state ?? '', + state: state.dietData.state ?? DietState.active, type: DietType( meat: state.dietData.type['meat'], veg: state.dietData.type['veg'], @@ -249,7 +300,7 @@ class CreateDietCubit extends Cubit { light: state.dietData.type['light'], ), details: state.dietData.details ?? '', - dailySchedule: state.dietData.dailySchedule ?? [], + dailySchedule: dailySchedule, author: Author( authorSlug: authorProfile.slug, authorName: authorProfile.name, @@ -267,32 +318,32 @@ class CreateDietCubit extends Cubit { return diet; } - Future publishDiet({bool toDraft = false}) async { + Future publishDiet() async { + emit(state.copyWith(isDietPublishing: true)); if (!_isFromValid()) return null; try { final image = await ImageCompressUtility.compressFile(File(state.dietData.image!.path)); - final dietState = toDraft ? _dietStateValues.last : state.dietData.state; - final diet = await createDietRepository.createDiet( - name: state.dietData.name, - duration: state.dietData.duration, + final dietState = state.dietData.state!; + final dailySchedule = state.dietData.dailySchedule; + await createDietRepository.createDiet( + name: state.dietData.name ?? '', + duration: state.dietData.duration ?? 7, state: dietState, image: image, meatType: state.dietData.type['meat'] == true ? '1' : '0', carbType: state.dietData.type['carb'] == true ? '1' : '0', vegType: state.dietData.type['veg'] == true ? '1' : '0', lightType: state.dietData.type['light'] == true ? '1' : '0', - details: state.dietData.details, + details: state.dietData.details ?? '', + dailySchedule: dailySchedule ?? [], ); - final dailySchedule = state.dietData.dailySchedule; - createDietRepository.createDietDailySchedule( - id: diet.id, - model: {'daily_schedule': dailySchedule}, - ); - emit(state.copyWith(published: !toDraft, drafted: toDraft)); + + emit(state.copyWith(published: dietState != DietState.draft, drafted: dietState == DietState.draft)); return state.dietData.name; - } catch (e, stackTrace) { + } on DioException catch (e, stackTrace) { log(e.toString(), stackTrace: stackTrace); } + emit(state.copyWith(isDietPublishing: false)); return null; } @@ -336,15 +387,11 @@ class CreateDietCubit extends Cubit { if (dailySchedule == null) { result = false; } else { - final dailyScheduleErrors = state.dailyScheduleErrors.map((element) { - return element.map((element) => element).toList(); - }).toList(); + final dailyScheduleErrors = [...state.dailyScheduleErrors]; for (final (dayIndex, day) in dailySchedule.indexed) { - for (final (mealIndex, meal) in day.indexed) { - if (meal.isEmpty) { - result = false; - dailyScheduleErrors[dayIndex][mealIndex] = 'Добавьте продукты'; - } + if (day.every((meal) => meal.isEmpty)) { + result = false; + dailyScheduleErrors[dayIndex] = 'Добавьте продукты'; } } emit(state.copyWith(dailyScheduleErrors: dailyScheduleErrors)); @@ -358,16 +405,13 @@ class CreateDietCubit extends Cubit { if (dailySchedule == null) { result = false; } else { - final dailyScheduleErrors = state.dailyScheduleErrors.map((element) { - return element.map((element) => element).toList(); - }).toList(); - for (final (mealIndex, meal) in dailySchedule[dayIndex].indexed) { - if (meal.isEmpty) { - result = false; - dailyScheduleErrors[dayIndex][mealIndex] = 'Добавьте продукты'; - } else { - dailyScheduleErrors[dayIndex][mealIndex] = ''; - } + final dailyScheduleErrors = [...state.dailyScheduleErrors]; + final day = dailySchedule[dayIndex]; + if (day.every((meal) => meal.isEmpty)) { + result = false; + dailyScheduleErrors[dayIndex] = 'Добавьте продукты'; + } else { + dailyScheduleErrors[dayIndex] = ''; } emit(state.copyWith(dailyScheduleErrors: dailyScheduleErrors)); } diff --git a/lib/features/create_diet/presentation/cubit/create_diet_state.dart b/lib/features/create_diet/presentation/cubit/create_diet_state.dart index b8b85b79..f0a6c2c6 100644 --- a/lib/features/create_diet/presentation/cubit/create_diet_state.dart +++ b/lib/features/create_diet/presentation/cubit/create_diet_state.dart @@ -9,6 +9,7 @@ part 'create_diet_state.freezed.dart'; class CreateDietState with _$CreateDietState { const factory CreateDietState({ required bool isLoading, + required bool isDietPublishing, required String? errorMessage, required CreateDietModel dietData, List>? copiedDay, @@ -17,15 +18,17 @@ class CreateDietState with _$CreateDietState { String? dietDurationError, String? dietStateError, String? dietImageError, - required List> dailyScheduleErrors, + required List dailyScheduleErrors, int? durationIndex, int? dietStateIndex, @Default(false) bool published, @Default(false) bool drafted, + @Default(false) bool isDietBeingEdited, }) = _CreateDietState; factory CreateDietState.initial() => CreateDietState( - dailyScheduleErrors: List.filled(21, ['', '', '', '', '']), + dailyScheduleErrors: List.filled(21, ''), + isDietPublishing: false, isLoading: false, errorMessage: null, dietData: CreateDietModel( diff --git a/lib/features/create_diet/presentation/cubit/create_diet_state.freezed.dart b/lib/features/create_diet/presentation/cubit/create_diet_state.freezed.dart index a49cbb70..cc266342 100644 --- a/lib/features/create_diet/presentation/cubit/create_diet_state.freezed.dart +++ b/lib/features/create_diet/presentation/cubit/create_diet_state.freezed.dart @@ -17,6 +17,7 @@ final _privateConstructorUsedError = UnsupportedError( /// @nodoc mixin _$CreateDietState { bool get isLoading => throw _privateConstructorUsedError; + bool get isDietPublishing => throw _privateConstructorUsedError; String? get errorMessage => throw _privateConstructorUsedError; CreateDietModel get dietData => throw _privateConstructorUsedError; List>? get copiedDay => @@ -26,12 +27,12 @@ mixin _$CreateDietState { String? get dietDurationError => throw _privateConstructorUsedError; String? get dietStateError => throw _privateConstructorUsedError; String? get dietImageError => throw _privateConstructorUsedError; - List> get dailyScheduleErrors => - throw _privateConstructorUsedError; + List get dailyScheduleErrors => throw _privateConstructorUsedError; int? get durationIndex => throw _privateConstructorUsedError; int? get dietStateIndex => throw _privateConstructorUsedError; bool get published => throw _privateConstructorUsedError; bool get drafted => throw _privateConstructorUsedError; + bool get isDietBeingEdited => throw _privateConstructorUsedError; /// Create a copy of CreateDietState /// with the given fields replaced by the non-null parameter values. @@ -48,6 +49,7 @@ abstract class $CreateDietStateCopyWith<$Res> { @useResult $Res call( {bool isLoading, + bool isDietPublishing, String? errorMessage, CreateDietModel dietData, List>? copiedDay, @@ -56,11 +58,12 @@ abstract class $CreateDietStateCopyWith<$Res> { String? dietDurationError, String? dietStateError, String? dietImageError, - List> dailyScheduleErrors, + List dailyScheduleErrors, int? durationIndex, int? dietStateIndex, bool published, - bool drafted}); + bool drafted, + bool isDietBeingEdited}); $CreateDietModelCopyWith<$Res> get dietData; } @@ -81,6 +84,7 @@ class _$CreateDietStateCopyWithImpl<$Res, $Val extends CreateDietState> @override $Res call({ Object? isLoading = null, + Object? isDietPublishing = null, Object? errorMessage = freezed, Object? dietData = null, Object? copiedDay = freezed, @@ -94,12 +98,17 @@ class _$CreateDietStateCopyWithImpl<$Res, $Val extends CreateDietState> Object? dietStateIndex = freezed, Object? published = null, Object? drafted = null, + Object? isDietBeingEdited = null, }) { return _then(_value.copyWith( isLoading: null == isLoading ? _value.isLoading : isLoading // ignore: cast_nullable_to_non_nullable as bool, + isDietPublishing: null == isDietPublishing + ? _value.isDietPublishing + : isDietPublishing // ignore: cast_nullable_to_non_nullable + as bool, errorMessage: freezed == errorMessage ? _value.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable @@ -135,7 +144,7 @@ class _$CreateDietStateCopyWithImpl<$Res, $Val extends CreateDietState> dailyScheduleErrors: null == dailyScheduleErrors ? _value.dailyScheduleErrors : dailyScheduleErrors // ignore: cast_nullable_to_non_nullable - as List>, + as List, durationIndex: freezed == durationIndex ? _value.durationIndex : durationIndex // ignore: cast_nullable_to_non_nullable @@ -152,6 +161,10 @@ class _$CreateDietStateCopyWithImpl<$Res, $Val extends CreateDietState> ? _value.drafted : drafted // ignore: cast_nullable_to_non_nullable as bool, + isDietBeingEdited: null == isDietBeingEdited + ? _value.isDietBeingEdited + : isDietBeingEdited // ignore: cast_nullable_to_non_nullable + as bool, ) as $Val); } @@ -176,6 +189,7 @@ abstract class _$$CreateDietStateImplCopyWith<$Res> @useResult $Res call( {bool isLoading, + bool isDietPublishing, String? errorMessage, CreateDietModel dietData, List>? copiedDay, @@ -184,11 +198,12 @@ abstract class _$$CreateDietStateImplCopyWith<$Res> String? dietDurationError, String? dietStateError, String? dietImageError, - List> dailyScheduleErrors, + List dailyScheduleErrors, int? durationIndex, int? dietStateIndex, bool published, - bool drafted}); + bool drafted, + bool isDietBeingEdited}); @override $CreateDietModelCopyWith<$Res> get dietData; @@ -208,6 +223,7 @@ class __$$CreateDietStateImplCopyWithImpl<$Res> @override $Res call({ Object? isLoading = null, + Object? isDietPublishing = null, Object? errorMessage = freezed, Object? dietData = null, Object? copiedDay = freezed, @@ -221,12 +237,17 @@ class __$$CreateDietStateImplCopyWithImpl<$Res> Object? dietStateIndex = freezed, Object? published = null, Object? drafted = null, + Object? isDietBeingEdited = null, }) { return _then(_$CreateDietStateImpl( isLoading: null == isLoading ? _value.isLoading : isLoading // ignore: cast_nullable_to_non_nullable as bool, + isDietPublishing: null == isDietPublishing + ? _value.isDietPublishing + : isDietPublishing // ignore: cast_nullable_to_non_nullable + as bool, errorMessage: freezed == errorMessage ? _value.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable @@ -262,7 +283,7 @@ class __$$CreateDietStateImplCopyWithImpl<$Res> dailyScheduleErrors: null == dailyScheduleErrors ? _value._dailyScheduleErrors : dailyScheduleErrors // ignore: cast_nullable_to_non_nullable - as List>, + as List, durationIndex: freezed == durationIndex ? _value.durationIndex : durationIndex // ignore: cast_nullable_to_non_nullable @@ -279,6 +300,10 @@ class __$$CreateDietStateImplCopyWithImpl<$Res> ? _value.drafted : drafted // ignore: cast_nullable_to_non_nullable as bool, + isDietBeingEdited: null == isDietBeingEdited + ? _value.isDietBeingEdited + : isDietBeingEdited // ignore: cast_nullable_to_non_nullable + as bool, )); } } @@ -288,6 +313,7 @@ class __$$CreateDietStateImplCopyWithImpl<$Res> class _$CreateDietStateImpl implements _CreateDietState { const _$CreateDietStateImpl( {required this.isLoading, + required this.isDietPublishing, required this.errorMessage, required this.dietData, final List>? copiedDay, @@ -296,17 +322,20 @@ class _$CreateDietStateImpl implements _CreateDietState { this.dietDurationError, this.dietStateError, this.dietImageError, - required final List> dailyScheduleErrors, + required final List dailyScheduleErrors, this.durationIndex, this.dietStateIndex, this.published = false, - this.drafted = false}) + this.drafted = false, + this.isDietBeingEdited = false}) : _copiedDay = copiedDay, _dailyScheduleErrors = dailyScheduleErrors; @override final bool isLoading; @override + final bool isDietPublishing; + @override final String? errorMessage; @override final CreateDietModel dietData; @@ -330,9 +359,9 @@ class _$CreateDietStateImpl implements _CreateDietState { final String? dietStateError; @override final String? dietImageError; - final List> _dailyScheduleErrors; + final List _dailyScheduleErrors; @override - List> get dailyScheduleErrors { + List get dailyScheduleErrors { if (_dailyScheduleErrors is EqualUnmodifiableListView) return _dailyScheduleErrors; // ignore: implicit_dynamic_type @@ -349,10 +378,13 @@ class _$CreateDietStateImpl implements _CreateDietState { @override @JsonKey() final bool drafted; + @override + @JsonKey() + final bool isDietBeingEdited; @override String toString() { - return 'CreateDietState(isLoading: $isLoading, errorMessage: $errorMessage, dietData: $dietData, copiedDay: $copiedDay, dietNameError: $dietNameError, dietDescriptionError: $dietDescriptionError, dietDurationError: $dietDurationError, dietStateError: $dietStateError, dietImageError: $dietImageError, dailyScheduleErrors: $dailyScheduleErrors, durationIndex: $durationIndex, dietStateIndex: $dietStateIndex, published: $published, drafted: $drafted)'; + return 'CreateDietState(isLoading: $isLoading, isDietPublishing: $isDietPublishing, errorMessage: $errorMessage, dietData: $dietData, copiedDay: $copiedDay, dietNameError: $dietNameError, dietDescriptionError: $dietDescriptionError, dietDurationError: $dietDurationError, dietStateError: $dietStateError, dietImageError: $dietImageError, dailyScheduleErrors: $dailyScheduleErrors, durationIndex: $durationIndex, dietStateIndex: $dietStateIndex, published: $published, drafted: $drafted, isDietBeingEdited: $isDietBeingEdited)'; } @override @@ -362,6 +394,8 @@ class _$CreateDietStateImpl implements _CreateDietState { other is _$CreateDietStateImpl && (identical(other.isLoading, isLoading) || other.isLoading == isLoading) && + (identical(other.isDietPublishing, isDietPublishing) || + other.isDietPublishing == isDietPublishing) && (identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage) && (identical(other.dietData, dietData) || @@ -386,13 +420,16 @@ class _$CreateDietStateImpl implements _CreateDietState { other.dietStateIndex == dietStateIndex) && (identical(other.published, published) || other.published == published) && - (identical(other.drafted, drafted) || other.drafted == drafted)); + (identical(other.drafted, drafted) || other.drafted == drafted) && + (identical(other.isDietBeingEdited, isDietBeingEdited) || + other.isDietBeingEdited == isDietBeingEdited)); } @override int get hashCode => Object.hash( runtimeType, isLoading, + isDietPublishing, errorMessage, dietData, const DeepCollectionEquality().hash(_copiedDay), @@ -405,7 +442,8 @@ class _$CreateDietStateImpl implements _CreateDietState { durationIndex, dietStateIndex, published, - drafted); + drafted, + isDietBeingEdited); /// Create a copy of CreateDietState /// with the given fields replaced by the non-null parameter values. @@ -420,6 +458,7 @@ class _$CreateDietStateImpl implements _CreateDietState { abstract class _CreateDietState implements CreateDietState { const factory _CreateDietState( {required final bool isLoading, + required final bool isDietPublishing, required final String? errorMessage, required final CreateDietModel dietData, final List>? copiedDay, @@ -428,15 +467,18 @@ abstract class _CreateDietState implements CreateDietState { final String? dietDurationError, final String? dietStateError, final String? dietImageError, - required final List> dailyScheduleErrors, + required final List dailyScheduleErrors, final int? durationIndex, final int? dietStateIndex, final bool published, - final bool drafted}) = _$CreateDietStateImpl; + final bool drafted, + final bool isDietBeingEdited}) = _$CreateDietStateImpl; @override bool get isLoading; @override + bool get isDietPublishing; + @override String? get errorMessage; @override CreateDietModel get dietData; @@ -453,7 +495,7 @@ abstract class _CreateDietState implements CreateDietState { @override String? get dietImageError; @override - List> get dailyScheduleErrors; + List get dailyScheduleErrors; @override int? get durationIndex; @override @@ -462,6 +504,8 @@ abstract class _CreateDietState implements CreateDietState { bool get published; @override bool get drafted; + @override + bool get isDietBeingEdited; /// Create a copy of CreateDietState /// with the given fields replaced by the non-null parameter values. diff --git a/lib/features/create_diet/presentation/diet_preview_screen.dart b/lib/features/create_diet/presentation/diet_preview_screen.dart index 7459be0d..879e5446 100644 --- a/lib/features/create_diet/presentation/diet_preview_screen.dart +++ b/lib/features/create_diet/presentation/diet_preview_screen.dart @@ -335,7 +335,7 @@ class _DietPreviewScreenState extends State { physics: NeverScrollableScrollPhysics(), shrinkWrap: true, itemBuilder: (context, index) { - return _dayOfPlan(widget.diet.dailySchedule[index], index, s); + return _dayOfPlan(widget.diet.dailySchedule[index] ?? {}, index, s); }, itemCount: widget.diet.dailySchedule.length, ), @@ -363,7 +363,7 @@ class _DietPreviewScreenState extends State { ); } - _dayOfPlan(List> day, int dayNumber, S s) { + _dayOfPlan(Map> day, int dayNumber, S s) { _choiceChipWidget(int index) { return ChoiceChip( selectedColor: appTheme.blueA400, @@ -431,8 +431,8 @@ class _DietPreviewScreenState extends State { ListView.builder( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), - itemBuilder: (context, index) => _daily(day[widget.selectedIndexes[dayNumber]][index], s), - itemCount: day[widget.selectedIndexes[dayNumber]].length, + itemBuilder: (context, index) => _daily(day[widget.selectedIndexes[dayNumber] + 1]?[index + 1], s), + itemCount: day[widget.selectedIndexes[dayNumber] + 1]?.length ?? 0, ), SizedBox(height: 8), ], @@ -450,7 +450,8 @@ class _DietPreviewScreenState extends State { ); } - _daily(DailySchedule daily, S s) { + _daily(DailySchedule? daily, S s) { + if (daily == null) return SizedBox.shrink(); return Padding( padding: const EdgeInsets.only(bottom: 12), child: Row( diff --git a/lib/features/create_diet/presentation/widgets/add_meal_widget.dart b/lib/features/create_diet/presentation/widgets/add_meal_widget.dart index f705adb4..c0c76b03 100644 --- a/lib/features/create_diet/presentation/widgets/add_meal_widget.dart +++ b/lib/features/create_diet/presentation/widgets/add_meal_widget.dart @@ -199,8 +199,7 @@ class _AddMealWidgetState extends State { final portion = DailySchedule( dailyNutrition: DailyNutrition(energy: calories, proteins: proteins, fats: fats, carbohydrates: carbohydrates), quantity: int.parse(quantityController.text), - name: glossary.name, - uniq: '', + name: glossary.name, productNutritionalValueId: glossary.id.toString(), portion: measurementUnits, ); @@ -240,7 +239,6 @@ class _AddMealWidgetState extends State { dailyNutrition: DailyNutrition(energy: calories, proteins: proteins, fats: fats, carbohydrates: carbohydrates), quantity: int.parse(quantityController.text), name: newGlossary.name, - uniq: '', productNutritionalValueId: newGlossary.id.toString(), portion: measurementUnits, ); diff --git a/lib/features/create_diet/presentation/widgets/day_widget.dart b/lib/features/create_diet/presentation/widgets/day_widget.dart index ba97708d..8ca5cc11 100644 --- a/lib/features/create_diet/presentation/widgets/day_widget.dart +++ b/lib/features/create_diet/presentation/widgets/day_widget.dart @@ -35,7 +35,7 @@ class _DayWidgetState extends State { return BlocBuilder( builder: (context, state) { return MainBackgroundBouble( - hasError: state.dailyScheduleErrors[widget.index].where((element) => element.isNotEmpty).isNotEmpty, + hasError: state.dailyScheduleErrors[widget.index].isNotEmpty, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -216,16 +216,15 @@ class _DayWidgetState extends State { ), ], ), - if (state.dailyScheduleErrors[widget.index][_selectedMealIndex].isNotEmpty) ...[ + if (state.dailyScheduleErrors[widget.index].isNotEmpty) ...[ SizedBox(height: 12), - CustomErrorWidget(error: state.dailyScheduleErrors[widget.index][_selectedMealIndex]), + CustomErrorWidget(error: state.dailyScheduleErrors[widget.index]), ], SizedBox(height: 20), ], ), ), BlocBuilder( - buildWhen: (previous, current) => previous.dietData.dailySchedule != current.dietData.dailySchedule, builder: (context, state) { if (state.dietData.dailySchedule != null) { final day = state.dietData.dailySchedule?[widget.index]; diff --git a/lib/features/create_diet/presentation/widgets/diet_image_picker_widget.dart b/lib/features/create_diet/presentation/widgets/diet_image_picker_widget.dart index 0e195a09..c15c70b6 100644 --- a/lib/features/create_diet/presentation/widgets/diet_image_picker_widget.dart +++ b/lib/features/create_diet/presentation/widgets/diet_image_picker_widget.dart @@ -71,6 +71,8 @@ class _DietImagePickerWidgetState extends State { final s = S.of(context); return BlocBuilder( builder: (context, state) { + final hasImage = state.dietData.image != null || state.dietData.imageUrl != null; + final hasFile = state.dietData.image != null; return Column( children: [ GestureDetector( @@ -81,17 +83,26 @@ class _DietImagePickerWidgetState extends State { height: 240, decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), - image: state.dietData.image != null ? DecorationImage(fit: BoxFit.cover, image: FileImage(File(state.dietData.image?.path ?? ''))) : null, + image: hasImage + ? DecorationImage( + fit: BoxFit.cover, + image: (hasFile + ? FileImage( + File(state.dietData.image?.path ?? ''), + ) + : NetworkImage(state.dietData.imageUrl ?? '')) as ImageProvider, + ) + : null, color: appTheme.gray50, ), width: MediaQuery.sizeOf(context).width, - padding: state.dietData.image != null ? null : EdgeInsets.all(8), - child: state.dietData.image != null + padding: hasImage ? null : EdgeInsets.all(8), + child: hasImage ? Padding( padding: const EdgeInsets.only(top: 6, right: 6), child: GestureDetector( onTap: () { - context.read().setImage(null); + context.read().setImage(null, imageUrl: null); }, child: Align( alignment: Alignment.topRight, diff --git a/lib/features/create_diet/presentation/widgets/diet_type_choice_widget.dart b/lib/features/create_diet/presentation/widgets/diet_type_choice_widget.dart index 184f43bd..112ddbad 100644 --- a/lib/features/create_diet/presentation/widgets/diet_type_choice_widget.dart +++ b/lib/features/create_diet/presentation/widgets/diet_type_choice_widget.dart @@ -18,8 +18,7 @@ class DietTypeChoiceWidget extends StatefulWidget { class _DietTypeChoiceWidgetState extends State { final List<(String, String)> choiceContent = []; @override - void didChangeDependencies() { - // const List typeValues = ['veg', 'light', 'carb', 'meat']; + void didChangeDependencies() { super.didChangeDependencies(); final s = S.of(context); if (choiceContent.isEmpty) { diff --git a/lib/features/create_diet/presentation/widgets/status_drop_down_widget.dart b/lib/features/create_diet/presentation/widgets/status_drop_down_widget.dart index 47443b58..b178eccd 100644 --- a/lib/features/create_diet/presentation/widgets/status_drop_down_widget.dart +++ b/lib/features/create_diet/presentation/widgets/status_drop_down_widget.dart @@ -4,6 +4,7 @@ import 'package:eatvio_app/features/create_diet/presentation/cubit/create_diet_c import 'package:eatvio_app/features/create_diet/presentation/cubit/create_diet_state.dart'; import 'package:eatvio_app/core/widgets/custom_drop_down_button.dart'; import 'package:eatvio_app/features/create_diet/presentation/widgets/error_widget.dart'; +import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart'; import 'package:eatvio_app/generated/l10n.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -18,14 +19,23 @@ class StatusDropDownWidget extends StatefulWidget { class _StatusDropDownWidgetState extends State { final List dietStateTitles = []; + late final List dietStates = DietState.values; @override void didChangeDependencies() { super.didChangeDependencies(); final s = S.of(context); if (dietStateTitles.isEmpty) { - dietStateTitles.add(s.active_diet_state); - dietStateTitles.add(s.personal_diet_state); + dietStates.forEach((elem) { + switch (elem) { + case DietState.active: + dietStateTitles.add(s.active_diet_state); + case DietState.draft: + dietStateTitles.add(s.draft); + case DietState.personal: + dietStateTitles.add(s.personal_diet_state); + } + }); } } @@ -45,7 +55,8 @@ class _StatusDropDownWidgetState extends State { ), onChanged: (value) { if (value != null) { - context.read().setDietState(dietStateTitles.indexOf(value)); + final index = dietStates.indexOf(value); + context.read().setDietState(value, index); } }, items: dietStateTitles @@ -55,11 +66,11 @@ class _StatusDropDownWidgetState extends State { dietStateTitles[index], style: TextStyles.textMMedium.copyWith(color: appTheme.black), ), - value: dietStateTitles[index], + value: dietStates[index], ), ) .toList(), - value: state.dietStateIndex == null ? null : dietStateTitles[state.dietStateIndex ?? 0], + value: state.dietStateIndex == null ? null : dietStates[state.dietStateIndex ?? 0], ), if (state.dietStateError != null) ...[ SizedBox( diff --git a/lib/features/create_diet/repositories/create_diet_repository.dart b/lib/features/create_diet/repositories/create_diet_repository.dart index 1dbed20d..ba9a6fa4 100644 --- a/lib/features/create_diet/repositories/create_diet_repository.dart +++ b/lib/features/create_diet/repositories/create_diet_repository.dart @@ -1,5 +1,5 @@ import 'dart:io'; - +import 'package:dio/dio.dart'; import 'package:eatvio_app/features/create_diet/services/create_diet_service.dart'; import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart'; @@ -8,40 +8,54 @@ class CreateDietRepository { CreateDietRepository({required this.createDietService}); Future createDiet({ - String? name, - int? duration, - String? state, - String? meatType, - String? carbType, - String? vegType, - String? lightType, - String? details, - File? image, + required String name, + required int duration, + required DietState state, + required String meatType, + required String carbType, + required String vegType, + required String lightType, + required String details, + required File image, + required List>> dailySchedule, }) { - return createDietService.createDiet( - name: name, - duration: duration, - state: state, - meatType: meatType, - carbType: carbType, - vegType: vegType, - lightType: lightType, - details: details, - image: image, - ); - } + final dietMap = {}; + for (final (dayIndex, day) in dailySchedule.indexed) { + for (final (mealIndex, meal) in day.indexed) { + for (final (productIndex, product) in meal.indexed) { + final jsonProduct = product.toJson(); + dietMap.addAll({ + 'daily_schedule[${dayIndex + 1}][${mealIndex + 1}][${productIndex}][name]': jsonProduct['name'], + 'daily_schedule[${dayIndex + 1}][${mealIndex + 1}][${productIndex}][portion]': jsonProduct['portion'], + 'daily_schedule[${dayIndex + 1}][${mealIndex + 1}][${productIndex}][quantity]': jsonProduct['quantity'], + 'daily_schedule[${dayIndex + 1}][${mealIndex + 1}][${productIndex}][product_nutritional_value_id]': jsonProduct['product_nutritional_value_id'], + }); + } + } + } - Future createDietDailySchedule({ - required int id, - required Map model, - }) { - try { - return createDietService.createDietDailySchedule( - id: id, - model: model, - ); - } catch (e) { - rethrow; + dietMap.addAll({ + 'name': name, + 'details': details, + 'duration': duration, + 'type[meat]': meatType, + 'type[carb]': carbType, + 'type[veg]': vegType, + 'type[light]': lightType, + 'image': MultipartFile.fromFileSync( + image.path, + filename: image.path.split(Platform.pathSeparator).last, + ), + }); + + final formData = FormData.fromMap(dietMap); + switch (state) { + case DietState.active: + return createDietService.createPublishedDiet(formData: formData); + case DietState.draft: + return createDietService.createDraftedDiet(formData: formData); + case DietState.personal: + return createDietService.createPersonalDiet(formData: formData); } } } diff --git a/lib/features/create_diet/services/create_diet_service.dart b/lib/features/create_diet/services/create_diet_service.dart index 07432e3a..471681ee 100644 --- a/lib/features/create_diet/services/create_diet_service.dart +++ b/lib/features/create_diet/services/create_diet_service.dart @@ -1,5 +1,3 @@ -import 'dart:io'; - import 'package:dio/dio.dart'; import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart'; import 'package:retrofit/retrofit.dart'; @@ -10,23 +8,21 @@ part 'create_diet_service.g.dart'; abstract class CreateDietService { factory CreateDietService(Dio dio, {String baseUrl}) = _CreateDietService; - @POST('/api/diets/create') + @POST('/api/diets/create/published') @MultiPart() - Future createDiet({ - @Part(name: 'name') String? name, - @Part(name: 'duration') int? duration, - @Part(name: 'state') String? state, - @Part(name: 'type[meat]') String? meatType, - @Part(name: 'type[carb]') String? carbType, - @Part(name: 'type[veg]') String? vegType, - @Part(name: 'type[light]') String? lightType, - @Part(name: 'details') String? details, - @Part(name: 'image') File? image, + Future createPublishedDiet({ + @Body() required FormData formData, }); - @POST('/api/diets/create/{id}/daily_schedule') - Future createDietDailySchedule({ - @Path() required int id, - @Body() required Map model, + @POST('/api/diets/create/drafted') + @MultiPart() + Future createDraftedDiet({ + @Body() required FormData formData, + }); + + @POST('/api/diets/create/personalized') + @MultiPart() + Future createPersonalDiet({ + @Body() required FormData formData, }); } diff --git a/lib/features/create_diet/services/create_diet_service.g.dart b/lib/features/create_diet/services/create_diet_service.g.dart index 0c5a4606..8d039872 100644 --- a/lib/features/create_diet/services/create_diet_service.g.dart +++ b/lib/features/create_diet/services/create_diet_service.g.dart @@ -9,11 +9,7 @@ part of 'create_diet_service.dart'; // ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element,unnecessary_string_interpolations class _CreateDietService implements CreateDietService { - _CreateDietService( - this._dio, { - this.baseUrl, - this.errorLogger, - }); + _CreateDietService(this._dio, {this.baseUrl, this.errorLogger}); final Dio _dio; @@ -22,98 +18,26 @@ class _CreateDietService implements CreateDietService { final ParseErrorLogger? errorLogger; @override - Future createDiet({ - String? name, - int? duration, - String? state, - String? meatType, - String? carbType, - String? vegType, - String? lightType, - String? details, - File? image, - }) async { + Future createPublishedDiet({required FormData formData}) async { final _extra = {}; final queryParameters = {}; - queryParameters.removeWhere((k, v) => v == null); final _headers = {}; - final _data = FormData(); - if (name != null) { - _data.fields.add(MapEntry( - 'name', - name, - )); - } - if (duration != null) { - _data.fields.add(MapEntry( - 'duration', - duration.toString(), - )); - } - if (state != null) { - _data.fields.add(MapEntry( - 'state', - state, - )); - } - if (meatType != null) { - _data.fields.add(MapEntry( - 'type[meat]', - meatType, - )); - } - if (carbType != null) { - _data.fields.add(MapEntry( - 'type[carb]', - carbType, - )); - } - if (vegType != null) { - _data.fields.add(MapEntry( - 'type[veg]', - vegType, - )); - } - if (lightType != null) { - _data.fields.add(MapEntry( - 'type[light]', - lightType, - )); - } - if (details != null) { - _data.fields.add(MapEntry( - 'details', - details, - )); - } - if (image != null) { - if (image != null) { - _data.files.add(MapEntry( - 'image', - MultipartFile.fromFileSync( - image.path, - filename: image.path.split(Platform.pathSeparator).last, - ), - )); - } - } - final _options = _setStreamType(Options( - method: 'POST', - headers: _headers, - extra: _extra, - contentType: 'multipart/form-data', - ) - .compose( - _dio.options, - '/api/diets/create', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + final _data = formData; + final _options = _setStreamType( + Options( + method: 'POST', + headers: _headers, + extra: _extra, + contentType: 'multipart/form-data', + ) + .compose( + _dio.options, + '/api/diets/create/published', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); final _result = await _dio.fetch>(_options); late CreatedDiet _value; try { @@ -126,32 +50,67 @@ class _CreateDietService implements CreateDietService { } @override - Future createDietDailySchedule({ - required int id, - required Map model, - }) async { + Future createDraftedDiet({required FormData formData}) async { final _extra = {}; final queryParameters = {}; final _headers = {}; - final _data = {}; - _data.addAll(model); - final _options = _setStreamType(Options( - method: 'POST', - headers: _headers, - extra: _extra, - ) - .compose( - _dio.options, - '/api/diets/create/${id}/daily_schedule', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); - await _dio.fetch(_options); + final _data = formData; + final _options = _setStreamType( + Options( + method: 'POST', + headers: _headers, + extra: _extra, + contentType: 'multipart/form-data', + ) + .compose( + _dio.options, + '/api/diets/create/drafted', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); + final _result = await _dio.fetch>(_options); + late CreatedDiet _value; + try { + _value = CreatedDiet.fromJson(_result.data!); + } on Object catch (e, s) { + errorLogger?.logError(e, s, _options); + rethrow; + } + return _value; + } + + @override + Future createPersonalDiet({required FormData formData}) async { + final _extra = {}; + final queryParameters = {}; + final _headers = {}; + final _data = formData; + final _options = _setStreamType( + Options( + method: 'POST', + headers: _headers, + extra: _extra, + contentType: 'multipart/form-data', + ) + .compose( + _dio.options, + '/api/diets/create/personalized', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); + final _result = await _dio.fetch>(_options); + late CreatedDiet _value; + try { + _value = CreatedDiet.fromJson(_result.data!); + } on Object catch (e, s) { + errorLogger?.logError(e, s, _options); + rethrow; + } + return _value; } RequestOptions _setStreamType(RequestOptions requestOptions) { @@ -167,10 +126,7 @@ class _CreateDietService implements CreateDietService { return requestOptions; } - String _combineBaseUrls( - String dioBaseUrl, - String? baseUrl, - ) { + String _combineBaseUrls(String dioBaseUrl, String? baseUrl) { if (baseUrl == null || baseUrl.trim().isEmpty) { return dioBaseUrl; } diff --git a/lib/features/create_plan/services/create_plan_service.g.dart b/lib/features/create_plan/services/create_plan_service.g.dart index af44f549..c93251e7 100644 --- a/lib/features/create_plan/services/create_plan_service.g.dart +++ b/lib/features/create_plan/services/create_plan_service.g.dart @@ -9,11 +9,7 @@ part of 'create_plan_service.dart'; // ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element,unnecessary_string_interpolations class _CreatePlanService implements CreatePlanService { - _CreatePlanService( - this._dio, { - this.baseUrl, - this.errorLogger, - }); + _CreatePlanService(this._dio, {this.baseUrl, this.errorLogger}); final Dio _dio; @@ -28,23 +24,21 @@ class _CreatePlanService implements CreatePlanService { final _headers = {}; final _data = {}; _data.addAll(model); - final _options = _setStreamType(Options( - method: 'POST', - headers: _headers, - extra: _extra, - contentType: 'multipart/form-data', - ) - .compose( - _dio.options, - '/api/plans/create', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + final _options = _setStreamType( + Options( + method: 'POST', + headers: _headers, + extra: _extra, + contentType: 'multipart/form-data', + ) + .compose( + _dio.options, + '/api/plans/create', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); await _dio.fetch(_options); } @@ -58,22 +52,16 @@ class _CreatePlanService implements CreatePlanService { final _headers = {}; final _data = {}; _data.addAll(model); - final _options = _setStreamType(Options( - method: 'POST', - headers: _headers, - extra: _extra, - ) - .compose( - _dio.options, - '/api/plans/create/${slug}/packet_option', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + final _options = _setStreamType( + Options(method: 'POST', headers: _headers, extra: _extra) + .compose( + _dio.options, + '/api/plans/create/${slug}/packet_option', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); await _dio.fetch(_options); } @@ -87,22 +75,16 @@ class _CreatePlanService implements CreatePlanService { final _headers = {}; final _data = {}; _data.addAll(model); - final _options = _setStreamType(Options( - method: 'POST', - headers: _headers, - extra: _extra, - ) - .compose( - _dio.options, - '/api/plans/create/${slug}/packet_options', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + final _options = _setStreamType( + Options(method: 'POST', headers: _headers, extra: _extra) + .compose( + _dio.options, + '/api/plans/create/${slug}/packet_options', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); await _dio.fetch(_options); } @@ -119,10 +101,7 @@ class _CreatePlanService implements CreatePlanService { return requestOptions; } - String _combineBaseUrls( - String dioBaseUrl, - String? baseUrl, - ) { + String _combineBaseUrls(String dioBaseUrl, String? baseUrl) { if (baseUrl == null || baseUrl.trim().isEmpty) { return dioBaseUrl; } diff --git a/lib/features/diary/services/diary_service.g.dart b/lib/features/diary/services/diary_service.g.dart index 4544f6bf..c7b3820f 100644 --- a/lib/features/diary/services/diary_service.g.dart +++ b/lib/features/diary/services/diary_service.g.dart @@ -9,11 +9,7 @@ part of 'diary_service.dart'; // ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element,unnecessary_string_interpolations class _DiaryService implements DiaryService { - _DiaryService( - this._dio, { - this.baseUrl, - this.errorLogger, - }); + _DiaryService(this._dio, {this.baseUrl, this.errorLogger}); final Dio _dio; @@ -22,33 +18,30 @@ class _DiaryService implements DiaryService { final ParseErrorLogger? errorLogger; @override - Future> getDiaryIndexByDate( - {required String date}) async { + Future> getDiaryIndexByDate({ + required String date, + }) async { final _extra = {}; final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType>(Options( - method: 'GET', - headers: _headers, - extra: _extra, - ) - .compose( - _dio.options, - '/api/diary/index/${date}', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + final _options = _setStreamType>( + Options(method: 'GET', headers: _headers, extra: _extra) + .compose( + _dio.options, + '/api/diary/index/${date}', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); final _result = await _dio.fetch>(_options); late List _value; try { _value = _result.data! - .map((dynamic i) => DiaryDayModel.fromJson(i as Map)) + .map( + (dynamic i) => DiaryDayModel.fromJson(i as Map), + ) .toList(); } on Object catch (e, s) { errorLogger?.logError(e, s, _options); @@ -63,22 +56,16 @@ class _DiaryService implements DiaryService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType(Options( - method: 'GET', - headers: _headers, - extra: _extra, - ) - .compose( - _dio.options, - '/api/diary/${diary}/show', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + final _options = _setStreamType( + Options(method: 'GET', headers: _headers, extra: _extra) + .compose( + _dio.options, + '/api/diary/${diary}/show', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); final _result = await _dio.fetch>(_options); late DiaryDayWrapperModel _value; try { @@ -96,22 +83,16 @@ class _DiaryService implements DiaryService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType(Options( - method: 'GET', - headers: _headers, - extra: _extra, - ) - .compose( - _dio.options, - '/api/diary/${diary}/dailyNutritionData', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + final _options = _setStreamType( + Options(method: 'GET', headers: _headers, extra: _extra) + .compose( + _dio.options, + '/api/diary/${diary}/dailyNutritionData', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); final _result = await _dio.fetch>(_options); late NutritionDataModel _value; try { @@ -133,30 +114,30 @@ class _DiaryService implements DiaryService { final queryParameters = {}; final _headers = {}; final _data = FormData(); - _data.files.add(MapEntry( - 'photo', - MultipartFile.fromFileSync( - photo.path, - filename: photo.path.split(Platform.pathSeparator).last, + _data.files.add( + MapEntry( + 'photo', + MultipartFile.fromFileSync( + photo.path, + filename: photo.path.split(Platform.pathSeparator).last, + ), ), - )); - final _options = _setStreamType(Options( - method: 'POST', - headers: _headers, - extra: _extra, - contentType: 'multipart/form-data', - ) - .compose( - _dio.options, - '/api/diary/${diary}/meals/${typeNo}/photo/upload', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + ); + final _options = _setStreamType( + Options( + method: 'POST', + headers: _headers, + extra: _extra, + contentType: 'multipart/form-data', + ) + .compose( + _dio.options, + '/api/diary/${diary}/meals/${typeNo}/photo/upload', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); await _dio.fetch(_options); } @@ -170,22 +151,16 @@ class _DiaryService implements DiaryService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType(Options( - method: 'DELETE', - headers: _headers, - extra: _extra, - ) - .compose( - _dio.options, - '/api/diary/${diaryId}/meals/${typeNo}/photo/${userAttachment}/delete', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + final _options = _setStreamType( + Options(method: 'DELETE', headers: _headers, extra: _extra) + .compose( + _dio.options, + '/api/diary/${diaryId}/meals/${typeNo}/photo/${userAttachment}/delete', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); await _dio.fetch(_options); } @@ -203,40 +178,27 @@ class _DiaryService implements DiaryService { queryParameters.removeWhere((k, v) => v == null); final _headers = {}; final _data = FormData(); - _data.fields.add(MapEntry( - 'product_name', - productName, - )); - _data.fields.add(MapEntry( - 'portion', - portion, - )); - _data.fields.add(MapEntry( - 'quantity', - quantity.toString(), - )); + _data.fields.add(MapEntry('product_name', productName)); + _data.fields.add(MapEntry('portion', portion)); + _data.fields.add(MapEntry('quantity', quantity.toString())); if (productNutritionalValueId != null) { - _data.fields.add(MapEntry( - 'product_nutritional_value_id', - productNutritionalValueId.toString(), - )); + _data.fields.add( + MapEntry( + 'product_nutritional_value_id', + productNutritionalValueId.toString(), + ), + ); } - final _options = _setStreamType(Options( - method: 'POST', - headers: _headers, - extra: _extra, - ) - .compose( - _dio.options, - '/api/diary/${diary}/meals/${typeNo}/portion/create', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + final _options = _setStreamType( + Options(method: 'POST', headers: _headers, extra: _extra) + .compose( + _dio.options, + '/api/diary/${diary}/meals/${typeNo}/portion/create', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); await _dio.fetch(_options); } @@ -252,22 +214,16 @@ class _DiaryService implements DiaryService { final _headers = {}; final _data = {}; _data.addAll(productInMeal); - final _options = _setStreamType(Options( - method: 'PUT', - headers: _headers, - extra: _extra, - ) - .compose( - _dio.options, - '/api/diary/${diary}/meals/${typeNo}/portions/${portionModel}/update', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + final _options = _setStreamType( + Options(method: 'PUT', headers: _headers, extra: _extra) + .compose( + _dio.options, + '/api/diary/${diary}/meals/${typeNo}/portions/${portionModel}/update', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); await _dio.fetch(_options); } @@ -281,22 +237,16 @@ class _DiaryService implements DiaryService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType(Options( - method: 'POST', - headers: _headers, - extra: _extra, - ) - .compose( - _dio.options, - '/api/diary/${diary}/meals/${typeNo}/${portionModel}/mark_eaten', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + final _options = _setStreamType( + Options(method: 'POST', headers: _headers, extra: _extra) + .compose( + _dio.options, + '/api/diary/${diary}/meals/${typeNo}/${portionModel}/mark_eaten', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); await _dio.fetch(_options); } @@ -310,22 +260,16 @@ class _DiaryService implements DiaryService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType(Options( - method: 'POST', - headers: _headers, - extra: _extra, - ) - .compose( - _dio.options, - '/api/diary/${diary}/meals/${typeNo}/${portionModel}/unmark_eaten', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + final _options = _setStreamType( + Options(method: 'POST', headers: _headers, extra: _extra) + .compose( + _dio.options, + '/api/diary/${diary}/meals/${typeNo}/${portionModel}/unmark_eaten', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); await _dio.fetch(_options); } @@ -339,22 +283,16 @@ class _DiaryService implements DiaryService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType(Options( - method: 'POST', - headers: _headers, - extra: _extra, - ) - .compose( - _dio.options, - '/api/diary/${diary}/meals/${typeNo}/portions/${portionModel}/restore', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + final _options = _setStreamType( + Options(method: 'POST', headers: _headers, extra: _extra) + .compose( + _dio.options, + '/api/diary/${diary}/meals/${typeNo}/portions/${portionModel}/restore', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); await _dio.fetch(_options); } @@ -368,22 +306,16 @@ class _DiaryService implements DiaryService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType(Options( - method: 'DELETE', - headers: _headers, - extra: _extra, - ) - .compose( - _dio.options, - '/api/diary/${diary}/meals/${typeNo}/portions/${portionModel}/delete', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + final _options = _setStreamType( + Options(method: 'DELETE', headers: _headers, extra: _extra) + .compose( + _dio.options, + '/api/diary/${diary}/meals/${typeNo}/portions/${portionModel}/delete', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); await _dio.fetch(_options); } @@ -396,22 +328,16 @@ class _DiaryService implements DiaryService { final queryParameters = {}; final _headers = {}; final _data = finishDiaryDayModel; - final _options = _setStreamType(Options( - method: 'POST', - headers: _headers, - extra: _extra, - ) - .compose( - _dio.options, - '/api/diary/${diary}/finishDay', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + final _options = _setStreamType( + Options(method: 'POST', headers: _headers, extra: _extra) + .compose( + _dio.options, + '/api/diary/${diary}/finishDay', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); await _dio.fetch(_options); } @@ -425,22 +351,16 @@ class _DiaryService implements DiaryService { final queryParameters = {}; final _headers = {}; final _data = {'satiety': satiety}; - final _options = _setStreamType(Options( - method: 'POST', - headers: _headers, - extra: _extra, - ) - .compose( - _dio.options, - '/api/diary/${diary}/meals/${typeNo}/satiety/fill', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + final _options = _setStreamType( + Options(method: 'POST', headers: _headers, extra: _extra) + .compose( + _dio.options, + '/api/diary/${diary}/meals/${typeNo}/satiety/fill', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); await _dio.fetch(_options); } @@ -454,49 +374,38 @@ class _DiaryService implements DiaryService { final queryParameters = {}; final _headers = {}; final _data = {'time': time}; - final _options = _setStreamType(Options( - method: 'POST', - headers: _headers, - extra: _extra, - ) - .compose( - _dio.options, - '/api/diary/${diary}/meals/${typeNo}/time/fill', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + final _options = _setStreamType( + Options(method: 'POST', headers: _headers, extra: _extra) + .compose( + _dio.options, + '/api/diary/${diary}/meals/${typeNo}/time/fill', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); await _dio.fetch(_options); } @override - Future sendProductToModeration( - {required Map data}) async { + Future sendProductToModeration({ + required Map data, + }) async { final _extra = {}; final queryParameters = {}; final _headers = {}; final _data = {}; _data.addAll(data); - final _options = _setStreamType(Options( - method: 'POST', - headers: _headers, - extra: _extra, - ) - .compose( - _dio.options, - '/api/diary/product_nutritional_values/sendToModeration', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + final _options = _setStreamType( + Options(method: 'POST', headers: _headers, extra: _extra) + .compose( + _dio.options, + '/api/diary/product_nutritional_values/sendToModeration', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); final _result = await _dio.fetch>(_options); late GlossaryModerationModel _value; try { @@ -521,10 +430,7 @@ class _DiaryService implements DiaryService { return requestOptions; } - String _combineBaseUrls( - String dioBaseUrl, - String? baseUrl, - ) { + String _combineBaseUrls(String dioBaseUrl, String? baseUrl) { if (baseUrl == null || baseUrl.trim().isEmpty) { return dioBaseUrl; } diff --git a/lib/features/diets/presentation/pages/about_diet_screen.dart b/lib/features/diets/presentation/pages/about_diet_screen.dart index 1c63c8f9..a701d978 100644 --- a/lib/features/diets/presentation/pages/about_diet_screen.dart +++ b/lib/features/diets/presentation/pages/about_diet_screen.dart @@ -454,7 +454,7 @@ class _AboutDietScreenState extends State { physics: NeverScrollableScrollPhysics(), shrinkWrap: true, itemBuilder: (context, index) { - return _dayOfPlan(widget.diet.dailySchedule[index], index, s); + return _dayOfPlan(widget.diet.dailySchedule[index + 1] ?? {}, index, s); }, itemCount: widget.diet.dailySchedule.length, ), @@ -500,7 +500,7 @@ class _AboutDietScreenState extends State { ); } - _dayOfPlan(List> day, int dayNumber, S s) { + _dayOfPlan(Map> day, int dayNumber, S s) { _choiceChipWidget(int index) { return ChoiceChip( selectedColor: appTheme.blueA400, @@ -568,8 +568,8 @@ class _AboutDietScreenState extends State { ListView.builder( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), - itemBuilder: (context, index) => _daily(day[widget.selectedIndexes[dayNumber]][index], s), - itemCount: day[widget.selectedIndexes[dayNumber]].length, + itemBuilder: (context, index) => _daily(day[widget.selectedIndexes[dayNumber] + 1]?[index + 1], s), + itemCount: day[widget.selectedIndexes[dayNumber] + 1]?.length ?? 0, ), SizedBox(height: 8), ], @@ -587,7 +587,8 @@ class _AboutDietScreenState extends State { ); } - _daily(DailySchedule daily, S s) { + _daily(DailySchedule? daily, S s) { + if (daily == null) return const SizedBox(); return Padding( padding: const EdgeInsets.only(bottom: 12), child: Row( diff --git a/lib/features/feed/models/diets_pagination_model.dart b/lib/features/feed/models/diets_pagination_model.dart index ba9fecf7..c67b8e07 100644 --- a/lib/features/feed/models/diets_pagination_model.dart +++ b/lib/features/feed/models/diets_pagination_model.dart @@ -23,10 +23,10 @@ class Diet with _$Diet { @JsonKey(name: "name") required String name, @JsonKey(name: "image") required String image, @JsonKey(name: "duration") required int duration, - @JsonKey(name: "state") required String state, + @JsonKey(name: "state") required DietState state, @JsonKey(name: "type") required DietType type, @JsonKey(name: "details") required String details, - @JsonKey(name: "daily_schedule") required List>> dailySchedule, + @JsonKey(name: "daily_schedule") required Map>> dailySchedule, @JsonKey(name: "author") required Author author, @JsonKey(name: "total_likes") required int totalLikes, @JsonKey(name: "total_views") required int totalViews, @@ -39,10 +39,30 @@ class Diet with _$Diet { factory Diet.fromJson(Map json) => _$DietFromJson(json); } +enum DietState { + @JsonKey(name: 'active') + active, + @JsonKey(name: 'draft') + draft, + @JsonKey(name: 'personal') + personal; + + String toString() { + switch (this) { + case DietState.active: + return 'active'; + case DietState.draft: + return 'draft'; + case DietState.personal: + return 'personal'; + } + } +} + @freezed class CreatedDiet with _$CreatedDiet { const factory CreatedDiet({ - @JsonKey(name: "id") required int id, + @JsonKey(name: "id") required int id, }) = _CreatedDiet; factory CreatedDiet.fromJson(Map json) => _$CreatedDietFromJson(json); @@ -51,9 +71,9 @@ class CreatedDiet with _$CreatedDiet { int parseDuration(dynamic duration) { if (duration is String) { return int.parse(duration); - }else { + } else { return duration; - } + } } @freezed @@ -74,9 +94,8 @@ class Author with _$Author { class DailySchedule with _$DailySchedule { const factory DailySchedule({ @JsonKey(name: "name") required String name, - @JsonKey(name: "uniq", includeToJson: false) required String uniq, @JsonKey(name: "portion") required Portion portion, - @JsonKey(name: "quantity") required int quantity, + @JsonKey(name: "quantity", fromJson: _parseQuantity) required int quantity, @JsonKey(includeToJson: false, includeFromJson: false) DailyNutrition? dailyNutrition, @JsonKey(name: 'product_nutritional_value_id', includeToJson: true, includeFromJson: false, includeIfNull: false) String? productNutritionalValueId, }) = _DailySchedule; @@ -84,8 +103,16 @@ class DailySchedule with _$DailySchedule { factory DailySchedule.fromJson(Map json) => _$DailyScheduleFromJson(json); } +int _parseQuantity(dynamic quantity) { + if (quantity is String) { + return int.parse(quantity); + } else { + return quantity; + } +} + enum Portion { - @JsonValue("grams") + @JsonValue("gr") GRAMS, @JsonValue("milliliters") MILLILITERS, diff --git a/lib/features/feed/models/diets_pagination_model.freezed.dart b/lib/features/feed/models/diets_pagination_model.freezed.dart index 37c410bc..cc185651 100644 --- a/lib/features/feed/models/diets_pagination_model.freezed.dart +++ b/lib/features/feed/models/diets_pagination_model.freezed.dart @@ -268,13 +268,13 @@ mixin _$Diet { @JsonKey(name: "duration") int get duration => throw _privateConstructorUsedError; @JsonKey(name: "state") - String get state => throw _privateConstructorUsedError; + DietState get state => throw _privateConstructorUsedError; @JsonKey(name: "type") DietType get type => throw _privateConstructorUsedError; @JsonKey(name: "details") String get details => throw _privateConstructorUsedError; @JsonKey(name: "daily_schedule") - List>> get dailySchedule => + Map>> get dailySchedule => throw _privateConstructorUsedError; @JsonKey(name: "author") Author get author => throw _privateConstructorUsedError; @@ -310,11 +310,11 @@ abstract class $DietCopyWith<$Res> { @JsonKey(name: "name") String name, @JsonKey(name: "image") String image, @JsonKey(name: "duration") int duration, - @JsonKey(name: "state") String state, + @JsonKey(name: "state") DietState state, @JsonKey(name: "type") DietType type, @JsonKey(name: "details") String details, @JsonKey(name: "daily_schedule") - List>> dailySchedule, + Map>> dailySchedule, @JsonKey(name: "author") Author author, @JsonKey(name: "total_likes") int totalLikes, @JsonKey(name: "total_views") int totalViews, @@ -378,7 +378,7 @@ class _$DietCopyWithImpl<$Res, $Val extends Diet> state: null == state ? _value.state : state // ignore: cast_nullable_to_non_nullable - as String, + as DietState, type: null == type ? _value.type : type // ignore: cast_nullable_to_non_nullable @@ -390,7 +390,7 @@ class _$DietCopyWithImpl<$Res, $Val extends Diet> dailySchedule: null == dailySchedule ? _value.dailySchedule : dailySchedule // ignore: cast_nullable_to_non_nullable - as List>>, + as Map>>, author: null == author ? _value.author : author // ignore: cast_nullable_to_non_nullable @@ -455,11 +455,11 @@ abstract class _$$DietImplCopyWith<$Res> implements $DietCopyWith<$Res> { @JsonKey(name: "name") String name, @JsonKey(name: "image") String image, @JsonKey(name: "duration") int duration, - @JsonKey(name: "state") String state, + @JsonKey(name: "state") DietState state, @JsonKey(name: "type") DietType type, @JsonKey(name: "details") String details, @JsonKey(name: "daily_schedule") - List>> dailySchedule, + Map>> dailySchedule, @JsonKey(name: "author") Author author, @JsonKey(name: "total_likes") int totalLikes, @JsonKey(name: "total_views") int totalViews, @@ -522,7 +522,7 @@ class __$$DietImplCopyWithImpl<$Res> state: null == state ? _value.state : state // ignore: cast_nullable_to_non_nullable - as String, + as DietState, type: null == type ? _value.type : type // ignore: cast_nullable_to_non_nullable @@ -534,7 +534,7 @@ class __$$DietImplCopyWithImpl<$Res> dailySchedule: null == dailySchedule ? _value._dailySchedule : dailySchedule // ignore: cast_nullable_to_non_nullable - as List>>, + as Map>>, author: null == author ? _value.author : author // ignore: cast_nullable_to_non_nullable @@ -579,7 +579,7 @@ class _$DietImpl implements _Diet { @JsonKey(name: "type") required this.type, @JsonKey(name: "details") required this.details, @JsonKey(name: "daily_schedule") - required final List>> dailySchedule, + required final Map>> dailySchedule, @JsonKey(name: "author") required this.author, @JsonKey(name: "total_likes") required this.totalLikes, @JsonKey(name: "total_views") required this.totalViews, @@ -608,20 +608,20 @@ class _$DietImpl implements _Diet { final int duration; @override @JsonKey(name: "state") - final String state; + final DietState state; @override @JsonKey(name: "type") final DietType type; @override @JsonKey(name: "details") final String details; - final List>> _dailySchedule; + final Map>> _dailySchedule; @override @JsonKey(name: "daily_schedule") - List>> get dailySchedule { - if (_dailySchedule is EqualUnmodifiableListView) return _dailySchedule; + Map>> get dailySchedule { + if (_dailySchedule is EqualUnmodifiableMapView) return _dailySchedule; // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_dailySchedule); + return EqualUnmodifiableMapView(_dailySchedule); } @override @@ -728,11 +728,11 @@ abstract class _Diet implements Diet { @JsonKey(name: "name") required final String name, @JsonKey(name: "image") required final String image, @JsonKey(name: "duration") required final int duration, - @JsonKey(name: "state") required final String state, + @JsonKey(name: "state") required final DietState state, @JsonKey(name: "type") required final DietType type, @JsonKey(name: "details") required final String details, @JsonKey(name: "daily_schedule") - required final List>> dailySchedule, + required final Map>> dailySchedule, @JsonKey(name: "author") required final Author author, @JsonKey(name: "total_likes") required final int totalLikes, @JsonKey(name: "total_views") required final int totalViews, @@ -758,7 +758,7 @@ abstract class _Diet implements Diet { int get duration; @override @JsonKey(name: "state") - String get state; + DietState get state; @override @JsonKey(name: "type") DietType get type; @@ -767,7 +767,7 @@ abstract class _Diet implements Diet { String get details; @override @JsonKey(name: "daily_schedule") - List>> get dailySchedule; + Map>> get dailySchedule; @override @JsonKey(name: "author") Author get author; @@ -1242,11 +1242,9 @@ DailySchedule _$DailyScheduleFromJson(Map json) { mixin _$DailySchedule { @JsonKey(name: "name") String get name => throw _privateConstructorUsedError; - @JsonKey(name: "uniq", includeToJson: false) - String get uniq => throw _privateConstructorUsedError; @JsonKey(name: "portion") Portion get portion => throw _privateConstructorUsedError; - @JsonKey(name: "quantity") + @JsonKey(name: "quantity", fromJson: _parseQuantity) int get quantity => throw _privateConstructorUsedError; @JsonKey(includeToJson: false, includeFromJson: false) DailyNutrition? get dailyNutrition => throw _privateConstructorUsedError; @@ -1275,9 +1273,8 @@ abstract class $DailyScheduleCopyWith<$Res> { @useResult $Res call( {@JsonKey(name: "name") String name, - @JsonKey(name: "uniq", includeToJson: false) String uniq, @JsonKey(name: "portion") Portion portion, - @JsonKey(name: "quantity") int quantity, + @JsonKey(name: "quantity", fromJson: _parseQuantity) int quantity, @JsonKey(includeToJson: false, includeFromJson: false) DailyNutrition? dailyNutrition, @JsonKey( @@ -1306,7 +1303,6 @@ class _$DailyScheduleCopyWithImpl<$Res, $Val extends DailySchedule> @override $Res call({ Object? name = null, - Object? uniq = null, Object? portion = null, Object? quantity = null, Object? dailyNutrition = freezed, @@ -1317,10 +1313,6 @@ class _$DailyScheduleCopyWithImpl<$Res, $Val extends DailySchedule> ? _value.name : name // ignore: cast_nullable_to_non_nullable as String, - uniq: null == uniq - ? _value.uniq - : uniq // ignore: cast_nullable_to_non_nullable - as String, portion: null == portion ? _value.portion : portion // ignore: cast_nullable_to_non_nullable @@ -1365,9 +1357,8 @@ abstract class _$$DailyScheduleImplCopyWith<$Res> @useResult $Res call( {@JsonKey(name: "name") String name, - @JsonKey(name: "uniq", includeToJson: false) String uniq, @JsonKey(name: "portion") Portion portion, - @JsonKey(name: "quantity") int quantity, + @JsonKey(name: "quantity", fromJson: _parseQuantity) int quantity, @JsonKey(includeToJson: false, includeFromJson: false) DailyNutrition? dailyNutrition, @JsonKey( @@ -1395,7 +1386,6 @@ class __$$DailyScheduleImplCopyWithImpl<$Res> @override $Res call({ Object? name = null, - Object? uniq = null, Object? portion = null, Object? quantity = null, Object? dailyNutrition = freezed, @@ -1406,10 +1396,6 @@ class __$$DailyScheduleImplCopyWithImpl<$Res> ? _value.name : name // ignore: cast_nullable_to_non_nullable as String, - uniq: null == uniq - ? _value.uniq - : uniq // ignore: cast_nullable_to_non_nullable - as String, portion: null == portion ? _value.portion : portion // ignore: cast_nullable_to_non_nullable @@ -1435,9 +1421,9 @@ class __$$DailyScheduleImplCopyWithImpl<$Res> class _$DailyScheduleImpl implements _DailySchedule { const _$DailyScheduleImpl( {@JsonKey(name: "name") required this.name, - @JsonKey(name: "uniq", includeToJson: false) required this.uniq, @JsonKey(name: "portion") required this.portion, - @JsonKey(name: "quantity") required this.quantity, + @JsonKey(name: "quantity", fromJson: _parseQuantity) + required this.quantity, @JsonKey(includeToJson: false, includeFromJson: false) this.dailyNutrition, @JsonKey( @@ -1454,13 +1440,10 @@ class _$DailyScheduleImpl implements _DailySchedule { @JsonKey(name: "name") final String name; @override - @JsonKey(name: "uniq", includeToJson: false) - final String uniq; - @override @JsonKey(name: "portion") final Portion portion; @override - @JsonKey(name: "quantity") + @JsonKey(name: "quantity", fromJson: _parseQuantity) final int quantity; @override @JsonKey(includeToJson: false, includeFromJson: false) @@ -1475,7 +1458,7 @@ class _$DailyScheduleImpl implements _DailySchedule { @override String toString() { - return 'DailySchedule(name: $name, uniq: $uniq, portion: $portion, quantity: $quantity, dailyNutrition: $dailyNutrition, productNutritionalValueId: $productNutritionalValueId)'; + return 'DailySchedule(name: $name, portion: $portion, quantity: $quantity, dailyNutrition: $dailyNutrition, productNutritionalValueId: $productNutritionalValueId)'; } @override @@ -1484,7 +1467,6 @@ class _$DailyScheduleImpl implements _DailySchedule { (other.runtimeType == runtimeType && other is _$DailyScheduleImpl && (identical(other.name, name) || other.name == name) && - (identical(other.uniq, uniq) || other.uniq == uniq) && (identical(other.portion, portion) || other.portion == portion) && (identical(other.quantity, quantity) || other.quantity == quantity) && @@ -1497,7 +1479,7 @@ class _$DailyScheduleImpl implements _DailySchedule { @JsonKey(includeFromJson: false, includeToJson: false) @override - int get hashCode => Object.hash(runtimeType, name, uniq, portion, quantity, + int get hashCode => Object.hash(runtimeType, name, portion, quantity, dailyNutrition, productNutritionalValueId); /// Create a copy of DailySchedule @@ -1519,9 +1501,9 @@ class _$DailyScheduleImpl implements _DailySchedule { abstract class _DailySchedule implements DailySchedule { const factory _DailySchedule( {@JsonKey(name: "name") required final String name, - @JsonKey(name: "uniq", includeToJson: false) required final String uniq, @JsonKey(name: "portion") required final Portion portion, - @JsonKey(name: "quantity") required final int quantity, + @JsonKey(name: "quantity", fromJson: _parseQuantity) + required final int quantity, @JsonKey(includeToJson: false, includeFromJson: false) final DailyNutrition? dailyNutrition, @JsonKey( @@ -1538,13 +1520,10 @@ abstract class _DailySchedule implements DailySchedule { @JsonKey(name: "name") String get name; @override - @JsonKey(name: "uniq", includeToJson: false) - String get uniq; - @override @JsonKey(name: "portion") Portion get portion; @override - @JsonKey(name: "quantity") + @JsonKey(name: "quantity", fromJson: _parseQuantity) int get quantity; @override @JsonKey(includeToJson: false, includeFromJson: false) diff --git a/lib/features/feed/models/diets_pagination_model.g.dart b/lib/features/feed/models/diets_pagination_model.g.dart index 7a54baa0..021fbfcf 100644 --- a/lib/features/feed/models/diets_pagination_model.g.dart +++ b/lib/features/feed/models/diets_pagination_model.g.dart @@ -29,16 +29,21 @@ _$DietImpl _$$DietImplFromJson(Map json) => _$DietImpl( name: json['name'] as String, image: json['image'] as String, duration: (json['duration'] as num).toInt(), - state: json['state'] as String, + state: $enumDecode(_$DietStateEnumMap, json['state']), type: DietType.fromJson(json['type'] as Map), details: json['details'] as String, - dailySchedule: (json['daily_schedule'] as List) - .map((e) => (e as List) - .map((e) => (e as List) - .map((e) => DailySchedule.fromJson(e as Map)) - .toList()) - .toList()) - .toList(), + dailySchedule: (json['daily_schedule'] as Map).map( + (k, e) => MapEntry( + int.parse(k), + (e as Map).map( + (k, e) => MapEntry( + int.parse(k), + (e as Map).map( + (k, e) => MapEntry(int.parse(k), + DailySchedule.fromJson(e as Map)), + )), + )), + ), author: Author.fromJson(json['author'] as Map), totalLikes: (json['total_likes'] as num).toInt(), totalViews: (json['total_views'] as num).toInt(), @@ -56,10 +61,13 @@ Map _$$DietImplToJson(_$DietImpl instance) => 'name': instance.name, 'image': instance.image, 'duration': instance.duration, - 'state': instance.state, + 'state': _$DietStateEnumMap[instance.state]!, 'type': instance.type, 'details': instance.details, - 'daily_schedule': instance.dailySchedule, + 'daily_schedule': instance.dailySchedule.map((k, e) => MapEntry( + k.toString(), + e.map((k, e) => MapEntry( + k.toString(), e.map((k, e) => MapEntry(k.toString(), e)))))), 'author': instance.author, 'total_likes': instance.totalLikes, 'total_views': instance.totalViews, @@ -69,6 +77,12 @@ Map _$$DietImplToJson(_$DietImpl instance) => 'daily_nutrition': instance.dailyNutrition, }; +const _$DietStateEnumMap = { + DietState.active: 'active', + DietState.draft: 'draft', + DietState.personal: 'personal', +}; + _$CreatedDietImpl _$$CreatedDietImplFromJson(Map json) => _$CreatedDietImpl( id: (json['id'] as num).toInt(), @@ -101,9 +115,8 @@ Map _$$AuthorImplToJson(_$AuthorImpl instance) => _$DailyScheduleImpl _$$DailyScheduleImplFromJson(Map json) => _$DailyScheduleImpl( name: json['name'] as String, - uniq: json['uniq'] as String, portion: $enumDecode(_$PortionEnumMap, json['portion']), - quantity: (json['quantity'] as num).toInt(), + quantity: _parseQuantity(json['quantity']), ); Map _$$DailyScheduleImplToJson(_$DailyScheduleImpl instance) => @@ -116,7 +129,7 @@ Map _$$DailyScheduleImplToJson(_$DailyScheduleImpl instance) => }; const _$PortionEnumMap = { - Portion.GRAMS: 'grams', + Portion.GRAMS: 'gr', Portion.MILLILITERS: 'milliliters', Portion.PCS: 'pcs', }; diff --git a/lib/features/feed/presentation/bloc/consultants_cubit/consultants_cubit.dart b/lib/features/feed/presentation/bloc/consultants_cubit/consultants_cubit.dart index 9b30f4cc..cf96b2a6 100644 --- a/lib/features/feed/presentation/bloc/consultants_cubit/consultants_cubit.dart +++ b/lib/features/feed/presentation/bloc/consultants_cubit/consultants_cubit.dart @@ -1,3 +1,5 @@ +import 'dart:developer'; + import 'package:eatvio_app/features/feed/presentation/bloc/consultants_cubit/consultants_state.dart'; import 'package:eatvio_app/features/feed/repositories/feed_repository.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -18,7 +20,8 @@ class ConsultantsCubit extends Cubit { isLoading: false, ), ); - } catch (e) { + } catch (e, st) { + log(e.toString(), stackTrace: st); emit(ConsultantsState.error(errorMessage: e.toString())); } } diff --git a/lib/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart b/lib/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart index 1f585375..de59de7e 100644 --- a/lib/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart +++ b/lib/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart @@ -107,9 +107,10 @@ class DietsCubit extends Cubit { errorMessage: null, ), ); - } catch (e) { + } catch (e, st) { + log(e.toString(), stackTrace: st); emit( - state.copyWith(errorMessage: e.toString()), + state.copyWith(isLoading: false), ); } } @@ -143,14 +144,13 @@ class DietsCubit extends Cubit { ); } } catch (e) { - emit(state.copyWith(errorMessage: e.toString())); + emit(state.copyWith(isLoading: false)); } } } Future likeDiet(int id, int index) async { - final currentDiets = state.dietsList; - // if (currentDiets.isEmpty) return; + final currentDiets = state.dietsList; final dietsForModification = [...currentDiets]; final currentDiet = currentDiets[index]; if (currentDiet.wasLikedByMe) { diff --git a/lib/features/feed/presentation/pages/feed_screen.dart b/lib/features/feed/presentation/pages/feed_screen.dart index 0dbe0b31..4527c0af 100644 --- a/lib/features/feed/presentation/pages/feed_screen.dart +++ b/lib/features/feed/presentation/pages/feed_screen.dart @@ -1,5 +1,6 @@ import 'package:easy_debounce/easy_debounce.dart'; import 'package:eatvio_app/core/widgets/add_item_button.dart'; +import 'package:eatvio_app/core/widgets/bottom_sheet_with_blur.dart'; import 'package:eatvio_app/core/widgets/custom_search_bar.dart'; import 'package:eatvio_app/features/create_diet/presentation/create_diet_screen.dart'; import 'package:eatvio_app/features/create_plan/presentation/create_plan_screen.dart'; @@ -14,6 +15,7 @@ import 'package:eatvio_app/features/feed/presentation/widgets/chip_group.dart'; import 'package:eatvio_app/features/feed/presentation/widgets/consultants.dart'; import 'package:eatvio_app/features/feed/presentation/widgets/diets.dart'; import 'package:eatvio_app/features/feed/presentation/widgets/plans.dart'; +import 'package:eatvio_app/features/feed/presentation/widgets/success_published_diet_bottom_sheet.dart'; import 'package:eatvio_app/features/feed/presentation/widgets/tags_modal_widget.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/plans_cubit/plans_cubit.dart'; import 'package:eatvio_app/core/locator_service.dart'; @@ -25,7 +27,6 @@ import 'package:go_router/go_router.dart'; import '../widgets/recipes.dart'; - class FeedScreen extends StatelessWidget { const FeedScreen({super.key}); @@ -260,10 +261,23 @@ class _FeedScreenContentState extends State { onTap: () => GoRouter.of(context).pushNamed(RecipeCreateScreen.name), ), 2 => AddItemButton( - onTap: state.profile?.role == 'consultant' ? () => GoRouter.of(context).pushNamed(CreateDietScreen.name) : null, + onTap: state.profile?.roles.contains('consultant') ?? false + ? () async { + final result = await GoRouter.of(context).pushNamed(CreateDietScreen.name); + if (result != null) { + showBottomSheetWithBlur( + userRootNavigator: true, + context: context, + child: SuccessPublishedDietBottomSheet( + title: result, + ), + ); + } + } + : null, ), 3 => AddItemButton( - onTap: state.profile?.role == 'consultant' ? () => GoRouter.of(context).pushNamed(CreatePlanScreen.name) : null, + onTap: state.profile?.roles.contains('consultant') ?? false ? () => GoRouter.of(context).pushNamed(CreatePlanScreen.name) : null, ), _ => AddItemButton() }, diff --git a/lib/features/feed/presentation/widgets/diets.dart b/lib/features/feed/presentation/widgets/diets.dart index 4d1ca2f3..b698065b 100644 --- a/lib/features/feed/presentation/widgets/diets.dart +++ b/lib/features/feed/presentation/widgets/diets.dart @@ -63,4 +63,4 @@ class Diets extends StatelessWidget { ), ); } -} \ No newline at end of file +} diff --git a/lib/features/feed/presentation/widgets/success_published_diet_bottom_sheet.dart b/lib/features/feed/presentation/widgets/success_published_diet_bottom_sheet.dart new file mode 100644 index 00000000..eade82c2 --- /dev/null +++ b/lib/features/feed/presentation/widgets/success_published_diet_bottom_sheet.dart @@ -0,0 +1,54 @@ +import 'package:eatvio_app/core/theme/custom_text_style.dart'; +import 'package:eatvio_app/core/theme/theme_helper.dart'; +import 'package:eatvio_app/core/widgets/bottom_sheet_handler_bar.dart'; +import 'package:eatvio_app/core/widgets/custom_outlined_button.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; + +class SuccessPublishedDietBottomSheet extends StatelessWidget { + const SuccessPublishedDietBottomSheet({super.key, required this.title}); + final String title; + @override + Widget build(BuildContext context) { + return Column( + children: [ + SizedBox( + height: 20, + ), + BottomSheetHandlerBar(), + SizedBox( + height: 20, + ), + Text( + title, + style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black), + ), + Text( + 'опубликованна', + style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black), + ), + SizedBox( + height: 20, + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: CustomOutlinedButton( + onPressed: () { + GoRouter.of(context).pop(); + }, + text: 'Хорошо', + height: 52, + buttonTextStyle: TextStyles.textSSemibold.copyWith(color: appTheme.whiteA700), + buttonStyle: ButtonStyle( + side: WidgetStatePropertyAll(BorderSide.none), + backgroundColor: WidgetStatePropertyAll(appTheme.blueA400), + ), + ), + ), + SizedBox( + height: 20, + ), + ], + ); + } +} diff --git a/lib/features/glossary/services/glossary_service.g.dart b/lib/features/glossary/services/glossary_service.g.dart index bd3a1137..cd6584f6 100644 --- a/lib/features/glossary/services/glossary_service.g.dart +++ b/lib/features/glossary/services/glossary_service.g.dart @@ -9,11 +9,7 @@ part of 'glossary_service.dart'; // ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element,unnecessary_string_interpolations class _GlossaryService implements GlossaryService { - _GlossaryService( - this._dio, { - this.baseUrl, - this.errorLogger, - }); + _GlossaryService(this._dio, {this.baseUrl, this.errorLogger}); final Dio _dio; @@ -22,28 +18,23 @@ class _GlossaryService implements GlossaryService { final ParseErrorLogger? errorLogger; @override - Future getGlossaryByQuery( - {required String query}) async { + Future getGlossaryByQuery({ + required String query, + }) async { final _extra = {}; final queryParameters = {r'search': query}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType(Options( - method: 'GET', - headers: _headers, - extra: _extra, - ) - .compose( - _dio.options, - '/api/glossaries/search', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + final _options = _setStreamType( + Options(method: 'GET', headers: _headers, extra: _extra) + .compose( + _dio.options, + '/api/glossaries/search', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); final _result = await _dio.fetch>(_options); late GlossaryPaginationModel _value; try { @@ -68,10 +59,7 @@ class _GlossaryService implements GlossaryService { return requestOptions; } - String _combineBaseUrls( - String dioBaseUrl, - String? baseUrl, - ) { + String _combineBaseUrls(String dioBaseUrl, String? baseUrl) { if (baseUrl == null || baseUrl.trim().isEmpty) { return dioBaseUrl; } diff --git a/lib/features/my_diets/presentation/cubit/my_diets_cubit.dart b/lib/features/my_diets/presentation/cubit/my_diets_cubit.dart index 7a998163..09753d80 100644 --- a/lib/features/my_diets/presentation/cubit/my_diets_cubit.dart +++ b/lib/features/my_diets/presentation/cubit/my_diets_cubit.dart @@ -1,5 +1,8 @@ +import 'dart:developer'; + import 'package:easy_debounce/easy_debounce.dart'; import 'package:eatvio_app/core/const.dart'; +import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart'; import 'package:eatvio_app/features/my_diets/presentation/cubit/my_diets_state.dart'; import 'package:eatvio_app/features/my_diets/repositories/my_diets_repository.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -28,6 +31,7 @@ class MyDietsCubit extends Cubit { 'name', 'name:desc', ]; + static const List _durationValues = [null, ...durationValues]; static const List _types = [null, ...dietTypeValues]; @@ -39,7 +43,7 @@ class MyDietsCubit extends Cubit { EasyDebounce.debounce( 'loadDiets', Duration(seconds: 1), - () => loadDiets( + () => loadCurrentDiets( query: _activeQuery, ), ); @@ -48,7 +52,7 @@ class MyDietsCubit extends Cubit { EasyDebounce.debounce( 'loadDiets', Duration(seconds: 1), - () => loadDiets( + () => loadCurrentDiets( query: _draftQuery, ), ); @@ -57,7 +61,7 @@ class MyDietsCubit extends Cubit { EasyDebounce.debounce( 'loadDiets', Duration(seconds: 1), - () => loadDiets( + () => loadCurrentDiets( query: _personalQuery, ), ); @@ -70,7 +74,7 @@ class MyDietsCubit extends Cubit { EasyDebounce.debounce( 'loadDiets', Duration(seconds: 1), - () => loadDiets( + () => loadCurrentDiets( query: _activeQuery, ), ); @@ -79,7 +83,7 @@ class MyDietsCubit extends Cubit { EasyDebounce.debounce( 'loadDiets', Duration(seconds: 1), - () => loadDiets( + () => loadCurrentDiets( query: _draftQuery, ), ); @@ -88,7 +92,7 @@ class MyDietsCubit extends Cubit { EasyDebounce.debounce( 'loadDiets', Duration(seconds: 1), - () => loadDiets( + () => loadCurrentDiets( query: _personalQuery, ), ); @@ -101,7 +105,7 @@ class MyDietsCubit extends Cubit { EasyDebounce.debounce( 'loadDiets', Duration(seconds: 1), - () => loadDiets( + () => loadCurrentDiets( query: _activeQuery, ), ); @@ -110,7 +114,7 @@ class MyDietsCubit extends Cubit { EasyDebounce.debounce( 'loadDiets', Duration(seconds: 1), - () => loadDiets( + () => loadCurrentDiets( query: _draftQuery, ), ); @@ -119,7 +123,7 @@ class MyDietsCubit extends Cubit { EasyDebounce.debounce( 'loadDiets', Duration(seconds: 1), - () => loadDiets( + () => loadCurrentDiets( query: _personalQuery, ), ); @@ -128,9 +132,34 @@ class MyDietsCubit extends Cubit { void changeSelectedStateIndex(int index) { emit(state.copyWith(selectedStateIndex: index)); + if (state.activeDiets.isEmpty) { + EasyDebounce.debounce( + 'loadActiveDiets', + Duration(seconds: 1), + () => loadCurrentDiets( + query: _activeQuery, + ), + ); + } else if (state.draftDiets.isEmpty) { + EasyDebounce.debounce( + 'loadDraftDiets', + Duration(seconds: 1), + () => loadCurrentDiets( + query: _draftQuery, + ), + ); + } else if (state.personalDiets.isEmpty) { + EasyDebounce.debounce( + 'loadPersonalDiets', + Duration(seconds: 1), + () => loadCurrentDiets( + query: _personalQuery, + ), + ); + } } - Future loadDiets({ + Future loadCurrentDiets({ String? query, }) async { switch (state.selectedStateIndex) { @@ -160,11 +189,13 @@ class MyDietsCubit extends Cubit { final type = _types[state.activeFilterState.typeIndex]; final duration = _durationValues[state.activeFilterState.durationIndex]; final sorting = _sortingValues[state.activeFilterState.sortingIndex]; + final dietState = DietState.active; final dietsPagination = await myDietsRepository.getDiets( query: query, types: type, duration: duration, sorting: sorting, + state: dietState.toString(), ); lastActivePage = dietsPagination.meta.lastPage; emit( @@ -174,7 +205,8 @@ class MyDietsCubit extends Cubit { error: null, ), ); - } catch (e) { + } catch (e, st) { + log(e.toString(), stackTrace: st); emit( state.copyWith(error: e.toString()), ); @@ -187,11 +219,13 @@ class MyDietsCubit extends Cubit { final type = _types[state.draftFilterState.typeIndex]; final duration = _durationValues[state.draftFilterState.durationIndex]; final sorting = _sortingValues[state.draftFilterState.sortingIndex]; + final dietState = DietState.draft; final dietsPagination = await myDietsRepository.getDiets( query: query, types: type, duration: duration, sorting: sorting, + state: dietState.toString(), ); lastActivePage = dietsPagination.meta.lastPage; emit( @@ -214,11 +248,13 @@ class MyDietsCubit extends Cubit { final type = _types[state.personalFilterState.typeIndex]; final duration = _durationValues[state.personalFilterState.durationIndex]; final sorting = _sortingValues[state.personalFilterState.sortingIndex]; + final dietState = DietState.personal; final dietsPagination = await myDietsRepository.getDiets( query: query, types: type, duration: duration, sorting: sorting, + state: dietState.toString(), ); lastActivePage = dietsPagination.meta.lastPage; emit( diff --git a/lib/features/my_diets/presentation/my_diets_screen.dart b/lib/features/my_diets/presentation/my_diets_screen.dart index 65ac8441..a58f3bdc 100644 --- a/lib/features/my_diets/presentation/my_diets_screen.dart +++ b/lib/features/my_diets/presentation/my_diets_screen.dart @@ -33,7 +33,7 @@ class MyDietsScreenContent extends StatelessWidget { final activeDietsScrollController = ScrollController(); final draftDietsScrollController = ScrollController(); final personalDietsScrollController = ScrollController(); - + final activeDietsSearchController = SearchController(); final draftDietsSearchController = SearchController(); final personalDietsSearchController = SearchController(); @@ -111,7 +111,7 @@ class MyDietsScreenContent extends StatelessWidget { 'searchDiets', Duration(milliseconds: 500), () { - context.read().loadDiets(query: query == '' ? null : query); + context.read().loadCurrentDiets(query: query == '' ? null : query); }, ); }, @@ -133,7 +133,7 @@ class MyDietsScreenContent extends StatelessWidget { ]; }, body: RefreshIndicator( - onRefresh: () => context.read().loadDiets(), + onRefresh: () => context.read().loadCurrentDiets(), child: BlocBuilder( builder: (BuildContext context, MyDietsState state) { if (state.isLoading) { diff --git a/lib/features/my_diets/presentation/widgets/my_diet_widget.dart b/lib/features/my_diets/presentation/widgets/my_diet_widget.dart index d173117e..ff8d060a 100644 --- a/lib/features/my_diets/presentation/widgets/my_diet_widget.dart +++ b/lib/features/my_diets/presentation/widgets/my_diet_widget.dart @@ -6,6 +6,7 @@ import 'package:eatvio_app/core/widgets/bottom_sheet_handler_bar.dart'; import 'package:eatvio_app/core/widgets/bottom_sheet_with_blur.dart'; import 'package:eatvio_app/core/widgets/custom_outlined_button.dart'; import 'package:eatvio_app/core/widgets/info_row.dart'; +import 'package:eatvio_app/features/create_diet/presentation/create_diet_screen.dart'; import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart'; import 'package:eatvio_app/features/my_diets/presentation/cubit/my_diets_cubit.dart'; import 'package:eatvio_app/features/my_diets/presentation/cubit/my_diets_state.dart'; @@ -110,6 +111,13 @@ class _MyDietWidgetState extends State { children: [ Expanded( child: CustomOutlinedButton( + onPressed: () { + if (state.selectedStateIndex == 1) { + } else if (state.selectedStateIndex == 2) { + } else { + GoRouter.of(context).pushNamed(CreateDietScreen.name, extra: widget.diet); + } + }, text: switch (state.selectedStateIndex) { 1 => s.publish, 2 => s.toOffer, @@ -160,6 +168,12 @@ class _MyDietWidgetState extends State { children: [ Expanded( child: CustomOutlinedButton( + onPressed: () { + if (state.selectedStateIndex == 0) { + } else { + GoRouter.of(context).pushNamed(CreateDietScreen.name, extra: widget.diet); + } + }, text: switch (state.selectedStateIndex) { 0 => s.removeFromActive, _ => s.edit, @@ -178,51 +192,49 @@ class _MyDietWidgetState extends State { onPressed: () async { final result = await context.read().deleteDiet(widget.diet.id); if (result) - Future.delayed(Duration(seconds: 3), () { - showBottomSheetWithBlur( - context: context, - child: Column( - children: [ - SizedBox( - height: 20, - ), - BottomSheetHandlerBar(), - SizedBox( - height: 20, - ), - Text( - '${widget.diet.name}', - style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black), - ), - Text( - s.deleted, - style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black), - ), - SizedBox( - height: 20, - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: CustomOutlinedButton( - onPressed: () { - context.pop(); - }, - text: 'Хорошо', - height: 52, - buttonTextStyle: TextStyles.textSSemibold.copyWith(color: appTheme.whiteA700), - buttonStyle: ButtonStyle( - side: WidgetStatePropertyAll(BorderSide.none), - backgroundColor: WidgetStatePropertyAll(appTheme.blueA400), - ), + showBottomSheetWithBlur( + context: context, + child: Column( + children: [ + SizedBox( + height: 20, + ), + BottomSheetHandlerBar(), + SizedBox( + height: 20, + ), + Text( + '${widget.diet.name}', + style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black), + ), + Text( + s.deleted, + style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black), + ), + SizedBox( + height: 20, + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: CustomOutlinedButton( + onPressed: () { + context.pop(); + }, + text: 'Хорошо', + height: 52, + buttonTextStyle: TextStyles.textSSemibold.copyWith(color: appTheme.whiteA700), + buttonStyle: ButtonStyle( + side: WidgetStatePropertyAll(BorderSide.none), + backgroundColor: WidgetStatePropertyAll(appTheme.blueA400), ), ), - SizedBox( - height: 20, - ), - ], - ), - ); - }); + ), + SizedBox( + height: 20, + ), + ], + ), + ); }, height: 52, width: 52, diff --git a/lib/features/my_diets/repositories/my_diets_repository.dart b/lib/features/my_diets/repositories/my_diets_repository.dart index 8c15a546..e3ec0dd1 100644 --- a/lib/features/my_diets/repositories/my_diets_repository.dart +++ b/lib/features/my_diets/repositories/my_diets_repository.dart @@ -20,6 +20,7 @@ class MyDietsRepository { String? types, int? duration, String? sorting, + String? state, }) async { try { return (await myDietsService.getDiets( @@ -28,6 +29,7 @@ class MyDietsRepository { types: types, duration: duration, sorting: sorting, + state: state, )); } catch (e) { rethrow; diff --git a/lib/features/my_diets/services/my_diets_service.dart b/lib/features/my_diets/services/my_diets_service.dart index 3a78d25e..41e3174f 100644 --- a/lib/features/my_diets/services/my_diets_service.dart +++ b/lib/features/my_diets/services/my_diets_service.dart @@ -12,13 +12,14 @@ abstract class MyDietsService { @GET('/api/profile/my_diets') Future getDiets({ @Query('page') required int page, - @Query('filters[name][\$startsWith]') String? query, + @Query('filters[name][\$startsWith]') String? query, + @Query('filters[state][\$eq]') String? state, @Query('filters[type][\$contains]') String? types, @Query('filters[duration][\$eq]') int? duration, @Query('sort') String? sorting, }); - @POST('/api/diets/delete/{dietId}') + @DELETE('/api/diets/delete/{dietId}') Future deleteDiet({ @Path() required int dietId, }); diff --git a/lib/features/my_diets/services/my_diets_service.g.dart b/lib/features/my_diets/services/my_diets_service.g.dart index f9244073..4c2ccf28 100644 --- a/lib/features/my_diets/services/my_diets_service.g.dart +++ b/lib/features/my_diets/services/my_diets_service.g.dart @@ -21,6 +21,7 @@ class _MyDietsService implements MyDietsService { Future getDiets({ required int page, String? query, + String? state, String? types, int? duration, String? sorting, @@ -29,6 +30,7 @@ class _MyDietsService implements MyDietsService { final queryParameters = { r'page': page, r'filters[name][$startsWith]': query, + r'filters[state][$eq]': state, r'filters[type][$contains]': types, r'filters[duration][$eq]': duration, r'sort': sorting, @@ -64,7 +66,7 @@ class _MyDietsService implements MyDietsService { final _headers = {}; const Map? _data = null; final _options = _setStreamType( - Options(method: 'POST', headers: _headers, extra: _extra) + Options(method: 'DELETE', headers: _headers, extra: _extra) .compose( _dio.options, '/api/diets/delete/${dietId}', diff --git a/lib/features/profile/models/profile_model.dart b/lib/features/profile/models/profile_model.dart index b6debe84..93c61635 100644 --- a/lib/features/profile/models/profile_model.dart +++ b/lib/features/profile/models/profile_model.dart @@ -18,7 +18,7 @@ class ProfileModel with _$ProfileModel { @JsonKey(name: 'is_entity_subscribed_by_me') required bool isEntitySubscribedByMe, @JsonKey(name: "slug") required String slug, @JsonKey(name: "profile_photo_url") required String profilePhotoUrl, - @JsonKey(name: "role") required String role, + @JsonKey(name: "roles") required List roles, @JsonKey(name: "badges") required List badges, @JsonKey(name: "subscriptions") required List subscriptions, @JsonKey(name: "subscribers") required List subscribers, diff --git a/lib/features/profile/models/profile_model.freezed.dart b/lib/features/profile/models/profile_model.freezed.dart index c46e1027..0f3eee2c 100644 --- a/lib/features/profile/models/profile_model.freezed.dart +++ b/lib/features/profile/models/profile_model.freezed.dart @@ -42,8 +42,8 @@ mixin _$ProfileModel { String get slug => throw _privateConstructorUsedError; @JsonKey(name: "profile_photo_url") String get profilePhotoUrl => throw _privateConstructorUsedError; - @JsonKey(name: "role") - String get role => throw _privateConstructorUsedError; + @JsonKey(name: "roles") + List get roles => throw _privateConstructorUsedError; @JsonKey(name: "badges") List get badges => throw _privateConstructorUsedError; @JsonKey(name: "subscriptions") @@ -86,7 +86,7 @@ abstract class $ProfileModelCopyWith<$Res> { @JsonKey(name: 'is_entity_subscribed_by_me') bool isEntitySubscribedByMe, @JsonKey(name: "slug") String slug, @JsonKey(name: "profile_photo_url") String profilePhotoUrl, - @JsonKey(name: "role") String role, + @JsonKey(name: "roles") List roles, @JsonKey(name: "badges") List badges, @JsonKey(name: "subscriptions") List subscriptions, @JsonKey(name: "subscribers") List subscribers, @@ -123,7 +123,7 @@ class _$ProfileModelCopyWithImpl<$Res, $Val extends ProfileModel> Object? isEntitySubscribedByMe = null, Object? slug = null, Object? profilePhotoUrl = null, - Object? role = null, + Object? roles = null, Object? badges = null, Object? subscriptions = null, Object? subscribers = null, @@ -175,10 +175,10 @@ class _$ProfileModelCopyWithImpl<$Res, $Val extends ProfileModel> ? _value.profilePhotoUrl : profilePhotoUrl // ignore: cast_nullable_to_non_nullable as String, - role: null == role - ? _value.role - : role // ignore: cast_nullable_to_non_nullable - as String, + roles: null == roles + ? _value.roles + : roles // ignore: cast_nullable_to_non_nullable + as List, badges: null == badges ? _value.badges : badges // ignore: cast_nullable_to_non_nullable @@ -237,7 +237,7 @@ abstract class _$$ProfileModelImplCopyWith<$Res> @JsonKey(name: 'is_entity_subscribed_by_me') bool isEntitySubscribedByMe, @JsonKey(name: "slug") String slug, @JsonKey(name: "profile_photo_url") String profilePhotoUrl, - @JsonKey(name: "role") String role, + @JsonKey(name: "roles") List roles, @JsonKey(name: "badges") List badges, @JsonKey(name: "subscriptions") List subscriptions, @JsonKey(name: "subscribers") List subscribers, @@ -273,7 +273,7 @@ class __$$ProfileModelImplCopyWithImpl<$Res> Object? isEntitySubscribedByMe = null, Object? slug = null, Object? profilePhotoUrl = null, - Object? role = null, + Object? roles = null, Object? badges = null, Object? subscriptions = null, Object? subscribers = null, @@ -325,10 +325,10 @@ class __$$ProfileModelImplCopyWithImpl<$Res> ? _value.profilePhotoUrl : profilePhotoUrl // ignore: cast_nullable_to_non_nullable as String, - role: null == role - ? _value.role - : role // ignore: cast_nullable_to_non_nullable - as String, + roles: null == roles + ? _value._roles + : roles // ignore: cast_nullable_to_non_nullable + as List, badges: null == badges ? _value._badges : badges // ignore: cast_nullable_to_non_nullable @@ -369,7 +369,7 @@ class _$ProfileModelImpl implements _ProfileModel { required this.isEntitySubscribedByMe, @JsonKey(name: "slug") required this.slug, @JsonKey(name: "profile_photo_url") required this.profilePhotoUrl, - @JsonKey(name: "role") required this.role, + @JsonKey(name: "roles") required final List roles, @JsonKey(name: "badges") required final List badges, @JsonKey(name: "subscriptions") required final List subscriptions, @@ -378,7 +378,8 @@ class _$ProfileModelImpl implements _ProfileModel { @JsonKey(name: "education_resource") this.educationResource, @JsonKey(name: "cert_photos") final List? diplomasAndCertificates}) - : _badges = badges, + : _roles = roles, + _badges = badges, _subscriptions = subscriptions, _subscribers = subscribers, _diplomasAndCertificates = diplomasAndCertificates; @@ -419,9 +420,15 @@ class _$ProfileModelImpl implements _ProfileModel { @override @JsonKey(name: "profile_photo_url") final String profilePhotoUrl; + final List _roles; @override - @JsonKey(name: "role") - final String role; + @JsonKey(name: "roles") + List get roles { + if (_roles is EqualUnmodifiableListView) return _roles; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_roles); + } + final List _badges; @override @JsonKey(name: "badges") @@ -466,7 +473,7 @@ class _$ProfileModelImpl implements _ProfileModel { @override String toString() { - return 'ProfileModel(id: $id, name: $name, email: $email, ratingPlace: $ratingPlace, emailVerifiedAt: $emailVerifiedAt, createdAt: $createdAt, updatedAt: $updatedAt, isPublicProfile: $isPublicProfile, isEntitySubscribedByMe: $isEntitySubscribedByMe, slug: $slug, profilePhotoUrl: $profilePhotoUrl, role: $role, badges: $badges, subscriptions: $subscriptions, subscribers: $subscribers, educationResource: $educationResource, diplomasAndCertificates: $diplomasAndCertificates)'; + return 'ProfileModel(id: $id, name: $name, email: $email, ratingPlace: $ratingPlace, emailVerifiedAt: $emailVerifiedAt, createdAt: $createdAt, updatedAt: $updatedAt, isPublicProfile: $isPublicProfile, isEntitySubscribedByMe: $isEntitySubscribedByMe, slug: $slug, profilePhotoUrl: $profilePhotoUrl, roles: $roles, badges: $badges, subscriptions: $subscriptions, subscribers: $subscribers, educationResource: $educationResource, diplomasAndCertificates: $diplomasAndCertificates)'; } @override @@ -492,7 +499,7 @@ class _$ProfileModelImpl implements _ProfileModel { (identical(other.slug, slug) || other.slug == slug) && (identical(other.profilePhotoUrl, profilePhotoUrl) || other.profilePhotoUrl == profilePhotoUrl) && - (identical(other.role, role) || other.role == role) && + const DeepCollectionEquality().equals(other._roles, _roles) && const DeepCollectionEquality().equals(other._badges, _badges) && const DeepCollectionEquality() .equals(other._subscriptions, _subscriptions) && @@ -519,7 +526,7 @@ class _$ProfileModelImpl implements _ProfileModel { isEntitySubscribedByMe, slug, profilePhotoUrl, - role, + const DeepCollectionEquality().hash(_roles), const DeepCollectionEquality().hash(_badges), const DeepCollectionEquality().hash(_subscriptions), const DeepCollectionEquality().hash(_subscribers), @@ -556,7 +563,7 @@ abstract class _ProfileModel implements ProfileModel { required final bool isEntitySubscribedByMe, @JsonKey(name: "slug") required final String slug, @JsonKey(name: "profile_photo_url") required final String profilePhotoUrl, - @JsonKey(name: "role") required final String role, + @JsonKey(name: "roles") required final List roles, @JsonKey(name: "badges") required final List badges, @JsonKey(name: "subscriptions") required final List subscriptions, @@ -605,8 +612,8 @@ abstract class _ProfileModel implements ProfileModel { @JsonKey(name: "profile_photo_url") String get profilePhotoUrl; @override - @JsonKey(name: "role") - String get role; + @JsonKey(name: "roles") + List get roles; @override @JsonKey(name: "badges") List get badges; diff --git a/lib/features/profile/models/profile_model.g.dart b/lib/features/profile/models/profile_model.g.dart index c7d0d444..e07e74c6 100644 --- a/lib/features/profile/models/profile_model.g.dart +++ b/lib/features/profile/models/profile_model.g.dart @@ -25,7 +25,7 @@ _$ProfileModelImpl _$$ProfileModelImplFromJson(Map json) => isEntitySubscribedByMe: json['is_entity_subscribed_by_me'] as bool, slug: json['slug'] as String, profilePhotoUrl: json['profile_photo_url'] as String, - role: json['role'] as String, + roles: (json['roles'] as List).map((e) => e as String).toList(), badges: (json['badges'] as List) .map((e) => BadgeModel.fromJson(e as Map)) .toList(), @@ -58,7 +58,7 @@ Map _$$ProfileModelImplToJson(_$ProfileModelImpl instance) => 'is_entity_subscribed_by_me': instance.isEntitySubscribedByMe, 'slug': instance.slug, 'profile_photo_url': instance.profilePhotoUrl, - 'role': instance.role, + 'roles': instance.roles, 'badges': instance.badges, 'subscriptions': instance.subscriptions, 'subscribers': instance.subscribers, diff --git a/lib/features/profile/presentation/pages/profile_screen.dart b/lib/features/profile/presentation/pages/profile_screen.dart index 788a5f3f..0b8b7af6 100644 --- a/lib/features/profile/presentation/pages/profile_screen.dart +++ b/lib/features/profile/presentation/pages/profile_screen.dart @@ -81,7 +81,7 @@ class _ProfileScreenState extends State { } if (isFirstFetch) { canSub = !state.profile.isEntitySubscribedByMe; - if (state.profile.role == 'consultant') { + if (state.profile.roles.contains('consultant')) { plansCubit..getPlans(state.profile.slug); } isFirstFetch = false; @@ -127,7 +127,7 @@ class _ProfileScreenState extends State { crossAxisAlignment: CrossAxisAlignment.center, children: [ _header(state), - if (state.profile.role == 'consultant') + if (state.profile.roles.contains('consultant')) Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -192,10 +192,10 @@ class _ProfileScreenState extends State { ), _subscriptionsAndSubscribers(state), if (state.profile.badges.isNotEmpty) Padding(padding: EdgeInsets.only(bottom: 16), child: _badges(state)), - if (state.profile.role == 'consultant') _socialLinks(state), - if (state.profile.role == 'consultant') _education(state), - if (state.profile.role == 'consultant') _diplomasAndCertificates(state), - if (state.profile.role == 'consultant') _activePlans(state), + if (state.profile.roles.contains('consultant')) _socialLinks(state), + if (state.profile.roles.contains('consultant')) _education(state), + if (state.profile.roles.contains('consultant')) _diplomasAndCertificates(state), + if (state.profile.roles.contains('consultant')) _activePlans(state), _blogPosts(state), ], ), @@ -228,11 +228,11 @@ class _ProfileScreenState extends State { ), _subscriptionsAndSubscribers(state), if (state.profile.badges.isNotEmpty) Padding(padding: EdgeInsets.only(bottom: 16), child: _badges(state)), - if (state.profile.role == 'consultant') _socialLinks(state), - if (state.profile.role == 'consultant') _education(state), - if (state.profile.role == 'consultant') _diplomasAndCertificates(state), + if (state.profile.roles.contains('consultant')) _socialLinks(state), + if (state.profile.roles.contains('consultant')) _education(state), + if (state.profile.roles.contains('consultant')) _diplomasAndCertificates(state), Padding(padding: EdgeInsets.only(bottom: 16), child: _charts()), - if (state.profile.role == 'consultant') _activePlans(state), + if (state.profile.roles.contains('consultant')) _activePlans(state), _newBlogPostButton(), _blogPosts(state), ], @@ -242,7 +242,7 @@ class _ProfileScreenState extends State { } _activePlans(ProfileStateLoaded state) { - if (state.profile.role != 'consultant') { + if (!state.profile.roles.contains('consultant')) { return const SizedBox.shrink(); } return BlocBuilder( @@ -372,7 +372,7 @@ class _ProfileScreenState extends State { } _diplomasAndCertificates(ProfileStateLoaded state) { - if (state.profile.role != 'consultant' || state.profile.diplomasAndCertificates == null || state.profile.diplomasAndCertificates!.isEmpty) { + if (!state.profile.roles.contains('consultant') || state.profile.diplomasAndCertificates == null || state.profile.diplomasAndCertificates!.isEmpty) { return const SizedBox.shrink(); } return Padding( @@ -456,7 +456,7 @@ class _ProfileScreenState extends State { } _education(ProfileStateLoaded state) { - if (state.profile.role != 'consultant' || + if (!state.profile.roles.contains('consultant') || state.profile.educationResource?.completedCourses == null || state.profile.educationResource?.completedCourses?.length == 0) { return const SizedBox.shrink(); @@ -549,7 +549,7 @@ class _ProfileScreenState extends State { } _socialLinks(ProfileStateLoaded state) { - if (state.profile.role != 'consultant') { + if (!state.profile.roles.contains('consultant')) { return const SizedBox.shrink(); } return Padding( diff --git a/lib/features/recipes/entities/recipe_create_entity.dart b/lib/features/recipes/entities/recipe_create_entity.dart index 92f7d642..6ca01db3 100644 --- a/lib/features/recipes/entities/recipe_create_entity.dart +++ b/lib/features/recipes/entities/recipe_create_entity.dart @@ -84,8 +84,10 @@ class RecipeCreateEntity with _$RecipeCreateEntity { TypeOfRecipe? typeOfRecipe, int? countOfPortions, double? energyInOnePortion, - String? totalCookTime, // hh:mm - String? activeCookTime, // hh:mm + int? totalCookHours, + int? totalCookMinutes, + int? activeCookHours, + int? activeCookMinutes, String? description, File? image, String? videoUrl, @@ -99,8 +101,8 @@ class RecipeCreateEntity with _$RecipeCreateEntity { type: typeOfRecipe?.toApiType(), servings: countOfPortions, energyPerServing: energyInOnePortion?.toInt(), - totalCookingTime: totalCookTime?.split(':').fold(0, (value, element) => (int.tryParse(element) ?? 0)), - activeCookTime: activeCookTime?.split(':').fold(0, (value, element) => (int.tryParse(element) ?? 0)), + totalCookingTime: ((totalCookHours ?? 0) * 60) + (totalCookMinutes ?? 0), + activeCookTime: ((activeCookHours ?? 0) * 60) + (activeCookMinutes ?? 0), description: description, image: image?.path, video_url: videoUrl, diff --git a/lib/features/recipes/entities/recipe_create_entity.freezed.dart b/lib/features/recipes/entities/recipe_create_entity.freezed.dart index 57535cc7..c5f4178d 100644 --- a/lib/features/recipes/entities/recipe_create_entity.freezed.dart +++ b/lib/features/recipes/entities/recipe_create_entity.freezed.dart @@ -20,8 +20,10 @@ mixin _$RecipeCreateEntity { TypeOfRecipe? get typeOfRecipe => throw _privateConstructorUsedError; int? get countOfPortions => throw _privateConstructorUsedError; double? get energyInOnePortion => throw _privateConstructorUsedError; - String? get totalCookTime => throw _privateConstructorUsedError; // hh:mm - String? get activeCookTime => throw _privateConstructorUsedError; // hh:mm + int? get totalCookHours => throw _privateConstructorUsedError; + int? get totalCookMinutes => throw _privateConstructorUsedError; + int? get activeCookHours => throw _privateConstructorUsedError; + int? get activeCookMinutes => throw _privateConstructorUsedError; String? get description => throw _privateConstructorUsedError; File? get image => throw _privateConstructorUsedError; String? get videoUrl => throw _privateConstructorUsedError; @@ -47,8 +49,10 @@ abstract class $RecipeCreateEntityCopyWith<$Res> { TypeOfRecipe? typeOfRecipe, int? countOfPortions, double? energyInOnePortion, - String? totalCookTime, - String? activeCookTime, + int? totalCookHours, + int? totalCookMinutes, + int? activeCookHours, + int? activeCookMinutes, String? description, File? image, String? videoUrl, @@ -76,8 +80,10 @@ class _$RecipeCreateEntityCopyWithImpl<$Res, $Val extends RecipeCreateEntity> Object? typeOfRecipe = freezed, Object? countOfPortions = freezed, Object? energyInOnePortion = freezed, - Object? totalCookTime = freezed, - Object? activeCookTime = freezed, + Object? totalCookHours = freezed, + Object? totalCookMinutes = freezed, + Object? activeCookHours = freezed, + Object? activeCookMinutes = freezed, Object? description = freezed, Object? image = freezed, Object? videoUrl = freezed, @@ -102,14 +108,22 @@ class _$RecipeCreateEntityCopyWithImpl<$Res, $Val extends RecipeCreateEntity> ? _value.energyInOnePortion : energyInOnePortion // ignore: cast_nullable_to_non_nullable as double?, - totalCookTime: freezed == totalCookTime - ? _value.totalCookTime - : totalCookTime // ignore: cast_nullable_to_non_nullable - as String?, - activeCookTime: freezed == activeCookTime - ? _value.activeCookTime - : activeCookTime // ignore: cast_nullable_to_non_nullable - as String?, + totalCookHours: freezed == totalCookHours + ? _value.totalCookHours + : totalCookHours // ignore: cast_nullable_to_non_nullable + as int?, + totalCookMinutes: freezed == totalCookMinutes + ? _value.totalCookMinutes + : totalCookMinutes // ignore: cast_nullable_to_non_nullable + as int?, + activeCookHours: freezed == activeCookHours + ? _value.activeCookHours + : activeCookHours // ignore: cast_nullable_to_non_nullable + as int?, + activeCookMinutes: freezed == activeCookMinutes + ? _value.activeCookMinutes + : activeCookMinutes // ignore: cast_nullable_to_non_nullable + as int?, description: freezed == description ? _value.description : description // ignore: cast_nullable_to_non_nullable @@ -151,8 +165,10 @@ abstract class _$$RecipeCreateEntityImplCopyWith<$Res> TypeOfRecipe? typeOfRecipe, int? countOfPortions, double? energyInOnePortion, - String? totalCookTime, - String? activeCookTime, + int? totalCookHours, + int? totalCookMinutes, + int? activeCookHours, + int? activeCookMinutes, String? description, File? image, String? videoUrl, @@ -178,8 +194,10 @@ class __$$RecipeCreateEntityImplCopyWithImpl<$Res> Object? typeOfRecipe = freezed, Object? countOfPortions = freezed, Object? energyInOnePortion = freezed, - Object? totalCookTime = freezed, - Object? activeCookTime = freezed, + Object? totalCookHours = freezed, + Object? totalCookMinutes = freezed, + Object? activeCookHours = freezed, + Object? activeCookMinutes = freezed, Object? description = freezed, Object? image = freezed, Object? videoUrl = freezed, @@ -204,14 +222,22 @@ class __$$RecipeCreateEntityImplCopyWithImpl<$Res> ? _value.energyInOnePortion : energyInOnePortion // ignore: cast_nullable_to_non_nullable as double?, - totalCookTime: freezed == totalCookTime - ? _value.totalCookTime - : totalCookTime // ignore: cast_nullable_to_non_nullable - as String?, - activeCookTime: freezed == activeCookTime - ? _value.activeCookTime - : activeCookTime // ignore: cast_nullable_to_non_nullable - as String?, + totalCookHours: freezed == totalCookHours + ? _value.totalCookHours + : totalCookHours // ignore: cast_nullable_to_non_nullable + as int?, + totalCookMinutes: freezed == totalCookMinutes + ? _value.totalCookMinutes + : totalCookMinutes // ignore: cast_nullable_to_non_nullable + as int?, + activeCookHours: freezed == activeCookHours + ? _value.activeCookHours + : activeCookHours // ignore: cast_nullable_to_non_nullable + as int?, + activeCookMinutes: freezed == activeCookMinutes + ? _value.activeCookMinutes + : activeCookMinutes // ignore: cast_nullable_to_non_nullable + as int?, description: freezed == description ? _value.description : description // ignore: cast_nullable_to_non_nullable @@ -248,8 +274,10 @@ class _$RecipeCreateEntityImpl extends _RecipeCreateEntity { this.typeOfRecipe, this.countOfPortions, this.energyInOnePortion, - this.totalCookTime, - this.activeCookTime, + this.totalCookHours, + this.totalCookMinutes, + this.activeCookHours, + this.activeCookMinutes, this.description, this.image, this.videoUrl, @@ -270,11 +298,13 @@ class _$RecipeCreateEntityImpl extends _RecipeCreateEntity { @override final double? energyInOnePortion; @override - final String? totalCookTime; -// hh:mm + final int? totalCookHours; @override - final String? activeCookTime; -// hh:mm + final int? totalCookMinutes; + @override + final int? activeCookHours; + @override + final int? activeCookMinutes; @override final String? description; @override @@ -307,7 +337,7 @@ class _$RecipeCreateEntityImpl extends _RecipeCreateEntity { @override String toString() { - return 'RecipeCreateEntity(title: $title, typeOfRecipe: $typeOfRecipe, countOfPortions: $countOfPortions, energyInOnePortion: $energyInOnePortion, totalCookTime: $totalCookTime, activeCookTime: $activeCookTime, description: $description, image: $image, videoUrl: $videoUrl, ingredients: $ingredients, steps: $steps, tags: $tags)'; + return 'RecipeCreateEntity(title: $title, typeOfRecipe: $typeOfRecipe, countOfPortions: $countOfPortions, energyInOnePortion: $energyInOnePortion, totalCookHours: $totalCookHours, totalCookMinutes: $totalCookMinutes, activeCookHours: $activeCookHours, activeCookMinutes: $activeCookMinutes, description: $description, image: $image, videoUrl: $videoUrl, ingredients: $ingredients, steps: $steps, tags: $tags)'; } @override @@ -322,10 +352,14 @@ class _$RecipeCreateEntityImpl extends _RecipeCreateEntity { other.countOfPortions == countOfPortions) && (identical(other.energyInOnePortion, energyInOnePortion) || other.energyInOnePortion == energyInOnePortion) && - (identical(other.totalCookTime, totalCookTime) || - other.totalCookTime == totalCookTime) && - (identical(other.activeCookTime, activeCookTime) || - other.activeCookTime == activeCookTime) && + (identical(other.totalCookHours, totalCookHours) || + other.totalCookHours == totalCookHours) && + (identical(other.totalCookMinutes, totalCookMinutes) || + other.totalCookMinutes == totalCookMinutes) && + (identical(other.activeCookHours, activeCookHours) || + other.activeCookHours == activeCookHours) && + (identical(other.activeCookMinutes, activeCookMinutes) || + other.activeCookMinutes == activeCookMinutes) && (identical(other.description, description) || other.description == description) && (identical(other.image, image) || other.image == image) && @@ -344,8 +378,10 @@ class _$RecipeCreateEntityImpl extends _RecipeCreateEntity { typeOfRecipe, countOfPortions, energyInOnePortion, - totalCookTime, - activeCookTime, + totalCookHours, + totalCookMinutes, + activeCookHours, + activeCookMinutes, description, image, videoUrl, @@ -369,8 +405,10 @@ abstract class _RecipeCreateEntity extends RecipeCreateEntity { final TypeOfRecipe? typeOfRecipe, final int? countOfPortions, final double? energyInOnePortion, - final String? totalCookTime, - final String? activeCookTime, + final int? totalCookHours, + final int? totalCookMinutes, + final int? activeCookHours, + final int? activeCookMinutes, final String? description, final File? image, final String? videoUrl, @@ -388,9 +426,13 @@ abstract class _RecipeCreateEntity extends RecipeCreateEntity { @override double? get energyInOnePortion; @override - String? get totalCookTime; // hh:mm + int? get totalCookHours; @override - String? get activeCookTime; // hh:mm + int? get totalCookMinutes; + @override + int? get activeCookHours; + @override + int? get activeCookMinutes; @override String? get description; @override diff --git a/lib/features/recipes/presentation/bloc/create_recipe_cubit/create_recipe_cubit.dart b/lib/features/recipes/presentation/bloc/create_recipe_cubit/create_recipe_cubit.dart index 00d4961b..a91e44dd 100644 --- a/lib/features/recipes/presentation/bloc/create_recipe_cubit/create_recipe_cubit.dart +++ b/lib/features/recipes/presentation/bloc/create_recipe_cubit/create_recipe_cubit.dart @@ -101,12 +101,20 @@ class CreateRecipeCubit extends Cubit { emit(state.copyWith.entity(energyInOnePortion: energy)); } - replaceTotalTime(String time) { - emit(state.copyWith.entity(totalCookTime: time)); + setTotalCookingMinutes(int minutes) { + emit(state.copyWith.entity(totalCookMinutes: minutes)); } - replaceActiveTime(String time) { - emit(state.copyWith.entity(activeCookTime: time)); + setTotalCookingHours(int hours) { + emit(state.copyWith.entity(totalCookHours: hours)); + } + + setActiveCookingMinutes(int minutes) { + emit(state.copyWith.entity(activeCookMinutes: minutes)); + } + + setActiveCookingHours(int hours) { + emit(state.copyWith.entity(activeCookHours: hours)); } replaceVideoUrl(String videoUrl) { @@ -190,7 +198,7 @@ class CreateRecipeCubit extends Cubit { } bool validateActiveCookTime() { - if (state.entity.activeCookTime == null || state.entity.activeCookTime == '00:00') { + if (state.entity.activeCookHours == null && state.entity.activeCookMinutes == null) { emit(state.copyWith(activeTimeValidationError: 'Поле не заполнено')); return false; } else { @@ -200,7 +208,7 @@ class CreateRecipeCubit extends Cubit { } bool validateTotalCookTime() { - if (state.entity.totalCookTime == null || state.entity.totalCookTime == '00:00') { + if (state.entity.totalCookHours == null || state.entity.totalCookMinutes == null) { emit(state.copyWith(cookingTimeValidationError: 'Поле не заполнено')); return false; } else { diff --git a/lib/features/recipes/presentation/widgets/time_of_cook_widget.dart b/lib/features/recipes/presentation/widgets/time_of_cook_widget.dart index 1c4e0306..e845a923 100644 --- a/lib/features/recipes/presentation/widgets/time_of_cook_widget.dart +++ b/lib/features/recipes/presentation/widgets/time_of_cook_widget.dart @@ -72,11 +72,9 @@ class _TimeOfCookWidgetState extends State { hasError: state.cookingTimeValidationError != null, textInputType: TextInputType.number, onChanged: (value) { - if (createRecipeCubit.state.entity.totalCookTime == null) { - createRecipeCubit.replaceTotalTime('${value.padLeft(2, '0')}:00'); - } else { - createRecipeCubit.replaceTotalTime('${value.padLeft(2, '0')}:${createRecipeCubit.state.entity.totalCookTime!.substring(3, 5)}'); - } + final hours = int.tryParse(value); + if (hours == null) return; + createRecipeCubit.setTotalCookingHours(hours); if (state.cookingTimeValidationError != null) { createRecipeCubit.validateTotalCookTime(); } @@ -100,11 +98,9 @@ class _TimeOfCookWidgetState extends State { hasError: state.cookingTimeValidationError != null, textInputType: TextInputType.number, onChanged: (value) { - if (createRecipeCubit.state.entity.totalCookTime == null) { - createRecipeCubit.replaceTotalTime('00:${value.padLeft(2, '0')}'); - } else { - createRecipeCubit.replaceTotalTime('${createRecipeCubit.state.entity.totalCookTime!.substring(0, 2)}:${value.padLeft(2, '0')}'); - } + final minutes = int.tryParse(value); + if (minutes == null) return; + createRecipeCubit.setTotalCookingMinutes(minutes); if (state.cookingTimeValidationError != null) { createRecipeCubit.validateTotalCookTime(); } @@ -162,11 +158,9 @@ class _TimeOfCookWidgetState extends State { hasError: state.activeTimeValidationError != null, textInputType: TextInputType.number, onChanged: (value) { - if (createRecipeCubit.state.entity.activeCookTime == null) { - createRecipeCubit.replaceActiveTime('${value.padLeft(2, '0')}:00'); - } else { - createRecipeCubit.replaceActiveTime('${value.padLeft(2, '0')}:${createRecipeCubit.state.entity.activeCookTime!.substring(3, 5)}'); - } + final hours = int.tryParse(value); + if (hours == null) return; + createRecipeCubit.setActiveCookingHours(hours); if (state.activeTimeValidationError != null) { createRecipeCubit.validateActiveCookTime(); @@ -191,11 +185,9 @@ class _TimeOfCookWidgetState extends State { hasError: state.activeTimeValidationError != null, textInputType: TextInputType.number, onChanged: (value) { - if (createRecipeCubit.state.entity.activeCookTime == null) { - createRecipeCubit.replaceActiveTime('00:${value.padLeft(2, '0')}'); - } else { - createRecipeCubit.replaceActiveTime('${createRecipeCubit.state.entity.activeCookTime!.substring(0, 2)}:${value.padLeft(2, '0')}'); - } + final minutes = int.tryParse(value); + if (minutes == null) return; + createRecipeCubit.setActiveCookingMinutes(minutes); if (state.activeTimeValidationError != null) { createRecipeCubit.validateActiveCookTime(); diff --git a/lib/features/recipes/services/recipe_service.g.dart b/lib/features/recipes/services/recipe_service.g.dart index f9882b29..e1e9d280 100644 --- a/lib/features/recipes/services/recipe_service.g.dart +++ b/lib/features/recipes/services/recipe_service.g.dart @@ -9,11 +9,7 @@ part of 'recipe_service.dart'; // ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element,unnecessary_string_interpolations class _RecipeService implements RecipeService { - _RecipeService( - this._dio, { - this.baseUrl, - this.errorLogger, - }); + _RecipeService(this._dio, {this.baseUrl, this.errorLogger}); final Dio _dio; @@ -27,22 +23,16 @@ class _RecipeService implements RecipeService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType(Options( - method: 'GET', - headers: _headers, - extra: _extra, - ) - .compose( - _dio.options, - '/api/recipes/show/${id}', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + final _options = _setStreamType( + Options(method: 'GET', headers: _headers, extra: _extra) + .compose( + _dio.options, + '/api/recipes/show/${id}', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); final _result = await _dio.fetch>(_options); late RecipeModel _value; try { @@ -60,30 +50,27 @@ class _RecipeService implements RecipeService { final queryParameters = {r'name': name}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType>>(Options( - method: 'GET', - headers: _headers, - extra: _extra, - ) - .compose( - _dio.options, - '/api/diary/product_nutritional_values/filter', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + final _options = _setStreamType>>( + Options(method: 'GET', headers: _headers, extra: _extra) + .compose( + _dio.options, + '/api/diary/product_nutritional_values/filter', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); final _result = await _dio.fetch>(_options); late Map> _value; try { - _value = _result.data!.map((k, dynamic v) => MapEntry( + _value = _result.data!.map( + (k, dynamic v) => MapEntry( k, (v as List) .map((i) => Product.fromJson(i as Map)) - .toList())); + .toList(), + ), + ); } on Object catch (e, s) { errorLogger?.logError(e, s, _options); rethrow; @@ -97,51 +84,40 @@ class _RecipeService implements RecipeService { final queryParameters = {}; final _headers = {}; final _data = formData; - final _options = _setStreamType(Options( - method: 'POST', - headers: _headers, - extra: _extra, - contentType: 'multipart/form-data', - ) - .compose( - _dio.options, - '/api/recipes/create', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + final _options = _setStreamType( + Options( + method: 'POST', + headers: _headers, + extra: _extra, + contentType: 'multipart/form-data', + ) + .compose( + _dio.options, + '/api/recipes/create', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); await _dio.fetch(_options); } @override - Future editRecipe( - Map recipe, - String id, - ) async { + Future editRecipe(Map recipe, String id) async { final _extra = {}; final queryParameters = {}; final _headers = {}; final _data = FormData.fromMap(recipe); - final _options = _setStreamType(Options( - method: 'POST', - headers: _headers, - extra: _extra, - ) - .compose( - _dio.options, - '/api/recipes/update/{id}', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + final _options = _setStreamType( + Options(method: 'POST', headers: _headers, extra: _extra) + .compose( + _dio.options, + '/api/recipes/update/{id}', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); final _result = await _dio.fetch>(_options); late RecipeModel _value; try { @@ -159,22 +135,16 @@ class _RecipeService implements RecipeService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType(Options( - method: 'GET', - headers: _headers, - extra: _extra, - ) - .compose( - _dio.options, - '/api/recipes/tags', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + final _options = _setStreamType( + Options(method: 'GET', headers: _headers, extra: _extra) + .compose( + _dio.options, + '/api/recipes/tags', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); final _result = await _dio.fetch>(_options); late RecipeTagModel _value; try { @@ -199,10 +169,7 @@ class _RecipeService implements RecipeService { return requestOptions; } - String _combineBaseUrls( - String dioBaseUrl, - String? baseUrl, - ) { + String _combineBaseUrls(String dioBaseUrl, String? baseUrl) { if (baseUrl == null || baseUrl.trim().isEmpty) { return dioBaseUrl; } diff --git a/lib/features/registration/services/registration_service.g.dart b/lib/features/registration/services/registration_service.g.dart index c7b90410..f9560e28 100644 --- a/lib/features/registration/services/registration_service.g.dart +++ b/lib/features/registration/services/registration_service.g.dart @@ -9,11 +9,7 @@ part of 'registration_service.dart'; // ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element,unnecessary_string_interpolations class _RegistrationService implements RegistrationService { - _RegistrationService( - this._dio, { - this.baseUrl, - this.errorLogger, - }); + _RegistrationService(this._dio, {this.baseUrl, this.errorLogger}); final Dio _dio; @@ -22,29 +18,24 @@ class _RegistrationService implements RegistrationService { final ParseErrorLogger? errorLogger; @override - Future> register( - {required Map sheet}) async { + Future> register({ + required Map sheet, + }) async { final _extra = {}; final queryParameters = {}; final _headers = {}; final _data = {}; _data.addAll(sheet); - final _options = _setStreamType>(Options( - method: 'POST', - headers: _headers, - extra: _extra, - ) - .compose( - _dio.options, - '/api/register', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + final _options = _setStreamType>( + Options(method: 'POST', headers: _headers, extra: _extra) + .compose( + _dio.options, + '/api/register', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); final _result = await _dio.fetch>(_options); late Map _value; try { @@ -62,22 +53,16 @@ class _RegistrationService implements RegistrationService { final queryParameters = {r'user_address': query}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType(Options( - method: 'GET', - headers: _headers, - extra: _extra, - ) - .compose( - _dio.options, - '/api/location_by_address', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + final _options = _setStreamType( + Options(method: 'GET', headers: _headers, extra: _extra) + .compose( + _dio.options, + '/api/location_by_address', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); final _result = await _dio.fetch>(_options); late LocationModel _value; try { @@ -101,22 +86,16 @@ class _RegistrationService implements RegistrationService { }; final _headers = {}; const Map? _data = null; - final _options = _setStreamType(Options( - method: 'GET', - headers: _headers, - extra: _extra, - ) - .compose( - _dio.options, - '/api/location_by_coordinate', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + final _options = _setStreamType( + Options(method: 'GET', headers: _headers, extra: _extra) + .compose( + _dio.options, + '/api/location_by_coordinate', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); final _result = await _dio.fetch>(_options); late LocationModel _value; try { @@ -141,10 +120,7 @@ class _RegistrationService implements RegistrationService { return requestOptions; } - String _combineBaseUrls( - String dioBaseUrl, - String? baseUrl, - ) { + String _combineBaseUrls(String dioBaseUrl, String? baseUrl) { if (baseUrl == null || baseUrl.trim().isEmpty) { return dioBaseUrl; } diff --git a/lib/features/settings/presentation/pages/settings_screen.dart b/lib/features/settings/presentation/pages/settings_screen.dart index af2e9387..bd28f36a 100644 --- a/lib/features/settings/presentation/pages/settings_screen.dart +++ b/lib/features/settings/presentation/pages/settings_screen.dart @@ -56,7 +56,7 @@ class _SettingsScreenState extends State { const SizedBox(height: 12), _aboutEatvio(state), const SizedBox(height: 12), - if (state.profile.role != 'consultant') + if (!state.profile.roles.contains('consultant')) Padding( padding: const EdgeInsets.only(bottom: 8), child: _becomeConsultantButton(state), diff --git a/lib/features/settings/services/settings_service.g.dart b/lib/features/settings/services/settings_service.g.dart index d08c842a..0ba4263c 100644 --- a/lib/features/settings/services/settings_service.g.dart +++ b/lib/features/settings/services/settings_service.g.dart @@ -9,11 +9,7 @@ part of 'settings_service.dart'; // ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element,unnecessary_string_interpolations class _SettingsService implements SettingsService { - _SettingsService( - this._dio, { - this.baseUrl, - this.errorLogger, - }); + _SettingsService(this._dio, {this.baseUrl, this.errorLogger}); final Dio _dio; @@ -27,22 +23,16 @@ class _SettingsService implements SettingsService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType(Options( - method: 'GET', - headers: _headers, - extra: _extra, - ) - .compose( - _dio.options, - '/api/profile/settings', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + final _options = _setStreamType( + Options(method: 'GET', headers: _headers, extra: _extra) + .compose( + _dio.options, + '/api/profile/settings', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); final _result = await _dio.fetch>(_options); late ProfileSettingsModel _value; try { @@ -55,29 +45,24 @@ class _SettingsService implements SettingsService { } @override - Future updateProfileSettings( - {required Map data}) async { + Future updateProfileSettings({ + required Map data, + }) async { final _extra = {}; final queryParameters = {}; final _headers = {}; final _data = {}; _data.addAll(data); - final _options = _setStreamType(Options( - method: 'PUT', - headers: _headers, - extra: _extra, - ) - .compose( - _dio.options, - '/api/profile/settings/update', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + final _options = _setStreamType( + Options(method: 'PUT', headers: _headers, extra: _extra) + .compose( + _dio.options, + '/api/profile/settings/update', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); final _result = await _dio.fetch>(_options); late ProfileSettingsModel _value; try { @@ -90,29 +75,24 @@ class _SettingsService implements SettingsService { } @override - Future updateProfileDetails( - {required Map data}) async { + Future updateProfileDetails({ + required Map data, + }) async { final _extra = {}; final queryParameters = {}; final _headers = {}; final _data = {}; _data.addAll(data); - final _options = _setStreamType(Options( - method: 'PUT', - headers: _headers, - extra: _extra, - ) - .compose( - _dio.options, - '/api/profile/update', - queryParameters: queryParameters, - data: _data, - ) - .copyWith( - baseUrl: _combineBaseUrls( - _dio.options.baseUrl, - baseUrl, - ))); + final _options = _setStreamType( + Options(method: 'PUT', headers: _headers, extra: _extra) + .compose( + _dio.options, + '/api/profile/update', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); final _result = await _dio.fetch>(_options); late ProfileDetailsModel _value; try { @@ -137,10 +117,7 @@ class _SettingsService implements SettingsService { return requestOptions; } - String _combineBaseUrls( - String dioBaseUrl, - String? baseUrl, - ) { + String _combineBaseUrls(String dioBaseUrl, String? baseUrl) { if (baseUrl == null || baseUrl.trim().isEmpty) { return dioBaseUrl; } diff --git a/test/features/profile/services/profile_service_test.dart b/test/features/profile/services/profile_service_test.dart index 4db6526b..dc04bfd2 100644 --- a/test/features/profile/services/profile_service_test.dart +++ b/test/features/profile/services/profile_service_test.dart @@ -23,7 +23,7 @@ void main() { isEntitySubscribedByMe: false, slug: 'slug', profilePhotoUrl: '', - role: 'user', + roles: ['user'], badges: [], subscriptions: [], subscribers: [],