feat(diary): add satiety rating bar, calorie graph

This commit is contained in:
mso7nueh
2024-11-08 12:33:52 +03:00
parent 39b43e88ec
commit c1d45d40bc
5 changed files with 289 additions and 1 deletions

View File

@@ -0,0 +1,7 @@
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15 0C6.71667 0 0 6.71667 0 15C0 20.0425 2.49667 24.4933 6.31167 27.2125C6.39833 21.8475 4.4475 15.8333 1.17 15.8333C0.783333 15.8333 0.47 15.8883 0.209167 15.9858C0.461667 15.355 1.00917 15 2.03333 15C5.59167 15 7.58833 22.0883 7.11 27.74C9.405 29.1642 12.1017 30 15 30C17.8992 30 20.5967 29.1633 22.8917 27.7392C22.4108 22.0667 24.4067 15 27.9675 15C28.995 15 29.5442 15.355 29.7942 15.9858C29.5325 15.8883 29.2183 15.8333 28.83 15.8333C25.5483 15.8333 23.5983 21.8325 23.6883 27.2125C27.5042 24.4933 30 20.0425 30 15C30 6.71667 23.2842 0 15 0Z" fill="#FFCC4D"/>
<path d="M15 0C6.71667 0 0 6.71667 0 15C0 15.9933 0.1025 16.9633 0.286667 17.9033C0.481667 17.1842 0.786667 16.4942 1.16833 15.8333C0.7825 15.8333 0.47 15.8883 0.21 15.9858C0.43 15.4367 0.895 15.1125 1.68333 15.0342C4.17667 11.5517 9.1975 9.16667 15 9.16667C20.8033 9.16667 25.8233 11.5508 28.3167 15.0333C29.1083 15.1117 29.575 15.435 29.7933 15.9858C29.5333 15.8883 29.2192 15.8333 28.8325 15.8333C29.2142 16.4942 29.5183 17.1842 29.7142 17.9033C29.8983 16.9633 30 15.9933 30 15C30 6.71667 23.2842 0 15 0Z" fill="#BDDDF4"/>
<path d="M6.12144 9.92495C5.3331 12.5716 6.2106 15.1691 8.08227 15.7266C9.95394 16.2849 12.1106 14.5916 12.8981 11.9449C13.6864 9.29911 12.8098 6.70078 10.9389 6.14328C9.06727 5.58578 6.9106 7.27911 6.12144 9.92495ZM23.8756 9.92495C24.6639 12.5716 23.7864 15.1691 21.9156 15.7266C20.0439 16.2849 17.8873 14.5916 17.0998 11.9449C16.3114 9.29911 17.1889 6.70078 19.0589 6.14328C20.9298 5.58578 23.0864 7.27911 23.8756 9.92495Z" fill="#F5F8FA"/>
<path d="M14.9987 15C12.7012 15 10.832 16.8692 10.832 19.1667V24.1667C10.832 26.4642 12.7012 28.3333 14.9987 28.3333C17.2962 28.3333 19.1654 26.4642 19.1654 24.1667V19.1667C19.1654 16.8692 17.2962 15 14.9987 15Z" fill="#664500"/>
<path d="M1.17111 15.8335C0.784443 15.8335 0.47111 15.8885 0.210277 15.986C0.270277 15.8369 0.349443 15.706 0.444443 15.5894C-1.10722 17.4985 2.37528 23.7835 0.682777 30.0002H6.06611C7.05778 24.2002 5.03694 15.8335 1.17111 15.8335ZM29.7953 15.986C29.5336 15.8885 29.2194 15.8335 28.8311 15.8335C24.9636 15.8335 22.9436 24.1685 23.9369 30.0002H29.3203C27.7319 24.1294 30.7003 18.2594 29.7953 15.986Z" fill="#FCAB40"/>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1,11 @@
<svg width="33" height="33" viewBox="0 0 33 33" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16.9878 30.2021C25.3279 30.2021 32.0888 23.4411 32.0888 15.1011C32.0888 6.76097 25.3279 0 16.9878 0C8.64769 0 1.88672 6.76097 1.88672 15.1011C1.88672 23.4411 8.64769 30.2021 16.9878 30.2021Z" fill="#FFCC4D"/>
<path d="M10.708 19.8169C10.7458 19.9671 11.6879 23.4906 16.9876 23.4906C22.288 23.4906 23.2293 19.9671 23.2671 19.8169C23.3132 19.6348 23.231 19.4461 23.0682 19.3521C22.9047 19.259 22.6999 19.2867 22.5649 19.4167C22.5489 19.4326 20.9256 20.9738 16.9876 20.9738C13.0495 20.9738 11.4253 19.4326 11.4102 19.4175C11.3297 19.3378 11.2223 19.2959 11.1149 19.2959C11.0445 19.2959 10.9731 19.3135 10.9085 19.3496C10.7441 19.4436 10.6619 19.634 10.708 19.8169Z" fill="#664500"/>
<path d="M11.9528 14.2623C13.1112 14.2623 14.0502 12.9476 14.0502 11.326C14.0502 9.70428 13.1112 8.38965 11.9528 8.38965C10.7945 8.38965 9.85547 9.70428 9.85547 11.326C9.85547 12.9476 10.7945 14.2623 11.9528 14.2623Z" fill="#664500"/>
<path d="M22.0192 14.2623C23.1776 14.2623 24.1166 12.9476 24.1166 11.326C24.1166 9.70428 23.1776 8.38965 22.0192 8.38965C20.8609 8.38965 19.9219 9.70428 19.9219 11.326C19.9219 12.9476 20.8609 14.2623 22.0192 14.2623Z" fill="#664500"/>
<path d="M2.72313 24.7491C0.20629 20.5543 2.30366 14.2622 2.30366 14.2622L11.9516 28.9438C11.9516 28.9438 5.23998 28.9438 2.72313 24.7491Z" fill="#FFCC4D" stroke="#FFCC4D"/>
<path d="M16.3648 31.9261C11.4769 31.7286 7.36752 26.5226 7.36752 26.5226L24.9354 26.5128C24.9354 26.5128 21.2527 32.1237 16.3648 31.9261Z" fill="#FFCC4D" stroke="#FFCC4D"/>
<path d="M31.0574 25.2319C28.1005 29.129 21.1818 29.3629 21.1818 29.3629L31.2492 14.2618C31.2492 14.2618 34.0144 21.3349 31.0574 25.2319Z" fill="#FFCC4D" stroke="#FFCC4D"/>
<path d="M2.30503 13.4233C2.30503 13.4233 -0.631285 20.1349 2.30503 24.7491C5.24134 29.3633 11.9529 29.3633 11.9529 29.3633" stroke="#664500" stroke-width="0.2"/>
<path d="M20.3429 29.7829C20.3429 29.7829 28.3129 29.3634 31.2492 25.5882C34.1855 21.8129 31.6687 14.2624 31.6687 14.2624" stroke="#664500" stroke-width="0.2"/>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -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<DiaryScreen> {
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<DiaryScreen> {
_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<DiaryScreen> {
);
}
_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<DiaryScreen> {
diaryDay.meals[currentSelectedMealNumber - 1].photos,
diaryDay,
),
_satietyRating(),
],
),
),
);
}
_chart() {
final List<ChartData> 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: <CircularSeries>[
RadialBarSeries<ChartData, int>(
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<void>(
context: context,
@@ -271,6 +526,7 @@ class _DiaryScreenState extends State<DiaryScreen> {
child: IconButton.filled(
style: IconButton.styleFrom(
backgroundColor: Colors.white,
elevation: 0,
),
onPressed: () async {
await diaryCubit.deletePhoto(
@@ -669,3 +925,16 @@ class _DiaryScreenState extends State<DiaryScreen> {
);
}
}
class ChartData {
int x, y;
String text;
Color color;
ChartData(
this.x,
this.y,
this.text,
this.color,
);
}

View File

@@ -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<void> main() async {
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await di.init();
runApp(MyApp());

View File

@@ -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