Commit 3a39548

derdilla <derdilla06@gmail.com>
2023-07-25 07:17:42
extract bar data to reusable function
1 parent f30fc7a
Changed files (2)
lib/components/measurement_graph.dart
@@ -1,10 +1,10 @@
-import 'dart:collection';
 import 'dart:math';
 
 import 'package:blood_pressure_app/components/consistent_future_builder.dart';
 import 'package:blood_pressure_app/components/display_interval_picker.dart';
 import 'package:blood_pressure_app/model/blood_pressure.dart';
 import 'package:blood_pressure_app/model/settings_store.dart';
+import 'package:collection/collection.dart';
 import 'package:fl_chart/fl_chart.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_gen/gen_l10n/app_localizations.dart';
@@ -30,149 +30,141 @@ class _LineChartState extends State<_LineChart> {
         Align(
           alignment: Alignment.topCenter,
           child: SizedBox(
-              height: widget.height,
-              child: Consumer<Settings>(
-                builder: (context, settings, child) {
-                  return Consumer<BloodPressureModel>(builder: (context, model, child) {
-                    var end = settings.displayDataEnd;
-                    return ConsistentFutureBuilder<UnmodifiableListView<BloodPressureRecord>>(
-                      future: (settings.graphStepSize == TimeStep.lifetime)
-                          ? model.all
-                          : model.getInTimeRange(settings.displayDataStart, end),
-                      onData: (context, fetchedData) {
-                        List<BloodPressureRecord> data = fetchedData.toList();
-                        data.sort((a, b) => a.creationTime.compareTo(b.creationTime));
-
-                        List<FlSpot> pulSpots = [];
-                        List<FlSpot> diaSpots = [];
-                        List<FlSpot> sysSpots = [];
-                        int pulMax = 0;
-                        int diaMax = 0;
-                        int sysMax = 0;
-                        for (var e in data) {
-                          final x = e.creationTime.millisecondsSinceEpoch.toDouble();
-                          if (e.diastolic != null) {
-                            diaSpots.add(FlSpot(x, e.diastolic!.toDouble()));
-                            diaMax = max(diaMax, e.diastolic!);
-                          }
-                          if (e.systolic != null) {
-                            sysSpots.add(FlSpot(x, e.systolic!.toDouble()));
-                            sysMax = max(sysMax, e.systolic!);
-                          }
-                          if (e.pulse != null) {
-                            pulSpots.add(FlSpot(x, e.pulse!.toDouble()));
-                            pulMax = max(pulMax, e.pulse!);
-                          }
-                        }
+            height: widget.height,
+            child: Consumer<Settings>(
+              builder: (context, settings, child) {
+                return Consumer<BloodPressureModel>(builder: (context, model, child) {
+                  var end = settings.displayDataEnd;
+                  return ConsistentFutureBuilder<UnmodifiableListView<BloodPressureRecord>>(
+                    future: (settings.graphStepSize == TimeStep.lifetime)
+                        ? model.all
+                        : model.getInTimeRange(settings.displayDataStart, end),
+                    onData: (context, fetchedData) {
+                      List<BloodPressureRecord> data = fetchedData.toList();
+                      data.sort((a, b) => a.creationTime.compareTo(b.creationTime));
 
-                        if (fetchedData.length < 2 || (diaSpots.length < 2 && sysSpots.length < 2 && pulSpots.length < 2)) {
-                          return Text(AppLocalizations.of(context)!.errNotEnoughDataToGraph);
+                      List<FlSpot> pulSpots = [];
+                      List<FlSpot> diaSpots = [];
+                      List<FlSpot> sysSpots = [];
+                      int pulMax = 0;
+                      int diaMax = 0;
+                      int sysMax = 0;
+                      for (var e in data) {
+                        final x = e.creationTime.millisecondsSinceEpoch.toDouble();
+                        if (e.diastolic != null) {
+                          diaSpots.add(FlSpot(x, e.diastolic!.toDouble()));
+                          diaMax = max(diaMax, e.diastolic!);
+                        }
+                        if (e.systolic != null) {
+                          sysSpots.add(FlSpot(x, e.systolic!.toDouble()));
+                          sysMax = max(sysMax, e.systolic!);
                         }
+                        if (e.pulse != null) {
+                          pulSpots.add(FlSpot(x, e.pulse!.toDouble()));
+                          pulMax = max(pulMax, e.pulse!);
+                        }
+                      }
 
-                        const noTitels = AxisTitles(sideTitles: SideTitles(reservedSize: 40, showTitles: false));
-                        return LineChart(
-                          LineChartData(
-                            minY: settings.validateInputs ? 30 : 0,
-                            maxY: max(pulMax.toDouble(), max(diaMax.toDouble(), sysMax.toDouble())) + 5,
-                            titlesData: FlTitlesData(
-                              topTitles: noTitels,
-                              rightTitles: noTitels,
-                              bottomTitles: AxisTitles(
-                                sideTitles: SideTitles(
-                                  showTitles: true,
-                                  interval: _lineChartTitleIntervall,
-                                  getTitlesWidget: (double pos, TitleMeta meta) {
-                                    // calculate new intervall
-                                    // as graphWidth can technically be as low as one max is needed here to avoid freezes
-                                    double graphWidth = meta.max - meta.min;
-                                    if ((max(graphWidth - 2,1) / settings.graphTitlesCount) != _lineChartTitleIntervall) {
-                                      // simple hack needed to change the state during build
-                                      // https://stackoverflow.com/a/63607696/21489239
-                                      Future.delayed(Duration.zero, () async {
-                                        setState(() {
-                                          _lineChartTitleIntervall = max(graphWidth - 2,1) / settings.graphTitlesCount;
-                                        });
+                      if (fetchedData.length < 2 || (diaSpots.length < 2 && sysSpots.length < 2 && pulSpots.length < 2)) {
+                        return Text(AppLocalizations.of(context)!.errNotEnoughDataToGraph);
+                      }
+
+                      const noTitels = AxisTitles(sideTitles: SideTitles(reservedSize: 40, showTitles: false));
+                      return LineChart(
+                        LineChartData(
+                          minY: settings.validateInputs ? 30 : 0,
+                          maxY: max(pulMax.toDouble(), max(diaMax.toDouble(), sysMax.toDouble())) + 5,
+                          titlesData: FlTitlesData(
+                            topTitles: noTitels,
+                            rightTitles: noTitels,
+                            bottomTitles: AxisTitles(
+                              sideTitles: SideTitles(
+                                showTitles: true,
+                                interval: _lineChartTitleIntervall,
+                                getTitlesWidget: (double pos, TitleMeta meta) {
+                                  // calculate new intervall
+                                  // as graphWidth can technically be as low as one max is needed here to avoid freezes
+                                  double graphWidth = meta.max - meta.min;
+                                  if ((max(graphWidth - 2,1) / settings.graphTitlesCount) != _lineChartTitleIntervall) {
+                                    // simple hack needed to change the state during build
+                                    // https://stackoverflow.com/a/63607696/21489239
+                                    Future.delayed(Duration.zero, () async {
+                                      setState(() {
+                                        _lineChartTitleIntervall = max(graphWidth - 2,1) / settings.graphTitlesCount;
                                       });
-                                    }
-
-                                    // don't show fixed titles, as they are replaced by long dates below
-                                    if (meta.axisPosition <= 1 || pos >= meta.max) {
-                                      return const SizedBox.shrink();
-                                    }
-
-                                    late final DateFormat formatter;
-                                    switch (settings.graphStepSize) {
-                                      case TimeStep.day:
-                                        formatter = DateFormat('H:m');
-                                        break;
-                                      case TimeStep.month:
-                                      case TimeStep.last7Days:
-                                        formatter = DateFormat('d');
-                                        break;
-                                      case TimeStep.week:
-                                        formatter = DateFormat('E');
-                                        break;
-                                      case TimeStep.year:
-                                        formatter = DateFormat('MMM');
-                                        break;
-                                      case TimeStep.lifetime:
-                                        formatter = DateFormat('yyyy');
-                                        break;
-                                      case TimeStep.last30Days:
-                                      case TimeStep.custom:
-                                        formatter = DateFormat.MMMd();
-                                    }
-                                    return Text(formatter
-                                        .format(DateTime.fromMillisecondsSinceEpoch(pos.toInt())));
-                                  }),
-                                ),
-                              ),
-                              lineTouchData: const LineTouchData(
-                                  touchTooltipData:
-                                  LineTouchTooltipData(tooltipMargin: -200, tooltipRoundedRadius: 20)),
-                              lineBarsData: [
-                                LineChartBarData(
-                                  spots: pulSpots,
-                                  dotData: const FlDotData(
-                                    show: false,
-                                  ),
-                                  color: settings.pulColor,
-                                  barWidth: settings.graphLineThickness,
+                                    });
+                                  }
+
+                                  // don't show fixed titles, as they are replaced by long dates below
+                                  if (meta.axisPosition <= 1 || pos >= meta.max) {
+                                    return const SizedBox.shrink();
+                                  }
+
+                                  late final DateFormat formatter;
+                                  switch (settings.graphStepSize) {
+                                    case TimeStep.day:
+                                      formatter = DateFormat('H:m');
+                                      break;
+                                    case TimeStep.month:
+                                    case TimeStep.last7Days:
+                                      formatter = DateFormat('d');
+                                      break;
+                                    case TimeStep.week:
+                                      formatter = DateFormat('E');
+                                      break;
+                                    case TimeStep.year:
+                                      formatter = DateFormat('MMM');
+                                      break;
+                                    case TimeStep.lifetime:
+                                      formatter = DateFormat('yyyy');
+                                      break;
+                                    case TimeStep.last30Days:
+                                    case TimeStep.custom:
+                                      formatter = DateFormat.MMMd();
+                                  }
+                                  return Text(formatter
+                                      .format(DateTime.fromMillisecondsSinceEpoch(pos.toInt())));
+                                }
                                 ),
-                                LineChartBarData(
-                                    spots: diaSpots,
-                                    color: settings.diaColor,
-                                    barWidth: settings.graphLineThickness,
-                                    dotData: const FlDotData(
-                                      show: false,
-                                    ),
-                                    belowBarData: BarAreaData(
-                                        show: true,
-                                        color: Colors.red.shade400.withAlpha(100),
-                                        cutOffY: settings.diaWarn.toDouble(),
-                                        applyCutOffY: true)),
-                                LineChartBarData(
-                                    spots: sysSpots,
-                                    color: settings.sysColor,
-                                    barWidth: settings.graphLineThickness,
-                                    dotData: const FlDotData(
-                                      show: false,
-                                    ),
-                                    belowBarData: BarAreaData(
-                                        show: true,
-                                        color: Colors.red.shade400.withAlpha(100),
-                                        cutOffY: settings.sysWarn.toDouble(),
-                                        applyCutOffY: true))
-                              ]));
-                      }
-                    );
-                  });
-                },
-              )),
+                            ),
+                          ),
+                          lineTouchData: const LineTouchData(
+                              touchTooltipData:
+                              LineTouchTooltipData(tooltipMargin: -200, tooltipRoundedRadius: 20)),
+                          lineBarsData: [
+                            _buildBarData(settings, sysSpots, settings.sysColor, true, settings.sysWarn.toDouble()),
+                            _buildBarData(settings, diaSpots, settings.diaColor, true, settings.diaWarn.toDouble()),
+                            _buildBarData(settings, pulSpots, settings.pulColor, false),
+                          ]
+                        )
+                      );
+                    }
+                  );
+                });
+              },
+            )
+          ),
         ),
       ],
     );
   }
+
+  LineChartBarData _buildBarData(Settings settings, List<FlSpot> spots, Color color, bool hasAreaData, [double? areaDataCutOff]) {
+    return LineChartBarData(
+        spots: spots,
+        color: color,
+        barWidth: settings.graphLineThickness,
+        dotData: const FlDotData(
+          show: false,
+        ),
+          belowBarData: BarAreaData(
+              show: hasAreaData,
+              color: Colors.red.shade400.withAlpha(100),
+              cutOffY: areaDataCutOff ?? 0,
+              applyCutOffY: true)
+    );
+  }
+
 }
 
 class MeasurementGraph extends StatelessWidget {
pubspec.yaml
@@ -49,6 +49,7 @@ dependencies:
   pdf: ^3.10.4
   jsaver: ^1.2.0
   package_info_plus: ^4.0.2
+  collection: any
 
 dev_dependencies:
   flutter_test: