diff --git a/lib/presentation/profile/my_profile_screen/my_profile_screen.dart b/lib/presentation/profile/my_profile_screen/my_profile_screen.dart index d10b70ab..03b9f4b2 100644 --- a/lib/presentation/profile/my_profile_screen/my_profile_screen.dart +++ b/lib/presentation/profile/my_profile_screen/my_profile_screen.dart @@ -1,23 +1,26 @@ import 'dart:convert'; -import 'dart:math'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:carousel_slider_plus/carousel_slider_plus.dart'; import 'package:eatvio_app/core/app_export.dart'; import 'package:eatvio_app/widgets/app_bar/appbar_subtitle.dart'; import 'package:eatvio_app/widgets/custom_text_form_field.dart'; -import 'package:fl_chart/fl_chart.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:go_router/go_router.dart'; import 'package:http/http.dart' as http; import 'package:image_picker/image_picker.dart'; -import 'package:intl/intl.dart'; +import 'package:syncfusion_flutter_charts/charts.dart'; import 'bloc/my_profile_bloc.dart'; import 'models/my_profile_model.dart'; class MyProfileScreen extends StatelessWidget { + int valuteToInt(String value) { + // Преобразование строки в целое число + return int.tryParse(value) ?? 0; // Возвращает 0, если преобразование не удалось + } + static Widget builder(BuildContext context) { return BlocProvider( create: (context) => MyProfileBloc( @@ -192,7 +195,7 @@ class MyProfileScreen extends StatelessWidget { _buildCarousel(BuildContext contex, MyProfileLoadedState state) { return CarouselSlider( - options: CarouselOptions(height: 340), + options: CarouselOptions(height: 370), items: [1, 2, 3].map((chartType) { return Builder( builder: (BuildContext context) { @@ -249,7 +252,7 @@ class MyProfileScreen extends StatelessWidget { ), ), SizedBox(height: 30.v), - _buildCircumferenceChart(context, state.circumferences, state.chartDates), + // _buildCircumferenceChart(context, state.circumferences, state.chartDates), _buildChartLegend(), ], ), @@ -295,355 +298,35 @@ class MyProfileScreen extends StatelessWidget { ); } - _buildChart(BuildContext context, List chartPoints, List? dates) { - List spots = []; - for (int i = 0; i < 4; i++) { - spots.add( - FlSpot((i * 10 / 10) + 1, chartPoints[i]), - ); + Widget _buildChart(BuildContext context, List chartPoints, List? dates) { + // Проверяем, что у нас есть 4 элемента в обоих списках + if (chartPoints.length != 4 || (dates != null && dates.length != 4)) { + return Center(child: Text('Должно быть ровно 4 точки и 4 даты.')); } - Widget bottomTitleWidgets(double value, TitleMeta meta, double chartWidth, List? dates) { - if (value % 1 != 0) { - return Container(); - } - final style = TextStyle( - color: Colors.blue, - fontWeight: FontWeight.bold, - fontSize: min(13, 13 * chartWidth / 300), - ); - int index = value.toInt(); - if (index >= 0 && index < dates!.length) { - // Проверка на допустимый индекс в массиве dates - String formattedDate = DateFormat('dd.MM').format(DateTime.parse(dates[index])); - return SideTitleWidget( - axisSide: meta.axisSide, - space: 16, - child: Text(formattedDate, style: style), - ); - } else { - return Container(); - } - } + // Преобразуем данные в список точек для графика + List chartData = List.generate(4, (index) { + return ChartData(dates![index], chartPoints[index]); + }); - Widget leftTitleWidgets(double value, TitleMeta meta, double chartWidth) { - final style = TextStyle( - color: Colors.blue, - fontWeight: FontWeight.bold, - fontSize: min(18, 18 * chartWidth / 300), - ); - return SideTitleWidget( - axisSide: meta.axisSide, - space: 16, - child: Text(meta.formattedValue, style: style), - ); - } - - return Padding( - padding: const EdgeInsets.only( - left: 12, - right: 20, - ), - child: AspectRatio( - aspectRatio: 1, - child: LayoutBuilder( - builder: (context, constraints) { - return LineChart( - LineChartData( - lineTouchData: LineTouchData( - touchTooltipData: LineTouchTooltipData( - maxContentWidth: 100, - // tooltipBgColor: Colors.black, - getTooltipItems: mapSpots(), - ), - handleBuiltInTouches: true, - getTouchLineStart: (data, index) => 0, - ), - lineBarsData: [ - LineChartBarData( - color: Colors.pink, - spots: spots, - isCurved: true, - isStrokeCapRound: true, - barWidth: 3, - belowBarData: BarAreaData( - show: false, - ), - dotData: const FlDotData(show: false), - ), - ], - minY: chartPoints.reduce((value, element) => value < element ? value : element), - maxY: chartPoints.reduce((value, element) => value > element ? value : element), - minX: 1, - maxX: 4, - titlesData: FlTitlesData( - leftTitles: AxisTitles( - sideTitles: SideTitles( - showTitles: true, - getTitlesWidget: (value, meta) => leftTitleWidgets(value, meta, constraints.maxWidth), - reservedSize: 56, - ), - drawBelowEverything: true, - ), - rightTitles: const AxisTitles( - sideTitles: SideTitles(showTitles: false), - ), - bottomTitles: AxisTitles( - sideTitles: SideTitles( - showTitles: true, - getTitlesWidget: (value, meta) => bottomTitleWidgets(value, meta, constraints.maxWidth, dates), - reservedSize: 36, - interval: 1, - ), - drawBelowEverything: true, - ), - topTitles: const AxisTitles( - sideTitles: SideTitles(showTitles: false), - ), - ), - gridData: FlGridData( - show: true, - drawHorizontalLine: true, - drawVerticalLine: true, - horizontalInterval: 1.5, - verticalInterval: 5, - checkToShowHorizontalLine: valuteToInt(), - getDrawingHorizontalLine: (_) => FlLine( - color: Colors.blue.withOpacity(1), - dashArray: [8, 2], - strokeWidth: 0.8, - ), - getDrawingVerticalLine: (_) => FlLine( - color: Colors.blue.withOpacity(1), - dashArray: [8, 2], - strokeWidth: 0.8, - ), - checkToShowVerticalLine: valuteToInt(), - ), - borderData: FlBorderData(show: false), - ), - ); - }, - ), + return Container( + height: 300, // Задайте нужную высоту для графика + child: SfCartesianChart( + title: ChartTitle(text: 'График значений'), + primaryXAxis: CategoryAxis(), + series: >[ + // Изменяем на CartesianSeries + LineSeries( + dataSource: chartData, + xValueMapper: (ChartData data, _) => data.date, + yValueMapper: (ChartData data, _) => data.value, + dataLabelSettings: DataLabelSettings(isVisible: true), + ), + ], ), ); } - valuteToInt() { - return (value) { - return value.toInt() == 0; - }; - } - - List Function(List) mapSpots() { - return (touchedSpots) { - return touchedSpots.map((LineBarSpot touchedSpot) { - final textStyle = TextStyle( - color: touchedSpot.bar.gradient?.colors[0] ?? touchedSpot.bar.color, - fontWeight: FontWeight.bold, - fontSize: 14, - ); - return LineTooltipItem( - '${touchedSpot.x}, ${touchedSpot.y.toStringAsFixed(2)}', - textStyle, - ); - }).toList(); - }; - } - - _buildCircumferenceChart(BuildContext context, chartPoints, List? dates) { -// Определение осей графика - final chestCircumferences = chartPoints.values.map((e) => e['chest_circumference']).toList(); - List spotsChest = []; - for (int i = 0; i < 4; i++) { - chestCircumferences[i] = chestCircumferences[i] * 10 / 10; - spotsChest.add( - FlSpot((i * 10 / 10) + 1, chestCircumferences[i] * 10 / 10), - ); - } - final waistCircumferences = chartPoints.values.map((e) => e['waist_circumference']).toList(); - List spotsWaist = []; - for (int i = 0; i < 4; i++) { - waistCircumferences[i] = waistCircumferences[i] * 10 / 10; - spotsWaist.add( - FlSpot((i * 10 / 10) + 1, waistCircumferences[i] * 10 / 10), - ); - } - final hipCircumferences = chartPoints.values.map((e) => e['hip_circumference']).toList(); - List spotsHip = []; - for (int i = 0; i < 4; i++) { - hipCircumferences[i] = hipCircumferences[i] * 10 / 10; - spotsHip.add( - FlSpot((i * 10 / 10) + 1, hipCircumferences[i]), - ); - } - - final allCircumferences = [...chestCircumferences, ...hipCircumferences, ...waistCircumferences]; - - Widget bottomTitleWidgets(double value, TitleMeta meta, double chartWidth, List? dates) { - if (value % 1 != 0) { - return Container(); - } - final style = TextStyle( - color: Colors.blue, - fontWeight: FontWeight.bold, - fontSize: min(13, 13 * chartWidth / 300), - ); - int index = value.toInt(); - if (index >= 0 && index < dates!.length) { - // Проверка на допустимый индекс в массиве dates - String formattedDate = DateFormat('dd.MM').format(DateTime.parse(dates[index])); - return SideTitleWidget( - axisSide: meta.axisSide, - space: 16, - child: Text(formattedDate, style: style), - ); - } else { - return Container(); - } - } - - Widget leftTitleWidgets(double value, TitleMeta meta, double chartWidth) { - final style = TextStyle( - color: Colors.blue, - fontWeight: FontWeight.bold, - fontSize: min(18, 18 * chartWidth / 300), - ); - return SideTitleWidget( - axisSide: meta.axisSide, - space: 16, - child: Text(meta.formattedValue, style: style), - ); - } - - return Padding( - padding: const EdgeInsets.only( - left: 12, - right: 20, - ), - child: AspectRatio( - aspectRatio: 1, - child: LayoutBuilder( - builder: (context, constraints) { - return LineChart( - LineChartData( - lineTouchData: LineTouchData( - touchTooltipData: LineTouchTooltipData( - maxContentWidth: 100, - // tooltipBgColor: Colors.black, - getTooltipItems: mapTouchedSpots(), - ), - handleBuiltInTouches: true, - getTouchLineStart: (data, index) => 0, - ), - lineBarsData: [ - LineChartBarData( - color: Colors.pink, - spots: spotsChest, - isCurved: true, - isStrokeCapRound: true, - barWidth: 3, - belowBarData: BarAreaData( - show: false, - ), - dotData: const FlDotData(show: false), - ), - LineChartBarData( - color: Colors.green, - spots: spotsWaist, - isCurved: true, - isStrokeCapRound: true, - barWidth: 3, - belowBarData: BarAreaData( - show: false, - ), - dotData: const FlDotData(show: false), - ), - LineChartBarData( - color: Colors.purple, - spots: spotsHip, - isCurved: true, - isStrokeCapRound: true, - barWidth: 3, - belowBarData: BarAreaData( - show: false, - ), - dotData: const FlDotData(show: false), - ), - ], - minY: allCircumferences.reduce((value, element) => value < element ? value : element), - maxY: allCircumferences.reduce((value, element) => value > element ? value : element), - minX: 1, - maxX: 4, - titlesData: FlTitlesData( - leftTitles: AxisTitles( - sideTitles: SideTitles( - showTitles: true, - getTitlesWidget: (value, meta) => leftTitleWidgets(value, meta, constraints.maxWidth), - reservedSize: 56, - ), - drawBelowEverything: true, - ), - rightTitles: const AxisTitles( - sideTitles: SideTitles(showTitles: false), - ), - bottomTitles: AxisTitles( - sideTitles: SideTitles( - showTitles: true, - getTitlesWidget: (value, meta) => bottomTitleWidgets(value, meta, constraints.maxWidth, dates), - reservedSize: 36, - interval: 1, - ), - drawBelowEverything: true, - ), - topTitles: const AxisTitles( - sideTitles: SideTitles(showTitles: false), - ), - ), - gridData: FlGridData( - show: true, - drawHorizontalLine: true, - drawVerticalLine: true, - horizontalInterval: 1.5, - verticalInterval: 5, - checkToShowHorizontalLine: valuteToInt(), - getDrawingHorizontalLine: (_) => FlLine( - color: Colors.blue.withOpacity(1), - dashArray: [8, 2], - strokeWidth: 0.8, - ), - getDrawingVerticalLine: (_) => FlLine( - color: Colors.blue.withOpacity(1), - dashArray: [8, 2], - strokeWidth: 0.8, - ), - checkToShowVerticalLine: valuteToInt(), - ), - borderData: FlBorderData(show: false), - ), - ); - }, - ), - ), - ); - } - - List Function(List) mapTouchedSpots() { - return (touchedSpots) { - return touchedSpots.map((LineBarSpot touchedSpot) { - final textStyle = TextStyle( - color: touchedSpot.bar.gradient?.colors[0] ?? touchedSpot.bar.color, - fontWeight: FontWeight.bold, - fontSize: 14, - ); - return LineTooltipItem( - '${touchedSpot.x}, ${touchedSpot.y.toStringAsFixed(2)}', - textStyle, - ); - }).toList(); - }; - } - /// Section Widget _buildPlans(BuildContext context, List? plans, List? imagePaths, List? states) { return Padding( @@ -962,3 +645,16 @@ class MyProfileScreen extends StatelessWidget { }; } } + +class ChartData { + final String date; + final double value; + + ChartData(this.date, this.value); + + valuteToInt() { + return (value) { + return value.toInt() == 0; + }; + } +}