feat(recipe): add recipe creating

This commit is contained in:
Alex
2024-12-18 11:55:32 +03:00
parent a58fbf1ee4
commit f6d4ea7df6
7 changed files with 0 additions and 2244 deletions

View File

@@ -1,300 +0,0 @@
import 'package:eatvio_app/core/data/selectionPopupModel/selection_popup_model.dart';
import 'package:eatvio_app/features/recipes/models/ingredient.dart';
import 'package:eatvio_app/features/recipes/models/recipe_model.dart';
import 'package:eatvio_app/features/recipes/presentation/bloc/recipe_create_state.dart';
import 'package:eatvio_app/features/recipes/reporitories/recipe_repository.dart';
import 'package:eatvio_app/features/recipes/models/product.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:image_picker/image_picker.dart';
class RecipeCreateCubit extends Cubit<RecipeCreateState> {
final RecipeRepository recipeRepository;
RecipeCreateCubit({required this.recipeRepository}) : super(const RecipeCreateState.loading());
loadRecipeById(String recipeID) async {
emit(const RecipeCreateStateLoading());
try {
final RecipeModel recipe = await recipeRepository.getRecipe(recipeID);
final List<SelectionPopupModel> types = [
SelectionPopupModel(title: 'Первые блюда', value: 'first_meals'),
SelectionPopupModel(title: 'Вторые блюда', value: 'second_meals'),
SelectionPopupModel(title: 'Cалаты', value: 'salads'),
SelectionPopupModel(title: 'Перекусы/закуски', value: 'snacks'),
SelectionPopupModel(title: 'Сладости', value: 'sweets'),
SelectionPopupModel(title: 'Напитки', value: 'drinks'),
SelectionPopupModel(title: 'Прочее', value: 'other'),
];
final List<SelectionPopupModel> cookingTimes = [
SelectionPopupModel(title: '10 минут', value: 10),
SelectionPopupModel(title: '20 минут', value: 20),
SelectionPopupModel(title: '30 минут', value: 30),
SelectionPopupModel(title: '1 час', value: 60),
SelectionPopupModel(title: '2 часа', value: 120),
SelectionPopupModel(title: '10 дней', value: 14400),
];
final List<SelectionPopupModel> statuses = [
SelectionPopupModel(title: 'Активна', value: 'active'),
SelectionPopupModel(title: 'Неактивна', value: 'inactive'),
];
final selectedType = types.firstWhere(
(type) => type.value == recipe.type,
orElse: () => types[0],
);
final selectedCookingTime = cookingTimes.firstWhere(
(time) => time.value == recipe.cooking_time,
orElse: () => cookingTimes[0],
);
final selectedStatus = statuses.firstWhere(
(status) => status.value == recipe.state,
orElse: () => statuses[0],
);
final stepControllers = recipe.steps?.map((step) {
return TextEditingController(text: step?.description);
}).toList();
final stepImages = recipe.steps?.map((step) {
return step?.image != null ? XFile(step!.image!) : null;
}).toList();
final ingredients = recipe.ingredients?.map((ingredient) {
return Ingredient(
name: ingredient!.name,
portion: ingredient.portion,
unit: ingredient.unit,
);
}).toList();
emit(RecipeCreateState.loaded(
picker: ImagePicker(),
recipeImage: XFile(recipe.image!),
titleController: TextEditingController(text: recipe.title),
productNameController: TextEditingController(),
ingredientController: TextEditingController(),
stepDescriptionController: TextEditingController(text: recipe.description),
videoLinkController: TextEditingController(text: recipe.video_url),
stepControllers: stepControllers ?? [],
stepImages: stepImages ?? [],
autocompleteList: [],
ingredients: ingredients ?? [],
numberOfSteps: 1,
ingredientAsItems: false,
types: types,
cookingTimes: cookingTimes,
statuses: statuses,
selectedType: selectedType,
selectedCookingTime: selectedCookingTime,
selectedStatus: selectedStatus,),);
} catch (e) {
emit(RecipeCreateState.error(errorMessage: e.toString()));
}
}
loadRecipeCreate() {
emit(const RecipeCreateStateLoading());
try {
final List<SelectionPopupModel> types = [
SelectionPopupModel(title: 'Первые блюда', value: 'first_meals'),
SelectionPopupModel(title: 'Вторые блюда', value: 'second_meals'),
SelectionPopupModel(title: 'Cалаты', value: 'salads'),
SelectionPopupModel(title: 'Перекусы/закуски', value: 'snacks'),
SelectionPopupModel(title: 'Сладости', value: 'sweets'),
SelectionPopupModel(title: 'Напитки', value: 'drinks'),
SelectionPopupModel(title: 'Прочее', value: 'other'),
];
final List<SelectionPopupModel> cookingTimes = [
SelectionPopupModel(title: '10 минут', value: 10),
SelectionPopupModel(title: '20 минут', value: 20),
SelectionPopupModel(title: '30 минут', value: 30),
SelectionPopupModel(title: '1 час', value: 60),
SelectionPopupModel(title: '2 часа', value: 120),
SelectionPopupModel(title: '10 дней', value: 14400),
];
final List<SelectionPopupModel> statuses = [
SelectionPopupModel(title: 'Активна', value: 'active'),
SelectionPopupModel(title: 'Неактивна', value: 'inactive'),
];
emit(RecipeCreateState.loaded(
picker: ImagePicker(),
titleController: TextEditingController(),
productNameController: TextEditingController(),
ingredientController: TextEditingController(),
stepDescriptionController: TextEditingController(),
videoLinkController: TextEditingController(),
stepControllers: [TextEditingController()],
stepImages: [null],
autocompleteList: [],
ingredients: [],
numberOfSteps: 1,
ingredientAsItems: false,
types: types,
cookingTimes: cookingTimes,
statuses: statuses,
selectedType: types[0],
selectedCookingTime: cookingTimes[0],
selectedStatus: statuses[0],),);
} catch (e) {
emit(RecipeCreateState.error(errorMessage: e.toString()));
}
}
publishRecipe(RecipeModel recipe) async {
await recipeRepository.publishRecipe(recipe);
}
editRecipe(RecipeModel recipe, String id) async {
await recipeRepository.editRecipe(recipe, id);
}
uploadRecipeImage(XFile? pickedFile) {
try {
if (state is RecipeCreateStateLoaded) {
var currentState = state as RecipeCreateStateLoaded;
var updatedState = currentState.copyWith(
recipeImage: pickedFile,
);
emit(updatedState);
}
} catch (e) {
emit(RecipeCreateState.error(errorMessage: e.toString()));
}
}
uploadStepImage(XFile? pickedFile, int stepNumber) {
try {
if (state is RecipeCreateStateLoaded) {
var currentState = state as RecipeCreateStateLoaded;
var updatedStepImages = List<XFile?>.from(currentState.stepImages);
if (stepNumber >= 0 && stepNumber < updatedStepImages.length) {
updatedStepImages[stepNumber] = pickedFile;
}
var updatedState = currentState.copyWith(
stepImages: updatedStepImages,
);
emit(updatedState);
}
} catch (e) {
emit(RecipeCreateState.error(errorMessage: e.toString()));
}
}
switchUnits(bool value) {
try {
if (state is RecipeCreateStateLoaded) {
var currentState = state as RecipeCreateStateLoaded;
var updatedState = currentState.copyWith(ingredientAsItems: value);
emit(updatedState);
}
} catch (e) {
emit(RecipeCreateState.error(errorMessage: e.toString()));
}
}
addIngredient(Ingredient ingredient) {
try {
if (state is RecipeCreateStateLoaded) {
var currentState = state as RecipeCreateStateLoaded;
bool ingredientExists = currentState.ingredients.any((existingIngredient) => existingIngredient.name == ingredient.name);
if (ingredientExists) {
emit(RecipeCreateState.error(errorMessage: 'Ингредиент уже существует.'));
return;
}
List<Ingredient> newIngredients = List<Ingredient>.from(currentState.ingredients);
newIngredients.add(ingredient);
var updatedState = currentState.copyWith(ingredients: newIngredients);
emit(updatedState);
}
} catch (e) {
emit(RecipeCreateState.error(errorMessage: e.toString()));
}
}
addStep() {
try {
if (state is RecipeCreateStateLoaded) {
var currentState = state as RecipeCreateStateLoaded;
List<XFile?> newStepImages = List<XFile?>.from(currentState.stepImages);
newStepImages.add(null);
List<TextEditingController> newStepControllers = List<TextEditingController>.from(currentState.stepControllers);
newStepControllers.add(TextEditingController());
var updatedState = currentState.copyWith(stepImages: newStepImages, stepControllers: newStepControllers, numberOfSteps: currentState.numberOfSteps + 1);
emit(updatedState);
}
} catch (e) {
emit(RecipeCreateState.error(errorMessage: e.toString()));
}
}
removeStep() {
try {
if (state is RecipeCreateStateLoaded) {
var currentState = state as RecipeCreateStateLoaded;
List<XFile?> newStepImages = List<XFile?>.from(currentState.stepImages);
newStepImages.removeLast();
List<TextEditingController> newStepControllers = List<TextEditingController>.from(currentState.stepControllers);
newStepControllers.removeLast();
var updatedState = currentState.copyWith(stepImages: newStepImages, stepControllers: newStepControllers, numberOfSteps: currentState.numberOfSteps - 1);
emit(updatedState);
}
} catch (e) {
emit(RecipeCreateState.error(errorMessage: e.toString()));
}
}
inputProduct(String input) async {
if (state is RecipeCreateStateLoaded) {
var currentState = state as RecipeCreateStateLoaded;
final Map<String, List<Product>> productNutritionalValues = await recipeRepository.inputProduct(input);
var updatedState = currentState.copyWith(
productNameController: TextEditingController(text: input),
autocompleteList: productNutritionalValues['product_nutritional_value'] ?? [],
);
emit(updatedState);
}
}
changeType(SelectionPopupModel type) {
if (state is RecipeCreateStateLoaded) {
var currentState = state as RecipeCreateStateLoaded;
RecipeCreateStateLoaded updatedState = currentState.copyWith(
selectedType: type,
);
emit(updatedState);
}
}
changeStatus(SelectionPopupModel status) {
if (state is RecipeCreateStateLoaded) {
var currentState = state as RecipeCreateStateLoaded;
RecipeCreateStateLoaded updatedState = currentState.copyWith(
selectedStatus: status,
);
emit(updatedState);
}
}
changeCookingTime(SelectionPopupModel cookingTime) {
if (state is RecipeCreateStateLoaded) {
var currentState = state as RecipeCreateStateLoaded;
RecipeCreateStateLoaded updatedState = currentState.copyWith(
selectedCookingTime: cookingTime,
);
emit(updatedState);
}
}
}

