feat(diary): Recipe create api route enabled

This commit is contained in:
2024-08-15 16:03:39 +03:00
parent bd9bf4843e
commit aced7e8bcb
15 changed files with 603 additions and 212 deletions

View File

@@ -21,33 +21,33 @@ Photo _$PhotoFromJson(Map<String, dynamic> json) {
/// @nodoc
mixin _$Photo {
int get id => throw _privateConstructorUsedError;
@JsonKey(name: 'original_name')
String get originalName => throw _privateConstructorUsedError;
String get path => throw _privateConstructorUsedError;
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$PhotoCopyWith<Photo> get copyWith => throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $PhotoCopyWith<$Res> {
factory $PhotoCopyWith(Photo value, $Res Function(Photo) then) = _$PhotoCopyWithImpl<$Res, Photo>;
factory $PhotoCopyWith(Photo value, $Res Function(Photo) then) =
_$PhotoCopyWithImpl<$Res, Photo>;
@useResult
$Res call({int id, @JsonKey(name: 'original_name') String originalName, String path});
$Res call(
{int id,
@JsonKey(name: 'original_name') String originalName,
String path});
}
/// @nodoc
class _$PhotoCopyWithImpl<$Res, $Val extends Photo> implements $PhotoCopyWith<$Res> {
class _$PhotoCopyWithImpl<$Res, $Val extends Photo>
implements $PhotoCopyWith<$Res> {
_$PhotoCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
@@ -77,16 +77,24 @@ class _$PhotoCopyWithImpl<$Res, $Val extends Photo> implements $PhotoCopyWith<$R
/// @nodoc
abstract class _$$PhotoImplCopyWith<$Res> implements $PhotoCopyWith<$Res> {
factory _$$PhotoImplCopyWith(_$PhotoImpl value, $Res Function(_$PhotoImpl) then) = __$$PhotoImplCopyWithImpl<$Res>;
factory _$$PhotoImplCopyWith(
_$PhotoImpl value, $Res Function(_$PhotoImpl) then) =
__$$PhotoImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({int id, @JsonKey(name: 'original_name') String originalName, String path});
$Res call(
{int id,
@JsonKey(name: 'original_name') String originalName,
String path});
}
/// @nodoc
class __$$PhotoImplCopyWithImpl<$Res> extends _$PhotoCopyWithImpl<$Res, _$PhotoImpl> implements _$$PhotoImplCopyWith<$Res> {
__$$PhotoImplCopyWithImpl(_$PhotoImpl _value, $Res Function(_$PhotoImpl) _then) : super(_value, _then);
class __$$PhotoImplCopyWithImpl<$Res>
extends _$PhotoCopyWithImpl<$Res, _$PhotoImpl>
implements _$$PhotoImplCopyWith<$Res> {
__$$PhotoImplCopyWithImpl(
_$PhotoImpl _value, $Res Function(_$PhotoImpl) _then)
: super(_value, _then);
@pragma('vm:prefer-inline')
@override
@@ -115,9 +123,13 @@ class __$$PhotoImplCopyWithImpl<$Res> extends _$PhotoCopyWithImpl<$Res, _$PhotoI
/// @nodoc
@JsonSerializable()
class _$PhotoImpl implements _Photo {
const _$PhotoImpl({required this.id, @JsonKey(name: 'original_name') required this.originalName, required this.path});
const _$PhotoImpl(
{required this.id,
@JsonKey(name: 'original_name') required this.originalName,
required this.path});
factory _$PhotoImpl.fromJson(Map<String, dynamic> json) => _$$PhotoImplFromJson(json);
factory _$PhotoImpl.fromJson(Map<String, dynamic> json) =>
_$$PhotoImplFromJson(json);
@override
final int id;
@@ -138,7 +150,8 @@ class _$PhotoImpl implements _Photo {
(other.runtimeType == runtimeType &&
other is _$PhotoImpl &&
(identical(other.id, id) || other.id == id) &&
(identical(other.originalName, originalName) || other.originalName == originalName) &&
(identical(other.originalName, originalName) ||
other.originalName == originalName) &&
(identical(other.path, path) || other.path == path));
}
@@ -149,7 +162,8 @@ class _$PhotoImpl implements _Photo {
@JsonKey(ignore: true)
@override
@pragma('vm:prefer-inline')
_$$PhotoImplCopyWith<_$PhotoImpl> get copyWith => __$$PhotoImplCopyWithImpl<_$PhotoImpl>(this, _$identity);
_$$PhotoImplCopyWith<_$PhotoImpl> get copyWith =>
__$$PhotoImplCopyWithImpl<_$PhotoImpl>(this, _$identity);
@override
Map<String, dynamic> toJson() {
@@ -160,21 +174,22 @@ class _$PhotoImpl implements _Photo {
}
abstract class _Photo implements Photo {
const factory _Photo({required final int id, @JsonKey(name: 'original_name') required final String originalName, required final String path}) = _$PhotoImpl;
const factory _Photo(
{required final int id,
@JsonKey(name: 'original_name') required final String originalName,
required final String path}) = _$PhotoImpl;
factory _Photo.fromJson(Map<String, dynamic> json) = _$PhotoImpl.fromJson;
@override
int get id;
@override
@JsonKey(name: 'original_name')
String get originalName;
@override
String get path;
@override
@JsonKey(ignore: true)
_$$PhotoImplCopyWith<_$PhotoImpl> get copyWith => throw _privateConstructorUsedError;
_$$PhotoImplCopyWith<_$PhotoImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@@ -12,7 +12,8 @@ _$PhotoImpl _$$PhotoImplFromJson(Map<String, dynamic> json) => _$PhotoImpl(
path: json['path'] as String,
);
Map<String, dynamic> _$$PhotoImplToJson(_$PhotoImpl instance) => <String, dynamic>{
Map<String, dynamic> _$$PhotoImplToJson(_$PhotoImpl instance) =>
<String, dynamic>{
'id': instance.id,
'original_name': instance.originalName,
'path': instance.path,

View File

@@ -7,7 +7,7 @@ part 'image.g.dart';
@freezed
class Image with _$Image {
const factory Image({
required String path,
String? path,
}) = _Image;
factory Image.fromJson(Map<String, Object?> json) => _$ImageFromJson(json);

View File

@@ -20,7 +20,7 @@ Image _$ImageFromJson(Map<String, dynamic> json) {
/// @nodoc
mixin _$Image {
String get path => throw _privateConstructorUsedError;
String? get path => throw _privateConstructorUsedError;
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
@@ -32,7 +32,7 @@ abstract class $ImageCopyWith<$Res> {
factory $ImageCopyWith(Image value, $Res Function(Image) then) =
_$ImageCopyWithImpl<$Res, Image>;
@useResult
$Res call({String path});
$Res call({String? path});
}
/// @nodoc
@@ -48,13 +48,13 @@ class _$ImageCopyWithImpl<$Res, $Val extends Image>
@pragma('vm:prefer-inline')
@override
$Res call({
Object? path = null,
Object? path = freezed,
}) {
return _then(_value.copyWith(
path: null == path
path: freezed == path
? _value.path
: path // ignore: cast_nullable_to_non_nullable
as String,
as String?,
) as $Val);
}
}
@@ -66,7 +66,7 @@ abstract class _$$ImageImplCopyWith<$Res> implements $ImageCopyWith<$Res> {
__$$ImageImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({String path});
$Res call({String? path});
}
/// @nodoc
@@ -80,13 +80,13 @@ class __$$ImageImplCopyWithImpl<$Res>
@pragma('vm:prefer-inline')
@override
$Res call({
Object? path = null,
Object? path = freezed,
}) {
return _then(_$ImageImpl(
path: null == path
path: freezed == path
? _value.path
: path // ignore: cast_nullable_to_non_nullable
as String,
as String?,
));
}
}
@@ -94,13 +94,13 @@ class __$$ImageImplCopyWithImpl<$Res>
/// @nodoc
@JsonSerializable()
class _$ImageImpl implements _Image {
const _$ImageImpl({required this.path});
const _$ImageImpl({this.path});
factory _$ImageImpl.fromJson(Map<String, dynamic> json) =>
_$$ImageImplFromJson(json);
@override
final String path;
final String? path;
@override
String toString() {
@@ -134,12 +134,12 @@ class _$ImageImpl implements _Image {
}
abstract class _Image implements Image {
const factory _Image({required final String path}) = _$ImageImpl;
const factory _Image({final String? path}) = _$ImageImpl;
factory _Image.fromJson(Map<String, dynamic> json) = _$ImageImpl.fromJson;
@override
String get path;
String? get path;
@override
@JsonKey(ignore: true)
_$$ImageImplCopyWith<_$ImageImpl> get copyWith =>

View File

@@ -7,9 +7,10 @@ part of 'image.dart';
// **************************************************************************
_$ImageImpl _$$ImageImplFromJson(Map<String, dynamic> json) => _$ImageImpl(
path: json['path'] as String,
path: json['path'] as String?,
);
Map<String, dynamic> _$$ImageImplToJson(_$ImageImpl instance) => <String, dynamic>{
Map<String, dynamic> _$$ImageImplToJson(_$ImageImpl instance) =>
<String, dynamic>{
'path': instance.path,
};

View File

@@ -12,6 +12,7 @@ class RecipeModel with _$RecipeModel {
int? id,
required List<Ingredient> ingredients,
required List<Step> steps,
required String title,
required String state,
required String description,
required String type,
@@ -20,6 +21,5 @@ class RecipeModel with _$RecipeModel {
num? cooking_time,
}) = _RecipeModel;
factory RecipeModel.fromJson(Map<String, Object?> json) =>
_$RecipeModelFromJson(json);
factory RecipeModel.fromJson(Map<String, Object?> json) => _$RecipeModelFromJson(json);
}

View File

@@ -23,6 +23,7 @@ mixin _$RecipeModel {
int? get id => throw _privateConstructorUsedError;
List<Ingredient> get ingredients => throw _privateConstructorUsedError;
List<Step> get steps => throw _privateConstructorUsedError;
String get title => throw _privateConstructorUsedError;
String get state => throw _privateConstructorUsedError;
String get description => throw _privateConstructorUsedError;
String get type => throw _privateConstructorUsedError;
@@ -46,6 +47,7 @@ abstract class $RecipeModelCopyWith<$Res> {
{int? id,
List<Ingredient> ingredients,
List<Step> steps,
String title,
String state,
String description,
String type,
@@ -72,6 +74,7 @@ class _$RecipeModelCopyWithImpl<$Res, $Val extends RecipeModel>
Object? id = freezed,
Object? ingredients = null,
Object? steps = null,
Object? title = null,
Object? state = null,
Object? description = null,
Object? type = null,
@@ -92,6 +95,10 @@ class _$RecipeModelCopyWithImpl<$Res, $Val extends RecipeModel>
? _value.steps
: steps // ignore: cast_nullable_to_non_nullable
as List<Step>,
title: null == title
? _value.title
: title // ignore: cast_nullable_to_non_nullable
as String,
state: null == state
? _value.state
: state // ignore: cast_nullable_to_non_nullable
@@ -140,6 +147,7 @@ abstract class _$$RecipeModelImplCopyWith<$Res>
{int? id,
List<Ingredient> ingredients,
List<Step> steps,
String title,
String state,
String description,
String type,
@@ -165,6 +173,7 @@ class __$$RecipeModelImplCopyWithImpl<$Res>
Object? id = freezed,
Object? ingredients = null,
Object? steps = null,
Object? title = null,
Object? state = null,
Object? description = null,
Object? type = null,
@@ -185,6 +194,10 @@ class __$$RecipeModelImplCopyWithImpl<$Res>
? _value._steps
: steps // ignore: cast_nullable_to_non_nullable
as List<Step>,
title: null == title
? _value.title
: title // ignore: cast_nullable_to_non_nullable
as String,
state: null == state
? _value.state
: state // ignore: cast_nullable_to_non_nullable
@@ -220,6 +233,7 @@ class _$RecipeModelImpl implements _RecipeModel {
{this.id,
required final List<Ingredient> ingredients,
required final List<Step> steps,
required this.title,
required this.state,
required this.description,
required this.type,
@@ -250,6 +264,8 @@ class _$RecipeModelImpl implements _RecipeModel {
return EqualUnmodifiableListView(_steps);
}
@override
final String title;
@override
final String state;
@override
@@ -265,7 +281,7 @@ class _$RecipeModelImpl implements _RecipeModel {
@override
String toString() {
return 'RecipeModel(id: $id, ingredients: $ingredients, steps: $steps, state: $state, description: $description, type: $type, image: $image, video_url: $video_url, cooking_time: $cooking_time)';
return 'RecipeModel(id: $id, ingredients: $ingredients, steps: $steps, title: $title, state: $state, description: $description, type: $type, image: $image, video_url: $video_url, cooking_time: $cooking_time)';
}
@override
@@ -277,6 +293,7 @@ class _$RecipeModelImpl implements _RecipeModel {
const DeepCollectionEquality()
.equals(other._ingredients, _ingredients) &&
const DeepCollectionEquality().equals(other._steps, _steps) &&
(identical(other.title, title) || other.title == title) &&
(identical(other.state, state) || other.state == state) &&
(identical(other.description, description) ||
other.description == description) &&
@@ -295,6 +312,7 @@ class _$RecipeModelImpl implements _RecipeModel {
id,
const DeepCollectionEquality().hash(_ingredients),
const DeepCollectionEquality().hash(_steps),
title,
state,
description,
type,
@@ -321,6 +339,7 @@ abstract class _RecipeModel implements RecipeModel {
{final int? id,
required final List<Ingredient> ingredients,
required final List<Step> steps,
required final String title,
required final String state,
required final String description,
required final String type,
@@ -338,6 +357,8 @@ abstract class _RecipeModel implements RecipeModel {
@override
List<Step> get steps;
@override
String get title;
@override
String get state;
@override
String get description;

View File

@@ -15,6 +15,7 @@ _$RecipeModelImpl _$$RecipeModelImplFromJson(Map<String, dynamic> json) =>
steps: (json['steps'] as List<dynamic>)
.map((e) => Step.fromJson(e as Map<String, dynamic>))
.toList(),
title: json['title'] as String,
state: json['state'] as String,
description: json['description'] as String,
type: json['type'] as String,
@@ -28,6 +29,7 @@ Map<String, dynamic> _$$RecipeModelImplToJson(_$RecipeModelImpl instance) =>
'id': instance.id,
'ingredients': instance.ingredients,
'steps': instance.steps,
'title': instance.title,
'state': instance.state,
'description': instance.description,
'type': instance.type,

View File

@@ -1,58 +1,69 @@
import 'package:eatvio_app/core/app_export.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/diary/models/product.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
class RecipeCreateCubit extends Cubit<RecipeCreateState> {
final RecipeRepository recipeRepository;
RecipeCreateCubit({required this.recipeRepository})
: super(const RecipeCreateState.loading());
RecipeCreateCubit({required this.recipeRepository}) : super(const RecipeCreateState.loading());
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(),
youtubeLinkController: TextEditingController(),
stepControllers: [TextEditingController()],
stepImages: [null],
ingredients: [],
numberOfSteps: 1,
ingredientAsItems: false,
types: [
SelectionPopupModel(title: 'Первые блюда'),
SelectionPopupModel(title: 'Вторые блюда'),
SelectionPopupModel(title: 'Cалаты'),
SelectionPopupModel(title: 'Перекусы/закуски'),
SelectionPopupModel(title: 'Сладости'),
SelectionPopupModel(title: 'Напитки'),
SelectionPopupModel(title: 'Прочее'),
],
cookingTimes: [
SelectionPopupModel(title: '10 минут'),
SelectionPopupModel(title: '20 минут'),
SelectionPopupModel(title: '30 минут'),
SelectionPopupModel(title: '1 час'),
SelectionPopupModel(title: '2 часа'),
SelectionPopupModel(title: '10 дней'),
],
statuses: [
SelectionPopupModel(title: 'Активна'),
SelectionPopupModel(title: 'Неактивна'),
],
));
picker: ImagePicker(),
titleController: TextEditingController(),
productNameController: TextEditingController(),
ingredientController: TextEditingController(),
stepDescriptionController: TextEditingController(),
youtubeLinkController: 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);
}
uploadRecipeImage(XFile? pickedFile) {
try {
if (state is RecipeCreateStateLoaded) {
@@ -106,18 +117,14 @@ class RecipeCreateCubit extends Cubit<RecipeCreateState> {
if (state is RecipeCreateStateLoaded) {
var currentState = state as RecipeCreateStateLoaded;
bool ingredientExists = currentState.ingredients.any(
(existingIngredient) =>
existingIngredient.product_name == ingredient.product_name);
bool ingredientExists = currentState.ingredients.any((existingIngredient) => existingIngredient.product_name == ingredient.product_name);
if (ingredientExists) {
emit(RecipeCreateState.error(
errorMessage: 'Ингредиент уже существует.'));
emit(RecipeCreateState.error(errorMessage: 'Ингредиент уже существует.'));
return;
}
List<Ingredient> newIngredients =
List<Ingredient>.from(currentState.ingredients);
List<Ingredient> newIngredients = List<Ingredient>.from(currentState.ingredients);
newIngredients.add(ingredient);
var updatedState = currentState.copyWith(ingredients: newIngredients);
@@ -134,13 +141,9 @@ class RecipeCreateCubit extends Cubit<RecipeCreateState> {
var currentState = state as RecipeCreateStateLoaded;
List<XFile?> newStepImages = List<XFile?>.from(currentState.stepImages);
newStepImages.add(null);
List<TextEditingController> newStepControllers =
List<TextEditingController>.from(currentState.stepControllers);
List<TextEditingController> newStepControllers = List<TextEditingController>.from(currentState.stepControllers);
newStepControllers.add(TextEditingController());
var updatedState = currentState.copyWith(
stepImages: newStepImages,
stepControllers: newStepControllers,
numberOfSteps: currentState.numberOfSteps + 1);
var updatedState = currentState.copyWith(stepImages: newStepImages, stepControllers: newStepControllers, numberOfSteps: currentState.numberOfSteps + 1);
emit(updatedState);
}
} catch (e) {
@@ -154,17 +157,58 @@ class RecipeCreateCubit extends Cubit<RecipeCreateState> {
var currentState = state as RecipeCreateStateLoaded;
List<XFile?> newStepImages = List<XFile?>.from(currentState.stepImages);
newStepImages.removeLast();
List<TextEditingController> newStepControllers =
List<TextEditingController>.from(currentState.stepControllers);
List<TextEditingController> newStepControllers = List<TextEditingController>.from(currentState.stepControllers);
newStepControllers.removeLast();
var updatedState = currentState.copyWith(
stepImages: newStepImages,
stepControllers: newStepControllers,
numberOfSteps: currentState.numberOfSteps - 1);
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);
print(productNutritionalValues);
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,5 +1,6 @@
import 'package:eatvio_app/features/recipes/models/recipe_model.dart';
import 'package:eatvio_app/features/recipes/models/ingredient.dart';
import 'package:eatvio_app/features/diary/models/product.dart';
import 'package:flutter/material.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:image_picker/image_picker.dart';
@@ -26,11 +27,15 @@ abstract class RecipeCreateState with _$RecipeCreateState {
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({

View File

@@ -32,11 +32,15 @@ mixin _$RecipeCreateState {
XFile? recipeImage,
List<XFile?> stepImages,
List<Ingredient> ingredients,
List<Product> autocompleteList,
int numberOfSteps,
bool ingredientAsItems,
List<SelectionPopupModel> types,
List<SelectionPopupModel> cookingTimes,
List<SelectionPopupModel> statuses)
List<SelectionPopupModel> statuses,
SelectionPopupModel selectedType,
SelectionPopupModel selectedCookingTime,
SelectionPopupModel selectedStatus)
loaded,
required TResult Function(String errorMessage) error,
}) =>
@@ -57,11 +61,15 @@ mixin _$RecipeCreateState {
XFile? recipeImage,
List<XFile?> stepImages,
List<Ingredient> ingredients,
List<Product> autocompleteList,
int numberOfSteps,
bool ingredientAsItems,
List<SelectionPopupModel> types,
List<SelectionPopupModel> cookingTimes,
List<SelectionPopupModel> statuses)?
List<SelectionPopupModel> statuses,
SelectionPopupModel selectedType,
SelectionPopupModel selectedCookingTime,
SelectionPopupModel selectedStatus)?
loaded,
TResult? Function(String errorMessage)? error,
}) =>
@@ -82,11 +90,15 @@ mixin _$RecipeCreateState {
XFile? recipeImage,
List<XFile?> stepImages,
List<Ingredient> ingredients,
List<Product> autocompleteList,
int numberOfSteps,
bool ingredientAsItems,
List<SelectionPopupModel> types,
List<SelectionPopupModel> cookingTimes,
List<SelectionPopupModel> statuses)?
List<SelectionPopupModel> statuses,
SelectionPopupModel selectedType,
SelectionPopupModel selectedCookingTime,
SelectionPopupModel selectedStatus)?
loaded,
TResult Function(String errorMessage)? error,
required TResult orElse(),
@@ -189,11 +201,15 @@ class _$RecipeCreateStateImpl implements _RecipeCreateState {
XFile? recipeImage,
List<XFile?> stepImages,
List<Ingredient> ingredients,
List<Product> autocompleteList,
int numberOfSteps,
bool ingredientAsItems,
List<SelectionPopupModel> types,
List<SelectionPopupModel> cookingTimes,
List<SelectionPopupModel> statuses)
List<SelectionPopupModel> statuses,
SelectionPopupModel selectedType,
SelectionPopupModel selectedCookingTime,
SelectionPopupModel selectedStatus)
loaded,
required TResult Function(String errorMessage) error,
}) {
@@ -217,11 +233,15 @@ class _$RecipeCreateStateImpl implements _RecipeCreateState {
XFile? recipeImage,
List<XFile?> stepImages,
List<Ingredient> ingredients,
List<Product> autocompleteList,
int numberOfSteps,
bool ingredientAsItems,
List<SelectionPopupModel> types,
List<SelectionPopupModel> cookingTimes,
List<SelectionPopupModel> statuses)?
List<SelectionPopupModel> statuses,
SelectionPopupModel selectedType,
SelectionPopupModel selectedCookingTime,
SelectionPopupModel selectedStatus)?
loaded,
TResult? Function(String errorMessage)? error,
}) {
@@ -245,11 +265,15 @@ class _$RecipeCreateStateImpl implements _RecipeCreateState {
XFile? recipeImage,
List<XFile?> stepImages,
List<Ingredient> ingredients,
List<Product> autocompleteList,
int numberOfSteps,
bool ingredientAsItems,
List<SelectionPopupModel> types,
List<SelectionPopupModel> cookingTimes,
List<SelectionPopupModel> statuses)?
List<SelectionPopupModel> statuses,
SelectionPopupModel selectedType,
SelectionPopupModel selectedCookingTime,
SelectionPopupModel selectedStatus)?
loaded,
TResult Function(String errorMessage)? error,
required TResult orElse(),
@@ -358,11 +382,15 @@ class _$RecipeCreateStateLoadingImpl implements RecipeCreateStateLoading {
XFile? recipeImage,
List<XFile?> stepImages,
List<Ingredient> ingredients,
List<Product> autocompleteList,
int numberOfSteps,
bool ingredientAsItems,
List<SelectionPopupModel> types,
List<SelectionPopupModel> cookingTimes,
List<SelectionPopupModel> statuses)
List<SelectionPopupModel> statuses,
SelectionPopupModel selectedType,
SelectionPopupModel selectedCookingTime,
SelectionPopupModel selectedStatus)
loaded,
required TResult Function(String errorMessage) error,
}) {
@@ -386,11 +414,15 @@ class _$RecipeCreateStateLoadingImpl implements RecipeCreateStateLoading {
XFile? recipeImage,
List<XFile?> stepImages,
List<Ingredient> ingredients,
List<Product> autocompleteList,
int numberOfSteps,
bool ingredientAsItems,
List<SelectionPopupModel> types,
List<SelectionPopupModel> cookingTimes,
List<SelectionPopupModel> statuses)?
List<SelectionPopupModel> statuses,
SelectionPopupModel selectedType,
SelectionPopupModel selectedCookingTime,
SelectionPopupModel selectedStatus)?
loaded,
TResult? Function(String errorMessage)? error,
}) {
@@ -414,11 +446,15 @@ class _$RecipeCreateStateLoadingImpl implements RecipeCreateStateLoading {
XFile? recipeImage,
List<XFile?> stepImages,
List<Ingredient> ingredients,
List<Product> autocompleteList,
int numberOfSteps,
bool ingredientAsItems,
List<SelectionPopupModel> types,
List<SelectionPopupModel> cookingTimes,
List<SelectionPopupModel> statuses)?
List<SelectionPopupModel> statuses,
SelectionPopupModel selectedType,
SelectionPopupModel selectedCookingTime,
SelectionPopupModel selectedStatus)?
loaded,
TResult Function(String errorMessage)? error,
required TResult orElse(),
@@ -490,13 +526,20 @@ abstract class _$$RecipeCreateStateLoadedImplCopyWith<$Res> {
XFile? recipeImage,
List<XFile?> stepImages,
List<Ingredient> ingredients,
List<Product> autocompleteList,
int numberOfSteps,
bool ingredientAsItems,
List<SelectionPopupModel> types,
List<SelectionPopupModel> cookingTimes,
List<SelectionPopupModel> statuses});
List<SelectionPopupModel> statuses,
SelectionPopupModel selectedType,
SelectionPopupModel selectedCookingTime,
SelectionPopupModel selectedStatus});
$RecipeModelCopyWith<$Res>? get recipe;
$SelectionPopupModelCopyWith<$Res> get selectedType;
$SelectionPopupModelCopyWith<$Res> get selectedCookingTime;
$SelectionPopupModelCopyWith<$Res> get selectedStatus;
}
/// @nodoc
@@ -522,11 +565,15 @@ class __$$RecipeCreateStateLoadedImplCopyWithImpl<$Res>
Object? recipeImage = freezed,
Object? stepImages = null,
Object? ingredients = null,
Object? autocompleteList = null,
Object? numberOfSteps = null,
Object? ingredientAsItems = null,
Object? types = null,
Object? cookingTimes = null,
Object? statuses = null,
Object? selectedType = null,
Object? selectedCookingTime = null,
Object? selectedStatus = null,
}) {
return _then(_$RecipeCreateStateLoadedImpl(
recipe: freezed == recipe
@@ -573,6 +620,10 @@ class __$$RecipeCreateStateLoadedImplCopyWithImpl<$Res>
? _value._ingredients
: ingredients // ignore: cast_nullable_to_non_nullable
as List<Ingredient>,
autocompleteList: null == autocompleteList
? _value._autocompleteList
: autocompleteList // ignore: cast_nullable_to_non_nullable
as List<Product>,
numberOfSteps: null == numberOfSteps
? _value.numberOfSteps
: numberOfSteps // ignore: cast_nullable_to_non_nullable
@@ -593,6 +644,18 @@ class __$$RecipeCreateStateLoadedImplCopyWithImpl<$Res>
? _value._statuses
: statuses // ignore: cast_nullable_to_non_nullable
as List<SelectionPopupModel>,
selectedType: null == selectedType
? _value.selectedType
: selectedType // ignore: cast_nullable_to_non_nullable
as SelectionPopupModel,
selectedCookingTime: null == selectedCookingTime
? _value.selectedCookingTime
: selectedCookingTime // ignore: cast_nullable_to_non_nullable
as SelectionPopupModel,
selectedStatus: null == selectedStatus
? _value.selectedStatus
: selectedStatus // ignore: cast_nullable_to_non_nullable
as SelectionPopupModel,
));
}
@@ -607,6 +670,31 @@ class __$$RecipeCreateStateLoadedImplCopyWithImpl<$Res>
return _then(_value.copyWith(recipe: value));
});
}
@override
@pragma('vm:prefer-inline')
$SelectionPopupModelCopyWith<$Res> get selectedType {
return $SelectionPopupModelCopyWith<$Res>(_value.selectedType, (value) {
return _then(_value.copyWith(selectedType: value));
});
}
@override
@pragma('vm:prefer-inline')
$SelectionPopupModelCopyWith<$Res> get selectedCookingTime {
return $SelectionPopupModelCopyWith<$Res>(_value.selectedCookingTime,
(value) {
return _then(_value.copyWith(selectedCookingTime: value));
});
}
@override
@pragma('vm:prefer-inline')
$SelectionPopupModelCopyWith<$Res> get selectedStatus {
return $SelectionPopupModelCopyWith<$Res>(_value.selectedStatus, (value) {
return _then(_value.copyWith(selectedStatus: value));
});
}
}
/// @nodoc
@@ -624,14 +712,19 @@ class _$RecipeCreateStateLoadedImpl implements RecipeCreateStateLoaded {
this.recipeImage,
required final List<XFile?> stepImages,
required final List<Ingredient> ingredients,
required final List<Product> autocompleteList,
required this.numberOfSteps,
required this.ingredientAsItems,
required final List<SelectionPopupModel> types,
required final List<SelectionPopupModel> cookingTimes,
required final List<SelectionPopupModel> statuses})
required final List<SelectionPopupModel> statuses,
required this.selectedType,
required this.selectedCookingTime,
required this.selectedStatus})
: _stepControllers = stepControllers,
_stepImages = stepImages,
_ingredients = ingredients,
_autocompleteList = autocompleteList,
_types = types,
_cookingTimes = cookingTimes,
_statuses = statuses;
@@ -676,6 +769,15 @@ class _$RecipeCreateStateLoadedImpl implements RecipeCreateStateLoaded {
return EqualUnmodifiableListView(_ingredients);
}
final List<Product> _autocompleteList;
@override
List<Product> get autocompleteList {
if (_autocompleteList is EqualUnmodifiableListView)
return _autocompleteList;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_autocompleteList);
}
@override
final int numberOfSteps;
@override
@@ -704,9 +806,16 @@ class _$RecipeCreateStateLoadedImpl implements RecipeCreateStateLoaded {
return EqualUnmodifiableListView(_statuses);
}
@override
final SelectionPopupModel selectedType;
@override
final SelectionPopupModel selectedCookingTime;
@override
final SelectionPopupModel selectedStatus;
@override
String toString() {
return 'RecipeCreateState.loaded(recipe: $recipe, picker: $picker, titleController: $titleController, productNameController: $productNameController, ingredientController: $ingredientController, stepDescriptionController: $stepDescriptionController, youtubeLinkController: $youtubeLinkController, stepControllers: $stepControllers, recipeImage: $recipeImage, stepImages: $stepImages, ingredients: $ingredients, numberOfSteps: $numberOfSteps, ingredientAsItems: $ingredientAsItems, types: $types, cookingTimes: $cookingTimes, statuses: $statuses)';
return 'RecipeCreateState.loaded(recipe: $recipe, picker: $picker, titleController: $titleController, productNameController: $productNameController, ingredientController: $ingredientController, stepDescriptionController: $stepDescriptionController, youtubeLinkController: $youtubeLinkController, stepControllers: $stepControllers, recipeImage: $recipeImage, stepImages: $stepImages, ingredients: $ingredients, autocompleteList: $autocompleteList, numberOfSteps: $numberOfSteps, ingredientAsItems: $ingredientAsItems, types: $types, cookingTimes: $cookingTimes, statuses: $statuses, selectedType: $selectedType, selectedCookingTime: $selectedCookingTime, selectedStatus: $selectedStatus)';
}
@override
@@ -735,6 +844,8 @@ class _$RecipeCreateStateLoadedImpl implements RecipeCreateStateLoaded {
.equals(other._stepImages, _stepImages) &&
const DeepCollectionEquality()
.equals(other._ingredients, _ingredients) &&
const DeepCollectionEquality()
.equals(other._autocompleteList, _autocompleteList) &&
(identical(other.numberOfSteps, numberOfSteps) ||
other.numberOfSteps == numberOfSteps) &&
(identical(other.ingredientAsItems, ingredientAsItems) ||
@@ -742,28 +853,39 @@ class _$RecipeCreateStateLoadedImpl implements RecipeCreateStateLoaded {
const DeepCollectionEquality().equals(other._types, _types) &&
const DeepCollectionEquality()
.equals(other._cookingTimes, _cookingTimes) &&
const DeepCollectionEquality().equals(other._statuses, _statuses));
const DeepCollectionEquality().equals(other._statuses, _statuses) &&
(identical(other.selectedType, selectedType) ||
other.selectedType == selectedType) &&
(identical(other.selectedCookingTime, selectedCookingTime) ||
other.selectedCookingTime == selectedCookingTime) &&
(identical(other.selectedStatus, selectedStatus) ||
other.selectedStatus == selectedStatus));
}
@override
int get hashCode => Object.hash(
runtimeType,
recipe,
picker,
titleController,
productNameController,
ingredientController,
stepDescriptionController,
youtubeLinkController,
const DeepCollectionEquality().hash(_stepControllers),
recipeImage,
const DeepCollectionEquality().hash(_stepImages),
const DeepCollectionEquality().hash(_ingredients),
numberOfSteps,
ingredientAsItems,
const DeepCollectionEquality().hash(_types),
const DeepCollectionEquality().hash(_cookingTimes),
const DeepCollectionEquality().hash(_statuses));
int get hashCode => Object.hashAll([
runtimeType,
recipe,
picker,
titleController,
productNameController,
ingredientController,
stepDescriptionController,
youtubeLinkController,
const DeepCollectionEquality().hash(_stepControllers),
recipeImage,
const DeepCollectionEquality().hash(_stepImages),
const DeepCollectionEquality().hash(_ingredients),
const DeepCollectionEquality().hash(_autocompleteList),
numberOfSteps,
ingredientAsItems,
const DeepCollectionEquality().hash(_types),
const DeepCollectionEquality().hash(_cookingTimes),
const DeepCollectionEquality().hash(_statuses),
selectedType,
selectedCookingTime,
selectedStatus
]);
@JsonKey(ignore: true)
@override
@@ -789,11 +911,15 @@ class _$RecipeCreateStateLoadedImpl implements RecipeCreateStateLoaded {
XFile? recipeImage,
List<XFile?> stepImages,
List<Ingredient> ingredients,
List<Product> autocompleteList,
int numberOfSteps,
bool ingredientAsItems,
List<SelectionPopupModel> types,
List<SelectionPopupModel> cookingTimes,
List<SelectionPopupModel> statuses)
List<SelectionPopupModel> statuses,
SelectionPopupModel selectedType,
SelectionPopupModel selectedCookingTime,
SelectionPopupModel selectedStatus)
loaded,
required TResult Function(String errorMessage) error,
}) {
@@ -809,11 +935,15 @@ class _$RecipeCreateStateLoadedImpl implements RecipeCreateStateLoaded {
recipeImage,
stepImages,
ingredients,
autocompleteList,
numberOfSteps,
ingredientAsItems,
types,
cookingTimes,
statuses);
statuses,
selectedType,
selectedCookingTime,
selectedStatus);
}
@override
@@ -833,11 +963,15 @@ class _$RecipeCreateStateLoadedImpl implements RecipeCreateStateLoaded {
XFile? recipeImage,
List<XFile?> stepImages,
List<Ingredient> ingredients,
List<Product> autocompleteList,
int numberOfSteps,
bool ingredientAsItems,
List<SelectionPopupModel> types,
List<SelectionPopupModel> cookingTimes,
List<SelectionPopupModel> statuses)?
List<SelectionPopupModel> statuses,
SelectionPopupModel selectedType,
SelectionPopupModel selectedCookingTime,
SelectionPopupModel selectedStatus)?
loaded,
TResult? Function(String errorMessage)? error,
}) {
@@ -853,11 +987,15 @@ class _$RecipeCreateStateLoadedImpl implements RecipeCreateStateLoaded {
recipeImage,
stepImages,
ingredients,
autocompleteList,
numberOfSteps,
ingredientAsItems,
types,
cookingTimes,
statuses);
statuses,
selectedType,
selectedCookingTime,
selectedStatus);
}
@override
@@ -877,11 +1015,15 @@ class _$RecipeCreateStateLoadedImpl implements RecipeCreateStateLoaded {
XFile? recipeImage,
List<XFile?> stepImages,
List<Ingredient> ingredients,
List<Product> autocompleteList,
int numberOfSteps,
bool ingredientAsItems,
List<SelectionPopupModel> types,
List<SelectionPopupModel> cookingTimes,
List<SelectionPopupModel> statuses)?
List<SelectionPopupModel> statuses,
SelectionPopupModel selectedType,
SelectionPopupModel selectedCookingTime,
SelectionPopupModel selectedStatus)?
loaded,
TResult Function(String errorMessage)? error,
required TResult orElse(),
@@ -899,11 +1041,15 @@ class _$RecipeCreateStateLoadedImpl implements RecipeCreateStateLoaded {
recipeImage,
stepImages,
ingredients,
autocompleteList,
numberOfSteps,
ingredientAsItems,
types,
cookingTimes,
statuses);
statuses,
selectedType,
selectedCookingTime,
selectedStatus);
}
return orElse();
}
@@ -959,11 +1105,15 @@ abstract class RecipeCreateStateLoaded implements RecipeCreateState {
final XFile? recipeImage,
required final List<XFile?> stepImages,
required final List<Ingredient> ingredients,
required final List<Product> autocompleteList,
required final int numberOfSteps,
required final bool ingredientAsItems,
required final List<SelectionPopupModel> types,
required final List<SelectionPopupModel> cookingTimes,
required final List<SelectionPopupModel> statuses}) =
required final List<SelectionPopupModel> statuses,
required final SelectionPopupModel selectedType,
required final SelectionPopupModel selectedCookingTime,
required final SelectionPopupModel selectedStatus}) =
_$RecipeCreateStateLoadedImpl;
RecipeModel? get recipe;
@@ -977,11 +1127,15 @@ abstract class RecipeCreateStateLoaded implements RecipeCreateState {
XFile? get recipeImage;
List<XFile?> get stepImages;
List<Ingredient> get ingredients;
List<Product> get autocompleteList;
int get numberOfSteps;
bool get ingredientAsItems;
List<SelectionPopupModel> get types;
List<SelectionPopupModel> get cookingTimes;
List<SelectionPopupModel> get statuses;
SelectionPopupModel get selectedType;
SelectionPopupModel get selectedCookingTime;
SelectionPopupModel get selectedStatus;
@JsonKey(ignore: true)
_$$RecipeCreateStateLoadedImplCopyWith<_$RecipeCreateStateLoadedImpl>
get copyWith => throw _privateConstructorUsedError;
@@ -1069,11 +1223,15 @@ class _$RecipeCreateStateErrorImpl implements RecipeCreateStateError {
XFile? recipeImage,
List<XFile?> stepImages,
List<Ingredient> ingredients,
List<Product> autocompleteList,
int numberOfSteps,
bool ingredientAsItems,
List<SelectionPopupModel> types,
List<SelectionPopupModel> cookingTimes,
List<SelectionPopupModel> statuses)
List<SelectionPopupModel> statuses,
SelectionPopupModel selectedType,
SelectionPopupModel selectedCookingTime,
SelectionPopupModel selectedStatus)
loaded,
required TResult Function(String errorMessage) error,
}) {
@@ -1097,11 +1255,15 @@ class _$RecipeCreateStateErrorImpl implements RecipeCreateStateError {
XFile? recipeImage,
List<XFile?> stepImages,
List<Ingredient> ingredients,
List<Product> autocompleteList,
int numberOfSteps,
bool ingredientAsItems,
List<SelectionPopupModel> types,
List<SelectionPopupModel> cookingTimes,
List<SelectionPopupModel> statuses)?
List<SelectionPopupModel> statuses,
SelectionPopupModel selectedType,
SelectionPopupModel selectedCookingTime,
SelectionPopupModel selectedStatus)?
loaded,
TResult? Function(String errorMessage)? error,
}) {
@@ -1125,11 +1287,15 @@ class _$RecipeCreateStateErrorImpl implements RecipeCreateStateError {
XFile? recipeImage,
List<XFile?> stepImages,
List<Ingredient> ingredients,
List<Product> autocompleteList,
int numberOfSteps,
bool ingredientAsItems,
List<SelectionPopupModel> types,
List<SelectionPopupModel> cookingTimes,
List<SelectionPopupModel> statuses)?
List<SelectionPopupModel> statuses,
SelectionPopupModel selectedType,
SelectionPopupModel selectedCookingTime,
SelectionPopupModel selectedStatus)?
loaded,
TResult Function(String errorMessage)? error,
required TResult orElse(),

