diff --git a/lib/features/diary/entities/nutrition_chart_data_entity.dart b/lib/features/diary/entities/nutrition_chart_data_entity.dart new file mode 100644 index 00000000..9602d7d7 --- /dev/null +++ b/lib/features/diary/entities/nutrition_chart_data_entity.dart @@ -0,0 +1,9 @@ +class NutritionChartDataEntity { + final double intake; + final double recommendation; + + NutritionChartDataEntity( + this.intake, + this.recommendation, + ); +} diff --git a/lib/features/diary/presentation/pages/diary_screen.dart b/lib/features/diary/presentation/pages/diary_screen.dart index 9c405a7e..fc222600 100644 --- a/lib/features/diary/presentation/pages/diary_screen.dart +++ b/lib/features/diary/presentation/pages/diary_screen.dart @@ -3,9 +3,9 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:eatvio_app/core/const.dart'; import 'package:eatvio_app/core/widgets/loader.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/calories_chat_widget.dart'; import 'package:eatvio_app/features/diary/presentation/widgets/finish_day_button_widget.dart'; import 'package:eatvio_app/features/diary/presentation/widgets/glossary_moderation_request_modal_widget.dart'; import 'package:eatvio_app/features/diary/presentation/widgets/satiety_rating_widget.dart'; @@ -19,7 +19,6 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_typeahead/flutter_typeahead.dart'; import 'package:image_picker/image_picker.dart'; -import 'package:syncfusion_flutter_gauges/gauges.dart'; import 'package:table_calendar/table_calendar.dart'; class DiaryScreen extends StatefulWidget { @@ -129,7 +128,10 @@ class _DiaryScreenState extends State { state.diary, state.currentSelectedSatietyRating, ), - if (state is DiaryStateLoaded && _selectedDay!.compareTo(today!) != 1) _chart(state.nutrition), + if (state is DiaryStateLoaded && _selectedDay!.compareTo(today!) != 1) + CaloriesChatWidget( + nutrition: state.nutrition, + ), if (state is DiaryStateLoaded && state.diary.closed == 0 && _selectedDay == today) Padding( padding: const EdgeInsets.only(top: 12), @@ -331,255 +333,6 @@ class _DiaryScreenState extends State { ); } - _chart(NutritionDataModel nutrition) { - final List chartData = [ - ChartData( - nutrition.dailyNutritionIntake.carbohydrates, - nutrition.dailyNutritionRecommendation.carbohydrates, - ), - ChartData( - nutrition.dailyNutritionIntake.fats, - nutrition.dailyNutritionRecommendation.fats, - ), - ChartData( - nutrition.dailyNutritionIntake.proteins, - nutrition.dailyNutritionRecommendation.proteins, - ), - ChartData( - nutrition.dailyNutritionIntake.energy, - nutrition.dailyNutritionRecommendation.energy, - ), - ]; - - return Container( - padding: const EdgeInsets.all(16), - margin: const EdgeInsets.only(top: 12), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - color: Colors.white, - ), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Text( - 'Ваш КБЖУ от дневной\nсуточной нормы', - textAlign: TextAlign.center, - style: TextStyle( - color: Color(0xFF323F4B), - fontWeight: FontWeight.w500, - fontSize: 18, - height: 1, - ), - ), - const SizedBox(height: 48), - Stack( - alignment: Alignment.bottomCenter, - children: [ - SfRadialGauge( - axes: [ - RadialAxis( - startAngle: 180, - endAngle: 0, - minimum: 0, - maximum: 100, - showLabels: false, - showTicks: false, - radiusFactor: 0.7, - showAxisLine: false, - pointers: [ - RangePointer( - value: 100, - width: 0.16, - animationDuration: 2000, - color: Color(0xFFF6FAFF), - sizeUnit: GaugeSizeUnit.factor, - enableAnimation: true, - cornerStyle: CornerStyle.bothCurve, - ), - RangePointer( - value: (chartData[0].intake / chartData[0].recommendation) * 100, - width: 0.16, - color: chartData[0].intake < chartData[0].recommendation ? appTheme.blueA400 : Colors.red, - sizeUnit: GaugeSizeUnit.factor, - enableAnimation: true, - cornerStyle: CornerStyle.bothCurve, - ), - RangePointer( - value: 100, - width: 0.16, - animationDuration: 2000, - color: Color(0xFFF6FAFF), - sizeUnit: GaugeSizeUnit.factor, - enableAnimation: true, - cornerStyle: CornerStyle.bothCurve, - pointerOffset: -0.18, - ), - RangePointer( - value: (chartData[1].intake / chartData[1].recommendation) * 100, - width: 0.16, - color: chartData[1].intake < chartData[1].recommendation ? appTheme.blueA400 : Colors.red, - sizeUnit: GaugeSizeUnit.factor, - enableAnimation: true, - cornerStyle: CornerStyle.bothCurve, - pointerOffset: -0.18, - ), - RangePointer( - value: 100, - width: 0.16, - animationDuration: 2000, - color: Color(0xFFF6FAFF), - sizeUnit: GaugeSizeUnit.factor, - enableAnimation: true, - cornerStyle: CornerStyle.bothCurve, - pointerOffset: -0.36, - ), - RangePointer( - value: (chartData[2].intake / chartData[2].recommendation) * 100, - width: 0.16, - color: chartData[2].intake < chartData[2].recommendation ? appTheme.blueA400 : Colors.red, - sizeUnit: GaugeSizeUnit.factor, - enableAnimation: true, - cornerStyle: CornerStyle.bothCurve, - pointerOffset: -0.36, - ), - RangePointer( - value: 100, - width: 0.16, - animationDuration: 2000, - color: Color(0xFFF6FAFF), - sizeUnit: GaugeSizeUnit.factor, - enableAnimation: true, - cornerStyle: CornerStyle.bothCurve, - pointerOffset: -0.54, - ), - RangePointer( - value: (chartData[3].intake / chartData[3].recommendation) * 100, - width: 0.16, - color: chartData[3].intake < chartData[3].recommendation ? appTheme.blueA400 : Colors.red, - sizeUnit: GaugeSizeUnit.factor, - enableAnimation: true, - cornerStyle: CornerStyle.bothCurve, - pointerOffset: -0.54, - ), - ], - annotations: [ - GaugeAnnotation( - widget: Transform.rotate( - angle: 30.1, - child: Text( - 'Углеводы', - style: TextStyle( - color: Colors.white, - fontSize: 12, - ), - ), - ), - angle: 198, - positionFactor: 0.92, - ), - GaugeAnnotation( - widget: Transform.rotate( - angle: 30, - child: Text( - 'Жиры', - style: TextStyle( - color: Colors.white, - fontSize: 12, - ), - ), - ), - angle: 190, - positionFactor: 1.1, - ), - GaugeAnnotation( - widget: Transform.rotate( - angle: 30, - child: Text( - 'Белки', - style: TextStyle( - color: Colors.white, - fontSize: 12, - ), - ), - ), - angle: 190, - positionFactor: 1.27, - ), - GaugeAnnotation( - widget: Transform.rotate( - angle: 30, - child: Text( - 'Калории', - style: TextStyle( - color: Colors.white, - fontSize: 12, - ), - ), - ), - angle: 192, - positionFactor: 1.46, - ), - ], - ), - ], - ), - Column( - children: [ - _chartData( - 'Калории', - '${nutrition.dailyNutritionIntake.energy.toStringAsFixed(0)} из ${nutrition.dailyNutritionRecommendation.energy.toStringAsFixed(0)} ккал', - ), - const SizedBox(height: 8), - _chartData( - 'Белки', - '${nutrition.dailyNutritionIntake.proteins.toStringAsFixed(0)} из ${nutrition.dailyNutritionRecommendation.proteins.toStringAsFixed( - 0, - )} грамм', - ), - const SizedBox(height: 8), - _chartData( - 'Жиры', - '${nutrition.dailyNutritionIntake.fats.toStringAsFixed(0)} из ${nutrition.dailyNutritionRecommendation.fats.toStringAsFixed(0)} грамм', - ), - const SizedBox(height: 8), - _chartData( - 'Углеводы', - '${nutrition.dailyNutritionIntake.carbohydrates.toStringAsFixed(0)} из ${nutrition.dailyNutritionRecommendation.carbohydrates.toStringAsFixed(0)} грамм', - ), - ], - ), - ], - ), - ], - ), - ); - } - - _chartData(String title, String value) { - return Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - title, - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.w500, - color: Color(0xFF323F4B), - ), - ), - Text( - value, - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.w500, - color: Color(0xFF323F4B), - ), - ), - ], - ); - } - _showImagePicker(DiaryDayModel diaryDay) { showCupertinoModalPopup( context: context, @@ -1083,13 +836,3 @@ class _DiaryScreenState extends State { ); } } - -class ChartData { - final double intake; - final double recommendation; - - ChartData( - this.intake, - this.recommendation, - ); -} diff --git a/lib/features/diary/presentation/widgets/calories_chat_widget.dart b/lib/features/diary/presentation/widgets/calories_chat_widget.dart new file mode 100644 index 00000000..c0dc8ae6 --- /dev/null +++ b/lib/features/diary/presentation/widgets/calories_chat_widget.dart @@ -0,0 +1,275 @@ +import 'package:eatvio_app/core/theme/theme_helper.dart'; +import 'package:eatvio_app/features/diary/entities/nutrition_chart_data_entity.dart'; +import 'package:eatvio_app/features/diary/models/nutrition_model.dart'; +import 'package:flutter/material.dart'; +import 'package:syncfusion_flutter_gauges/gauges.dart'; + +class CaloriesChatWidget extends StatefulWidget { + final NutritionDataModel nutrition; + + CaloriesChatWidget({ + super.key, + required this.nutrition, + }); + + @override + State createState() => _CaloriesChatWidgetState(); +} + +class _CaloriesChatWidgetState extends State { + late final List nutritionChartData; + + @override + void initState() { + super.initState(); + nutritionChartData = [ + NutritionChartDataEntity( + widget.nutrition.dailyNutritionIntake.carbohydrates, + widget.nutrition.dailyNutritionRecommendation.carbohydrates, + ), + NutritionChartDataEntity( + widget.nutrition.dailyNutritionIntake.fats, + widget.nutrition.dailyNutritionRecommendation.fats, + ), + NutritionChartDataEntity( + widget.nutrition.dailyNutritionIntake.proteins, + widget.nutrition.dailyNutritionRecommendation.proteins, + ), + NutritionChartDataEntity( + widget.nutrition.dailyNutritionIntake.energy, + widget.nutrition.dailyNutritionRecommendation.energy, + ), + ]; + } + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.all(16), + margin: const EdgeInsets.only(top: 12), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: Colors.white, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + 'Ваш КБЖУ от дневной\nсуточной нормы', + textAlign: TextAlign.center, + style: TextStyle( + color: Color(0xFF323F4B), + fontWeight: FontWeight.w500, + fontSize: 18, + height: 1, + ), + ), + const SizedBox(height: 48), + Stack( + alignment: Alignment.bottomCenter, + children: [ + SfRadialGauge( + axes: [ + RadialAxis( + startAngle: 180, + endAngle: 0, + minimum: 0, + maximum: 100, + showLabels: false, + showTicks: false, + radiusFactor: 0.7, + showAxisLine: false, + pointers: [ + RangePointer( + value: 100, + width: 0.16, + animationDuration: 2000, + color: Color(0xFFF6FAFF), + sizeUnit: GaugeSizeUnit.factor, + enableAnimation: true, + cornerStyle: CornerStyle.bothCurve, + ), + RangePointer( + value: (nutritionChartData[0].intake / nutritionChartData[0].recommendation) * 100, + width: 0.16, + color: nutritionChartData[0].intake < nutritionChartData[0].recommendation ? appTheme.blueA400 : Colors.red, + sizeUnit: GaugeSizeUnit.factor, + enableAnimation: true, + cornerStyle: CornerStyle.bothCurve, + ), + RangePointer( + value: 100, + width: 0.16, + animationDuration: 2000, + color: Color(0xFFF6FAFF), + sizeUnit: GaugeSizeUnit.factor, + enableAnimation: true, + cornerStyle: CornerStyle.bothCurve, + pointerOffset: -0.18, + ), + RangePointer( + value: (nutritionChartData[1].intake / nutritionChartData[1].recommendation) * 100, + width: 0.16, + color: nutritionChartData[1].intake < nutritionChartData[1].recommendation ? appTheme.blueA400 : Colors.red, + sizeUnit: GaugeSizeUnit.factor, + enableAnimation: true, + cornerStyle: CornerStyle.bothCurve, + pointerOffset: -0.18, + ), + RangePointer( + value: 100, + width: 0.16, + animationDuration: 2000, + color: Color(0xFFF6FAFF), + sizeUnit: GaugeSizeUnit.factor, + enableAnimation: true, + cornerStyle: CornerStyle.bothCurve, + pointerOffset: -0.36, + ), + RangePointer( + value: (nutritionChartData[2].intake / nutritionChartData[2].recommendation) * 100, + width: 0.16, + color: nutritionChartData[2].intake < nutritionChartData[2].recommendation ? appTheme.blueA400 : Colors.red, + sizeUnit: GaugeSizeUnit.factor, + enableAnimation: true, + cornerStyle: CornerStyle.bothCurve, + pointerOffset: -0.36, + ), + RangePointer( + value: 100, + width: 0.16, + animationDuration: 2000, + color: Color(0xFFF6FAFF), + sizeUnit: GaugeSizeUnit.factor, + enableAnimation: true, + cornerStyle: CornerStyle.bothCurve, + pointerOffset: -0.54, + ), + RangePointer( + value: (nutritionChartData[3].intake / nutritionChartData[3].recommendation) * 100, + width: 0.16, + color: nutritionChartData[3].intake < nutritionChartData[3].recommendation ? appTheme.blueA400 : Colors.red, + sizeUnit: GaugeSizeUnit.factor, + enableAnimation: true, + cornerStyle: CornerStyle.bothCurve, + pointerOffset: -0.54, + ), + ], + annotations: [ + GaugeAnnotation( + widget: Transform.rotate( + angle: 30.1, + child: Text( + 'Углеводы', + style: TextStyle( + color: Colors.white, + fontSize: 12, + ), + ), + ), + angle: 198, + positionFactor: 0.92, + ), + GaugeAnnotation( + widget: Transform.rotate( + angle: 30, + child: Text( + 'Жиры', + style: TextStyle( + color: Colors.white, + fontSize: 12, + ), + ), + ), + angle: 190, + positionFactor: 1.1, + ), + GaugeAnnotation( + widget: Transform.rotate( + angle: 30, + child: Text( + 'Белки', + style: TextStyle( + color: Colors.white, + fontSize: 12, + ), + ), + ), + angle: 190, + positionFactor: 1.27, + ), + GaugeAnnotation( + widget: Transform.rotate( + angle: 30, + child: Text( + 'Калории', + style: TextStyle( + color: Colors.white, + fontSize: 12, + ), + ), + ), + angle: 192, + positionFactor: 1.46, + ), + ], + ), + ], + ), + Column( + children: [ + _chartData( + 'Калории', + '${widget.nutrition.dailyNutritionIntake.energy.toStringAsFixed(0)} из ${widget.nutrition.dailyNutritionRecommendation.energy.toStringAsFixed(0)} ккал', + ), + const SizedBox(height: 8), + _chartData( + 'Белки', + '${widget.nutrition.dailyNutritionIntake.proteins.toStringAsFixed(0)} из ${widget.nutrition.dailyNutritionRecommendation.proteins.toStringAsFixed( + 0, + )} грамм', + ), + const SizedBox(height: 8), + _chartData( + 'Жиры', + '${widget.nutrition.dailyNutritionIntake.fats.toStringAsFixed(0)} из ${widget.nutrition.dailyNutritionRecommendation.fats.toStringAsFixed(0)} грамм', + ), + const SizedBox(height: 8), + _chartData( + 'Углеводы', + '${widget.nutrition.dailyNutritionIntake.carbohydrates.toStringAsFixed(0)} из ${widget.nutrition.dailyNutritionRecommendation.carbohydrates.toStringAsFixed(0)} грамм', + ), + ], + ), + ], + ), + ], + ), + ); + } + + _chartData(String title, String value) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + title, + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.w500, + color: Color(0xFF323F4B), + ), + ), + Text( + value, + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.w500, + color: Color(0xFF323F4B), + ), + ), + ], + ); + } +} diff --git a/lib/features/diary/presentation/widgets/glossary_moderation_request_modal_widget.dart b/lib/features/diary/presentation/widgets/glossary_moderation_request_modal_widget.dart index 3461d687..8e68c21b 100644 --- a/lib/features/diary/presentation/widgets/glossary_moderation_request_modal_widget.dart +++ b/lib/features/diary/presentation/widgets/glossary_moderation_request_modal_widget.dart @@ -225,7 +225,7 @@ class _GlossaryModerationRequestModalWidgetState extends State { late FixedExtentScrollController weightKiloController; late FixedExtentScrollController weightGramsController; - late int weightKilo; - late int weightGrams; + int weightKilo = 20; + int weightGrams = 0; @override Widget build(BuildContext context) { diff --git a/lib/features/settings/presentation/pages/physical_form_screen.dart b/lib/features/settings/presentation/pages/physical_form_screen.dart index 6b712a45..2b2aa24d 100644 --- a/lib/features/settings/presentation/pages/physical_form_screen.dart +++ b/lib/features/settings/presentation/pages/physical_form_screen.dart @@ -25,6 +25,7 @@ class _PhysicalFormScreenState extends State { final waistCircumferenceController = TextEditingController(); final hipCircumferenceController = TextEditingController(); final heightController = TextEditingController(); + final weightController = TextEditingController(); @override void initState() { @@ -33,6 +34,7 @@ class _PhysicalFormScreenState extends State { waistCircumferenceController.text = widget.settingsEntity.profileDetailsModel.waistCircumference.toString(); hipCircumferenceController.text = widget.settingsEntity.profileDetailsModel.hipCircumference.toString(); heightController.text = widget.settingsEntity.profileDetailsModel.height.toString(); + weightController.text = widget.settingsEntity.profileDetailsModel.weight.toString(); } @override @@ -83,6 +85,15 @@ class _PhysicalFormScreenState extends State { hintText: 'см', textInputAction: TextInputAction.done, ), + SizedBox(height: 16), + Text('Вес'), + SizedBox(height: 4), + CustomTextFormField( + inputFormatters: [digitsOnly], + controller: weightController, + hintText: 'кг', + textInputAction: TextInputAction.done, + ), ], ), ), @@ -98,6 +109,7 @@ class _PhysicalFormScreenState extends State { waistCircumference: int.parse(waistCircumferenceController.text), hipCircumference: int.parse(hipCircumferenceController.text), height: int.parse(heightController.text), + weight: double.parse(weightController.text), ), ); GoRouter.of(context).pop();