diff --git a/lib/features/blog_post_create/presentation/pages/blog_post_create_screen.dart b/lib/features/blog_post_create/presentation/pages/blog_post_create_screen.dart index 0254d3c7..6da09b9e 100644 --- a/lib/features/blog_post_create/presentation/pages/blog_post_create_screen.dart +++ b/lib/features/blog_post_create/presentation/pages/blog_post_create_screen.dart @@ -568,6 +568,7 @@ class _BlogPostCreateScreenState extends State { CustomTextFormField(key: AppKeys.blogPostCreateScreenVideoLinkTextField, controller: videoUrlController), const SizedBox(height: 80), _createBlogPostButton(), + const SizedBox(height: 80), ], ), ), diff --git a/lib/features/create_recipe/presentation/pages/recipe_create_screen.dart b/lib/features/create_recipe/presentation/pages/recipe_create_screen.dart index 96fb5a38..a749186d 100644 --- a/lib/features/create_recipe/presentation/pages/recipe_create_screen.dart +++ b/lib/features/create_recipe/presentation/pages/recipe_create_screen.dart @@ -134,7 +134,7 @@ class _RecipeCreateScreenState extends State { padding: const EdgeInsets.all(16), alignment: Alignment.center, child: Text( - widget.recipe != null ? 'Обновить' : 'Опубликовать', + (widget.recipe != null && widget.recipe?.state != 'drafted') ? 'Обновить' : 'Опубликовать', style: const TextStyle(fontSize: 16, color: Colors.white, fontWeight: FontWeight.w600), ), ), @@ -180,7 +180,7 @@ class _RecipeCreateScreenState extends State { padding: const EdgeInsets.all(16), alignment: Alignment.center, child: Text( - 'Сохранить как черновик', + widget.recipe != null ? 'Обновить черновик' : 'Сохранить как черновик', style: TextStyle(fontSize: 16, color: appTheme.blueA400, fontWeight: FontWeight.w600), ), ), diff --git a/lib/features/recipe/models/my_recipe_model.dart b/lib/features/recipe/models/my_recipe_model.dart index c55f2e77..c3f82b17 100644 --- a/lib/features/recipe/models/my_recipe_model.dart +++ b/lib/features/recipe/models/my_recipe_model.dart @@ -1,5 +1,6 @@ import 'package:eatvio_app/features/create_recipe/models/recipe_model.dart'; import 'package:eatvio_app/features/create_recipe/models/step.dart' as cr_step; +import 'package:eatvio_app/features/create_recipe/models/ingredient.dart' as cr_ingredient; import 'package:eatvio_app/features/feed/models/recipes_model.dart'; import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; @@ -83,3 +84,26 @@ extension MyRecipeModelX on MyRecipeModel { ); } } + +extension RecipeToRecipeModelX on Recipe { + RecipeModel toRecipeModel() { + return RecipeModel( + title: title, + description: description, + image: image, + totalCookingTime: cookingTime, + activeCookTime: activeCookingTime, + energyPerServing: calories.toInt(), + videoUrl: videoUrl, + state: 'active', + steps: steps?.map((e) => cr_step.Step(image: e.image, description: e.description)).toList(), + ingredients: ingredients?.map((e) => cr_ingredient.Ingredient( + name: e.name, + portion: e.portion, + unit: e.unit ?? '', + productId: e.productId, + )).toList() ?? [], + tags: tags.map((e) => e.name).toList(), + ); + } +} diff --git a/lib/features/recipe/presentation/pages/my_recipes_screen.dart b/lib/features/recipe/presentation/pages/my_recipes_screen.dart index 4c409ea7..2b8668a8 100644 --- a/lib/features/recipe/presentation/pages/my_recipes_screen.dart +++ b/lib/features/recipe/presentation/pages/my_recipes_screen.dart @@ -33,39 +33,40 @@ class MyRecipesScreen extends StatelessWidget { create: (BuildContext context) => sl()..getMyRecipes(), child: BlocBuilder( builder: (BuildContext context, MyRecipesState state) { - return Column( + return Stack( children: [ - MyRecipesTab( - selectedIndex: state is MyRecipesStateLoaded - ? (state.selectedState == MyRecipesCubit.drafted ? 1 : 0) - : 0, - onTabChanged: (index) { - if (index == 0) { - context.read().setActiveState(); - } else { - context.read().setDraftedState(); - } - }, - ), - Expanded( + Positioned.fill( child: state is MyRecipesStateLoaded ? state.recipes.isEmpty - ? Center( - child: Text( - state.selectedState == MyRecipesCubit.drafted - ? 'Нет черновиков' - : 'Нет опубликованных рецептов', - style: TextStyles.textLMedium.copyWith(color: appTheme.gray500), - ), - ) - : ListView.separated( - padding: const EdgeInsets.symmetric(vertical: 16), - itemBuilder: (context, index) => MyRecipeWidget(recipe: state.recipes[index]), - separatorBuilder: (context, index) => const SizedBox(height: 12), - itemCount: state.recipes.length, - ) + ? Center( + child: Text( + state.selectedState == MyRecipesCubit.drafted ? 'Нет черновиков' : 'Нет опубликованных рецептов', + style: TextStyles.textLMedium.copyWith(color: appTheme.gray500), + ), + ) + : ListView.separated( + padding: const EdgeInsets.only(top: 80, bottom: 16), + itemBuilder: (context, index) => MyRecipeWidget(recipe: state.recipes[index]), + separatorBuilder: (context, index) => const SizedBox(height: 12), + itemCount: state.recipes.length, + ) : const Center(child: CircularProgressIndicator()), ), + Positioned( + top: 16, + left: 16, + right: 16, + child: MyRecipesTab( + selectedIndex: state is MyRecipesStateLoaded ? (state.selectedState == MyRecipesCubit.drafted ? 1 : 0) : 0, + onTabChanged: (index) { + if (index == 0) { + context.read().setActiveState(); + } else { + context.read().setDraftedState(); + } + }, + ), + ), ], ); }, diff --git a/lib/features/recipe/presentation/widgets/my_recipe_widget.dart b/lib/features/recipe/presentation/widgets/my_recipe_widget.dart index 0855b609..31c92082 100644 --- a/lib/features/recipe/presentation/widgets/my_recipe_widget.dart +++ b/lib/features/recipe/presentation/widgets/my_recipe_widget.dart @@ -12,6 +12,7 @@ import 'package:eatvio_app/features/recipe/presentation/cubit/my_recipes_cubit/m import 'package:eatvio_app/generated/l10n.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:eatvio_app/features/create_recipe/presentation/bloc/create_recipe_cubit/create_recipe_cubit.dart'; import 'package:eatvio_app/features/create_recipe/presentation/pages/recipe_create_screen.dart'; import 'package:eatvio_app/core/widgets/markdown_html_widget.dart'; import 'package:flutter_svg/flutter_svg.dart'; @@ -145,8 +146,17 @@ class _MyRecipeWidgetState extends State { Expanded( child: isDraft ? CustomOutlinedButton( - onPressed: () { - context.push(RecipeCreateScreen.path, extra: widget.recipe.toRecipe()); + onPressed: () async { + showDialog( + context: context, + barrierColor: Colors.black12, + builder: (context) => const Center(child: CircularProgressIndicator()), + ); + final fullRecipe = await context.read().getRecipeById(widget.recipe.slug); + if (context.mounted) { + Navigator.pop(context); // close dialog + context.push(RecipeCreateScreen.path, extra: fullRecipe); + } }, height: 52, buttonStyle: ButtonStyle( @@ -180,27 +190,6 @@ class _MyRecipeWidgetState extends State { ], ), ), - if (!isDraft) - PopupMenuItem( - onTap: () async { - final result = await context.read().draftRecipe(widget.recipe.id); - if (result) { - showSuccessToast('Рецепт перенесен в черновики'); - if (context.mounted) { - context.read().getMyRecipes(); - } - } else { - showErrorToast('Не удалось перенести в черновики'); - } - }, - child: Row( - children: [ - Icon(Icons.archive_outlined, size: 20, color: appTheme.black), - const SizedBox(width: 8), - const Text('В черновик', style: TextStyles.textSMedium), - ], - ), - ), ], child: CustomOutlinedButton( onPressed: () {}, @@ -225,21 +214,36 @@ class _MyRecipeWidgetState extends State { width: double.infinity, child: CustomOutlinedButton( onPressed: () async { - // Publish draft - final recipeModel = widget.recipe.toRecipeModel(); - final success = await context.read().publishDraft(recipeModel, widget.recipe.slug); - if (success && context.mounted) { - showSuccessToast('Черновик опубликован'); - context.read().setDraftedState(); - } else { - showErrorToast('Заполните все необходимые поля для публикации рецепта'); - if (context.mounted) { - context.push(RecipeCreateScreen.path, extra: { - 'recipe': widget.recipe.toRecipe(), - 'autoValidate': true, - }); - } - } + showDialog( + context: context, + barrierColor: Colors.black12, + builder: (context) => const Center(child: CircularProgressIndicator()), + ); + final fullRecipe = await context.read().getRecipeById(widget.recipe.slug); + final createCubit = sl(); + await createCubit.recipeToEntity(fullRecipe); + + if (context.mounted) { + Navigator.pop(context); + if (createCubit.validateAll()) { + final success = await createCubit.publishRecipe(true, widget.recipe.slug); + if (success && context.mounted) { + showSuccessToast('Черновик опубликован'); + context.read().setDraftedState(); + } else { + showErrorToast('Не удалось опубликовать черновик'); + } + } else { + showErrorToast('Заполните все необходимые поля для публикации рецепта'); + if (context.mounted) { + context.push(RecipeCreateScreen.path, extra: { + 'recipe': fullRecipe, + 'autoValidate': true, + }); + } + } + await createCubit.close(); + } }, height: 52, buttonStyle: ButtonStyle( @@ -252,6 +256,35 @@ class _MyRecipeWidgetState extends State { ), ), ), + if (!isDraft) + Padding( + padding: const EdgeInsets.only(top: 8), + child: SizedBox( + width: double.infinity, + child: CustomOutlinedButton( + onPressed: () async { + final result = await context.read().draftRecipe(widget.recipe.id); + if (result) { + showSuccessToast('Рецепт перенесен в черновики'); + if (context.mounted) { + context.read().getMyRecipes(); + } + } else { + showErrorToast('Не удалось перенести в черновики'); + } + }, + height: 52, + buttonStyle: ButtonStyle( + shape: WidgetStatePropertyAll(RoundedRectangleBorder(borderRadius: BorderRadius.circular(20))), + backgroundColor: WidgetStatePropertyAll(appTheme.lightGray0), + side: const WidgetStatePropertyAll(BorderSide.none), + ), + text: 'Снять с публикации', + buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.black), + ), + ), + ), + const SizedBox(height: 16), ], ), ),