feat(settings): add weight

This commit is contained in:
Alex
2024-11-27 10:51:08 +03:00
parent d006e4e21a
commit 421190b6c9
6 changed files with 307 additions and 268 deletions

View File

@@ -0,0 +1,9 @@
class NutritionChartDataEntity {
final double intake;
final double recommendation;
NutritionChartDataEntity(
this.intake,
this.recommendation,
);
}

View File

@@ -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<DiaryScreen> {
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<DiaryScreen> {
);
}
_chart(NutritionDataModel nutrition) {
final List<ChartData> 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>[
RadialAxis(
startAngle: 180,
endAngle: 0,
minimum: 0,
maximum: 100,
showLabels: false,
showTicks: false,
radiusFactor: 0.7,
showAxisLine: false,
pointers: <GaugePointer>[
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>[
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<void>(
context: context,
@@ -1083,13 +836,3 @@ class _DiaryScreenState extends State<DiaryScreen> {
);
}
}
class ChartData {
final double intake;
final double recommendation;
ChartData(
this.intake,
this.recommendation,
);
}

View File

@@ -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<CaloriesChatWidget> createState() => _CaloriesChatWidgetState();
}
class _CaloriesChatWidgetState extends State<CaloriesChatWidget> {
late final List<NutritionChartDataEntity> 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>[
RadialAxis(
startAngle: 180,
endAngle: 0,
minimum: 0,
maximum: 100,
showLabels: false,
showTicks: false,
radiusFactor: 0.7,
showAxisLine: false,
pointers: <GaugePointer>[
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>[
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),
),
),
],
);
}
}

View File

@@ -225,7 +225,7 @@ class _GlossaryModerationRequestModalWidgetState extends State<GlossaryModeratio
child: CustomTextFormField(
hintText: 'Калории',
controller: energyController,
keyboardType: TextInputType.number,
keyboardType: TextInputType.numberWithOptions(),
),
),
const SizedBox(width: 8),
@@ -233,7 +233,7 @@ class _GlossaryModerationRequestModalWidgetState extends State<GlossaryModeratio
child: CustomTextFormField(
hintText: 'Белки',
controller: proteinsController,
keyboardType: TextInputType.number,
keyboardType: TextInputType.numberWithOptions(),
),
),
],
@@ -246,7 +246,7 @@ class _GlossaryModerationRequestModalWidgetState extends State<GlossaryModeratio
child: CustomTextFormField(
hintText: 'Жиры',
controller: fatsController,
keyboardType: TextInputType.number,
keyboardType: TextInputType.numberWithOptions(),
),
),
const SizedBox(width: 8),
@@ -254,7 +254,7 @@ class _GlossaryModerationRequestModalWidgetState extends State<GlossaryModeratio
child: CustomTextFormField(
hintText: 'Углеводы',
controller: carbohydratesController,
keyboardType: TextInputType.number,
keyboardType: TextInputType.numberWithOptions(),
),
),
],

View File

@@ -23,8 +23,8 @@ class WeightChartWidget extends StatefulWidget {
class _WeightChartWidgetState extends State<WeightChartWidget> {
late FixedExtentScrollController weightKiloController;
late FixedExtentScrollController weightGramsController;
late int weightKilo;
late int weightGrams;
int weightKilo = 20;
int weightGrams = 0;
@override
Widget build(BuildContext context) {

View File

@@ -25,6 +25,7 @@ class _PhysicalFormScreenState extends State<PhysicalFormScreen> {
final waistCircumferenceController = TextEditingController();
final hipCircumferenceController = TextEditingController();
final heightController = TextEditingController();
final weightController = TextEditingController();
@override
void initState() {
@@ -33,6 +34,7 @@ class _PhysicalFormScreenState extends State<PhysicalFormScreen> {
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<PhysicalFormScreen> {
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<PhysicalFormScreen> {
waistCircumference: int.parse(waistCircumferenceController.text),
hipCircumference: int.parse(hipCircumferenceController.text),
height: int.parse(heightController.text),
weight: double.parse(weightController.text),
),
);
GoRouter.of(context).pop();