View File

@@ -1,5 +1,6 @@
import 'dart:io';
import 'package:eatvio_app/core/app_export.dart';
import 'package:eatvio_app/features/diary/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/image.dart' as image;
@@ -49,8 +50,8 @@ class RecipeCreateScreen extends StatelessWidget {
);
}
Widget _buildRecipeCreate(
BuildContext context, RecipeCreateStateLoaded state) {
Widget _buildRecipeCreate(BuildContext context, RecipeCreateStateLoaded state) {
List<String> _options = state.autocompleteList.map((Product item) => item.name).toList();
return Scaffold(
appBar: AppBar(
toolbarHeight: 0,
@@ -86,18 +87,16 @@ class RecipeCreateScreen extends StatelessWidget {
Text('Тип блюда'),
SizedBox(height: 8),
CustomDropDown(
value: state.types[0],
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);
final pickedFile = await state.picker.pickImage(source: ImageSource.gallery);
context.read<RecipeCreateCubit>().uploadRecipeImage(pickedFile);
},
child: state.recipeImage == null
? Container(
@@ -121,31 +120,71 @@ class RecipeCreateScreen extends StatelessWidget {
],
),
)
: Image.file(File(state.recipeImage!.path),
height: 200, fit: BoxFit.cover),
: Image.file(File(state.recipeImage!.path), height: 200, fit: BoxFit.cover),
),
SizedBox(height: 16),
Text('Время приготовления'),
SizedBox(height: 8),
CustomDropDown(
items: state.cookingTimes,
value: state.cookingTimes[0],
value: state.selectedCookingTime,
onChanged: changeCookingTime(context),
),
SizedBox(height: 16),
Text('Статус'),
SizedBox(height: 8),
CustomDropDown(
items: state.statuses,
value: state.statuses[0],
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]),
for (int j = 0; j < state.ingredients.length; j++) _buildIngredient(state.ingredients[j]),
SizedBox(height: 24),
CustomTextFormField(
hintText: 'Введите название продукта',
controller: state.productNameController,
RawAutocomplete<String>(
optionsBuilder: _buildOptions(_options),
fieldViewBuilder: (
BuildContext context,
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(
@@ -153,18 +192,14 @@ class RecipeCreateScreen extends StatelessWidget {
fillColor: appTheme.gray50,
controller: state.ingredientController,
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
],
inputFormatters: <TextInputFormatter>[FilteringTextInputFormatter.digitsOnly],
),
SizedBox(height: 8),
Row(children: [
Text('гр'),
Switch(
value: state.ingredientAsItems,
onChanged: (bool value) => context
.read<RecipeCreateCubit>()
.switchUnits(value),
onChanged: (bool value) => context.read<RecipeCreateCubit>().switchUnits(value),
activeColor: appTheme.blueA400,
inactiveThumbColor: Colors.grey,
inactiveTrackColor: Colors.grey.shade300,
@@ -187,16 +222,10 @@ class RecipeCreateScreen extends StatelessWidget {
'+',
style: theme.textTheme.titleSmall,
),
onPressed: () => context
.read<RecipeCreateCubit>()
.addIngredient(new Ingredient(
product_name:
state.productNameController.text,
portion: int.parse(
state.ingredientController.text),
unit: state.ingredientAsItems
? 'pcs'
: 'gr'))),
onPressed: () => context.read<RecipeCreateCubit>().addIngredient(new Ingredient(
product_name: state.productNameController.text,
portion: int.parse(state.ingredientController.text),
unit: state.ingredientAsItems ? 'pcs' : 'gr'))),
),
SizedBox(height: 24),
Text('Описание рецепта'),
@@ -207,8 +236,7 @@ class RecipeCreateScreen extends StatelessWidget {
controller: state.stepDescriptionController,
),
SizedBox(height: 24),
for (int i = 0; i < state.numberOfSteps; i++)
_buildStep(context, i, state),
for (int i = 0; i < state.numberOfSteps; i++) _buildStep(context, i, state),
SizedBox(height: 24),
Container(
height: 48,
@@ -221,8 +249,7 @@ class RecipeCreateScreen extends StatelessWidget {
borderRadius: BorderRadius.circular(8),
),
backgroundColor: appTheme.blueA400,
onPressed: () =>
context.read<RecipeCreateCubit>().addStep(),
onPressed: () => context.read<RecipeCreateCubit>().addStep(),
label: Text(
'+',
style: theme.textTheme.titleSmall,
@@ -241,8 +268,7 @@ class RecipeCreateScreen extends StatelessWidget {
borderRadius: BorderRadius.circular(8),
),
backgroundColor: Colors.grey,
onPressed: () =>
context.read<RecipeCreateCubit>().removeStep(),
onPressed: () => context.read<RecipeCreateCubit>().removeStep(),
label: Text(
'-',
style: theme.textTheme.titleSmall,
@@ -269,7 +295,7 @@ class RecipeCreateScreen extends StatelessWidget {
borderRadius: BorderRadius.circular(8),
),
backgroundColor: appTheme.blueA400,
onPressed: () {},
onPressed: () => context.read<RecipeCreateCubit>().publishRecipe(createRecipeFromState(state)),
label: Text(
'Опубликовать',
style: theme.textTheme.titleSmall,
@@ -285,23 +311,15 @@ class RecipeCreateScreen extends StatelessWidget {
);
}
_buildStep(
BuildContext context, int stepNumber, RecipeCreateStateLoaded state) {
_buildStep(BuildContext context, int stepNumber, RecipeCreateStateLoaded state) {
return Column(
children: [
Row(children: [
Text('Шаг ${stepNumber + 1}'),
Spacer(),
Text('Всего шагов: ${state.numberOfSteps}')
]),
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);
final pickedFile = await state.picker.pickImage(source: ImageSource.gallery);
context.read<RecipeCreateCubit>().uploadStepImage(pickedFile, stepNumber);
},
child: state.stepImages[stepNumber] == null
? Container(
@@ -326,8 +344,7 @@ class RecipeCreateScreen extends StatelessWidget {
],
),
)
: Image.file(File(state.stepImages[stepNumber]!.path),
height: 150, fit: BoxFit.cover)),
: Image.file(File(state.stepImages[stepNumber]!.path), height: 150, fit: BoxFit.cover)),
SizedBox(height: 16),
CustomTextFormField(
hintText: 'Введите описание шага',
@@ -361,9 +378,7 @@ class RecipeCreateScreen extends StatelessWidget {
top: 5.v,
),
child: Text(
ingredient.product_name.length > 8
? ingredient.product_name.substring(0, 8)
: ingredient.product_name,
ingredient.product_name.length > 8 ? ingredient.product_name.substring(0, 8) : ingredient.product_name,
style: CustomTextStyles.titleMedium16,
),
),
@@ -374,9 +389,7 @@ class RecipeCreateScreen extends StatelessWidget {
bottom: 3.v,
),
child: Text(
ingredient.portion.toString() +
' ' +
ingredient.unit.toString().tr,
ingredient.portion.toString() + ' ' + ingredient.unit.toString().tr,
),
),
Spacer(),
@@ -395,35 +408,75 @@ class RecipeCreateScreen extends StatelessWidget {
);
}
_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;
// Подготовка шагов (например, можно создать шаги из stepControllers)
List<step.Step> steps = [];
for (int i = 0; i < state.stepControllers.length; i++) {
image.Image picStep = image.Image(path: state.stepImages[i]?.path ?? "");
if (state.stepControllers[i].text.isNotEmpty) {
steps.add(step.Step(description: state.stepControllers[i].text));
steps.add(step.Step(
description: state.stepControllers[i].text,
image: picStep,
));
}
}
// Подготовка изображения
image.Image pic = image.Image(path: state.recipeImage?.path ?? '');
// Создание экземпляра RecipeModel
return RecipeModel(
final RecipeModel recipe = RecipeModel(
id: null,
ingredients: ingredients,
steps: steps,
state: 'draft',
description: state.titleController.text,
type: state.types.first.value,
state: state.selectedStatus.value,
type: state.selectedType.value,
cooking_time: state.selectedCookingTime.value,
description: state.stepDescriptionController.text,
title: state.titleController.text,
image: pic,
video_url: state.youtubeLinkController.text.isNotEmpty
? state.youtubeLinkController.text
: null,
cooking_time:
state.cookingTimes.isNotEmpty ? state.cookingTimes.first.value : null,
video_url: state.youtubeLinkController.text.isNotEmpty ? state.youtubeLinkController.text : null,
);
print(recipe);
return recipe;
}
}

View File

@@ -1,9 +1,27 @@
import 'package:eatvio_app/features/recipes/models/recipe_model.dart';
import 'package:eatvio_app/features/recipes/services/recipe_service.dart';
import 'package:eatvio_app/features/diary/models/product.dart';
class RecipeRepository {
final RecipeService recipeService;
RecipeRepository({required this.recipeService});
Future<Map<String, List<Product>>> inputProduct(String name) async {
try {
return await recipeService.getInputProduct(name);
} catch (e) {
rethrow;
}
}
Future<RecipeModel> publishRecipe(RecipeModel recipe) async {
try {
return await recipeService.publishRecipe(recipe);
} catch (e) {
rethrow;
}
}
/*Future<RecipeModel> getRecipe(int recipeID) async {
try {
return (await recipeService.getRecipe(recipeID));

View File

@@ -1,6 +1,7 @@
import 'package:dio/dio.dart';
import 'package:eatvio_app/features/recipes/models/recipe_model.dart';
import 'package:retrofit/retrofit.dart';
import 'package:eatvio_app/features/diary/models/product.dart';
part 'recipe_service.g.dart';
@@ -10,4 +11,10 @@ abstract class RecipeService {
@GET('/api/recipe/{id}/show/')
Future<Map<String, RecipeModel>> getRecipe(@Path() int id);
@GET('/api/diary/product_nutritional_values/filter')
Future<Map<String, List<Product>>> getInputProduct(@Query('name') String name);
@POST('/api/recipes/create')
Future<RecipeModel> publishRecipe(RecipeModel recipe);
}

View File

@@ -46,6 +46,64 @@ class _RecipeService implements RecipeService {
return _value;
}
@override
Future<Map<String, List<Product>>> getInputProduct(String name) async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{r'name': name};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _result = await _dio.fetch<Map<String, dynamic>>(
_setStreamType<Map<String, List<Product>>>(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,
))));
var _value = _result.data!.map((k, dynamic v) => MapEntry(
k,
(v as List)
.map((i) => Product.fromJson(i as Map<String, dynamic>))
.toList()));
return _value;
}
@override
Future<RecipeModel> publishRecipe(RecipeModel recipe) async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _result = await _dio
.fetch<Map<String, dynamic>>(_setStreamType<RecipeModel>(Options(
method: 'POST',
headers: _headers,
extra: _extra,
)
.compose(
_dio.options,
'/api/recipes/create',
queryParameters: queryParameters,
data: _data,
)
.copyWith(
baseUrl: _combineBaseUrls(
_dio.options.baseUrl,
baseUrl,
))));
final _value = RecipeModel.fromJson(_result.data!);
return _value;
}
RequestOptions _setStreamType<T>(RequestOptions requestOptions) {
if (T != dynamic &&
!(requestOptions.responseType == ResponseType.bytes ||