forked from eatvio/eatvio_app
feat(recipe): Models, service and repository for eecpe create. Recipe create now uses cubit
This commit is contained in:
14
lib/features/recipes/models/image.dart
Normal file
14
lib/features/recipes/models/image.dart
Normal file
@@ -0,0 +1,14 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'image.freezed.dart';
|
||||
|
||||
part 'image.g.dart';
|
||||
|
||||
@freezed
|
||||
class Image with _$Image {
|
||||
const factory Image({
|
||||
required String path,
|
||||
}) = _Image;
|
||||
|
||||
factory Image.fromJson(Map<String, Object?> json) => _$ImageFromJson(json);
|
||||
}
|
||||
147
lib/features/recipes/models/image.freezed.dart
Normal file
147
lib/features/recipes/models/image.freezed.dart
Normal file
@@ -0,0 +1,147 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'image.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||
|
||||
Image _$ImageFromJson(Map<String, dynamic> json) {
|
||||
return _Image.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$Image {
|
||||
String get path => throw _privateConstructorUsedError;
|
||||
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
$ImageCopyWith<Image> get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $ImageCopyWith<$Res> {
|
||||
factory $ImageCopyWith(Image value, $Res Function(Image) then) =
|
||||
_$ImageCopyWithImpl<$Res, Image>;
|
||||
@useResult
|
||||
$Res call({String path});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$ImageCopyWithImpl<$Res, $Val extends Image>
|
||||
implements $ImageCopyWith<$Res> {
|
||||
_$ImageCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? path = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
path: null == path
|
||||
? _value.path
|
||||
: path // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$ImageImplCopyWith<$Res> implements $ImageCopyWith<$Res> {
|
||||
factory _$$ImageImplCopyWith(
|
||||
_$ImageImpl value, $Res Function(_$ImageImpl) then) =
|
||||
__$$ImageImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({String path});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$ImageImplCopyWithImpl<$Res>
|
||||
extends _$ImageCopyWithImpl<$Res, _$ImageImpl>
|
||||
implements _$$ImageImplCopyWith<$Res> {
|
||||
__$$ImageImplCopyWithImpl(
|
||||
_$ImageImpl _value, $Res Function(_$ImageImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? path = null,
|
||||
}) {
|
||||
return _then(_$ImageImpl(
|
||||
path: null == path
|
||||
? _value.path
|
||||
: path // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$ImageImpl implements _Image {
|
||||
const _$ImageImpl({required this.path});
|
||||
|
||||
factory _$ImageImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$ImageImplFromJson(json);
|
||||
|
||||
@override
|
||||
final String path;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Image(path: $path)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$ImageImpl &&
|
||||
(identical(other.path, path) || other.path == path));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, path);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$ImageImplCopyWith<_$ImageImpl> get copyWith =>
|
||||
__$$ImageImplCopyWithImpl<_$ImageImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$ImageImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _Image implements Image {
|
||||
const factory _Image({required final String path}) = _$ImageImpl;
|
||||
|
||||
factory _Image.fromJson(Map<String, dynamic> json) = _$ImageImpl.fromJson;
|
||||
|
||||
@override
|
||||
String get path;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$ImageImplCopyWith<_$ImageImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
16
lib/features/recipes/models/image.g.dart
Normal file
16
lib/features/recipes/models/image.g.dart
Normal file
@@ -0,0 +1,16 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'image.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$ImageImpl _$$ImageImplFromJson(Map<String, dynamic> json) => _$ImageImpl(
|
||||
path: json['path'] as String,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$ImageImplToJson(_$ImageImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'path': instance.path,
|
||||
};
|
||||
18
lib/features/recipes/models/ingredient.dart
Normal file
18
lib/features/recipes/models/ingredient.dart
Normal file
@@ -0,0 +1,18 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'ingredient.freezed.dart';
|
||||
|
||||
part 'ingredient.g.dart';
|
||||
|
||||
@freezed
|
||||
class Ingredient with _$Ingredient {
|
||||
const factory Ingredient({
|
||||
int? id,
|
||||
required String product_name,
|
||||
required String unit,
|
||||
required num portion,
|
||||
}) = _Ingredient;
|
||||
|
||||
factory Ingredient.fromJson(Map<String, Object?> json) =>
|
||||
_$IngredientFromJson(json);
|
||||
}
|
||||
208
lib/features/recipes/models/ingredient.freezed.dart
Normal file
208
lib/features/recipes/models/ingredient.freezed.dart
Normal file
@@ -0,0 +1,208 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'ingredient.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||
|
||||
Ingredient _$IngredientFromJson(Map<String, dynamic> json) {
|
||||
return _Ingredient.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$Ingredient {
|
||||
int? get id => throw _privateConstructorUsedError;
|
||||
String get product_name => throw _privateConstructorUsedError;
|
||||
String get unit => throw _privateConstructorUsedError;
|
||||
num get portion => throw _privateConstructorUsedError;
|
||||
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
$IngredientCopyWith<Ingredient> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $IngredientCopyWith<$Res> {
|
||||
factory $IngredientCopyWith(
|
||||
Ingredient value, $Res Function(Ingredient) then) =
|
||||
_$IngredientCopyWithImpl<$Res, Ingredient>;
|
||||
@useResult
|
||||
$Res call({int? id, String product_name, String unit, num portion});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$IngredientCopyWithImpl<$Res, $Val extends Ingredient>
|
||||
implements $IngredientCopyWith<$Res> {
|
||||
_$IngredientCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? id = freezed,
|
||||
Object? product_name = null,
|
||||
Object? unit = null,
|
||||
Object? portion = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
id: freezed == id
|
||||
? _value.id
|
||||
: id // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
product_name: null == product_name
|
||||
? _value.product_name
|
||||
: product_name // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
unit: null == unit
|
||||
? _value.unit
|
||||
: unit // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
portion: null == portion
|
||||
? _value.portion
|
||||
: portion // ignore: cast_nullable_to_non_nullable
|
||||
as num,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$IngredientImplCopyWith<$Res>
|
||||
implements $IngredientCopyWith<$Res> {
|
||||
factory _$$IngredientImplCopyWith(
|
||||
_$IngredientImpl value, $Res Function(_$IngredientImpl) then) =
|
||||
__$$IngredientImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({int? id, String product_name, String unit, num portion});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$IngredientImplCopyWithImpl<$Res>
|
||||
extends _$IngredientCopyWithImpl<$Res, _$IngredientImpl>
|
||||
implements _$$IngredientImplCopyWith<$Res> {
|
||||
__$$IngredientImplCopyWithImpl(
|
||||
_$IngredientImpl _value, $Res Function(_$IngredientImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? id = freezed,
|
||||
Object? product_name = null,
|
||||
Object? unit = null,
|
||||
Object? portion = null,
|
||||
}) {
|
||||
return _then(_$IngredientImpl(
|
||||
id: freezed == id
|
||||
? _value.id
|
||||
: id // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
product_name: null == product_name
|
||||
? _value.product_name
|
||||
: product_name // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
unit: null == unit
|
||||
? _value.unit
|
||||
: unit // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
portion: null == portion
|
||||
? _value.portion
|
||||
: portion // ignore: cast_nullable_to_non_nullable
|
||||
as num,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$IngredientImpl implements _Ingredient {
|
||||
const _$IngredientImpl(
|
||||
{this.id,
|
||||
required this.product_name,
|
||||
required this.unit,
|
||||
required this.portion});
|
||||
|
||||
factory _$IngredientImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$IngredientImplFromJson(json);
|
||||
|
||||
@override
|
||||
final int? id;
|
||||
@override
|
||||
final String product_name;
|
||||
@override
|
||||
final String unit;
|
||||
@override
|
||||
final num portion;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Ingredient(id: $id, product_name: $product_name, unit: $unit, portion: $portion)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$IngredientImpl &&
|
||||
(identical(other.id, id) || other.id == id) &&
|
||||
(identical(other.product_name, product_name) ||
|
||||
other.product_name == product_name) &&
|
||||
(identical(other.unit, unit) || other.unit == unit) &&
|
||||
(identical(other.portion, portion) || other.portion == portion));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, id, product_name, unit, portion);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$IngredientImplCopyWith<_$IngredientImpl> get copyWith =>
|
||||
__$$IngredientImplCopyWithImpl<_$IngredientImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$IngredientImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _Ingredient implements Ingredient {
|
||||
const factory _Ingredient(
|
||||
{final int? id,
|
||||
required final String product_name,
|
||||
required final String unit,
|
||||
required final num portion}) = _$IngredientImpl;
|
||||
|
||||
factory _Ingredient.fromJson(Map<String, dynamic> json) =
|
||||
_$IngredientImpl.fromJson;
|
||||
|
||||
@override
|
||||
int? get id;
|
||||
@override
|
||||
String get product_name;
|
||||
@override
|
||||
String get unit;
|
||||
@override
|
||||
num get portion;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$IngredientImplCopyWith<_$IngredientImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
23
lib/features/recipes/models/ingredient.g.dart
Normal file
23
lib/features/recipes/models/ingredient.g.dart
Normal file
@@ -0,0 +1,23 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'ingredient.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$IngredientImpl _$$IngredientImplFromJson(Map<String, dynamic> json) =>
|
||||
_$IngredientImpl(
|
||||
id: (json['id'] as num?)?.toInt(),
|
||||
product_name: json['product_name'] as String,
|
||||
unit: json['unit'] as String,
|
||||
portion: json['portion'] as num,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$IngredientImplToJson(_$IngredientImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'product_name': instance.product_name,
|
||||
'unit': instance.unit,
|
||||
'portion': instance.portion,
|
||||
};
|
||||
25
lib/features/recipes/models/recipe_model.dart
Normal file
25
lib/features/recipes/models/recipe_model.dart
Normal file
@@ -0,0 +1,25 @@
|
||||
import 'package:eatvio_app/features/recipes/models/image.dart';
|
||||
import 'package:eatvio_app/features/recipes/models/ingredient.dart';
|
||||
import 'package:eatvio_app/features/recipes/models/step.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'recipe_model.freezed.dart';
|
||||
part 'recipe_model.g.dart';
|
||||
|
||||
@freezed
|
||||
class RecipeModel with _$RecipeModel {
|
||||
const factory RecipeModel({
|
||||
int? id,
|
||||
required List<Ingredient> ingredients,
|
||||
required List<Step> steps,
|
||||
required String state,
|
||||
required String description,
|
||||
required String type,
|
||||
required Image image,
|
||||
String? video_url,
|
||||
num? cooking_time,
|
||||
}) = _RecipeModel;
|
||||
|
||||
factory RecipeModel.fromJson(Map<String, Object?> json) =>
|
||||
_$RecipeModelFromJson(json);
|
||||
}
|
||||
356
lib/features/recipes/models/recipe_model.freezed.dart
Normal file
356
lib/features/recipes/models/recipe_model.freezed.dart
Normal file
@@ -0,0 +1,356 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'recipe_model.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||
|
||||
RecipeModel _$RecipeModelFromJson(Map<String, dynamic> json) {
|
||||
return _RecipeModel.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$RecipeModel {
|
||||
int? get id => throw _privateConstructorUsedError;
|
||||
List<Ingredient> get ingredients => throw _privateConstructorUsedError;
|
||||
List<Step> get steps => throw _privateConstructorUsedError;
|
||||
String get state => throw _privateConstructorUsedError;
|
||||
String get description => throw _privateConstructorUsedError;
|
||||
String get type => throw _privateConstructorUsedError;
|
||||
Image get image => throw _privateConstructorUsedError;
|
||||
String? get video_url => throw _privateConstructorUsedError;
|
||||
num? get cooking_time => throw _privateConstructorUsedError;
|
||||
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
$RecipeModelCopyWith<RecipeModel> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $RecipeModelCopyWith<$Res> {
|
||||
factory $RecipeModelCopyWith(
|
||||
RecipeModel value, $Res Function(RecipeModel) then) =
|
||||
_$RecipeModelCopyWithImpl<$Res, RecipeModel>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{int? id,
|
||||
List<Ingredient> ingredients,
|
||||
List<Step> steps,
|
||||
String state,
|
||||
String description,
|
||||
String type,
|
||||
Image image,
|
||||
String? video_url,
|
||||
num? cooking_time});
|
||||
|
||||
$ImageCopyWith<$Res> get image;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$RecipeModelCopyWithImpl<$Res, $Val extends RecipeModel>
|
||||
implements $RecipeModelCopyWith<$Res> {
|
||||
_$RecipeModelCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? id = freezed,
|
||||
Object? ingredients = null,
|
||||
Object? steps = null,
|
||||
Object? state = null,
|
||||
Object? description = null,
|
||||
Object? type = null,
|
||||
Object? image = null,
|
||||
Object? video_url = freezed,
|
||||
Object? cooking_time = freezed,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
id: freezed == id
|
||||
? _value.id
|
||||
: id // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
ingredients: null == ingredients
|
||||
? _value.ingredients
|
||||
: ingredients // ignore: cast_nullable_to_non_nullable
|
||||
as List<Ingredient>,
|
||||
steps: null == steps
|
||||
? _value.steps
|
||||
: steps // ignore: cast_nullable_to_non_nullable
|
||||
as List<Step>,
|
||||
state: null == state
|
||||
? _value.state
|
||||
: state // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
description: null == description
|
||||
? _value.description
|
||||
: description // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
type: null == type
|
||||
? _value.type
|
||||
: type // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
image: null == image
|
||||
? _value.image
|
||||
: image // ignore: cast_nullable_to_non_nullable
|
||||
as Image,
|
||||
video_url: freezed == video_url
|
||||
? _value.video_url
|
||||
: video_url // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
cooking_time: freezed == cooking_time
|
||||
? _value.cooking_time
|
||||
: cooking_time // ignore: cast_nullable_to_non_nullable
|
||||
as num?,
|
||||
) as $Val);
|
||||
}
|
||||
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$ImageCopyWith<$Res> get image {
|
||||
return $ImageCopyWith<$Res>(_value.image, (value) {
|
||||
return _then(_value.copyWith(image: value) as $Val);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$RecipeModelImplCopyWith<$Res>
|
||||
implements $RecipeModelCopyWith<$Res> {
|
||||
factory _$$RecipeModelImplCopyWith(
|
||||
_$RecipeModelImpl value, $Res Function(_$RecipeModelImpl) then) =
|
||||
__$$RecipeModelImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{int? id,
|
||||
List<Ingredient> ingredients,
|
||||
List<Step> steps,
|
||||
String state,
|
||||
String description,
|
||||
String type,
|
||||
Image image,
|
||||
String? video_url,
|
||||
num? cooking_time});
|
||||
|
||||
@override
|
||||
$ImageCopyWith<$Res> get image;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$RecipeModelImplCopyWithImpl<$Res>
|
||||
extends _$RecipeModelCopyWithImpl<$Res, _$RecipeModelImpl>
|
||||
implements _$$RecipeModelImplCopyWith<$Res> {
|
||||
__$$RecipeModelImplCopyWithImpl(
|
||||
_$RecipeModelImpl _value, $Res Function(_$RecipeModelImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? id = freezed,
|
||||
Object? ingredients = null,
|
||||
Object? steps = null,
|
||||
Object? state = null,
|
||||
Object? description = null,
|
||||
Object? type = null,
|
||||
Object? image = null,
|
||||
Object? video_url = freezed,
|
||||
Object? cooking_time = freezed,
|
||||
}) {
|
||||
return _then(_$RecipeModelImpl(
|
||||
id: freezed == id
|
||||
? _value.id
|
||||
: id // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
ingredients: null == ingredients
|
||||
? _value._ingredients
|
||||
: ingredients // ignore: cast_nullable_to_non_nullable
|
||||
as List<Ingredient>,
|
||||
steps: null == steps
|
||||
? _value._steps
|
||||
: steps // ignore: cast_nullable_to_non_nullable
|
||||
as List<Step>,
|
||||
state: null == state
|
||||
? _value.state
|
||||
: state // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
description: null == description
|
||||
? _value.description
|
||||
: description // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
type: null == type
|
||||
? _value.type
|
||||
: type // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
image: null == image
|
||||
? _value.image
|
||||
: image // ignore: cast_nullable_to_non_nullable
|
||||
as Image,
|
||||
video_url: freezed == video_url
|
||||
? _value.video_url
|
||||
: video_url // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
cooking_time: freezed == cooking_time
|
||||
? _value.cooking_time
|
||||
: cooking_time // ignore: cast_nullable_to_non_nullable
|
||||
as num?,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$RecipeModelImpl implements _RecipeModel {
|
||||
const _$RecipeModelImpl(
|
||||
{this.id,
|
||||
required final List<Ingredient> ingredients,
|
||||
required final List<Step> steps,
|
||||
required this.state,
|
||||
required this.description,
|
||||
required this.type,
|
||||
required this.image,
|
||||
this.video_url,
|
||||
this.cooking_time})
|
||||
: _ingredients = ingredients,
|
||||
_steps = steps;
|
||||
|
||||
factory _$RecipeModelImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$RecipeModelImplFromJson(json);
|
||||
|
||||
@override
|
||||
final int? id;
|
||||
final List<Ingredient> _ingredients;
|
||||
@override
|
||||
List<Ingredient> get ingredients {
|
||||
if (_ingredients is EqualUnmodifiableListView) return _ingredients;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_ingredients);
|
||||
}
|
||||
|
||||
final List<Step> _steps;
|
||||
@override
|
||||
List<Step> get steps {
|
||||
if (_steps is EqualUnmodifiableListView) return _steps;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_steps);
|
||||
}
|
||||
|
||||
@override
|
||||
final String state;
|
||||
@override
|
||||
final String description;
|
||||
@override
|
||||
final String type;
|
||||
@override
|
||||
final Image image;
|
||||
@override
|
||||
final String? video_url;
|
||||
@override
|
||||
final num? cooking_time;
|
||||
|
||||
@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)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$RecipeModelImpl &&
|
||||
(identical(other.id, id) || other.id == id) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._ingredients, _ingredients) &&
|
||||
const DeepCollectionEquality().equals(other._steps, _steps) &&
|
||||
(identical(other.state, state) || other.state == state) &&
|
||||
(identical(other.description, description) ||
|
||||
other.description == description) &&
|
||||
(identical(other.type, type) || other.type == type) &&
|
||||
(identical(other.image, image) || other.image == image) &&
|
||||
(identical(other.video_url, video_url) ||
|
||||
other.video_url == video_url) &&
|
||||
(identical(other.cooking_time, cooking_time) ||
|
||||
other.cooking_time == cooking_time));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
id,
|
||||
const DeepCollectionEquality().hash(_ingredients),
|
||||
const DeepCollectionEquality().hash(_steps),
|
||||
state,
|
||||
description,
|
||||
type,
|
||||
image,
|
||||
video_url,
|
||||
cooking_time);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$RecipeModelImplCopyWith<_$RecipeModelImpl> get copyWith =>
|
||||
__$$RecipeModelImplCopyWithImpl<_$RecipeModelImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$RecipeModelImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _RecipeModel implements RecipeModel {
|
||||
const factory _RecipeModel(
|
||||
{final int? id,
|
||||
required final List<Ingredient> ingredients,
|
||||
required final List<Step> steps,
|
||||
required final String state,
|
||||
required final String description,
|
||||
required final String type,
|
||||
required final Image image,
|
||||
final String? video_url,
|
||||
final num? cooking_time}) = _$RecipeModelImpl;
|
||||
|
||||
factory _RecipeModel.fromJson(Map<String, dynamic> json) =
|
||||
_$RecipeModelImpl.fromJson;
|
||||
|
||||
@override
|
||||
int? get id;
|
||||
@override
|
||||
List<Ingredient> get ingredients;
|
||||
@override
|
||||
List<Step> get steps;
|
||||
@override
|
||||
String get state;
|
||||
@override
|
||||
String get description;
|
||||
@override
|
||||
String get type;
|
||||
@override
|
||||
Image get image;
|
||||
@override
|
||||
String? get video_url;
|
||||
@override
|
||||
num? get cooking_time;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$RecipeModelImplCopyWith<_$RecipeModelImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
37
lib/features/recipes/models/recipe_model.g.dart
Normal file
37
lib/features/recipes/models/recipe_model.g.dart
Normal file
@@ -0,0 +1,37 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'recipe_model.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$RecipeModelImpl _$$RecipeModelImplFromJson(Map<String, dynamic> json) =>
|
||||
_$RecipeModelImpl(
|
||||
id: (json['id'] as num?)?.toInt(),
|
||||
ingredients: (json['ingredients'] as List<dynamic>)
|
||||
.map((e) => Ingredient.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
steps: (json['steps'] as List<dynamic>)
|
||||
.map((e) => Step.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
state: json['state'] as String,
|
||||
description: json['description'] as String,
|
||||
type: json['type'] as String,
|
||||
image: Image.fromJson(json['image'] as Map<String, dynamic>),
|
||||
video_url: json['video_url'] as String?,
|
||||
cooking_time: json['cooking_time'] as num?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$RecipeModelImplToJson(_$RecipeModelImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'ingredients': instance.ingredients,
|
||||
'steps': instance.steps,
|
||||
'state': instance.state,
|
||||
'description': instance.description,
|
||||
'type': instance.type,
|
||||
'image': instance.image,
|
||||
'video_url': instance.video_url,
|
||||
'cooking_time': instance.cooking_time,
|
||||
};
|
||||
17
lib/features/recipes/models/step.dart
Normal file
17
lib/features/recipes/models/step.dart
Normal file
@@ -0,0 +1,17 @@
|
||||
import 'package:eatvio_app/features/recipes/models/image.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'step.freezed.dart';
|
||||
|
||||
part 'step.g.dart';
|
||||
|
||||
@freezed
|
||||
class Step with _$Step {
|
||||
const factory Step({
|
||||
int? id,
|
||||
Image? image,
|
||||
String? description,
|
||||
}) = _Step;
|
||||
|
||||
factory Step.fromJson(Map<String, Object?> json) => _$StepFromJson(json);
|
||||
}
|
||||
199
lib/features/recipes/models/step.freezed.dart
Normal file
199
lib/features/recipes/models/step.freezed.dart
Normal file
@@ -0,0 +1,199 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'step.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||
|
||||
Step _$StepFromJson(Map<String, dynamic> json) {
|
||||
return _Step.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$Step {
|
||||
int? get id => throw _privateConstructorUsedError;
|
||||
Image? get image => throw _privateConstructorUsedError;
|
||||
String? get description => throw _privateConstructorUsedError;
|
||||
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
$StepCopyWith<Step> get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $StepCopyWith<$Res> {
|
||||
factory $StepCopyWith(Step value, $Res Function(Step) then) =
|
||||
_$StepCopyWithImpl<$Res, Step>;
|
||||
@useResult
|
||||
$Res call({int? id, Image? image, String? description});
|
||||
|
||||
$ImageCopyWith<$Res>? get image;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$StepCopyWithImpl<$Res, $Val extends Step>
|
||||
implements $StepCopyWith<$Res> {
|
||||
_$StepCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? id = freezed,
|
||||
Object? image = freezed,
|
||||
Object? description = freezed,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
id: freezed == id
|
||||
? _value.id
|
||||
: id // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
image: freezed == image
|
||||
? _value.image
|
||||
: image // ignore: cast_nullable_to_non_nullable
|
||||
as Image?,
|
||||
description: freezed == description
|
||||
? _value.description
|
||||
: description // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
) as $Val);
|
||||
}
|
||||
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$ImageCopyWith<$Res>? get image {
|
||||
if (_value.image == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $ImageCopyWith<$Res>(_value.image!, (value) {
|
||||
return _then(_value.copyWith(image: value) as $Val);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$StepImplCopyWith<$Res> implements $StepCopyWith<$Res> {
|
||||
factory _$$StepImplCopyWith(
|
||||
_$StepImpl value, $Res Function(_$StepImpl) then) =
|
||||
__$$StepImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({int? id, Image? image, String? description});
|
||||
|
||||
@override
|
||||
$ImageCopyWith<$Res>? get image;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$StepImplCopyWithImpl<$Res>
|
||||
extends _$StepCopyWithImpl<$Res, _$StepImpl>
|
||||
implements _$$StepImplCopyWith<$Res> {
|
||||
__$$StepImplCopyWithImpl(_$StepImpl _value, $Res Function(_$StepImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? id = freezed,
|
||||
Object? image = freezed,
|
||||
Object? description = freezed,
|
||||
}) {
|
||||
return _then(_$StepImpl(
|
||||
id: freezed == id
|
||||
? _value.id
|
||||
: id // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
image: freezed == image
|
||||
? _value.image
|
||||
: image // ignore: cast_nullable_to_non_nullable
|
||||
as Image?,
|
||||
description: freezed == description
|
||||
? _value.description
|
||||
: description // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$StepImpl implements _Step {
|
||||
const _$StepImpl({this.id, this.image, this.description});
|
||||
|
||||
factory _$StepImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$StepImplFromJson(json);
|
||||
|
||||
@override
|
||||
final int? id;
|
||||
@override
|
||||
final Image? image;
|
||||
@override
|
||||
final String? description;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Step(id: $id, image: $image, description: $description)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$StepImpl &&
|
||||
(identical(other.id, id) || other.id == id) &&
|
||||
(identical(other.image, image) || other.image == image) &&
|
||||
(identical(other.description, description) ||
|
||||
other.description == description));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, id, image, description);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$StepImplCopyWith<_$StepImpl> get copyWith =>
|
||||
__$$StepImplCopyWithImpl<_$StepImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$StepImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _Step implements Step {
|
||||
const factory _Step(
|
||||
{final int? id,
|
||||
final Image? image,
|
||||
final String? description}) = _$StepImpl;
|
||||
|
||||
factory _Step.fromJson(Map<String, dynamic> json) = _$StepImpl.fromJson;
|
||||
|
||||
@override
|
||||
int? get id;
|
||||
@override
|
||||
Image? get image;
|
||||
@override
|
||||
String? get description;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$StepImplCopyWith<_$StepImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
22
lib/features/recipes/models/step.g.dart
Normal file
22
lib/features/recipes/models/step.g.dart
Normal file
@@ -0,0 +1,22 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'step.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$StepImpl _$$StepImplFromJson(Map<String, dynamic> json) => _$StepImpl(
|
||||
id: (json['id'] as num?)?.toInt(),
|
||||
image: json['image'] == null
|
||||
? null
|
||||
: Image.fromJson(json['image'] as Map<String, dynamic>),
|
||||
description: json['description'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$StepImplToJson(_$StepImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'image': instance.image,
|
||||
'description': instance.description,
|
||||
};
|
||||
170
lib/features/recipes/presentation/bloc/recipe_create_cubit.dart
Normal file
170
lib/features/recipes/presentation/bloc/recipe_create_cubit.dart
Normal file
@@ -0,0 +1,170 @@
|
||||
import 'package:eatvio_app/core/app_export.dart';
|
||||
import 'package:eatvio_app/features/recipes/models/ingredient.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: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());
|
||||
|
||||
loadRecipeCreate() {
|
||||
emit(const RecipeCreateStateLoading());
|
||||
try {
|
||||
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: 'Неактивна'),
|
||||
],
|
||||
));
|
||||
} catch (e) {
|
||||
emit(RecipeCreateState.error(errorMessage: e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
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.product_name == ingredient.product_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 = 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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import 'package:eatvio_app/features/recipes/models/recipe_model.dart';
|
||||
import 'package:eatvio_app/features/recipes/models/ingredient.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
|
||||
import '../../../../data/models/selectionPopupModel/selection_popup_model.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 youtubeLinkController,
|
||||
required List<TextEditingController> stepControllers,
|
||||
XFile? recipeImage,
|
||||
required List<XFile?> stepImages,
|
||||
required List<Ingredient> ingredients,
|
||||
required int numberOfSteps,
|
||||
required bool ingredientAsItems,
|
||||
required List<SelectionPopupModel> types,
|
||||
required List<SelectionPopupModel> cookingTimes,
|
||||
required List<SelectionPopupModel> statuses,
|
||||
}) = RecipeCreateStateLoaded;
|
||||
|
||||
const factory RecipeCreateState.error({
|
||||
required String errorMessage,
|
||||
}) = RecipeCreateStateError;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,72 +1,56 @@
|
||||
//import 'dart:io';
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
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/models/image.dart' as image;
|
||||
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/widgets/custom_drop_down.dart';
|
||||
import 'package:eatvio_app/widgets/custom_text_form_field.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../../../presentation/feed/blog_post_create_screen/bloc/blog_post_create_bloc.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
|
||||
class RecipeCreateScreen extends StatefulWidget {
|
||||
RecipeCreateScreen({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
State<RecipeCreateScreen> createState() => _RecipeCreateScreenState();
|
||||
}
|
||||
|
||||
class _RecipeCreateScreenState extends State<RecipeCreateScreen> {
|
||||
final TextEditingController titleController = TextEditingController();
|
||||
|
||||
final TextEditingController productNameController = TextEditingController();
|
||||
|
||||
final TextEditingController portionController = TextEditingController();
|
||||
|
||||
final TextEditingController stepDescriptionController =
|
||||
TextEditingController();
|
||||
|
||||
final TextEditingController youtubeLinkController = TextEditingController();
|
||||
|
||||
final List<SelectionPopupModel> types = [
|
||||
SelectionPopupModel(title: 'Первые блюда'),
|
||||
SelectionPopupModel(title: 'Вторые блюда'),
|
||||
SelectionPopupModel(title: 'Cалаты'),
|
||||
SelectionPopupModel(title: 'Перекусы/закуски'),
|
||||
SelectionPopupModel(title: 'Сладости'),
|
||||
SelectionPopupModel(title: 'Напитки'),
|
||||
SelectionPopupModel(title: 'Прочее'),
|
||||
];
|
||||
|
||||
final List<SelectionPopupModel> cookingTimes = [
|
||||
SelectionPopupModel(title: '10 минут'),
|
||||
SelectionPopupModel(title: '20 минут'),
|
||||
SelectionPopupModel(title: '30 минут'),
|
||||
SelectionPopupModel(title: '1 час'),
|
||||
SelectionPopupModel(title: '2 часа'),
|
||||
SelectionPopupModel(title: '10 дней'),
|
||||
];
|
||||
|
||||
final List<SelectionPopupModel> statuses = [
|
||||
SelectionPopupModel(title: 'Активна'),
|
||||
SelectionPopupModel(title: 'Неактивна'),
|
||||
];
|
||||
|
||||
int numberOfSteps = 1;
|
||||
XFile? recipeImage; // Переменная для общей фотографии рецепта
|
||||
List<XFile?> stepImages = []; // Список фотографий для каждого шага
|
||||
final ImagePicker _picker = ImagePicker();
|
||||
bool portionAsItems = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
stepImages.add(null); // Добавляем начальный элемент для первого шага
|
||||
// ignore: must_be_immutable
|
||||
class RecipeCreateScreen extends StatelessWidget {
|
||||
RecipeCreateScreen({Key? key}) : super(key: key);
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<RecipeCreateCubit, RecipeCreateState>(
|
||||
builder: (context, state) {
|
||||
if (state is RecipeCreateStateLoaded) {
|
||||
return _buildRecipeCreate(context, state);
|
||||
} else if (state is RecipeCreateStateLoading) {
|
||||
return Scaffold(
|
||||
body: Center(
|
||||
child: CupertinoActivityIndicator(),
|
||||
),
|
||||
);
|
||||
} 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 build(BuildContext context) {
|
||||
Widget _buildRecipeCreate(
|
||||
BuildContext context, RecipeCreateStateLoaded state) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
toolbarHeight: 0,
|
||||
@@ -94,30 +78,28 @@ class _RecipeCreateScreenState extends State<RecipeCreateScreen> {
|
||||
Text('Заголовок'),
|
||||
SizedBox(height: 8),
|
||||
CustomTextFormField(
|
||||
validator: _validateTitle,
|
||||
fillColor: appTheme.gray50,
|
||||
controller: titleController,
|
||||
controller: state.titleController,
|
||||
hintText: 'Заголовок',
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Text('Тип блюда'),
|
||||
SizedBox(height: 8),
|
||||
CustomDropDown(
|
||||
value: types[0],
|
||||
items: types,
|
||||
value: state.types[0],
|
||||
items: state.types,
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Text('Изображение'),
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
final pickedFile = await _picker.pickImage(
|
||||
source: ImageSource.gallery);
|
||||
setState(() {
|
||||
recipeImage =
|
||||
pickedFile; // Сохраняем общее изображение рецепта
|
||||
});
|
||||
final pickedFile = await state.picker
|
||||
.pickImage(source: ImageSource.gallery);
|
||||
context
|
||||
.read<RecipeCreateCubit>()
|
||||
.uploadRecipeImage(pickedFile);
|
||||
},
|
||||
child: recipeImage == null
|
||||
child: state.recipeImage == null
|
||||
? Container(
|
||||
height: 128,
|
||||
decoration: AppDecoration.fillGray.copyWith(
|
||||
@@ -139,49 +121,53 @@ class _RecipeCreateScreenState extends State<RecipeCreateScreen> {
|
||||
],
|
||||
),
|
||||
)
|
||||
: Image.file(File(recipeImage!.path),
|
||||
: Image.file(File(state.recipeImage!.path),
|
||||
height: 200, fit: BoxFit.cover),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Text('Время приготовления'),
|
||||
SizedBox(height: 8),
|
||||
CustomDropDown(
|
||||
items: cookingTimes,
|
||||
value: cookingTimes[0],
|
||||
items: state.cookingTimes,
|
||||
value: state.cookingTimes[0],
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Text('Статус'),
|
||||
SizedBox(height: 8),
|
||||
CustomDropDown(
|
||||
items: statuses,
|
||||
value: statuses[0],
|
||||
items: state.statuses,
|
||||
value: state.statuses[0],
|
||||
),
|
||||
SizedBox(height: 24),
|
||||
if (!state.ingredients.isEmpty)
|
||||
for (int j = 0; j < state.ingredients.length; j++)
|
||||
_buildIngredient(state.ingredients[j]),
|
||||
SizedBox(height: 24),
|
||||
CustomTextFormField(
|
||||
hintText: 'Введите название продукта',
|
||||
controller: productNameController,
|
||||
controller: state.productNameController,
|
||||
),
|
||||
SizedBox(height: 24),
|
||||
CustomTextFormField(
|
||||
hintText: 'Порция',
|
||||
fillColor: appTheme.gray50,
|
||||
controller: portionController,
|
||||
controller: state.ingredientController,
|
||||
keyboardType: TextInputType.number,
|
||||
inputFormatters: <TextInputFormatter>[
|
||||
FilteringTextInputFormatter.digitsOnly
|
||||
],
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
Row(children: [
|
||||
Text('гр'),
|
||||
Switch(
|
||||
value: portionAsItems,
|
||||
onChanged: (bool value) {
|
||||
setState(() {
|
||||
portionAsItems = value;
|
||||
});
|
||||
},
|
||||
activeColor: appTheme.blueA400, // Цвет активной части
|
||||
inactiveThumbColor:
|
||||
Colors.grey, // Цвет ползунка, когда выключен
|
||||
inactiveTrackColor: Colors
|
||||
.grey.shade300, // Цвет трека, когда выключен
|
||||
value: state.ingredientAsItems,
|
||||
onChanged: (bool value) => context
|
||||
.read<RecipeCreateCubit>()
|
||||
.switchUnits(value),
|
||||
activeColor: appTheme.blueA400,
|
||||
inactiveThumbColor: Colors.grey,
|
||||
inactiveTrackColor: Colors.grey.shade300,
|
||||
),
|
||||
Text('шт'),
|
||||
]),
|
||||
@@ -190,19 +176,27 @@ class _RecipeCreateScreenState extends State<RecipeCreateScreen> {
|
||||
height: 48,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: FloatingActionButton.extended(
|
||||
highlightElevation: 0,
|
||||
elevation: 0,
|
||||
focusElevation: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
backgroundColor: appTheme.blueA400,
|
||||
onPressed: () {},
|
||||
label: Text(
|
||||
'+',
|
||||
style: theme.textTheme.titleSmall,
|
||||
),
|
||||
),
|
||||
highlightElevation: 0,
|
||||
elevation: 0,
|
||||
focusElevation: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
backgroundColor: appTheme.blueA400,
|
||||
label: Text(
|
||||
'+',
|
||||
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'))),
|
||||
),
|
||||
SizedBox(height: 24),
|
||||
Text('Описание рецепта'),
|
||||
@@ -210,10 +204,11 @@ class _RecipeCreateScreenState extends State<RecipeCreateScreen> {
|
||||
CustomTextFormField(
|
||||
maxLines: 8,
|
||||
minLines: 8,
|
||||
controller: stepDescriptionController,
|
||||
controller: state.stepDescriptionController,
|
||||
),
|
||||
SizedBox(height: 24),
|
||||
for (int i = 0; i < numberOfSteps; i++) _buildStep(i),
|
||||
for (int i = 0; i < state.numberOfSteps; i++)
|
||||
_buildStep(context, i, state),
|
||||
SizedBox(height: 24),
|
||||
Container(
|
||||
height: 48,
|
||||
@@ -226,12 +221,8 @@ class _RecipeCreateScreenState extends State<RecipeCreateScreen> {
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
backgroundColor: appTheme.blueA400,
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
stepImages.add(null);
|
||||
numberOfSteps++;
|
||||
});
|
||||
},
|
||||
onPressed: () =>
|
||||
context.read<RecipeCreateCubit>().addStep(),
|
||||
label: Text(
|
||||
'+',
|
||||
style: theme.textTheme.titleSmall,
|
||||
@@ -250,14 +241,8 @@ class _RecipeCreateScreenState extends State<RecipeCreateScreen> {
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
backgroundColor: Colors.grey,
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
if (numberOfSteps > 1) {
|
||||
numberOfSteps--;
|
||||
stepImages.removeLast();
|
||||
}
|
||||
});
|
||||
},
|
||||
onPressed: () =>
|
||||
context.read<RecipeCreateCubit>().removeStep(),
|
||||
label: Text(
|
||||
'-',
|
||||
style: theme.textTheme.titleSmall,
|
||||
@@ -270,7 +255,7 @@ class _RecipeCreateScreenState extends State<RecipeCreateScreen> {
|
||||
CustomTextFormField(
|
||||
hintText: 'Введите описание шага',
|
||||
fillColor: appTheme.gray50,
|
||||
controller: youtubeLinkController,
|
||||
controller: state.youtubeLinkController,
|
||||
),
|
||||
SizedBox(height: 24),
|
||||
Container(
|
||||
@@ -300,25 +285,25 @@ class _RecipeCreateScreenState extends State<RecipeCreateScreen> {
|
||||
);
|
||||
}
|
||||
|
||||
_buildStep(int stepNumber) {
|
||||
_buildStep(
|
||||
BuildContext context, int stepNumber, RecipeCreateStateLoaded state) {
|
||||
return Column(
|
||||
children: [
|
||||
Row(children: [
|
||||
Text('Шаг ${stepNumber + 1}'),
|
||||
Spacer(),
|
||||
Text('Всего шагов: $numberOfSteps')
|
||||
Text('Всего шагов: ${state.numberOfSteps}')
|
||||
]),
|
||||
SizedBox(height: 8),
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
final pickedFile =
|
||||
await _picker.pickImage(source: ImageSource.gallery);
|
||||
setState(() {
|
||||
stepImages[stepNumber] =
|
||||
pickedFile; // Сохраняем изображение для текущего шага
|
||||
});
|
||||
await state.picker.pickImage(source: ImageSource.gallery);
|
||||
context
|
||||
.read<RecipeCreateCubit>()
|
||||
.uploadStepImage(pickedFile, stepNumber);
|
||||
},
|
||||
child: stepImages[stepNumber] == null
|
||||
child: state.stepImages[stepNumber] == null
|
||||
? Container(
|
||||
height: 128,
|
||||
decoration: AppDecoration.fillGray.copyWith(
|
||||
@@ -341,7 +326,7 @@ class _RecipeCreateScreenState extends State<RecipeCreateScreen> {
|
||||
],
|
||||
),
|
||||
)
|
||||
: Image.file(File(stepImages[stepNumber]!.path),
|
||||
: Image.file(File(state.stepImages[stepNumber]!.path),
|
||||
height: 150, fit: BoxFit.cover)),
|
||||
SizedBox(height: 16),
|
||||
CustomTextFormField(
|
||||
@@ -349,28 +334,96 @@ class _RecipeCreateScreenState extends State<RecipeCreateScreen> {
|
||||
maxLines: 8,
|
||||
minLines: 8,
|
||||
fillColor: appTheme.gray50,
|
||||
controller: state.stepControllers[stepNumber],
|
||||
),
|
||||
SizedBox(height: 24),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
addImage(BuildContext context, bool isLoading) {
|
||||
if (!isLoading) {
|
||||
return () async {
|
||||
final picker = ImagePicker();
|
||||
XFile? image = await picker.pickImage(source: ImageSource.gallery);
|
||||
if (image != null) {
|
||||
context.read<BlogPostCreateBloc>().add(UploadImages(image));
|
||||
_buildIngredient(Ingredient ingredient) {
|
||||
return Container(
|
||||
margin: EdgeInsets.symmetric(horizontal: 10.h),
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 8.h,
|
||||
vertical: 6.v,
|
||||
),
|
||||
decoration: AppDecoration.fillGray.copyWith(
|
||||
borderRadius: BorderRadiusStyle.roundedBorder5,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: 7.h,
|
||||
top: 5.v,
|
||||
),
|
||||
child: Text(
|
||||
ingredient.product_name.length > 8
|
||||
? ingredient.product_name.substring(0, 8)
|
||||
: ingredient.product_name,
|
||||
style: CustomTextStyles.titleMedium16,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: 20.h,
|
||||
top: 3.v,
|
||||
bottom: 3.v,
|
||||
),
|
||||
child: Text(
|
||||
ingredient.portion.toString() +
|
||||
' ' +
|
||||
ingredient.unit.toString().tr,
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
GestureDetector(
|
||||
// onTap: removeIngredient(context, ingredient),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: 10),
|
||||
child: Icon(
|
||||
Icons.close,
|
||||
color: appTheme.blueGray300,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
RecipeModel createRecipeFromState(RecipeCreateStateLoaded state) {
|
||||
// Подготовка ингредиентов
|
||||
List<Ingredient> ingredients = state.ingredients;
|
||||
|
||||
// Подготовка шагов (например, можно создать шаги из stepControllers)
|
||||
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));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String? _validateTitle(value) {
|
||||
if (value!.isEmpty) {
|
||||
return 'Пожалуйста, введите заголовок';
|
||||
// Подготовка изображения
|
||||
image.Image pic = image.Image(path: state.recipeImage?.path ?? '');
|
||||
|
||||
// Создание экземпляра RecipeModel
|
||||
return RecipeModel(
|
||||
id: null,
|
||||
ingredients: ingredients,
|
||||
steps: steps,
|
||||
state: 'draft',
|
||||
description: state.titleController.text,
|
||||
type: state.types.first.value,
|
||||
image: pic,
|
||||
video_url: state.youtubeLinkController.text.isNotEmpty
|
||||
? state.youtubeLinkController.text
|
||||
: null,
|
||||
cooking_time:
|
||||
state.cookingTimes.isNotEmpty ? state.cookingTimes.first.value : null,
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
14
lib/features/recipes/reporitories/recipe_repository.dart
Normal file
14
lib/features/recipes/reporitories/recipe_repository.dart
Normal file
@@ -0,0 +1,14 @@
|
||||
import 'package:eatvio_app/features/recipes/services/recipe_service.dart';
|
||||
|
||||
class RecipeRepository {
|
||||
final RecipeService recipeService;
|
||||
|
||||
RecipeRepository({required this.recipeService});
|
||||
/*Future<RecipeModel> getRecipe(int recipeID) async {
|
||||
try {
|
||||
return (await recipeService.getRecipe(recipeID));
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
13
lib/features/recipes/services/recipe_service.dart
Normal file
13
lib/features/recipes/services/recipe_service.dart
Normal file
@@ -0,0 +1,13 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:eatvio_app/features/recipes/models/recipe_model.dart';
|
||||
import 'package:retrofit/retrofit.dart';
|
||||
|
||||
part 'recipe_service.g.dart';
|
||||
|
||||
@RestApi()
|
||||
abstract class RecipeService {
|
||||
factory RecipeService(Dio dio, {String baseUrl}) = _RecipeService;
|
||||
|
||||
@GET('/api/recipe/{id}/show/')
|
||||
Future<Map<String, RecipeModel>> getRecipe(@Path() int id);
|
||||
}
|
||||
78
lib/features/recipes/services/recipe_service.g.dart
Normal file
78
lib/features/recipes/services/recipe_service.g.dart
Normal file
@@ -0,0 +1,78 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'recipe_service.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RetrofitGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element
|
||||
|
||||
class _RecipeService implements RecipeService {
|
||||
_RecipeService(
|
||||
this._dio, {
|
||||
this.baseUrl,
|
||||
});
|
||||
|
||||
final Dio _dio;
|
||||
|
||||
String? baseUrl;
|
||||
|
||||
@override
|
||||
Future<Map<String, RecipeModel>> getRecipe(int id) 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<Map<String, RecipeModel>>(Options(
|
||||
method: 'GET',
|
||||
headers: _headers,
|
||||
extra: _extra,
|
||||
)
|
||||
.compose(
|
||||
_dio.options,
|
||||
'/api/recipe/${id}/show/',
|
||||
queryParameters: queryParameters,
|
||||
data: _data,
|
||||
)
|
||||
.copyWith(
|
||||
baseUrl: _combineBaseUrls(
|
||||
_dio.options.baseUrl,
|
||||
baseUrl,
|
||||
))));
|
||||
var _value = _result.data!.map((k, dynamic v) =>
|
||||
MapEntry(k, RecipeModel.fromJson(v as Map<String, dynamic>)));
|
||||
return _value;
|
||||
}
|
||||
|
||||
RequestOptions _setStreamType<T>(RequestOptions requestOptions) {
|
||||
if (T != dynamic &&
|
||||
!(requestOptions.responseType == ResponseType.bytes ||
|
||||
requestOptions.responseType == ResponseType.stream)) {
|
||||
if (T == String) {
|
||||
requestOptions.responseType = ResponseType.plain;
|
||||
} else {
|
||||
requestOptions.responseType = ResponseType.json;
|
||||
}
|
||||
}
|
||||
return requestOptions;
|
||||
}
|
||||
|
||||
String _combineBaseUrls(
|
||||
String dioBaseUrl,
|
||||
String? baseUrl,
|
||||
) {
|
||||
if (baseUrl == null || baseUrl.trim().isEmpty) {
|
||||
return dioBaseUrl;
|
||||
}
|
||||
|
||||
final url = Uri.parse(baseUrl);
|
||||
|
||||
if (url.isAbsolute) {
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
return Uri.parse(dioBaseUrl).resolveUri(url).toString();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user