View File

@@ -1,42 +0,0 @@
import 'package:eatvio_app/core/data/selectionPopupModel/selection_popup_model.dart';
import 'package:eatvio_app/features/recipes/models/recipe_model.dart';
import 'package:eatvio_app/features/recipes/models/ingredient.dart';
import 'package:eatvio_app/features/recipes/models/product.dart';
import 'package:flutter/material.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:image_picker/image_picker.dart';
part 'recipe_create_state.freezed.dart';
@freezed
abstract class RecipeCreateState with _$RecipeCreateState {
const factory RecipeCreateState() = _RecipeCreateState;
const factory RecipeCreateState.loading() = RecipeCreateStateLoading;
const factory RecipeCreateState.loaded({
RecipeModel? recipe,
required ImagePicker picker,
required TextEditingController titleController,
required TextEditingController productNameController,
required TextEditingController ingredientController,
required TextEditingController stepDescriptionController,
required TextEditingController videoLinkController,
required List<TextEditingController> stepControllers,
XFile? recipeImage,
required List<XFile?> stepImages,
required List<Ingredient> ingredients,
required List<Product> autocompleteList,
required int numberOfSteps,
required bool ingredientAsItems,
required List<SelectionPopupModel> types,
required List<SelectionPopupModel> cookingTimes,
required List<SelectionPopupModel> statuses,
required SelectionPopupModel selectedType,
required SelectionPopupModel selectedCookingTime,
required SelectionPopupModel selectedStatus,
}) = RecipeCreateStateLoaded;
const factory RecipeCreateState.error({
required String errorMessage,
}) = RecipeCreateStateError;
}

