feat(diary): diet

This commit is contained in:
Alex
2024-12-24 16:52:06 +03:00
parent c6a60eccd9
commit 67d8bb58ee
13 changed files with 451 additions and 86 deletions

View File

@@ -4,6 +4,17 @@ part 'diary_day_model.freezed.dart';
part 'diary_day_model.g.dart';
enum PortionState {
active,
filled_diet,
eaten_from_diet,
eaten,
eaten_deleted,
eaten_edited,
commented,
reviewed_by_user,
}
@freezed
class DiaryDayWrapperModel with _$DiaryDayWrapperModel {
const factory DiaryDayWrapperModel({
@@ -37,7 +48,7 @@ class MealModel with _$MealModel {
@JsonKey(name: "type_no") required int typeNumber,
@JsonKey(name: "satiety") required int satiety,
@JsonKey(name: "mood") required int mood,
@JsonKey(name: "portions") required List<Portion> portions,
@JsonKey(name: "portions") required List<PortionModel> portions,
@JsonKey(name: "photos") required List<DiaryPhotoModel> photos,
}) = _MealModel;
@@ -57,16 +68,18 @@ class DiaryPhotoModel with _$DiaryPhotoModel {
}
@freezed
class Portion with _$Portion {
const factory Portion({
class PortionModel with _$PortionModel {
const factory PortionModel({
@JsonKey(name: "id") required int id,
@JsonKey(name: "product_nutritional_value_id") int? productNutritionalValueId,
@JsonKey(name: "product_name") required String productName,
@JsonKey(name: "quantity") required int quantity,
@JsonKey(name: "portion") required String portion,
@JsonKey(name: "from_diet") required bool fromDiet,
}) = _Portion;
@JsonKey(name: "state") required PortionState portionState,
}) = _PortionModel;
factory Portion.fromJson(Map<String, dynamic> json) => _$PortionFromJson(json);
factory PortionModel.fromJson(Map<String, dynamic> json) => _$PortionModelFromJson(json);
}
@freezed

View File

@@ -545,7 +545,7 @@ mixin _$MealModel {
@JsonKey(name: "mood")
int get mood => throw _privateConstructorUsedError;
@JsonKey(name: "portions")
List<Portion> get portions => throw _privateConstructorUsedError;
List<PortionModel> get portions => throw _privateConstructorUsedError;
@JsonKey(name: "photos")
List<DiaryPhotoModel> get photos => throw _privateConstructorUsedError;
@@ -570,7 +570,7 @@ abstract class $MealModelCopyWith<$Res> {
@JsonKey(name: "type_no") int typeNumber,
@JsonKey(name: "satiety") int satiety,
@JsonKey(name: "mood") int mood,
@JsonKey(name: "portions") List<Portion> portions,
@JsonKey(name: "portions") List<PortionModel> portions,
@JsonKey(name: "photos") List<DiaryPhotoModel> photos});
}
@@ -621,7 +621,7 @@ class _$MealModelCopyWithImpl<$Res, $Val extends MealModel>
portions: null == portions
? _value.portions
: portions // ignore: cast_nullable_to_non_nullable
as List<Portion>,
as List<PortionModel>,
photos: null == photos
? _value.photos
: photos // ignore: cast_nullable_to_non_nullable
@@ -644,7 +644,7 @@ abstract class _$$MealModelImplCopyWith<$Res>
@JsonKey(name: "type_no") int typeNumber,
@JsonKey(name: "satiety") int satiety,
@JsonKey(name: "mood") int mood,
@JsonKey(name: "portions") List<Portion> portions,
@JsonKey(name: "portions") List<PortionModel> portions,
@JsonKey(name: "photos") List<DiaryPhotoModel> photos});
}
@@ -693,7 +693,7 @@ class __$$MealModelImplCopyWithImpl<$Res>
portions: null == portions
? _value._portions
: portions // ignore: cast_nullable_to_non_nullable
as List<Portion>,
as List<PortionModel>,
photos: null == photos
? _value._photos
: photos // ignore: cast_nullable_to_non_nullable
@@ -711,7 +711,7 @@ class _$MealModelImpl implements _MealModel {
@JsonKey(name: "type_no") required this.typeNumber,
@JsonKey(name: "satiety") required this.satiety,
@JsonKey(name: "mood") required this.mood,
@JsonKey(name: "portions") required final List<Portion> portions,
@JsonKey(name: "portions") required final List<PortionModel> portions,
@JsonKey(name: "photos") required final List<DiaryPhotoModel> photos})
: _portions = portions,
_photos = photos;
@@ -734,10 +734,10 @@ class _$MealModelImpl implements _MealModel {
@override
@JsonKey(name: "mood")
final int mood;
final List<Portion> _portions;
final List<PortionModel> _portions;
@override
@JsonKey(name: "portions")
List<Portion> get portions {
List<PortionModel> get portions {
if (_portions is EqualUnmodifiableListView) return _portions;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_portions);
@@ -807,7 +807,7 @@ abstract class _MealModel implements MealModel {
@JsonKey(name: "type_no") required final int typeNumber,
@JsonKey(name: "satiety") required final int satiety,
@JsonKey(name: "mood") required final int mood,
@JsonKey(name: "portions") required final List<Portion> portions,
@JsonKey(name: "portions") required final List<PortionModel> portions,
@JsonKey(name: "photos")
required final List<DiaryPhotoModel> photos}) = _$MealModelImpl;
@@ -831,7 +831,7 @@ abstract class _MealModel implements MealModel {
int get mood;
@override
@JsonKey(name: "portions")
List<Portion> get portions;
List<PortionModel> get portions;
@override
@JsonKey(name: "photos")
List<DiaryPhotoModel> get photos;
@@ -1071,14 +1071,16 @@ abstract class _DiaryPhotoModel implements DiaryPhotoModel {
throw _privateConstructorUsedError;
}
Portion _$PortionFromJson(Map<String, dynamic> json) {
return _Portion.fromJson(json);
PortionModel _$PortionModelFromJson(Map<String, dynamic> json) {
return _PortionModel.fromJson(json);
}
/// @nodoc
mixin _$Portion {
mixin _$PortionModel {
@JsonKey(name: "id")
int get id => throw _privateConstructorUsedError;
@JsonKey(name: "product_nutritional_value_id")
int? get productNutritionalValueId => throw _privateConstructorUsedError;
@JsonKey(name: "product_name")
String get productName => throw _privateConstructorUsedError;
@JsonKey(name: "quantity")
@@ -1087,55 +1089,68 @@ mixin _$Portion {
String get portion => throw _privateConstructorUsedError;
@JsonKey(name: "from_diet")
bool get fromDiet => throw _privateConstructorUsedError;
@JsonKey(name: "state")
PortionState get portionState => throw _privateConstructorUsedError;
/// Serializes this Portion to a JSON map.
/// Serializes this PortionModel to a JSON map.
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
/// Create a copy of Portion
/// Create a copy of PortionModel
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$PortionCopyWith<Portion> get copyWith => throw _privateConstructorUsedError;
$PortionModelCopyWith<PortionModel> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $PortionCopyWith<$Res> {
factory $PortionCopyWith(Portion value, $Res Function(Portion) then) =
_$PortionCopyWithImpl<$Res, Portion>;
abstract class $PortionModelCopyWith<$Res> {
factory $PortionModelCopyWith(
PortionModel value, $Res Function(PortionModel) then) =
_$PortionModelCopyWithImpl<$Res, PortionModel>;
@useResult
$Res call(
{@JsonKey(name: "id") int id,
@JsonKey(name: "product_nutritional_value_id")
int? productNutritionalValueId,
@JsonKey(name: "product_name") String productName,
@JsonKey(name: "quantity") int quantity,
@JsonKey(name: "portion") String portion,
@JsonKey(name: "from_diet") bool fromDiet});
@JsonKey(name: "from_diet") bool fromDiet,
@JsonKey(name: "state") PortionState portionState});
}
/// @nodoc
class _$PortionCopyWithImpl<$Res, $Val extends Portion>
implements $PortionCopyWith<$Res> {
_$PortionCopyWithImpl(this._value, this._then);
class _$PortionModelCopyWithImpl<$Res, $Val extends PortionModel>
implements $PortionModelCopyWith<$Res> {
_$PortionModelCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of Portion
/// Create a copy of PortionModel
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? id = null,
Object? productNutritionalValueId = freezed,
Object? productName = null,
Object? quantity = null,
Object? portion = null,
Object? fromDiet = null,
Object? portionState = null,
}) {
return _then(_value.copyWith(
id: null == id
? _value.id
: id // ignore: cast_nullable_to_non_nullable
as int,
productNutritionalValueId: freezed == productNutritionalValueId
? _value.productNutritionalValueId
: productNutritionalValueId // ignore: cast_nullable_to_non_nullable
as int?,
productName: null == productName
? _value.productName
: productName // ignore: cast_nullable_to_non_nullable
@@ -1152,49 +1167,63 @@ class _$PortionCopyWithImpl<$Res, $Val extends Portion>
? _value.fromDiet
: fromDiet // ignore: cast_nullable_to_non_nullable
as bool,
portionState: null == portionState
? _value.portionState
: portionState // ignore: cast_nullable_to_non_nullable
as PortionState,
) as $Val);
}
}
/// @nodoc
abstract class _$$PortionImplCopyWith<$Res> implements $PortionCopyWith<$Res> {
factory _$$PortionImplCopyWith(
_$PortionImpl value, $Res Function(_$PortionImpl) then) =
__$$PortionImplCopyWithImpl<$Res>;
abstract class _$$PortionModelImplCopyWith<$Res>
implements $PortionModelCopyWith<$Res> {
factory _$$PortionModelImplCopyWith(
_$PortionModelImpl value, $Res Function(_$PortionModelImpl) then) =
__$$PortionModelImplCopyWithImpl<$Res>;
@override
@useResult
$Res call(
{@JsonKey(name: "id") int id,
@JsonKey(name: "product_nutritional_value_id")
int? productNutritionalValueId,
@JsonKey(name: "product_name") String productName,
@JsonKey(name: "quantity") int quantity,
@JsonKey(name: "portion") String portion,
@JsonKey(name: "from_diet") bool fromDiet});
@JsonKey(name: "from_diet") bool fromDiet,
@JsonKey(name: "state") PortionState portionState});
}
/// @nodoc
class __$$PortionImplCopyWithImpl<$Res>
extends _$PortionCopyWithImpl<$Res, _$PortionImpl>
implements _$$PortionImplCopyWith<$Res> {
__$$PortionImplCopyWithImpl(
_$PortionImpl _value, $Res Function(_$PortionImpl) _then)
class __$$PortionModelImplCopyWithImpl<$Res>
extends _$PortionModelCopyWithImpl<$Res, _$PortionModelImpl>
implements _$$PortionModelImplCopyWith<$Res> {
__$$PortionModelImplCopyWithImpl(
_$PortionModelImpl _value, $Res Function(_$PortionModelImpl) _then)
: super(_value, _then);
/// Create a copy of Portion
/// Create a copy of PortionModel
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? id = null,
Object? productNutritionalValueId = freezed,
Object? productName = null,
Object? quantity = null,
Object? portion = null,
Object? fromDiet = null,
Object? portionState = null,
}) {
return _then(_$PortionImpl(
return _then(_$PortionModelImpl(
id: null == id
? _value.id
: id // ignore: cast_nullable_to_non_nullable
as int,
productNutritionalValueId: freezed == productNutritionalValueId
? _value.productNutritionalValueId
: productNutritionalValueId // ignore: cast_nullable_to_non_nullable
as int?,
productName: null == productName
? _value.productName
: productName // ignore: cast_nullable_to_non_nullable
@@ -1211,27 +1240,37 @@ class __$$PortionImplCopyWithImpl<$Res>
? _value.fromDiet
: fromDiet // ignore: cast_nullable_to_non_nullable
as bool,
portionState: null == portionState
? _value.portionState
: portionState // ignore: cast_nullable_to_non_nullable
as PortionState,
));
}
}
/// @nodoc
@JsonSerializable()
class _$PortionImpl implements _Portion {
const _$PortionImpl(
class _$PortionModelImpl implements _PortionModel {
const _$PortionModelImpl(
{@JsonKey(name: "id") required this.id,
@JsonKey(name: "product_nutritional_value_id")
this.productNutritionalValueId,
@JsonKey(name: "product_name") required this.productName,
@JsonKey(name: "quantity") required this.quantity,
@JsonKey(name: "portion") required this.portion,
@JsonKey(name: "from_diet") required this.fromDiet});
@JsonKey(name: "from_diet") required this.fromDiet,
@JsonKey(name: "state") required this.portionState});
factory _$PortionImpl.fromJson(Map<String, dynamic> json) =>
_$$PortionImplFromJson(json);
factory _$PortionModelImpl.fromJson(Map<String, dynamic> json) =>
_$$PortionModelImplFromJson(json);
@override
@JsonKey(name: "id")
final int id;
@override
@JsonKey(name: "product_nutritional_value_id")
final int? productNutritionalValueId;
@override
@JsonKey(name: "product_name")
final String productName;
@override
@@ -1243,63 +1282,78 @@ class _$PortionImpl implements _Portion {
@override
@JsonKey(name: "from_diet")
final bool fromDiet;
@override
@JsonKey(name: "state")
final PortionState portionState;
@override
String toString() {
return 'Portion(id: $id, productName: $productName, quantity: $quantity, portion: $portion, fromDiet: $fromDiet)';
return 'PortionModel(id: $id, productNutritionalValueId: $productNutritionalValueId, productName: $productName, quantity: $quantity, portion: $portion, fromDiet: $fromDiet, portionState: $portionState)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$PortionImpl &&
other is _$PortionModelImpl &&
(identical(other.id, id) || other.id == id) &&
(identical(other.productNutritionalValueId,
productNutritionalValueId) ||
other.productNutritionalValueId == productNutritionalValueId) &&
(identical(other.productName, productName) ||
other.productName == productName) &&
(identical(other.quantity, quantity) ||
other.quantity == quantity) &&
(identical(other.portion, portion) || other.portion == portion) &&
(identical(other.fromDiet, fromDiet) ||
other.fromDiet == fromDiet));
other.fromDiet == fromDiet) &&
(identical(other.portionState, portionState) ||
other.portionState == portionState));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode =>
Object.hash(runtimeType, id, productName, quantity, portion, fromDiet);
int get hashCode => Object.hash(runtimeType, id, productNutritionalValueId,
productName, quantity, portion, fromDiet, portionState);
/// Create a copy of Portion
/// Create a copy of PortionModel
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$PortionImplCopyWith<_$PortionImpl> get copyWith =>
__$$PortionImplCopyWithImpl<_$PortionImpl>(this, _$identity);
_$$PortionModelImplCopyWith<_$PortionModelImpl> get copyWith =>
__$$PortionModelImplCopyWithImpl<_$PortionModelImpl>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$$PortionImplToJson(
return _$$PortionModelImplToJson(
this,
);
}
}
abstract class _Portion implements Portion {
const factory _Portion(
abstract class _PortionModel implements PortionModel {
const factory _PortionModel(
{@JsonKey(name: "id") required final int id,
@JsonKey(name: "product_nutritional_value_id")
final int? productNutritionalValueId,
@JsonKey(name: "product_name") required final String productName,
@JsonKey(name: "quantity") required final int quantity,
@JsonKey(name: "portion") required final String portion,
@JsonKey(name: "from_diet") required final bool fromDiet}) =
_$PortionImpl;
@JsonKey(name: "from_diet") required final bool fromDiet,
@JsonKey(name: "state") required final PortionState portionState}) =
_$PortionModelImpl;
factory _Portion.fromJson(Map<String, dynamic> json) = _$PortionImpl.fromJson;
factory _PortionModel.fromJson(Map<String, dynamic> json) =
_$PortionModelImpl.fromJson;
@override
@JsonKey(name: "id")
int get id;
@override
@JsonKey(name: "product_nutritional_value_id")
int? get productNutritionalValueId;
@override
@JsonKey(name: "product_name")
String get productName;
@override
@@ -1311,12 +1365,15 @@ abstract class _Portion implements Portion {
@override
@JsonKey(name: "from_diet")
bool get fromDiet;
@override
@JsonKey(name: "state")
PortionState get portionState;
/// Create a copy of Portion
/// Create a copy of PortionModel
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$PortionImplCopyWith<_$PortionImpl> get copyWith =>
_$$PortionModelImplCopyWith<_$PortionModelImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@@ -53,7 +53,7 @@ _$MealModelImpl _$$MealModelImplFromJson(Map<String, dynamic> json) =>
satiety: (json['satiety'] as num).toInt(),
mood: (json['mood'] as num).toInt(),
portions: (json['portions'] as List<dynamic>)
.map((e) => Portion.fromJson(e as Map<String, dynamic>))
.map((e) => PortionModel.fromJson(e as Map<String, dynamic>))
.toList(),
photos: (json['photos'] as List<dynamic>)
.map((e) => DiaryPhotoModel.fromJson(e as Map<String, dynamic>))
@@ -89,24 +89,40 @@ Map<String, dynamic> _$$DiaryPhotoModelImplToJson(
'size': instance.size,
};
_$PortionImpl _$$PortionImplFromJson(Map<String, dynamic> json) =>
_$PortionImpl(
_$PortionModelImpl _$$PortionModelImplFromJson(Map<String, dynamic> json) =>
_$PortionModelImpl(
id: (json['id'] as num).toInt(),
productNutritionalValueId:
(json['product_nutritional_value_id'] as num?)?.toInt(),
productName: json['product_name'] as String,
quantity: (json['quantity'] as num).toInt(),
portion: json['portion'] as String,
fromDiet: json['from_diet'] as bool,
portionState: $enumDecode(_$PortionStateEnumMap, json['state']),
);
Map<String, dynamic> _$$PortionImplToJson(_$PortionImpl instance) =>
Map<String, dynamic> _$$PortionModelImplToJson(_$PortionModelImpl instance) =>
<String, dynamic>{
'id': instance.id,
'product_nutritional_value_id': instance.productNutritionalValueId,
'product_name': instance.productName,
'quantity': instance.quantity,
'portion': instance.portion,
'from_diet': instance.fromDiet,
'state': _$PortionStateEnumMap[instance.portionState]!,
};
const _$PortionStateEnumMap = {
PortionState.active: 'active',
PortionState.filled_diet: 'filled_diet',
PortionState.eaten_from_diet: 'eaten_from_diet',
PortionState.eaten: 'eaten',
PortionState.eaten_deleted: 'eaten_deleted',
PortionState.eaten_edited: 'eaten_edited',
PortionState.commented: 'commented',
PortionState.reviewed_by_user: 'reviewed_by_user',
};
_$TypeOfDiaryModelImpl _$$TypeOfDiaryModelImplFromJson(
Map<String, dynamic> json) =>
_$TypeOfDiaryModelImpl(

View File

@@ -102,15 +102,73 @@ class DiaryCubit extends Cubit<DiaryState> {
required String portion,
required int quantity,
int? productNutritionalValueId,
required PortionState portionState,
}) async {
await diaryRepository.updateProductInMeal(
if (portionState == PortionState.filled_diet || portionState == PortionState.eaten_from_diet) {
// await diaryRepository.deleteProductFromMeal(
// diaryId: diaryId,
// mealId: mealId,
// portionId: portionId,
// );
// todo delete product from diet
await diaryRepository.addPortionToMeal(
diaryId: diaryId,
mealId: mealId,
productName: productName,
portion: portion,
quantity: quantity,
productNutritionalValueId: productNutritionalValueId,
);
} else {
await diaryRepository.updateProductInMeal(
diaryId: diaryId,
mealId: mealId,
portionId: portionId,
productName: productName,
portion: portion,
quantity: quantity,
productNutritionalValueId: productNutritionalValueId,
portionState: portionState,
);
}
await fetchDiary();
}
markEaten({
required int diaryId,
required int mealId,
required int portionId,
}) async {
await diaryRepository.markEaten(
diaryId: diaryId,
mealId: mealId,
portionId: portionId,
);
await fetchDiary();
}
unmarkEaten({
required int diaryId,
required int mealId,
required int portionId,
}) async {
await diaryRepository.unmarkEaten(
diaryId: diaryId,
mealId: mealId,
portionId: portionId,
);
await fetchDiary();
}
restore({
required int diaryId,
required int mealId,
required int portionId,
}) async {
await diaryRepository.restore(
diaryId: diaryId,
mealId: mealId,
portionId: portionId,
productName: productName,
portion: portion,
quantity: quantity,
productNutritionalValueId: productNutritionalValueId,
);
await fetchDiary();
}

View File

@@ -35,7 +35,6 @@ class _DiaryScreenState extends State<DiaryScreen> {
CalendarWidget(),
if (state is DiaryStateLoading) const Loader(),
if (state is DiaryStateLoaded) MealWidget(),
const SizedBox(height: 12),
CaloriesChartWidget(),
],
),

View File

@@ -10,7 +10,7 @@ import 'package:eatvio_app/features/glossary/models/glossary_model.dart';
import 'package:flutter/material.dart';
class AddProductModal extends StatefulWidget {
final Portion? portion;
final PortionModel? portion;
final DiaryStateLoaded state;
final DiaryCubit diaryCubit;
@@ -221,6 +221,7 @@ class _AddProductModalState extends State<AddProductModal> {
: 'pcs',
quantity: int.parse(quantityController.text),
productNutritionalValueId: selectedGlossary?.id,
portionState: widget.portion!.portionState,
);
}
Navigator.of(context).pop();

View File

@@ -1,12 +1,15 @@
import 'package:dotted_border/dotted_border.dart';
import 'package:eatvio_app/core/theme/theme_helper.dart';
import 'package:eatvio_app/features/diary/models/diary_day_model.dart';
import 'package:eatvio_app/features/diary/presentation/bloc/diary_cubit.dart';
import 'package:eatvio_app/features/diary/presentation/bloc/diary_state.dart';
import 'package:eatvio_app/features/diary/presentation/widgets/add_product_modal.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart';
class ProductWidget extends StatefulWidget {
final Portion portion;
final PortionModel portion;
const ProductWidget({
super.key,
@@ -20,15 +23,17 @@ class ProductWidget extends StatefulWidget {
class _ProductWidgetState extends State<ProductWidget> {
late final DiaryCubit diaryCubit;
late String portionName;
late bool isEaten;
@override
void initState() {
super.initState();
diaryCubit = context.read<DiaryCubit>();
portionName = widget.portion == 'gr' ? 'гр' : 'шт';
isEaten = widget.portion.portionState == PortionState.eaten_from_diet ? true : false;
}
updateProductInMeal(DiaryStateLoaded state, Portion portion) {
updateProductInMeal(DiaryStateLoaded state, PortionModel portion) {
return showModalBottomSheet(
useRootNavigator: true,
context: context,
@@ -49,16 +54,80 @@ class _ProductWidgetState extends State<ProductWidget> {
return BlocBuilder<DiaryCubit, DiaryState>(
builder: (context, state) {
if (state is DiaryStateLoaded) {
return ListTile(
onTap: () => updateProductInMeal(state, widget.portion),
trailing: Icon(Icons.more_vert_rounded),
title: Text(widget.portion.productName),
subtitle: Text('${widget.portion.quantity} ${widget.portion.portion == 'gr' ? 'гр' : 'шт'}'),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
tileColor: Color(0xFFF6FAFF),
);
if (widget.portion.portionState == PortionState.eaten_deleted) {
return DottedBorder(
dashPattern: [6, 6],
padding: EdgeInsets.zero,
borderPadding: EdgeInsets.zero,
borderType: BorderType.RRect,
radius: Radius.circular(20),
color: Color(0xFF6D6F71),
child: ListTile(
onTap: () => diaryCubit.restore(
diaryId: state.diary.id,
mealId: state.selectedMeal,
portionId: widget.portion.id,
),
trailing: SvgPicture.asset(
'assets/icons/revert_product.svg',
),
horizontalTitleGap: 0,
contentPadding: widget.portion.fromDiet ? EdgeInsets.only(right: 24, left: 4) : null,
title: Text(widget.portion.productName),
subtitle: Text('${widget.portion.quantity} ${widget.portion.portion == 'gr' ? 'гр' : 'шт'}'),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
tileColor: Color(0xFFF6FAFF03).withValues(alpha: 0.01),
),
);
} else {
return ListTile(
onTap: () => updateProductInMeal(state, widget.portion),
trailing: Icon(Icons.more_vert_rounded),
leading: widget.portion.fromDiet
? Transform.scale(
scale: 1.2,
child: Checkbox(
value: isEaten,
onChanged: (value) {
setState(() {
isEaten = value!;
});
if (isEaten) {
diaryCubit.markEaten(
diaryId: state.diary.id,
mealId: state.selectedMeal,
portionId: widget.portion.id,
);
} else {
diaryCubit.unmarkEaten(
diaryId: state.diary.id,
mealId: state.selectedMeal,
portionId: widget.portion.id,
);
}
},
activeColor: appTheme.blueA400,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(4),
),
side: BorderSide(
color: Color(0xFF809CB9),
),
),
)
: null,
horizontalTitleGap: 0,
contentPadding: widget.portion.fromDiet ? EdgeInsets.only(right: 24, left: 4) : null,
title: Text(widget.portion.productName),
subtitle: Text('${widget.portion.quantity} ${widget.portion.portion == 'gr' ? 'гр' : 'шт'}'),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
tileColor: Color(0xFFF6FAFF),
);
}
}
return const SizedBox.shrink();
},

View File

@@ -51,6 +51,7 @@ class DiaryRepository {
required String portion,
required int quantity,
int? productNutritionalValueId,
required PortionState portionState,
}) async {
Map<String, Object?> data = ProductInMeal(
productName: productName,
@@ -58,6 +59,7 @@ class DiaryRepository {
quantity: quantity,
).toJson();
data['product_nutritional_value_id'] = productNutritionalValueId;
data['state'] = portionState.name;
return await diaryService.updateProductInMeal(
diary: diaryId,
typeNo: mealId,
@@ -66,6 +68,42 @@ class DiaryRepository {
);
}
Future<void> markEaten({
required int diaryId,
required int mealId,
required int portionId,
}) async {
return await diaryService.markEaten(
diary: diaryId,
typeNo: mealId,
portionModel: portionId,
);
}
Future<void> unmarkEaten({
required int diaryId,
required int mealId,
required int portionId,
}) async {
return await diaryService.unmarkEaten(
diary: diaryId,
typeNo: mealId,
portionModel: portionId,
);
}
Future<void> restore({
required int diaryId,
required int mealId,
required int portionId,
}) async {
return await diaryService.restore(
diary: diaryId,
typeNo: mealId,
portionModel: portionId,
);
}
Future<void> deleteProductFromMeal({
required int diaryId,
required int mealId,

View File

@@ -60,6 +60,27 @@ abstract class DiaryService {
@Body() required Map<String, dynamic> productInMeal,
});
@POST('/api/diary/{diary}/meals/{type_no}/{portionModel}/mark_eaten')
Future<void> markEaten({
@Path('diary') required int diary,
@Path('type_no') required int typeNo,
@Path('portionModel') required int portionModel,
});
@POST('/api/diary/{diary}/meals/{type_no}/{portionModel}/unmark_eaten')
Future<void> unmarkEaten({
@Path('diary') required int diary,
@Path('type_no') required int typeNo,
@Path('portionModel') required int portionModel,
});
@POST('/api/diary/{diary}/meals/{type_no}/portions/{portionModel}/restore')
Future<void> restore({
@Path('diary') required int diary,
@Path('type_no') required int typeNo,
@Path('portionModel') required int portionModel,
});
@DELETE('/api/diary/{diary}/meals/{type_no}/portions/{portionModel}/delete')
Future<void> deleteProductFromMeal({
@Path('diary') required int diary,

View File

@@ -271,6 +271,93 @@ class _DiaryService implements DiaryService {
await _dio.fetch<void>(_options);
}
@override
Future<void> markEaten({
required int diary,
required int typeNo,
required int portionModel,
}) async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<void>(Options(
method: 'POST',
headers: _headers,
extra: _extra,
)
.compose(
_dio.options,
'/api/diary/${diary}/meals/${typeNo}/${portionModel}/mark_eaten',
queryParameters: queryParameters,
data: _data,
)
.copyWith(
baseUrl: _combineBaseUrls(
_dio.options.baseUrl,
baseUrl,
)));
await _dio.fetch<void>(_options);
}
@override
Future<void> unmarkEaten({
required int diary,
required int typeNo,
required int portionModel,
}) async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<void>(Options(
method: 'POST',
headers: _headers,
extra: _extra,
)
.compose(
_dio.options,
'/api/diary/${diary}/meals/${typeNo}/${portionModel}/unmark_eaten',
queryParameters: queryParameters,
data: _data,
)
.copyWith(
baseUrl: _combineBaseUrls(
_dio.options.baseUrl,
baseUrl,
)));
await _dio.fetch<void>(_options);
}
@override
Future<void> restore({
required int diary,
required int typeNo,
required int portionModel,
}) async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<void>(Options(
method: 'POST',
headers: _headers,
extra: _extra,
)
.compose(
_dio.options,
'/api/diary/${diary}/meals/${typeNo}/portions/${portionModel}/restore',
queryParameters: queryParameters,
data: _data,
)
.copyWith(
baseUrl: _combineBaseUrls(
_dio.options.baseUrl,
baseUrl,
)));
await _dio.fetch<void>(_options);
}
@override
Future<void> deleteProductFromMeal({
required int diary,

View File

@@ -907,10 +907,12 @@ class _ProfileScreenState extends State<ProfileScreen> {
value: 'view',
child: Text('Посмотреть'),
),
if (widget.author == null)
PopupMenuItem(
value: 'replace',
child: Text('Заменить'),
),
if (widget.author == null)
PopupMenuItem(
value: 'delete',
child: Text('Удалить'),