From c91e83adaf84695b14bbb8488ecd367abd4963e5 Mon Sep 17 00:00:00 2001 From: misha Date: Mon, 9 Feb 2026 10:39:51 +0300 Subject: [PATCH] feat(my_diets): fixed draft, active and personal diets creation, updating --- lib/core/routing/other_routes.dart | 17 ++-- .../success_published_diet_bottom_sheet.dart | 46 +++++------ .../presentation/create_diet_screen.dart | 53 +++++++----- .../presentation/cubit/create_diet_cubit.dart | 46 +++++++++-- .../presentation/diet_preview_screen.dart | 56 ++++++++++++- .../presentation/widgets/add_meal_widget.dart | 4 +- .../repositories/create_diet_repository.dart | 81 ++++++++++--------- .../widgets/add_portion_widget.dart | 4 +- .../feed/models/diets_pagination_model.dart | 2 +- .../feed/presentation/pages/feed_screen.dart | 2 +- .../presentation/my_diets_screen.dart | 2 +- .../presentation/widgets/my_diet_widget.dart | 18 ++++- 12 files changed, 221 insertions(+), 110 deletions(-) diff --git a/lib/core/routing/other_routes.dart b/lib/core/routing/other_routes.dart index c09f8983..0e30336e 100644 --- a/lib/core/routing/other_routes.dart +++ b/lib/core/routing/other_routes.dart @@ -71,16 +71,16 @@ class OtherRoutes { try { final profileRepository = sl(); final profile = await profileRepository.getMyProfile(); - + final firebaseApi = sl(); - await firebaseApi.registerPushToken(); + await firebaseApi.registerPushToken(); if (profile.emailVerifiedAt != null || (prefs.getBool(PrefsKeys.isEmailVerificationSkipped) ?? false)) { return RouteConstants.feedScreen; } return RouteConstants.verifyEmailScreen; } catch (e) { - return '/auth-screen'; + return '/auth-screen'; } } else { return '/auth-screen'; @@ -111,12 +111,12 @@ class OtherRoutes { // При любой ошибке пропускаем проверку версии return null; }); - + if (versions == null) { // Если проверка не удалась, пропускаем экран обновления return RouteConstants.welcomeScreen; } - + PackageInfo packageInfo = await PackageInfo.fromPlatform(); String version = packageInfo.version; Version currentVersion = Version.parse(version); @@ -163,15 +163,16 @@ class OtherRoutes { final diet = data['diet'] as Diet?; final isEditing = data['isEditing'] as bool?; return CreateDietScreen(diet: diet, isEditing: isEditing); - }, ), GoRoute( path: DietPreviewScreen.path, name: DietPreviewScreen.name, builder: (context, state) { - final data = state.extra as Diet; - return DietPreviewScreen(diet: data); + final data = state.extra as Map; + final diet = data['diet'] as Diet; + final isImageInBase64 = data['isImageInBase64'] as bool; + return DietPreviewScreen(diet: diet, isImageInBase64: isImageInBase64,); }, ), GoRoute(path: RouteConstants.createPlanScreen, name: 'createPlanScreen', builder: (context, state) => const CreatePlanScreen()), diff --git a/lib/core/widgets/success_published_diet_bottom_sheet.dart b/lib/core/widgets/success_published_diet_bottom_sheet.dart index 223ed220..5b5625b7 100644 --- a/lib/core/widgets/success_published_diet_bottom_sheet.dart +++ b/lib/core/widgets/success_published_diet_bottom_sheet.dart @@ -8,32 +8,33 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; class SuccessPublishedDietOrPlanBottomSheet extends StatelessWidget { - const SuccessPublishedDietOrPlanBottomSheet({super.key, required this.title, this.isPlan = false}); + const SuccessPublishedDietOrPlanBottomSheet({super.key, required this.title, this.isPlan = false, this.isDrafted, this.isUpdated}); final String title; final bool isPlan; + final bool? isDrafted; + final bool? isUpdated; @override Widget build(BuildContext context) { final s = S.of(context); + final String text; + if (isDrafted == true) { + text = 'cохранена в черновиках'; + } else if (isUpdated == true) { + text = 'успешно обновлена'; + } else if (isPlan == true) { + text = 'опубликован'; + } else { + text = 'опубликованна'; + } + return Column( children: [ - const SizedBox( - height: 20, - ), + const SizedBox(height: 20), const BottomSheetHandlerBar(), - const SizedBox( - height: 20, - ), - Text( - title, - style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black), - ), - Text( - isPlan ? 'опубликован' : 'опубликованна', - style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black), - ), - const SizedBox( - height: 20, - ), + const SizedBox(height: 20), + Text(title, style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black)), + Text(text, style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black)), + const SizedBox(height: 20), Padding( padding: const EdgeInsets.symmetric(horizontal: 20), child: CustomOutlinedButton( @@ -43,15 +44,10 @@ class SuccessPublishedDietOrPlanBottomSheet extends StatelessWidget { text: s.ok, height: 52, buttonTextStyle: TextStyles.textSSemibold.copyWith(color: appTheme.whiteA700), - buttonStyle: ButtonStyle( - side: const WidgetStatePropertyAll(BorderSide.none), - backgroundColor: WidgetStatePropertyAll(appTheme.blueA400), - ), + buttonStyle: ButtonStyle(side: const WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll(appTheme.blueA400)), ), ), - const SizedBox( - height: 20, - ), + const SizedBox(height: 20), ], ); } diff --git a/lib/features/create_diet/presentation/create_diet_screen.dart b/lib/features/create_diet/presentation/create_diet_screen.dart index 0abb37a9..6596fd87 100644 --- a/lib/features/create_diet/presentation/create_diet_screen.dart +++ b/lib/features/create_diet/presentation/create_diet_screen.dart @@ -32,21 +32,21 @@ class CreateDietScreen extends StatelessWidget { const CreateDietScreen({super.key, this.diet, this.isEditing}); final Diet? diet; - final bool? isEditing; + final bool? isEditing; @override Widget build(BuildContext context) { return BlocProvider( create: (context) => sl()..setInitialData(diet), - child: CreateDietScreenContent(diet: diet), + child: CreateDietScreenContent(diet: diet, isEditing: isEditing), ); } } class CreateDietScreenContent extends StatefulWidget { - const CreateDietScreenContent({super.key, this.diet}); + const CreateDietScreenContent({super.key, this.diet, this.isEditing}); final Diet? diet; - + final bool? isEditing; @override State createState() => _CreateDietScreenContentState(); } @@ -88,7 +88,7 @@ class _CreateDietScreenContentState extends State { context.pop(); showBottomSheetWithBlur( context: context, - child: SuccessPublishedDietOrPlanBottomSheet(title: '${state.dietData.name ?? 'Диета'} сохраненна в черновиках'), + child: SuccessPublishedDietOrPlanBottomSheet(title: state.dietData.name ?? 'Диета', isDrafted: true), ); }); } @@ -182,14 +182,21 @@ class _CreateDietScreenContentState extends State { children: [ CustomOutlinedButton( onPressed: () async { - context.read().setDietState(DietState.draft); - if (widget.diet != null) { + if (widget.diet != null && widget.isEditing == true) { + if (state.dietState == DietState.draft) { + context.read().setDietState(DietState.active); + } else { + context.read().setDietState(DietState.draft); + } final result = await context.read().updateDiet(widget.diet!.id); if (result == 'error') { if (!context.mounted) return; showErrorDialog(context, title: '${s.could_not_update_diet} ${state.dietData.name}'); } } else { + if (state.dietState != DietState.draft) { + context.read().setDietState(DietState.draft); + } final result = await context.read().createDiet(); if (result == 'error') { if (!context.mounted) return; @@ -197,15 +204,7 @@ class _CreateDietScreenContentState extends State { } } }, - // onPressed: state.isDietPublishing - // ? () {} - // : () async { - // final diet = await context.read().getDietForPreview(); - // if (diet == null) return; - // if (!context.mounted) return; - // GoRouter.of(context).pushNamed(DietPreviewScreen.name, extra: diet); - // }, - text: "В черновик", + text: state.dietState == DietState.draft && widget.isEditing == true ? s.publish : "В черновик", height: 52, buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.gray), buttonStyle: ButtonStyle( @@ -221,7 +220,9 @@ class _CreateDietScreenContentState extends State { final diet = await context.read().getDietForPreview(); if (diet == null) return; if (!context.mounted) return; - GoRouter.of(context).pushNamed(DietPreviewScreen.name, extra: diet); + GoRouter.of( + context, + ).pushNamed(DietPreviewScreen.name, extra: {'diet': diet, 'isImageInBase64': state.dietData.imageUrl == null}); }, text: s.preview, height: 52, @@ -237,13 +238,21 @@ class _CreateDietScreenContentState extends State { else CustomOutlinedButton( onPressed: () async { - if (widget.diet != null) { - final result = await context.read().updateDiet( - widget.diet!.id, - ); + if (widget.diet != null && widget.isEditing == true) { + final result = await context.read().updateDiet(widget.diet!.id); if (result == 'error') { if (!context.mounted) return; showErrorDialog(context, title: '${s.could_not_update_diet} ${state.dietData.name}'); + } else { + Future.delayed(const Duration(milliseconds: 500), () { + if (!context.mounted) return; + context.pop(); + showBottomSheetWithBlur( + userRootNavigator: true, + context: context, + child: SuccessPublishedDietOrPlanBottomSheet(title: state.dietData.name ?? 'Диета', isUpdated: true), + ); + }); } } else { final result = await context.read().createDiet(); @@ -253,7 +262,7 @@ class _CreateDietScreenContentState extends State { } } }, - text: widget.diet != null ? s.save : s.publish, + text: widget.diet != null && widget.isEditing == true ? s.save : s.publish, height: 52, buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700), buttonStyle: ButtonStyle( 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 9cc64123..22803a76 100644 --- a/lib/features/create_diet/presentation/cubit/create_diet_cubit.dart +++ b/lib/features/create_diet/presentation/cubit/create_diet_cubit.dart @@ -49,6 +49,12 @@ class CreateDietCubit extends Cubit { type['carb'] = diet.type.carb ?? false; type['light'] = diet.type.light ?? false; final appConfig = sl(); + String? imageUrl; + if (diet.image?.startsWith('https') == true) { + imageUrl = diet.image; + } else if (diet.image != null && diet.image?.isNotEmpty == true) { + imageUrl = '${appConfig.baseUrl}/storage/${diet.image}'; + } emit( state.copyWith.dietData( dailySchedule: dailySchedule, @@ -57,8 +63,7 @@ class CreateDietCubit extends Cubit { name: diet.name, duration: diet.duration, type: type, - // Avoid network image URLs during tests to prevent HTTP fetch attempts - imageUrl: appConfig.buildType == AppBuildType.tests ? null : '${appConfig.baseUrl}/storage/${diet.image}', + imageUrl: appConfig.buildType == AppBuildType.tests ? null : imageUrl, ), ); emit(state.copyWith(dietState: diet.state, durationIndex: durationValues.indexOf(diet.duration))); @@ -196,7 +201,6 @@ class CreateDietCubit extends Cubit { } Future getDietForPreview() async { - if (!_isFromValid()) return null; final authorProfile = await profileRepository.getMyProfile(); final imageBytes = (await state.dietData.image?.readAsBytes()) ?? []; String image = base64.encode(imageBytes); @@ -305,7 +309,10 @@ class CreateDietCubit extends Cubit { Future createDiet() async { emit(state.copyWith(isDietPublishing: true)); - if (!_isFromValid()) { + if ([DietState.active, DietState.personal].contains(state.dietState) && !_isFromValid()) { + emit(state.copyWith(isDietPublishing: false)); + return 'validation'; + } else if (!_isFormValidForDraft()) { emit(state.copyWith(isDietPublishing: false)); return 'validation'; } @@ -324,12 +331,12 @@ class CreateDietCubit extends Cubit { name: state.dietData.name ?? '', duration: state.dietData.duration ?? 7, state: dietState, - image: image ?? file!, + image: image ?? file, 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 ?? [], ); @@ -343,7 +350,12 @@ class CreateDietCubit extends Cubit { } Future updateDiet(int dietId) async { - // if (!_isFromValid()) return 'error'; + if ([DietState.active, DietState.personal].contains(state.dietState) && !_isFromValid()) { + return 'error'; + } else if (!_isFormValidForDraft()) { + return 'error'; + } + try { File? image; if (state.dietData.image != null) { @@ -359,7 +371,7 @@ class CreateDietCubit extends Cubit { 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?.isEmpty ?? true ? null : state.dietData.details, dailySchedule: state.dietData.dailySchedule, ); return null; @@ -369,6 +381,24 @@ class CreateDietCubit extends Cubit { } } + bool _isFormValidForDraft() { + bool result = true; + if ((state.dietData.name?.length ?? 0) < 3) { + result = false; + emit(state.copyWith(dietNameError: 'Длинна названия не может быть меньше 3 символов')); + } + if (state.dietData.name == null || state.dietData.name == '') { + result = false; + emit(state.copyWith(dietNameError: 'Поле не заполнено')); + } + + if (state.dietData.details?.length != null && (state.dietData.details?.isNotEmpty ?? false) && (state.dietData.details?.length ?? 4) < 3) { + result = false; + emit(state.copyWith(dietDescriptionError: 'Длинна описания не может быть меньше 3 символов')); + } + return result; + } + bool _isFromValid() { bool result = true; if ((state.dietData.name?.length ?? 0) < 3) { diff --git a/lib/features/create_diet/presentation/diet_preview_screen.dart b/lib/features/create_diet/presentation/diet_preview_screen.dart index 2d059896..c7482cd4 100644 --- a/lib/features/create_diet/presentation/diet_preview_screen.dart +++ b/lib/features/create_diet/presentation/diet_preview_screen.dart @@ -1,6 +1,9 @@ import 'dart:convert'; import 'dart:typed_data'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:eatvio_app/core/app_config.dart'; import 'package:eatvio_app/core/enums/product_type.dart'; +import 'package:eatvio_app/core/locator_service.dart'; import 'package:eatvio_app/core/utils/localization_utils.dart'; import 'package:eatvio_app/core/widgets/custom_divider.dart'; import 'package:eatvio_app/core/widgets/info_row.dart'; @@ -18,10 +21,11 @@ import 'package:flutter_svg/svg.dart'; class DietPreviewScreen extends StatefulWidget { final Diet diet; + final bool isImageInBase64; late final List selectedIndexes; static const name = 'createDietScreenPreview'; static const path = '/create-diet-screen/preview'; - DietPreviewScreen({super.key, required this.diet}) { + DietPreviewScreen({super.key, required this.diet, required this.isImageInBase64}) { selectedIndexes = List.generate(diet.dailySchedule.length, (_) => 0); } @@ -35,7 +39,7 @@ class _DietPreviewScreenState extends State { @override void initState() { super.initState(); - if (widget.diet.image != null) { + if (widget.diet.image != null && widget.isImageInBase64) { imageData = base64.decode(widget.diet.image!); } } @@ -109,6 +113,54 @@ class _DietPreviewScreenState extends State { ), ), ], + ) + else if (!widget.isImageInBase64 && widget.diet.image != null && (widget.diet.image?.isNotEmpty ?? false)) + Stack( + children: [ + CachedNetworkImage( + imageUrl: widget.diet.image?.startsWith('https') == true + ? widget.diet.image! + : '${sl().baseUrl}/storage/${widget.diet.image}', + height: 300, + width: MediaQuery.sizeOf(context).width, + fit: BoxFit.fill, + ), + Positioned( + bottom: 16, + left: 0, + right: 0, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + InfoBouble( + backgroundColor: appTheme.whiteA700, + children: [ + SvgPicture.asset('assets/icons/eye.svg', width: 18, height: 12), + const SizedBox(width: 8), + Text(widget.diet.totalViews.toString(), style: TextStyles.textXSSemibold.copyWith(color: appTheme.black)), + ], + ), + const SizedBox(width: 12), + GestureDetector( + onTap: () {}, + child: InfoBouble( + backgroundColor: appTheme.whiteA700, + children: [ + SvgPicture.asset( + 'assets/icons/heart.svg', + width: 14, + height: 12, + colorFilter: widget.diet.wasLikedByMe ? ColorFilter.mode(appTheme.blueA400, BlendMode.srcIn) : null, + ), + const SizedBox(width: 8), + Text(widget.diet.totalLikes.toString(), style: TextStyles.textXSSemibold.copyWith(color: appTheme.black)), + ], + ), + ), + ], + ), + ), + ], ), const SizedBox(height: 16), Padding( 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 ececed87..a8eb36d5 100644 --- a/lib/features/create_diet/presentation/widgets/add_meal_widget.dart +++ b/lib/features/create_diet/presentation/widgets/add_meal_widget.dart @@ -185,7 +185,7 @@ class _AddMealWidgetState extends State { dailyNutrition: DailyNutrition(energy: calories, proteins: proteins, fats: fats, carbohydrates: carbohydrates), quantity: int.parse(quantityController.text), name: glossary.name, - productNutritionalValueId: glossary.id.toString(), + productNutritionalValueId: glossary.id, portion: measurementUnits, ); if (portionIndex == null) { @@ -212,7 +212,7 @@ class _AddMealWidgetState extends State { dailyNutrition: DailyNutrition(energy: calories, proteins: proteins, fats: fats, carbohydrates: carbohydrates), quantity: int.parse(quantityController.text), name: newGlossary.name, - productNutritionalValueId: newGlossary.id.toString(), + productNutritionalValueId: newGlossary.id, portion: measurementUnits, ); if (portionIndex == null) { diff --git a/lib/features/create_diet/repositories/create_diet_repository.dart b/lib/features/create_diet/repositories/create_diet_repository.dart index 84c17072..546d975d 100644 --- a/lib/features/create_diet/repositories/create_diet_repository.dart +++ b/lib/features/create_diet/repositories/create_diet_repository.dart @@ -11,44 +11,56 @@ class CreateDietRepository { 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, + required String? meatType, + required String? carbType, + required String? vegType, + required String? lightType, + required String? details, + required File? image, + required List>>? dailySchedule, }) { 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'], - }); + if (dailySchedule != null) { + 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'], + }); + } } } } + if (details != null) { + dietMap.addAll({'description_md': details}); + } - dietMap.addAll({ - 'name': name, - 'description_md': 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, - ), - }); + if (meatType != null) { + dietMap.addAll({'type[meat]': meatType}); + } - final formData = FormData.fromMap(dietMap); + if (carbType != null) { + dietMap.addAll({'type[carb]': carbType}); + } + + if (vegType != null) { + dietMap.addAll({'type[veg]': vegType}); + } + + if (lightType != null) { + dietMap.addAll({'type[light]': lightType}); + } + if (image != null) { + dietMap.addAll({'image': MultipartFile.fromFileSync(image.path, filename: image.path.split(Platform.pathSeparator).last)}); + } + + dietMap.addAll({'name': name, 'duration': duration}); + + final formData = FormData.fromMap(dietMap); switch (state) { case DietState.active: return createDietService.createPublishedDiet(formData: formData); @@ -133,12 +145,7 @@ class CreateDietRepository { dietMap.addAll({'type[light]': lightType}); } if (image != null) { - dietMap.addAll({ - 'image': MultipartFile.fromFileSync( - image.path, - filename: image.path.split(Platform.pathSeparator).last, - ), - }); + dietMap.addAll({'image': MultipartFile.fromFileSync(image.path, filename: image.path.split(Platform.pathSeparator).last)}); } final formData = FormData.fromMap(dietMap); diff --git a/lib/features/create_recipe/presentation/widgets/add_portion_widget.dart b/lib/features/create_recipe/presentation/widgets/add_portion_widget.dart index 597bc09b..9fd0a25d 100644 --- a/lib/features/create_recipe/presentation/widgets/add_portion_widget.dart +++ b/lib/features/create_recipe/presentation/widgets/add_portion_widget.dart @@ -182,7 +182,7 @@ class _AddPortionWidgetState extends State { dailyNutrition: DailyNutrition(energy: calories, proteins: proteins, fats: fats, carbohydrates: carbohydrates), quantity: int.parse(quantityController.text), name: glossary.name, - productNutritionalValueId: glossary.id.toString(), + productNutritionalValueId: glossary.id, portion: measurementUnits, ); if (portionIndex == null) { @@ -212,7 +212,7 @@ class _AddPortionWidgetState extends State { dailyNutrition: DailyNutrition(energy: calories, proteins: proteins, fats: fats, carbohydrates: carbohydrates), quantity: int.parse(quantityController.text), name: newGlossary.name, - productNutritionalValueId: newGlossary.id.toString(), + productNutritionalValueId: newGlossary.id, portion: measurementUnits, ); if (portionIndex == null) { diff --git a/lib/features/feed/models/diets_pagination_model.dart b/lib/features/feed/models/diets_pagination_model.dart index 857a529b..aec36295 100644 --- a/lib/features/feed/models/diets_pagination_model.dart +++ b/lib/features/feed/models/diets_pagination_model.dart @@ -105,7 +105,7 @@ abstract class DailySchedule with _$DailySchedule { @JsonKey(name: "portion") required Portion portion, @JsonKey(name: "quantity", fromJson: _parseQuantity) required int quantity, @JsonKey(name: 'nutrition', includeToJson: false) DailyNutrition? dailyNutrition, - @JsonKey(name: 'product_nutritional_value_id', includeToJson: true, includeFromJson: false, includeIfNull: false) String? productNutritionalValueId, + @JsonKey(name: 'product_nutritional_value_id', includeToJson: true, includeFromJson: true, includeIfNull: false) int? productNutritionalValueId, }) = _DailySchedule; factory DailySchedule.fromJson(Map json) => _$DailyScheduleFromJson(json); diff --git a/lib/features/feed/presentation/pages/feed_screen.dart b/lib/features/feed/presentation/pages/feed_screen.dart index 408f00c4..579c8d21 100644 --- a/lib/features/feed/presentation/pages/feed_screen.dart +++ b/lib/features/feed/presentation/pages/feed_screen.dart @@ -234,7 +234,7 @@ class _FeedScreenContentState extends State { 2 => AddItemButton( onTap: state.profile?.roles.contains('consultant') ?? false ? () async { - await GoRouter.of(context).pushNamed(CreateDietScreen.name); + await GoRouter.of(context).pushNamed(CreateDietScreen.name, extra: {'isEditing': false}); } : null, ), diff --git a/lib/features/my_diets/presentation/my_diets_screen.dart b/lib/features/my_diets/presentation/my_diets_screen.dart index 01ed19fa..4a409f5d 100644 --- a/lib/features/my_diets/presentation/my_diets_screen.dart +++ b/lib/features/my_diets/presentation/my_diets_screen.dart @@ -107,7 +107,7 @@ class MyDietsScreenContent extends StatelessWidget { ), ), const SizedBox(width: 12), - AddItemButton(onTap: () => GoRouter.of(context).pushNamed(CreateDietScreen.name)), + AddItemButton(onTap: () => GoRouter.of(context).pushNamed(CreateDietScreen.name, extra: {'isEditing': false})), const SizedBox(width: 4), ], ), 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 166ff523..c4f7aeaf 100644 --- a/lib/features/my_diets/presentation/widgets/my_diet_widget.dart +++ b/lib/features/my_diets/presentation/widgets/my_diet_widget.dart @@ -251,7 +251,7 @@ class _MyDietWidgetState extends State { Expanded( child: CustomOutlinedButton( onPressed: () async { - GoRouter.of(context).pushNamed(DietPreviewScreen.name, extra: widget.diet); + GoRouter.of(context).pushNamed(DietPreviewScreen.name, extra: {'diet': widget.diet, 'isImageInBase64': false}); }, text: 'Превью', height: 52, @@ -263,6 +263,22 @@ class _MyDietWidgetState extends State { ), ), ), + const SizedBox(width: 6), + CustomOutlinedButton( + onPressed: () async { + _deleteDiet(widget.diet, context); + }, + height: 52, + width: 52, + leftIcon: SvgPicture.asset('assets/icons/trash_can.svg', width: 20, height: 20), + buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.red), + buttonStyle: ButtonStyle( + shape: WidgetStatePropertyAll(RoundedRectangleBorder(borderRadius: BorderRadius.circular(20))), + backgroundColor: WidgetStatePropertyAll(appTheme.lightGray0), + side: const WidgetStatePropertyAll(BorderSide.none), + ), + text: '', + ), ], ), ],