forked from eatvio/eatvio_app
Finished circumference charts
This commit is contained in:
@@ -108,6 +108,9 @@ final Map<String, String> ru = {
|
||||
|
||||
// Личный кабинет Screen
|
||||
"loading": "Загрузка...",
|
||||
"weight_chart": "График веса",
|
||||
"circumferences_chart": "График обхватов",
|
||||
"bodymass_chart": "График ИМТ",
|
||||
"exit": "Выйти",
|
||||
"my_blog": "Мой блог", "lbl_01_04_21": "01.04.21", "lbl_01_05_21": "01.05.21",
|
||||
|
||||
|
||||
@@ -53,8 +53,10 @@ class MyProfileBloc extends Bloc<MyProfileEvent, MyProfileState> {
|
||||
);
|
||||
final data = jsonDecode(response.body);
|
||||
emit(state.copyWith(
|
||||
user: data['user'],
|
||||
chartPoints: data['chartPoints'],
|
||||
userDetails: data['userDetails']));
|
||||
user: data['user'],
|
||||
chartPoints: data['chartPoints'],
|
||||
userDetails: data['userDetails'],
|
||||
circumferences: data['circumferences'],
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,24 +5,32 @@ part of 'my_profile_bloc.dart';
|
||||
/// Represents the state of MyProfile in the application.
|
||||
class MyProfileState extends Equatable {
|
||||
MyProfileState(
|
||||
{this.myProfileModelObj, this.user, this.userDetails, this.chartPoints});
|
||||
{this.myProfileModelObj,
|
||||
this.user,
|
||||
this.userDetails,
|
||||
this.chartPoints,
|
||||
this.circumferences});
|
||||
|
||||
MyProfileModel? myProfileModelObj;
|
||||
Map<String, dynamic>? user;
|
||||
Map<String, dynamic>? userDetails;
|
||||
Map<String, dynamic>? chartPoints;
|
||||
Map<String, dynamic>? circumferences;
|
||||
|
||||
@override
|
||||
List<Object?> get props => [myProfileModelObj, user, chartPoints];
|
||||
List<Object?> get props =>
|
||||
[myProfileModelObj, user, chartPoints, circumferences];
|
||||
MyProfileState copyWith(
|
||||
{MyProfileModel? myProfileModelObj,
|
||||
Map<String, dynamic>? user,
|
||||
Map<String, dynamic>? userDetails,
|
||||
Map<String, dynamic>? chartPoints}) {
|
||||
Map<String, dynamic>? chartPoints,
|
||||
Map<String, dynamic>? circumferences}) {
|
||||
return MyProfileState(
|
||||
myProfileModelObj: myProfileModelObj ?? this.myProfileModelObj,
|
||||
user: user ?? this.user,
|
||||
userDetails: userDetails ?? this.userDetails,
|
||||
circumferences: circumferences ?? this.circumferences,
|
||||
chartPoints: chartPoints ?? this.chartPoints);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,17 +40,6 @@ class MyProfileScreen extends StatelessWidget {
|
||||
SizedBox(height: 15.v),
|
||||
_buildSettings(context),
|
||||
SizedBox(height: 30.v),
|
||||
/*_buildChart(
|
||||
context,
|
||||
state.chartPoints?.values
|
||||
.map<int>((e) => e['weight'])
|
||||
.toList()
|
||||
.map((i) => i.toDouble())
|
||||
.toList() ??
|
||||
[0.0, 0.0, 0.0, 0.0],
|
||||
state.chartPoints?.values
|
||||
.map<String>((e) => e['created_at'])
|
||||
.toList()),*/
|
||||
CarouselSlider(
|
||||
options: CarouselOptions(height: 370.0),
|
||||
items: [1, 2, 3].map((chartType) {
|
||||
@@ -58,10 +47,16 @@ class MyProfileScreen extends StatelessWidget {
|
||||
builder: (BuildContext context) {
|
||||
switch (chartType) {
|
||||
case 1: // График веса
|
||||
return Container(
|
||||
decoration:
|
||||
BoxDecoration(color: Colors.white),
|
||||
child: _buildChart(
|
||||
return Column(children: [
|
||||
Text(
|
||||
"weight_chart".tr,
|
||||
style: CustomTextStyles.titleMediumBlack
|
||||
.copyWith(
|
||||
color: appTheme.black900,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 50.v),
|
||||
_buildChart(
|
||||
context,
|
||||
state.chartPoints?.values
|
||||
.map<int>((e) => e['weight'])
|
||||
@@ -72,29 +67,48 @@ class MyProfileScreen extends StatelessWidget {
|
||||
state.chartPoints?.values
|
||||
.map<String>((e) => e['created_at'])
|
||||
.toList()),
|
||||
);
|
||||
]);
|
||||
case 2: // График ИМТ
|
||||
return Container(
|
||||
decoration:
|
||||
BoxDecoration(color: Colors.white),
|
||||
child: _buildChart(
|
||||
return Column(children: [
|
||||
Text(
|
||||
"bodymass_chart".tr,
|
||||
style: CustomTextStyles.titleMediumBlack
|
||||
.copyWith(
|
||||
color: appTheme.black900,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 50.v),
|
||||
_buildChart(
|
||||
context,
|
||||
_bodyMassIndex(
|
||||
state.chartPoints!.values
|
||||
state.chartPoints?.values
|
||||
.map<int>((e) => e['weight'])
|
||||
.toList()
|
||||
.map((i) => i.toDouble())
|
||||
.toList(),
|
||||
state.userDetails!['height']
|
||||
.toInt()) ??
|
||||
[0.0, 0.0, 0.0, 0.0],
|
||||
.toList() ??
|
||||
[10.0, 20.0, 30.0, 40.0],
|
||||
state.userDetails?['height']
|
||||
.toInt() ??
|
||||
160),
|
||||
state.chartPoints?.values
|
||||
.map<String>((e) => e['created_at'])
|
||||
.toList()),
|
||||
);
|
||||
case 3:
|
||||
return Text('text',
|
||||
style: TextStyle(fontSize: 16.0));
|
||||
]);
|
||||
case 3: //График обхватов
|
||||
return Column(children: [
|
||||
Text(
|
||||
"circumferences_chart".tr,
|
||||
style: CustomTextStyles.titleMediumBlack
|
||||
.copyWith(
|
||||
color: appTheme.black900,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 50.v),
|
||||
_buildCircumferenceChart(
|
||||
context,
|
||||
state.circumferences,
|
||||
)
|
||||
]);
|
||||
default:
|
||||
return Text('text',
|
||||
style: TextStyle(fontSize: 16.0));
|
||||
@@ -175,12 +189,6 @@ class MyProfileScreen extends StatelessWidget {
|
||||
|
||||
/// Section Widget
|
||||
Widget _buildChart(BuildContext context, List<double> chartPoints, dates) {
|
||||
// Определение данных для графика
|
||||
/* List<FlSpot> chartData = chartPoints
|
||||
.map((point) =>
|
||||
FlSpot(point['created_at'] as double, point['weight'] as double))
|
||||
.toList(); */
|
||||
|
||||
// Определение осей графика
|
||||
List<FlSpot> spots = [];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
@@ -188,7 +196,6 @@ class MyProfileScreen extends StatelessWidget {
|
||||
FlSpot((i * 10 / 10) + 1, chartPoints[i]),
|
||||
);
|
||||
}
|
||||
print(spots);
|
||||
|
||||
Widget bottomTitleWidgets(double value, TitleMeta meta, double chartWidth) {
|
||||
if (value % 1 != 0) {
|
||||
@@ -332,6 +339,206 @@ class MyProfileScreen extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCircumferenceChart(BuildContext context, chartPoints) {
|
||||
// Определение осей графика
|
||||
final chestCircumferences =
|
||||
chartPoints.values.map((e) => e['chest_circumference']).toList();
|
||||
List<FlSpot> 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<FlSpot> 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<FlSpot> 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) {
|
||||
if (value % 1 != 0) {
|
||||
return Container();
|
||||
}
|
||||
final style = TextStyle(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: min(18, 18 * chartWidth / 300),
|
||||
);
|
||||
return SideTitleWidget(
|
||||
axisSide: meta.axisSide,
|
||||
space: 16,
|
||||
child: Text(meta.formattedValue, style: style),
|
||||
);
|
||||
}
|
||||
|
||||
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,
|
||||
bottom: 12,
|
||||
right: 20,
|
||||
top: 18,
|
||||
),
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1,
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
return LineChart(
|
||||
LineChartData(
|
||||
lineTouchData: LineTouchData(
|
||||
touchTooltipData: LineTouchTooltipData(
|
||||
maxContentWidth: 100,
|
||||
tooltipBgColor: Colors.black,
|
||||
getTooltipItems: (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();
|
||||
},
|
||||
),
|
||||
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),
|
||||
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: (value) {
|
||||
return value.toInt() == 0;
|
||||
},
|
||||
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: (value) {
|
||||
return value.toInt() == 0;
|
||||
},
|
||||
),
|
||||
borderData: FlBorderData(show: false),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Section Widget
|
||||
Widget _buildWidget(BuildContext context) {
|
||||
return Padding(
|
||||
|
||||
Reference in New Issue
Block a user