diff --git a/assets/icons/satiety_emoji_left.svg b/assets/icons/satiety_emoji_left.svg new file mode 100644 index 00000000..e2a21bda --- /dev/null +++ b/assets/icons/satiety_emoji_left.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/assets/icons/satiety_emoji_right.svg b/assets/icons/satiety_emoji_right.svg new file mode 100644 index 00000000..6791ee88 --- /dev/null +++ b/assets/icons/satiety_emoji_right.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/lib/features/diary/presentation/pages/diary_screen.dart b/lib/features/diary/presentation/pages/diary_screen.dart index 21ec0314..0c181902 100644 --- a/lib/features/diary/presentation/pages/diary_screen.dart +++ b/lib/features/diary/presentation/pages/diary_screen.dart @@ -11,10 +11,12 @@ import 'package:eatvio_app/widgets/custom_text_form_field.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_rating_bar/flutter_rating_bar.dart'; 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:table_calendar/table_calendar.dart'; class DiaryScreen extends StatefulWidget { @@ -34,6 +36,7 @@ class _DiaryScreenState extends State { final productNameController = TextEditingController(); final quantityController = TextEditingController(); int currentSelectedPhotoIndex = 0; + double currentSelectedSatietyRating = 3; @override Widget build(BuildContext context) { @@ -60,6 +63,7 @@ class _DiaryScreenState extends State { _calendar(state), if (state is DiaryStateLoading) _loader(), if (state is DiaryStateLoaded) _meals(state.diary), + if (state is DiaryStateLoaded) _chart(), const SizedBox(height: 32), ], ), @@ -70,6 +74,166 @@ class _DiaryScreenState extends State { ); } + _satietyRating() { + return Padding( + padding: const EdgeInsets.only(top: 12), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + 'Ваша сытость после приёма пищи', + style: TextStyle( + fontSize: 16, + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + SvgPicture.asset( + 'assets/icons/satiety_emoji_left.svg', + height: 32, + width: 32, + ), + RatingBar.builder( + initialRating: 3, + itemCount: 6, + itemSize: MediaQuery.of(context).size.width / 6 - (124 / 6), + itemBuilder: (context, index) { + switch (index) { + case 0: + return Container( + width: MediaQuery.of(context).size.width / 6, + height: 16, + margin: currentSelectedSatietyRating == 1 ? EdgeInsets.symmetric(horizontal: 2) : null, + decoration: BoxDecoration( + color: Color(0xFFC82222), + border: currentSelectedSatietyRating == 1 + ? Border.all( + width: 2, + color: Color(0xFFAA3333), + strokeAlign: BorderSide.strokeAlignOutside, + ) + : null, + borderRadius: currentSelectedSatietyRating == 1 + ? BorderRadius.horizontal( + left: Radius.circular(8), + right: Radius.circular(2), + ) + : BorderRadius.horizontal( + left: Radius.circular(8), + ), + ), + ); + case 1: + return Container( + width: MediaQuery.of(context).size.width / 6, + height: 16, + margin: currentSelectedSatietyRating == 2 ? EdgeInsets.symmetric(horizontal: 2) : null, + decoration: BoxDecoration( + color: Color(0xFFFF3E3E), + border: currentSelectedSatietyRating == 2 + ? Border.all( + width: 2, + color: Color(0xFF550000), + strokeAlign: BorderSide.strokeAlignOutside, + ) + : null, + borderRadius: currentSelectedSatietyRating == 2 ? BorderRadius.circular(2) : null, + ), + ); + case 2: + return Container( + width: MediaQuery.of(context).size.width / 6, + height: 16, + margin: currentSelectedSatietyRating == 3 ? EdgeInsets.symmetric(horizontal: 2) : null, + decoration: BoxDecoration( + color: Color(0xFFF8C926), + border: currentSelectedSatietyRating == 3 + ? Border.all( + width: 2, + color: Color(0xFF8C5D00), + strokeAlign: BorderSide.strokeAlignOutside, + ) + : null, + borderRadius: currentSelectedSatietyRating == 3 ? BorderRadius.circular(2) : null, + ), + ); + case 3: + return Container( + width: MediaQuery.of(context).size.width / 6, + height: 16, + margin: currentSelectedSatietyRating == 4 ? EdgeInsets.symmetric(horizontal: 2) : null, + decoration: BoxDecoration( + color: Color(0xFFFFF3BF), + border: currentSelectedSatietyRating == 4 + ? Border.all( + width: 2, + color: Color(0xFFB5911B), + strokeAlign: BorderSide.strokeAlignOutside, + ) + : null, + borderRadius: currentSelectedSatietyRating == 4 ? BorderRadius.circular(2) : null, + ), + ); + case 4: + return Container( + width: MediaQuery.of(context).size.width / 6, + height: 16, + margin: currentSelectedSatietyRating == 5 ? EdgeInsets.symmetric(horizontal: 2) : null, + decoration: BoxDecoration( + color: Color(0xFF62E833), + border: currentSelectedSatietyRating == 5 + ? Border.all( + width: 2, + color: Color(0xFF276918), + strokeAlign: BorderSide.strokeAlignOutside, + ) + : null, + borderRadius: currentSelectedSatietyRating == 5 ? BorderRadius.circular(2) : null, + ), + ); + default: + return Container( + width: MediaQuery.of(context).size.width / 6, + height: 16, + margin: currentSelectedSatietyRating == 6 ? EdgeInsets.symmetric(horizontal: 2) : null, + decoration: BoxDecoration( + color: Color(0xFF4DCE20), + border: currentSelectedSatietyRating == 6 + ? Border.all( + width: 2, + color: Color(0xFF184D12), + strokeAlign: BorderSide.strokeAlignOutside, + ) + : null, + borderRadius: currentSelectedSatietyRating == 6 + ? BorderRadius.horizontal( + left: Radius.circular(2), + right: Radius.circular(8), + ) + : BorderRadius.horizontal( + right: Radius.circular(8), + ), + ), + ); + } + }, + onRatingUpdate: (value) => setState(() { + currentSelectedSatietyRating = value; + }), + ), + SvgPicture.asset( + 'assets/icons/satiety_emoji_right.svg', + height: 32, + width: 32, + ), + ], + ), + ], + ), + ); + } + _arrowDown() { return Container( padding: const EdgeInsets.only(top: 8, bottom: 16), @@ -189,12 +353,103 @@ class _DiaryScreenState extends State { diaryDay.meals[currentSelectedMealNumber - 1].photos, diaryDay, ), + _satietyRating(), ], ), ), ); } + _chart() { + final List chartData = [ + ChartData(1924, 200, '100%', Colors.blue), + ChartData(1925, 50, '100%', Colors.green), + ChartData(1926, 70, '100%', Colors.red), + ChartData(1926, 70, '100%', Colors.brown), + ]; + + 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, + ), + ), + 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, + ), + ], + ), + ), + ), + ), + _chartData('Калории', '0 ккал'), + const SizedBox(height: 8), + _chartData('Белки', '0 грамм'), + const SizedBox(height: 8), + _chartData('Жиры', '0 грамм'), + const SizedBox(height: 8), + _chartData('Углеводы', '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, @@ -271,6 +526,7 @@ class _DiaryScreenState extends State { child: IconButton.filled( style: IconButton.styleFrom( backgroundColor: Colors.white, + elevation: 0, ), onPressed: () async { await diaryCubit.deletePhoto( @@ -669,3 +925,16 @@ class _DiaryScreenState extends State { ); } } + +class ChartData { + int x, y; + String text; + Color color; + + ChartData( + this.x, + this.y, + this.text, + this.color, + ); +} diff --git a/lib/main.dart b/lib/main.dart index ce09857f..816adbe7 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -11,7 +11,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:keyboard_dismisser/keyboard_dismisser.dart'; -Future main() async { +void main() async { WidgetsFlutterBinding.ensureInitialized(); await di.init(); runApp(MyApp()); diff --git a/pubspec.yaml b/pubspec.yaml index b589dd00..080157d0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -50,6 +50,7 @@ dependencies: rive: ^0.13.15 mask_text_input_formatter: ^2.9.0 lottie: ^3.1.3 + flutter_rating_bar: ^4.0.1 dev_dependencies: build_runner: ^2.4.13