View File

@@ -1,516 +0,0 @@
import 'package:eatvio_app/core/const.dart';
import 'package:eatvio_app/core/theme/app_decoration.dart';
import 'package:eatvio_app/core/widgets/custom_drop_down.dart';
import 'package:eatvio_app/core/widgets/loader.dart';
import 'package:eatvio_app/features/recipes/models/product.dart';
import 'package:eatvio_app/features/recipes/models/ingredient.dart';
import 'package:eatvio_app/features/recipes/models/recipe_model.dart';
import 'package:eatvio_app/features/recipes/models/step.dart' as step;
import 'package:eatvio_app/features/recipes/presentation/bloc/recipe_create_cubit.dart';
import 'package:eatvio_app/features/recipes/presentation/bloc/recipe_create_state.dart';
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/custom_text_form_field.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:image_picker/image_picker.dart';
// ignore: must_be_immutable
class RecipeEditScreen extends StatelessWidget {
final String recipeID;
const RecipeEditScreen({
required this.recipeID,
super.key,
});
Widget build(BuildContext context) {
if (recipeID != "0") {
context.read<RecipeCreateCubit>().loadRecipeById(recipeID);
}
return BlocBuilder<RecipeCreateCubit, RecipeCreateState>(
builder: (context, state) {
if (state is RecipeCreateStateLoaded) {
return _buildRecipeCreate(context, state);
} else if (state is RecipeCreateStateLoading) {
return Scaffold(
body: Loader(),
);
} else if (state is RecipeCreateStateError) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(16),
child: Center(
child: Text(state.errorMessage),
),
),
);
} else
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(16),
child: Center(
child: Text("Неопределенная ошибка"),
),
),
);
},
);
}
Widget _buildRecipeCreate(BuildContext context, RecipeCreateStateLoaded state) {
List<String> _options = state.autocompleteList.map((Product item) => item.name).toList();
return Scaffold(
appBar: AppBar(
actions: [
InkWell(
borderRadius: BorderRadius.circular(16),
child: Ink(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(height: 4),
Text(
state.titleController.text,
style: TextStyle(
color: Colors.black,
fontSize: 14,
fontWeight: FontWeight.w400,
height: 1,
),
),
],
),
),
),
],
),
backgroundColor: Color.fromARGB(255, 240, 242, 245),
resizeToAvoidBottomInset: true,
body: SizedBox(
width: double.maxFinite,
child: SingleChildScrollView(
child: Column(
children: [
Container(
padding: EdgeInsets.symmetric(
horizontal: 24,
vertical: 12,
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: const BorderRadius.all(Radius.circular(8)),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Заголовок'),
SizedBox(height: 8),
CustomTextFormField(
fillColor: appTheme.gray50,
controller: state.titleController,
hintText: 'Заголовок',
),
SizedBox(height: 16),
Text('Тип блюда'),
SizedBox(height: 8),
CustomDropDown(
value: state.selectedType,
items: state.types,
onChanged: changeType(context),
),
SizedBox(height: 16),
Text('Изображение'),
GestureDetector(
onTap: () async {
final pickedFile = await state.picker.pickImage(source: ImageSource.gallery);
context.read<RecipeCreateCubit>().uploadRecipeImage(pickedFile);
},
child: state.recipeImage == null
? Container(
height: 128,
decoration: AppDecoration.fillGray.copyWith(
borderRadius: BorderRadius.circular(16),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(
Icons.photo_library,
color: appTheme.blueGray300,
),
SizedBox(width: 8),
Text(
"Добавить фото",
selectionColor: appTheme.blueA400,
),
],
),
)
: Image.network(
baseUrl + '/storage/' + state.recipeImage!.path,
height: 150,
fit: BoxFit.cover,
),
),
SizedBox(height: 16),
Text('Время приготовления'),
SizedBox(height: 8),
CustomDropDown(
items: state.cookingTimes,
value: state.selectedCookingTime,
onChanged: changeCookingTime(context),
),
SizedBox(height: 16),
Text('Статус'),
SizedBox(height: 8),
CustomDropDown(
items: state.statuses,
value: state.selectedStatus,
onChanged: changeStatus(context),
),
SizedBox(height: 24),
if (!state.ingredients.isEmpty)
for (int j = 0; j < state.ingredients.length; j++) _buildIngredient(state.ingredients[j]),
SizedBox(height: 24),
RawAutocomplete<String>(
optionsBuilder: _buildOptions(_options),
fieldViewBuilder: (
BuildContext context,
TextEditingController productEditingController,
FocusNode focusNodeName,
VoidCallback onFieldSubmitted,
) {
return CustomTextFormField(
hintText: 'Введите название продукта',
controller: TextEditingController(text: state.productNameController.text),
focusNode: focusNodeName,
onChanged: getAutocomplete(context, focusNodeName),
);
},
optionsViewBuilder: (
BuildContext context,
AutocompleteOnSelected<String> onSelected,
Iterable<String> options,
) {
return Align(
alignment: Alignment.topLeft,
child: Material(
elevation: 4.0,
child: SizedBox(
height: 200.0,
child: ListView.builder(
padding: const EdgeInsets.all(8.0),
itemCount: options.length,
itemBuilder: (BuildContext context, int index) {
final String option = options.elementAt(index);
return GestureDetector(
onTap: selectProduct(onSelected, option, state),
child: ListTile(
title: Text(option),
),
);
},
),
),
),
);
},
),
SizedBox(height: 24),
CustomTextFormField(
hintText: 'Порция',
fillColor: appTheme.gray50,
controller: state.ingredientController,
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[FilteringTextInputFormatter.digitsOnly],
),
SizedBox(height: 8),
Row(children: [
Text('гр'),
Switch(
value: state.ingredientAsItems,
onChanged: (bool value) => context.read<RecipeCreateCubit>().switchUnits(value),
activeColor: appTheme.blueA400,
inactiveThumbColor: Colors.grey,
inactiveTrackColor: Colors.grey.shade300,
),
Text('шт'),
],),
SizedBox(height: 8),
Container(
height: 48,
width: MediaQuery.of(context).size.width,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
backgroundColor: appTheme.blueA400,
),
child: Text(
'+',
style: theme.textTheme.titleSmall,
),
onPressed: () => context.read<RecipeCreateCubit>().addIngredient(new Ingredient(
name: state.productNameController.text,
portion: state.ingredientController.text,
unit: state.ingredientAsItems ? 'pcs' : 'gr',),),),
),
SizedBox(height: 24),
Text('Описание рецепта'),
SizedBox(height: 8),
CustomTextFormField(
maxLines: 8,
minLines: 8,
controller: state.stepDescriptionController,
),
SizedBox(height: 24),
for (int i = 0; i < state.numberOfSteps; i++) _buildStep(context, i, state),
SizedBox(height: 24),
Container(
height: 48,
width: MediaQuery.of(context).size.width,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
backgroundColor: appTheme.blueA400,
),
child: Text(
'+',
style: theme.textTheme.titleSmall,
),
onPressed: () => context.read<RecipeCreateCubit>().addStep(),
),
),
SizedBox(height: 8),
Container(
height: 48,
width: MediaQuery.of(context).size.width,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
backgroundColor: appTheme.blueA400,
),
child: Text(
'-',
style: theme.textTheme.titleSmall,
),
onPressed: () => context.read<RecipeCreateCubit>().removeStep(),
),
),
SizedBox(height: 24),
Text('Ссылка на видео (video)'),
SizedBox(height: 8),
CustomTextFormField(
hintText: 'Введите описание шага',
fillColor: appTheme.gray50,
controller: state.videoLinkController,
),
SizedBox(height: 24),
Container(
height: 48,
width: MediaQuery.of(context).size.width,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
backgroundColor: appTheme.blueA400,
),
child: Text(
'Опубликовать',
style: theme.textTheme.titleSmall,
),
onPressed: () => context.read<RecipeCreateCubit>().editRecipe(createRecipeFromState(state), recipeID),
),
),
],
),),
],
),
),
),
);
}
_buildStep(BuildContext context, int stepNumber, RecipeCreateStateLoaded state) {
return Column(
children: [
Row(children: [Text('Шаг ${stepNumber + 1}'), Spacer(), Text('Всего шагов: ${state.numberOfSteps}')]),
SizedBox(height: 8),
GestureDetector(
onTap: () async {
final pickedFile = await state.picker.pickImage(source: ImageSource.gallery);
context.read<RecipeCreateCubit>().uploadStepImage(pickedFile, stepNumber);
},
child: state.stepImages[stepNumber] == null
? Container(
height: 128,
decoration: AppDecoration.fillGray.copyWith(
borderRadius: BorderRadius.circular(16),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(
Icons.photo_library,
color: appTheme.blueGray300,
),
SizedBox(width: 8),
Text(
"Добавить фото",
selectionColor: appTheme.blueA400,
),
SizedBox(height: 8),
],
),
)
: Image.network(
baseUrl + '/storage/' + state.stepImages[stepNumber]!.path,
height: 150,
fit: BoxFit.cover,
),),
SizedBox(height: 16),
CustomTextFormField(
hintText: 'Введите описание шага',
maxLines: 8,
minLines: 8,
fillColor: appTheme.gray50,
controller: state.stepControllers[stepNumber],
),
SizedBox(height: 24),
],
);
}
_buildIngredient(Ingredient ingredient) {
return Container(
margin: EdgeInsets.symmetric(horizontal: 12),
padding: EdgeInsets.symmetric(
horizontal: 8,
vertical: 8,
),
decoration: AppDecoration.fillGray.copyWith(
borderRadius: BorderRadiusStyle.roundedBorder5,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: EdgeInsets.only(
left: 8,
top: 8,
),
child: Text(
ingredient.name.length > 8 ? ingredient.name.substring(0, 8) : ingredient.name,
style: CustomTextStyles.titleMedium16,
),
),
Padding(
padding: EdgeInsets.only(
left: 24,
top: 4,
bottom: 4,
),
child: Text(
ingredient.portion.toString() + ' ' + ingredient.unit.toString(),
),
),
Spacer(),
GestureDetector(
// onTap: removeIngredient(context, ingredient),
child: Padding(
padding: const EdgeInsets.only(right: 10),
child: Icon(
Icons.close,
color: appTheme.blueGray300,
),
),
),
],
),
);
}
_buildOptions(List<String> _options) {
return (TextEditingValue textEditingValue) {
return _options.where((String option) {
return true;
});
};
}
selectProduct(AutocompleteOnSelected<String> onSelected, String option, RecipeCreateStateLoaded state) {
state.productNameController.text = option;
return () {
onSelected(option);
};
}
getAutocomplete(BuildContext context, FocusNode focusNode) {
return (value) {
if (value.length > 2) {
context.read<RecipeCreateCubit>().inputProduct(value);
}
};
}
changeType(BuildContext context) {
return (value) {
context.read<RecipeCreateCubit>().changeType(value);
};
}
changeStatus(BuildContext context) {
return (value) {
context.read<RecipeCreateCubit>().changeStatus(value);
};
}
changeCookingTime(BuildContext context) {
return (value) {
context.read<RecipeCreateCubit>().changeCookingTime(value);
};
}
RecipeModel createRecipeFromState(RecipeCreateStateLoaded state) {
List<Ingredient> ingredients = state.ingredients;
List<step.Step> steps = [];
for (int i = 0; i < state.stepControllers.length; i++) {
if (state.stepControllers[i].text.isNotEmpty) {
steps.add(step.Step(
description: state.stepControllers[i].text,
image: state.stepImages[i]?.path,
),);
}
}
final RecipeModel recipe = RecipeModel(
ingredients: ingredients,
steps: steps,
state: state.selectedStatus.value,
type: state.selectedType.value,
cooking_time: state.selectedCookingTime.value,
description: state.stepDescriptionController.text,
title: state.titleController.text,
image: state.recipeImage?.path,
video_url: state.videoLinkController.text.isNotEmpty ? state.videoLinkController.text : null,
);
return recipe;
}
}