From bc8cff2a55429e12429d6285e307ad36af938c75 Mon Sep 17 00:00:00 2001 From: mso7nueh Date: Mon, 11 Nov 2024 13:29:05 +0300 Subject: [PATCH] feat(diary): chart update --- .../diary/models/nutrition_model.dart | 27 ++ .../diary/models/nutrition_model.freezed.dart | 437 ++++++++++++++++++ .../diary/models/nutrition_model.g.dart | 40 ++ .../diary/presentation/bloc/diary_cubit.dart | 6 + .../diary/presentation/bloc/diary_state.dart | 2 + .../bloc/diary_state.freezed.dart | 91 ++-- .../presentation/pages/diary_screen.dart | 178 +++++-- .../widgets/satiety_rating_widget.dart | 12 +- .../diary/repositories/diary_repository.dart | 9 +- .../diary/services/diary_service.dart | 6 + .../diary/services/diary_service.g.dart | 33 ++ pubspec.yaml | 1 + 12 files changed, 760 insertions(+), 82 deletions(-) create mode 100644 lib/features/diary/models/nutrition_model.dart create mode 100644 lib/features/diary/models/nutrition_model.freezed.dart create mode 100644 lib/features/diary/models/nutrition_model.g.dart diff --git a/lib/features/diary/models/nutrition_model.dart b/lib/features/diary/models/nutrition_model.dart new file mode 100644 index 00000000..73103842 --- /dev/null +++ b/lib/features/diary/models/nutrition_model.dart @@ -0,0 +1,27 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'nutrition_model.freezed.dart'; + +part 'nutrition_model.g.dart'; + +@freezed +class NutritionDataModel with _$NutritionDataModel { + const factory NutritionDataModel({ + required NutritionModel dailyNutritionIntake, + required NutritionModel dailyNutritionRecommendation, + }) = _NutritionDataModel; + + factory NutritionDataModel.fromJson(Map json) => _$NutritionDataModelFromJson(json); +} + +@freezed +class NutritionModel with _$NutritionModel { + const factory NutritionModel({ + required double energy, + required double proteins, + required double fats, + required double carbohydrates, + }) = _NutritionModel; + + factory NutritionModel.fromJson(Map json) => _$NutritionModelFromJson(json); +} diff --git a/lib/features/diary/models/nutrition_model.freezed.dart b/lib/features/diary/models/nutrition_model.freezed.dart new file mode 100644 index 00000000..46da50b5 --- /dev/null +++ b/lib/features/diary/models/nutrition_model.freezed.dart @@ -0,0 +1,437 @@ +// 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 'nutrition_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(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'); + +NutritionDataModel _$NutritionDataModelFromJson(Map json) { + return _NutritionDataModel.fromJson(json); +} + +/// @nodoc +mixin _$NutritionDataModel { + NutritionModel get dailyNutritionIntake => throw _privateConstructorUsedError; + NutritionModel get dailyNutritionRecommendation => + throw _privateConstructorUsedError; + + /// Serializes this NutritionDataModel to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of NutritionDataModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $NutritionDataModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $NutritionDataModelCopyWith<$Res> { + factory $NutritionDataModelCopyWith( + NutritionDataModel value, $Res Function(NutritionDataModel) then) = + _$NutritionDataModelCopyWithImpl<$Res, NutritionDataModel>; + @useResult + $Res call( + {NutritionModel dailyNutritionIntake, + NutritionModel dailyNutritionRecommendation}); + + $NutritionModelCopyWith<$Res> get dailyNutritionIntake; + $NutritionModelCopyWith<$Res> get dailyNutritionRecommendation; +} + +/// @nodoc +class _$NutritionDataModelCopyWithImpl<$Res, $Val extends NutritionDataModel> + implements $NutritionDataModelCopyWith<$Res> { + _$NutritionDataModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of NutritionDataModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? dailyNutritionIntake = null, + Object? dailyNutritionRecommendation = null, + }) { + return _then(_value.copyWith( + dailyNutritionIntake: null == dailyNutritionIntake + ? _value.dailyNutritionIntake + : dailyNutritionIntake // ignore: cast_nullable_to_non_nullable + as NutritionModel, + dailyNutritionRecommendation: null == dailyNutritionRecommendation + ? _value.dailyNutritionRecommendation + : dailyNutritionRecommendation // ignore: cast_nullable_to_non_nullable + as NutritionModel, + ) as $Val); + } + + /// Create a copy of NutritionDataModel + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $NutritionModelCopyWith<$Res> get dailyNutritionIntake { + return $NutritionModelCopyWith<$Res>(_value.dailyNutritionIntake, (value) { + return _then(_value.copyWith(dailyNutritionIntake: value) as $Val); + }); + } + + /// Create a copy of NutritionDataModel + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $NutritionModelCopyWith<$Res> get dailyNutritionRecommendation { + return $NutritionModelCopyWith<$Res>(_value.dailyNutritionRecommendation, + (value) { + return _then( + _value.copyWith(dailyNutritionRecommendation: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$NutritionDataModelImplCopyWith<$Res> + implements $NutritionDataModelCopyWith<$Res> { + factory _$$NutritionDataModelImplCopyWith(_$NutritionDataModelImpl value, + $Res Function(_$NutritionDataModelImpl) then) = + __$$NutritionDataModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {NutritionModel dailyNutritionIntake, + NutritionModel dailyNutritionRecommendation}); + + @override + $NutritionModelCopyWith<$Res> get dailyNutritionIntake; + @override + $NutritionModelCopyWith<$Res> get dailyNutritionRecommendation; +} + +/// @nodoc +class __$$NutritionDataModelImplCopyWithImpl<$Res> + extends _$NutritionDataModelCopyWithImpl<$Res, _$NutritionDataModelImpl> + implements _$$NutritionDataModelImplCopyWith<$Res> { + __$$NutritionDataModelImplCopyWithImpl(_$NutritionDataModelImpl _value, + $Res Function(_$NutritionDataModelImpl) _then) + : super(_value, _then); + + /// Create a copy of NutritionDataModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? dailyNutritionIntake = null, + Object? dailyNutritionRecommendation = null, + }) { + return _then(_$NutritionDataModelImpl( + dailyNutritionIntake: null == dailyNutritionIntake + ? _value.dailyNutritionIntake + : dailyNutritionIntake // ignore: cast_nullable_to_non_nullable + as NutritionModel, + dailyNutritionRecommendation: null == dailyNutritionRecommendation + ? _value.dailyNutritionRecommendation + : dailyNutritionRecommendation // ignore: cast_nullable_to_non_nullable + as NutritionModel, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$NutritionDataModelImpl implements _NutritionDataModel { + const _$NutritionDataModelImpl( + {required this.dailyNutritionIntake, + required this.dailyNutritionRecommendation}); + + factory _$NutritionDataModelImpl.fromJson(Map json) => + _$$NutritionDataModelImplFromJson(json); + + @override + final NutritionModel dailyNutritionIntake; + @override + final NutritionModel dailyNutritionRecommendation; + + @override + String toString() { + return 'NutritionDataModel(dailyNutritionIntake: $dailyNutritionIntake, dailyNutritionRecommendation: $dailyNutritionRecommendation)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$NutritionDataModelImpl && + (identical(other.dailyNutritionIntake, dailyNutritionIntake) || + other.dailyNutritionIntake == dailyNutritionIntake) && + (identical(other.dailyNutritionRecommendation, + dailyNutritionRecommendation) || + other.dailyNutritionRecommendation == + dailyNutritionRecommendation)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash( + runtimeType, dailyNutritionIntake, dailyNutritionRecommendation); + + /// Create a copy of NutritionDataModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$NutritionDataModelImplCopyWith<_$NutritionDataModelImpl> get copyWith => + __$$NutritionDataModelImplCopyWithImpl<_$NutritionDataModelImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$NutritionDataModelImplToJson( + this, + ); + } +} + +abstract class _NutritionDataModel implements NutritionDataModel { + const factory _NutritionDataModel( + {required final NutritionModel dailyNutritionIntake, + required final NutritionModel dailyNutritionRecommendation}) = + _$NutritionDataModelImpl; + + factory _NutritionDataModel.fromJson(Map json) = + _$NutritionDataModelImpl.fromJson; + + @override + NutritionModel get dailyNutritionIntake; + @override + NutritionModel get dailyNutritionRecommendation; + + /// Create a copy of NutritionDataModel + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$NutritionDataModelImplCopyWith<_$NutritionDataModelImpl> get copyWith => + throw _privateConstructorUsedError; +} + +NutritionModel _$NutritionModelFromJson(Map json) { + return _NutritionModel.fromJson(json); +} + +/// @nodoc +mixin _$NutritionModel { + double get energy => throw _privateConstructorUsedError; + double get proteins => throw _privateConstructorUsedError; + double get fats => throw _privateConstructorUsedError; + double get carbohydrates => throw _privateConstructorUsedError; + + /// Serializes this NutritionModel to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of NutritionModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $NutritionModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $NutritionModelCopyWith<$Res> { + factory $NutritionModelCopyWith( + NutritionModel value, $Res Function(NutritionModel) then) = + _$NutritionModelCopyWithImpl<$Res, NutritionModel>; + @useResult + $Res call( + {double energy, double proteins, double fats, double carbohydrates}); +} + +/// @nodoc +class _$NutritionModelCopyWithImpl<$Res, $Val extends NutritionModel> + implements $NutritionModelCopyWith<$Res> { + _$NutritionModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of NutritionModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? energy = null, + Object? proteins = null, + Object? fats = null, + Object? carbohydrates = null, + }) { + return _then(_value.copyWith( + energy: null == energy + ? _value.energy + : energy // ignore: cast_nullable_to_non_nullable + as double, + proteins: null == proteins + ? _value.proteins + : proteins // ignore: cast_nullable_to_non_nullable + as double, + fats: null == fats + ? _value.fats + : fats // ignore: cast_nullable_to_non_nullable + as double, + carbohydrates: null == carbohydrates + ? _value.carbohydrates + : carbohydrates // ignore: cast_nullable_to_non_nullable + as double, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$NutritionModelImplCopyWith<$Res> + implements $NutritionModelCopyWith<$Res> { + factory _$$NutritionModelImplCopyWith(_$NutritionModelImpl value, + $Res Function(_$NutritionModelImpl) then) = + __$$NutritionModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {double energy, double proteins, double fats, double carbohydrates}); +} + +/// @nodoc +class __$$NutritionModelImplCopyWithImpl<$Res> + extends _$NutritionModelCopyWithImpl<$Res, _$NutritionModelImpl> + implements _$$NutritionModelImplCopyWith<$Res> { + __$$NutritionModelImplCopyWithImpl( + _$NutritionModelImpl _value, $Res Function(_$NutritionModelImpl) _then) + : super(_value, _then); + + /// Create a copy of NutritionModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? energy = null, + Object? proteins = null, + Object? fats = null, + Object? carbohydrates = null, + }) { + return _then(_$NutritionModelImpl( + energy: null == energy + ? _value.energy + : energy // ignore: cast_nullable_to_non_nullable + as double, + proteins: null == proteins + ? _value.proteins + : proteins // ignore: cast_nullable_to_non_nullable + as double, + fats: null == fats + ? _value.fats + : fats // ignore: cast_nullable_to_non_nullable + as double, + carbohydrates: null == carbohydrates + ? _value.carbohydrates + : carbohydrates // ignore: cast_nullable_to_non_nullable + as double, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$NutritionModelImpl implements _NutritionModel { + const _$NutritionModelImpl( + {required this.energy, + required this.proteins, + required this.fats, + required this.carbohydrates}); + + factory _$NutritionModelImpl.fromJson(Map json) => + _$$NutritionModelImplFromJson(json); + + @override + final double energy; + @override + final double proteins; + @override + final double fats; + @override + final double carbohydrates; + + @override + String toString() { + return 'NutritionModel(energy: $energy, proteins: $proteins, fats: $fats, carbohydrates: $carbohydrates)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$NutritionModelImpl && + (identical(other.energy, energy) || other.energy == energy) && + (identical(other.proteins, proteins) || + other.proteins == proteins) && + (identical(other.fats, fats) || other.fats == fats) && + (identical(other.carbohydrates, carbohydrates) || + other.carbohydrates == carbohydrates)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => + Object.hash(runtimeType, energy, proteins, fats, carbohydrates); + + /// Create a copy of NutritionModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$NutritionModelImplCopyWith<_$NutritionModelImpl> get copyWith => + __$$NutritionModelImplCopyWithImpl<_$NutritionModelImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$NutritionModelImplToJson( + this, + ); + } +} + +abstract class _NutritionModel implements NutritionModel { + const factory _NutritionModel( + {required final double energy, + required final double proteins, + required final double fats, + required final double carbohydrates}) = _$NutritionModelImpl; + + factory _NutritionModel.fromJson(Map json) = + _$NutritionModelImpl.fromJson; + + @override + double get energy; + @override + double get proteins; + @override + double get fats; + @override + double get carbohydrates; + + /// Create a copy of NutritionModel + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$NutritionModelImplCopyWith<_$NutritionModelImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/features/diary/models/nutrition_model.g.dart b/lib/features/diary/models/nutrition_model.g.dart new file mode 100644 index 00000000..6ecd533c --- /dev/null +++ b/lib/features/diary/models/nutrition_model.g.dart @@ -0,0 +1,40 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'nutrition_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$NutritionDataModelImpl _$$NutritionDataModelImplFromJson( + Map json) => + _$NutritionDataModelImpl( + dailyNutritionIntake: NutritionModel.fromJson( + json['dailyNutritionIntake'] as Map), + dailyNutritionRecommendation: NutritionModel.fromJson( + json['dailyNutritionRecommendation'] as Map), + ); + +Map _$$NutritionDataModelImplToJson( + _$NutritionDataModelImpl instance) => + { + 'dailyNutritionIntake': instance.dailyNutritionIntake, + 'dailyNutritionRecommendation': instance.dailyNutritionRecommendation, + }; + +_$NutritionModelImpl _$$NutritionModelImplFromJson(Map json) => + _$NutritionModelImpl( + energy: (json['energy'] as num).toDouble(), + proteins: (json['proteins'] as num).toDouble(), + fats: (json['fats'] as num).toDouble(), + carbohydrates: (json['carbohydrates'] as num).toDouble(), + ); + +Map _$$NutritionModelImplToJson( + _$NutritionModelImpl instance) => + { + 'energy': instance.energy, + 'proteins': instance.proteins, + 'fats': instance.fats, + 'carbohydrates': instance.carbohydrates, + }; diff --git a/lib/features/diary/presentation/bloc/diary_cubit.dart b/lib/features/diary/presentation/bloc/diary_cubit.dart index 62d81086..16df5d4f 100644 --- a/lib/features/diary/presentation/bloc/diary_cubit.dart +++ b/lib/features/diary/presentation/bloc/diary_cubit.dart @@ -1,6 +1,7 @@ import 'dart:io'; import 'package:eatvio_app/features/diary/models/diary_day_model.dart'; +import 'package:eatvio_app/features/diary/models/nutrition_model.dart'; import 'package:eatvio_app/features/diary/presentation/bloc/diary_state.dart'; import 'package:eatvio_app/features/diary/repositories/diary_repository.dart'; import 'package:eatvio_app/features/glossary/models/glossary_model.dart'; @@ -23,6 +24,7 @@ class DiaryCubit extends Cubit { emit( DiaryState.loaded( diary: await diaryRepository.getDiaryByDate(date), + nutrition: await getNutrition(await diaryRepository.getDiaryIndexByDate(date)), currentSelectedSatietyRating: currentSelectedSatietyRating, ), ); @@ -32,6 +34,10 @@ class DiaryCubit extends Cubit { } } + Future getNutrition(int index) async { + return (await diaryRepository.getNutritionData(index)); + } + addProductToMeal({ required int diaryId, required int mealId, diff --git a/lib/features/diary/presentation/bloc/diary_state.dart b/lib/features/diary/presentation/bloc/diary_state.dart index 85221b31..001c9d16 100644 --- a/lib/features/diary/presentation/bloc/diary_state.dart +++ b/lib/features/diary/presentation/bloc/diary_state.dart @@ -1,4 +1,5 @@ import 'package:eatvio_app/features/diary/models/diary_day_model.dart'; +import 'package:eatvio_app/features/diary/models/nutrition_model.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; part 'diary_state.freezed.dart'; @@ -15,6 +16,7 @@ class DiaryState with _$DiaryState { const factory DiaryState.loaded({ required DiaryDayModel diary, + required NutritionDataModel nutrition, required double currentSelectedSatietyRating, }) = DiaryStateLoaded; } diff --git a/lib/features/diary/presentation/bloc/diary_state.freezed.dart b/lib/features/diary/presentation/bloc/diary_state.freezed.dart index 6e0778c4..58fa1471 100644 --- a/lib/features/diary/presentation/bloc/diary_state.freezed.dart +++ b/lib/features/diary/presentation/bloc/diary_state.freezed.dart @@ -21,8 +21,8 @@ mixin _$DiaryState { TResult Function() $default, { required TResult Function() loading, required TResult Function(String errorMessage) error, - required TResult Function( - DiaryDayModel diary, double currentSelectedSatietyRating) + required TResult Function(DiaryDayModel diary, NutritionDataModel nutrition, + double currentSelectedSatietyRating) loaded, }) => throw _privateConstructorUsedError; @@ -31,7 +31,8 @@ mixin _$DiaryState { TResult? Function()? $default, { TResult? Function()? loading, TResult? Function(String errorMessage)? error, - TResult? Function(DiaryDayModel diary, double currentSelectedSatietyRating)? + TResult? Function(DiaryDayModel diary, NutritionDataModel nutrition, + double currentSelectedSatietyRating)? loaded, }) => throw _privateConstructorUsedError; @@ -40,7 +41,8 @@ mixin _$DiaryState { TResult Function()? $default, { TResult Function()? loading, TResult Function(String errorMessage)? error, - TResult Function(DiaryDayModel diary, double currentSelectedSatietyRating)? + TResult Function(DiaryDayModel diary, NutritionDataModel nutrition, + double currentSelectedSatietyRating)? loaded, required TResult orElse(), }) => @@ -137,8 +139,8 @@ class _$DiaryStateImpl implements _DiaryState { TResult Function() $default, { required TResult Function() loading, required TResult Function(String errorMessage) error, - required TResult Function( - DiaryDayModel diary, double currentSelectedSatietyRating) + required TResult Function(DiaryDayModel diary, NutritionDataModel nutrition, + double currentSelectedSatietyRating) loaded, }) { return $default(); @@ -150,7 +152,8 @@ class _$DiaryStateImpl implements _DiaryState { TResult? Function()? $default, { TResult? Function()? loading, TResult? Function(String errorMessage)? error, - TResult? Function(DiaryDayModel diary, double currentSelectedSatietyRating)? + TResult? Function(DiaryDayModel diary, NutritionDataModel nutrition, + double currentSelectedSatietyRating)? loaded, }) { return $default?.call(); @@ -162,7 +165,8 @@ class _$DiaryStateImpl implements _DiaryState { TResult Function()? $default, { TResult Function()? loading, TResult Function(String errorMessage)? error, - TResult Function(DiaryDayModel diary, double currentSelectedSatietyRating)? + TResult Function(DiaryDayModel diary, NutritionDataModel nutrition, + double currentSelectedSatietyRating)? loaded, required TResult orElse(), }) { @@ -258,8 +262,8 @@ class _$DiaryStateLoadingImpl implements DiaryStateLoading { TResult Function() $default, { required TResult Function() loading, required TResult Function(String errorMessage) error, - required TResult Function( - DiaryDayModel diary, double currentSelectedSatietyRating) + required TResult Function(DiaryDayModel diary, NutritionDataModel nutrition, + double currentSelectedSatietyRating) loaded, }) { return loading(); @@ -271,7 +275,8 @@ class _$DiaryStateLoadingImpl implements DiaryStateLoading { TResult? Function()? $default, { TResult? Function()? loading, TResult? Function(String errorMessage)? error, - TResult? Function(DiaryDayModel diary, double currentSelectedSatietyRating)? + TResult? Function(DiaryDayModel diary, NutritionDataModel nutrition, + double currentSelectedSatietyRating)? loaded, }) { return loading?.call(); @@ -283,7 +288,8 @@ class _$DiaryStateLoadingImpl implements DiaryStateLoading { TResult Function()? $default, { TResult Function()? loading, TResult Function(String errorMessage)? error, - TResult Function(DiaryDayModel diary, double currentSelectedSatietyRating)? + TResult Function(DiaryDayModel diary, NutritionDataModel nutrition, + double currentSelectedSatietyRating)? loaded, required TResult orElse(), }) { @@ -408,8 +414,8 @@ class _$DiaryStateErrorImpl implements DiaryStateError { TResult Function() $default, { required TResult Function() loading, required TResult Function(String errorMessage) error, - required TResult Function( - DiaryDayModel diary, double currentSelectedSatietyRating) + required TResult Function(DiaryDayModel diary, NutritionDataModel nutrition, + double currentSelectedSatietyRating) loaded, }) { return error(errorMessage); @@ -421,7 +427,8 @@ class _$DiaryStateErrorImpl implements DiaryStateError { TResult? Function()? $default, { TResult? Function()? loading, TResult? Function(String errorMessage)? error, - TResult? Function(DiaryDayModel diary, double currentSelectedSatietyRating)? + TResult? Function(DiaryDayModel diary, NutritionDataModel nutrition, + double currentSelectedSatietyRating)? loaded, }) { return error?.call(errorMessage); @@ -433,7 +440,8 @@ class _$DiaryStateErrorImpl implements DiaryStateError { TResult Function()? $default, { TResult Function()? loading, TResult Function(String errorMessage)? error, - TResult Function(DiaryDayModel diary, double currentSelectedSatietyRating)? + TResult Function(DiaryDayModel diary, NutritionDataModel nutrition, + double currentSelectedSatietyRating)? loaded, required TResult orElse(), }) { @@ -500,9 +508,13 @@ abstract class _$$DiaryStateLoadedImplCopyWith<$Res> { $Res Function(_$DiaryStateLoadedImpl) then) = __$$DiaryStateLoadedImplCopyWithImpl<$Res>; @useResult - $Res call({DiaryDayModel diary, double currentSelectedSatietyRating}); + $Res call( + {DiaryDayModel diary, + NutritionDataModel nutrition, + double currentSelectedSatietyRating}); $DiaryDayModelCopyWith<$Res> get diary; + $NutritionDataModelCopyWith<$Res> get nutrition; } /// @nodoc @@ -519,6 +531,7 @@ class __$$DiaryStateLoadedImplCopyWithImpl<$Res> @override $Res call({ Object? diary = null, + Object? nutrition = null, Object? currentSelectedSatietyRating = null, }) { return _then(_$DiaryStateLoadedImpl( @@ -526,6 +539,10 @@ class __$$DiaryStateLoadedImplCopyWithImpl<$Res> ? _value.diary : diary // ignore: cast_nullable_to_non_nullable as DiaryDayModel, + nutrition: null == nutrition + ? _value.nutrition + : nutrition // ignore: cast_nullable_to_non_nullable + as NutritionDataModel, currentSelectedSatietyRating: null == currentSelectedSatietyRating ? _value.currentSelectedSatietyRating : currentSelectedSatietyRating // ignore: cast_nullable_to_non_nullable @@ -542,22 +559,36 @@ class __$$DiaryStateLoadedImplCopyWithImpl<$Res> return _then(_value.copyWith(diary: value)); }); } + + /// Create a copy of DiaryState + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $NutritionDataModelCopyWith<$Res> get nutrition { + return $NutritionDataModelCopyWith<$Res>(_value.nutrition, (value) { + return _then(_value.copyWith(nutrition: value)); + }); + } } /// @nodoc class _$DiaryStateLoadedImpl implements DiaryStateLoaded { const _$DiaryStateLoadedImpl( - {required this.diary, required this.currentSelectedSatietyRating}); + {required this.diary, + required this.nutrition, + required this.currentSelectedSatietyRating}); @override final DiaryDayModel diary; @override + final NutritionDataModel nutrition; + @override final double currentSelectedSatietyRating; @override String toString() { - return 'DiaryState.loaded(diary: $diary, currentSelectedSatietyRating: $currentSelectedSatietyRating)'; + return 'DiaryState.loaded(diary: $diary, nutrition: $nutrition, currentSelectedSatietyRating: $currentSelectedSatietyRating)'; } @override @@ -566,6 +597,8 @@ class _$DiaryStateLoadedImpl implements DiaryStateLoaded { (other.runtimeType == runtimeType && other is _$DiaryStateLoadedImpl && (identical(other.diary, diary) || other.diary == diary) && + (identical(other.nutrition, nutrition) || + other.nutrition == nutrition) && (identical(other.currentSelectedSatietyRating, currentSelectedSatietyRating) || other.currentSelectedSatietyRating == @@ -574,7 +607,7 @@ class _$DiaryStateLoadedImpl implements DiaryStateLoaded { @override int get hashCode => - Object.hash(runtimeType, diary, currentSelectedSatietyRating); + Object.hash(runtimeType, diary, nutrition, currentSelectedSatietyRating); /// Create a copy of DiaryState /// with the given fields replaced by the non-null parameter values. @@ -591,11 +624,11 @@ class _$DiaryStateLoadedImpl implements DiaryStateLoaded { TResult Function() $default, { required TResult Function() loading, required TResult Function(String errorMessage) error, - required TResult Function( - DiaryDayModel diary, double currentSelectedSatietyRating) + required TResult Function(DiaryDayModel diary, NutritionDataModel nutrition, + double currentSelectedSatietyRating) loaded, }) { - return loaded(diary, currentSelectedSatietyRating); + return loaded(diary, nutrition, currentSelectedSatietyRating); } @override @@ -604,10 +637,11 @@ class _$DiaryStateLoadedImpl implements DiaryStateLoaded { TResult? Function()? $default, { TResult? Function()? loading, TResult? Function(String errorMessage)? error, - TResult? Function(DiaryDayModel diary, double currentSelectedSatietyRating)? + TResult? Function(DiaryDayModel diary, NutritionDataModel nutrition, + double currentSelectedSatietyRating)? loaded, }) { - return loaded?.call(diary, currentSelectedSatietyRating); + return loaded?.call(diary, nutrition, currentSelectedSatietyRating); } @override @@ -616,12 +650,13 @@ class _$DiaryStateLoadedImpl implements DiaryStateLoaded { TResult Function()? $default, { TResult Function()? loading, TResult Function(String errorMessage)? error, - TResult Function(DiaryDayModel diary, double currentSelectedSatietyRating)? + TResult Function(DiaryDayModel diary, NutritionDataModel nutrition, + double currentSelectedSatietyRating)? loaded, required TResult orElse(), }) { if (loaded != null) { - return loaded(diary, currentSelectedSatietyRating); + return loaded(diary, nutrition, currentSelectedSatietyRating); } return orElse(); } @@ -667,10 +702,12 @@ class _$DiaryStateLoadedImpl implements DiaryStateLoaded { abstract class DiaryStateLoaded implements DiaryState { const factory DiaryStateLoaded( {required final DiaryDayModel diary, + required final NutritionDataModel nutrition, required final double currentSelectedSatietyRating}) = _$DiaryStateLoadedImpl; DiaryDayModel get diary; + NutritionDataModel get nutrition; double get currentSelectedSatietyRating; /// Create a copy of DiaryState diff --git a/lib/features/diary/presentation/pages/diary_screen.dart b/lib/features/diary/presentation/pages/diary_screen.dart index 91fdbf29..791df947 100644 --- a/lib/features/diary/presentation/pages/diary_screen.dart +++ b/lib/features/diary/presentation/pages/diary_screen.dart @@ -2,6 +2,7 @@ import 'dart:io'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:eatvio_app/core/const.dart'; import 'package:eatvio_app/features/diary/models/diary_day_model.dart'; +import 'package:eatvio_app/features/diary/models/nutrition_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/satiety_rating_widget.dart'; @@ -16,7 +17,7 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_typeahead/flutter_typeahead.dart'; import 'package:image_picker/image_picker.dart'; import 'package:rive/rive.dart'; -import 'package:syncfusion_flutter_charts/charts.dart'; +import 'package:syncfusion_flutter_gauges/gauges.dart'; import 'package:table_calendar/table_calendar.dart'; class DiaryScreen extends StatefulWidget { @@ -66,7 +67,7 @@ class _DiaryScreenState extends State { state.diary, state.currentSelectedSatietyRating, ), - if (state is DiaryStateLoaded) _chart(), + if (state is DiaryStateLoaded) _chart(state.nutrition), const SizedBox(height: 32), ], ), @@ -208,30 +209,26 @@ class _DiaryScreenState extends State { ); } - _chart() { + _chart(NutritionDataModel nutrition) { final List chartData = [ ChartData( - 1924, - 200, - '100%', + nutrition.dailyNutritionIntake.carbohydrates, + nutrition.dailyNutritionRecommendation.carbohydrates, Color(0xFFFF9500), ), ChartData( - 1925, - 50, - '100%', + nutrition.dailyNutritionIntake.fats, + nutrition.dailyNutritionRecommendation.fats, Color(0xFFFF3B30), ), ChartData( - 1926, - 70, - '100%', + nutrition.dailyNutritionIntake.proteins, + nutrition.dailyNutritionRecommendation.proteins, Color(0xFF4CD964), ), ChartData( - 1926, - 70, - '100%', + nutrition.dailyNutritionIntake.energy, + nutrition.dailyNutritionRecommendation.energy, Color(0xFF007AFF), ), ]; @@ -257,38 +254,126 @@ class _DiaryScreenState extends State { height: 1, ), ), - Transform.rotate( - angle: -1.5708, - child: ClipRect( - child: Align( - alignment: Alignment.centerRight, - widthFactor: 0.5, - child: SfCircularChart( - series: [ - RadialBarSeries( - dataSource: chartData, - xValueMapper: (ChartData data, _) => data.x, - yValueMapper: (ChartData data, _) => data.y, - pointColorMapper: (ChartData data, _) => data.color, - trackColor: Color.fromRGBO(59, 130, 246, 1), - trackOpacity: 0.1, - gap: "8%", - radius: "110%", - innerRadius: '20%', - cornerStyle: CornerStyle.bothCurve, - ), - ], + SfRadialGauge( + axes: [ + RadialAxis( + startAngle: 180, + endAngle: 0, + minimum: 0, + maximum: 100, + showLabels: false, + showTicks: false, + radiusFactor: 0.8, + axisLineStyle: AxisLineStyle( + thickness: 0.1, + color: Colors.grey[200], + thicknessUnit: GaugeSizeUnit.factor, ), + pointers: [ + // Carbohydrates Arc + RangePointer( + value: (chartData[0].intake / chartData[0].recommendation) * 100, + width: 0.1, + color: chartData[0].color, + sizeUnit: GaugeSizeUnit.factor, + enableAnimation: true, + cornerStyle: CornerStyle.bothCurve, // Rounded ends + ), + // Fats Arc + RangePointer( + value: (chartData[1].intake / chartData[1].recommendation) * 100, + width: 0.1, + color: chartData[1].color, + sizeUnit: GaugeSizeUnit.factor, + enableAnimation: true, + cornerStyle: CornerStyle.bothCurve, + pointerOffset: -0.12, + ), + // Proteins Arc + RangePointer( + value: (chartData[2].intake / chartData[2].recommendation) * 100, + width: 0.1, + color: chartData[2].color, + sizeUnit: GaugeSizeUnit.factor, + enableAnimation: true, + cornerStyle: CornerStyle.bothCurve, + pointerOffset: -0.24, + ), + // Calories Arc + RangePointer( + value: (chartData[3].intake / chartData[3].recommendation) * 100, + width: 0.1, + color: chartData[3].color, + sizeUnit: GaugeSizeUnit.factor, + enableAnimation: true, + cornerStyle: CornerStyle.bothCurve, + pointerOffset: -0.36, + ), + ], + annotations: [ + // Label for Carbohydrates + GaugeAnnotation( + widget: Transform.rotate( + angle: 30, + child: Text( + 'Углеводы', + style: TextStyle(color: Colors.white, fontSize: 12), + ), + ), + angle: 194, + positionFactor: 1, + ), + // Label for Fats + GaugeAnnotation( + widget: Transform.rotate( + angle: 30, + child: Text( + 'Жиры', + style: TextStyle(color: Colors.white, fontSize: 12), + ), + ), + angle: 190, + positionFactor: 1.07, + ), + // Label for Proteins + GaugeAnnotation( + widget: Transform.rotate( + angle: 30, + child: Text( + 'Белки', + style: TextStyle(color: Colors.white, fontSize: 12), + ), + ), + angle: 190, + positionFactor: 1.19, + ), + // Label for Calories + GaugeAnnotation( + widget: Transform.rotate( + angle: 30, + child: Text( + 'Калории', + style: TextStyle(color: Colors.white, fontSize: 12), + ), + ), + angle: 192, + positionFactor: 1.31, + ), + ], ), - ), + ], ), - _chartData('Калории', '0 ккал'), + _chartData('Калории', + '${nutrition.dailyNutritionIntake.energy.toStringAsFixed(0)} из ${nutrition.dailyNutritionRecommendation.energy.toStringAsFixed(0)} ккал'), const SizedBox(height: 8), - _chartData('Белки', '0 грамм'), + _chartData('Белки', + '${nutrition.dailyNutritionIntake.proteins.toStringAsFixed(0)} из ${nutrition.dailyNutritionRecommendation.proteins.toStringAsFixed(0)} грамм'), const SizedBox(height: 8), - _chartData('Жиры', '0 грамм'), + _chartData( + 'Жиры', '${nutrition.dailyNutritionIntake.fats.toStringAsFixed(0)} из ${nutrition.dailyNutritionRecommendation.fats.toStringAsFixed(0)} грамм'), const SizedBox(height: 8), - _chartData('Углеводы', '0 грамм'), + _chartData('Углеводы', + '${nutrition.dailyNutritionIntake.carbohydrates.toStringAsFixed(0)} из ${nutrition.dailyNutritionRecommendation.carbohydrates.toStringAsFixed(0)} грамм'), ], ), ); @@ -795,14 +880,13 @@ class _DiaryScreenState extends State { } class ChartData { - int x, y; - String text; - Color color; + final double intake; + final double recommendation; + final Color color; ChartData( - this.x, - this.y, - this.text, + this.intake, + this.recommendation, this.color, ); } diff --git a/lib/features/diary/presentation/widgets/satiety_rating_widget.dart b/lib/features/diary/presentation/widgets/satiety_rating_widget.dart index d12fa114..4376f274 100644 --- a/lib/features/diary/presentation/widgets/satiety_rating_widget.dart +++ b/lib/features/diary/presentation/widgets/satiety_rating_widget.dart @@ -47,7 +47,7 @@ class _SatietyRatingWidgetState extends State { case 0: return Container( width: MediaQuery.of(context).size.width / 6, - height: 16, + height: 24, margin: widget.currentSelectedSatietyRating == 1 ? EdgeInsets.symmetric(horizontal: 2) : null, decoration: BoxDecoration( color: Color(0xFFC82222), @@ -71,7 +71,7 @@ class _SatietyRatingWidgetState extends State { case 1: return Container( width: MediaQuery.of(context).size.width / 6, - height: 16, + height: 24, margin: widget.currentSelectedSatietyRating == 2 ? EdgeInsets.symmetric(horizontal: 2) : null, decoration: BoxDecoration( color: Color(0xFFFF3E3E), @@ -88,7 +88,7 @@ class _SatietyRatingWidgetState extends State { case 2: return Container( width: MediaQuery.of(context).size.width / 6, - height: 16, + height: 24, margin: widget.currentSelectedSatietyRating == 3 ? EdgeInsets.symmetric(horizontal: 2) : null, decoration: BoxDecoration( color: Color(0xFFF8C926), @@ -105,7 +105,7 @@ class _SatietyRatingWidgetState extends State { case 3: return Container( width: MediaQuery.of(context).size.width / 6, - height: 16, + height: 24, margin: widget.currentSelectedSatietyRating == 4 ? EdgeInsets.symmetric(horizontal: 2) : null, decoration: BoxDecoration( color: Color(0xFFFFF3BF), @@ -122,7 +122,7 @@ class _SatietyRatingWidgetState extends State { case 4: return Container( width: MediaQuery.of(context).size.width / 6, - height: 16, + height: 24, margin: widget.currentSelectedSatietyRating == 5 ? EdgeInsets.symmetric(horizontal: 2) : null, decoration: BoxDecoration( color: Color(0xFF62E833), @@ -139,7 +139,7 @@ class _SatietyRatingWidgetState extends State { default: return Container( width: MediaQuery.of(context).size.width / 6, - height: 16, + height: 24, margin: widget.currentSelectedSatietyRating == 6 ? EdgeInsets.symmetric(horizontal: 2) : null, decoration: BoxDecoration( color: Color(0xFF4DCE20), diff --git a/lib/features/diary/repositories/diary_repository.dart b/lib/features/diary/repositories/diary_repository.dart index b9b8243c..abb05a33 100644 --- a/lib/features/diary/repositories/diary_repository.dart +++ b/lib/features/diary/repositories/diary_repository.dart @@ -1,5 +1,6 @@ import 'dart:io'; import 'package:eatvio_app/features/diary/models/diary_day_model.dart'; +import 'package:eatvio_app/features/diary/models/nutrition_model.dart'; import 'package:eatvio_app/features/diary/services/diary_service.dart'; class DiaryRepository { @@ -11,15 +12,19 @@ class DiaryRepository { Future getDiaryByDate(String date) async { return (await diaryService.getDiaryDay( - index: await _getDiaryIndexByDate(date), + index: await getDiaryIndexByDate(date), )) .diary; } - Future _getDiaryIndexByDate(String date) async { + Future getDiaryIndexByDate(String date) async { return (await diaryService.getDiaryIndexByDate(date: date)).id; } + Future getNutritionData(int index) async { + return await diaryService.getNutrition(index: index); + } + Future addPortionToMeal({ required int diaryId, required int mealId, diff --git a/lib/features/diary/services/diary_service.dart b/lib/features/diary/services/diary_service.dart index 16990b1b..bf7f1763 100644 --- a/lib/features/diary/services/diary_service.dart +++ b/lib/features/diary/services/diary_service.dart @@ -2,6 +2,7 @@ import 'dart:io'; import 'package:dio/dio.dart'; import 'package:eatvio_app/features/diary/models/diary_day_model.dart'; import 'package:eatvio_app/features/diary/models/diary_index_model.dart'; +import 'package:eatvio_app/features/diary/models/nutrition_model.dart'; import 'package:retrofit/retrofit.dart'; part 'diary_service.g.dart'; @@ -20,6 +21,11 @@ abstract class DiaryService { @Path('diary_id') required int index, }); + @GET('/api/diary/{diary_id}/dailyNutritionData') + Future getNutrition({ + @Path('diary_id') required int index, + }); + @POST('/api/diary/{diary_id}/meal/{meal_id}/photo/upload') @MultiPart() Future uploadPhotoOfMeal({ diff --git a/lib/features/diary/services/diary_service.g.dart b/lib/features/diary/services/diary_service.g.dart index 74de16af..1672b50a 100644 --- a/lib/features/diary/services/diary_service.g.dart +++ b/lib/features/diary/services/diary_service.g.dart @@ -87,6 +87,39 @@ class _DiaryService implements DiaryService { return _value; } + @override + Future getNutrition({required int index}) async { + final _extra = {}; + final queryParameters = {}; + final _headers = {}; + const Map? _data = null; + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diary/${index}/dailyNutritionData', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); + final _result = await _dio.fetch>(_options); + late NutritionDataModel _value; + try { + _value = NutritionDataModel.fromJson(_result.data!); + } on Object catch (e, s) { + errorLogger?.logError(e, s, _options); + rethrow; + } + return _value; + } + @override Future uploadPhotoOfMeal({ required int diaryId, diff --git a/pubspec.yaml b/pubspec.yaml index 080157d0..a0ffdb94 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -40,6 +40,7 @@ dependencies: google_fonts: ^6.2.1 location: ^7.0.1 syncfusion_flutter_charts: ^27.1.55 + syncfusion_flutter_gauges: ^27.1.58 table_calendar: ^3.1.2 flutter_keyboard_visibility: ^6.0.0 share_plus: ^10.1.0