Commit eadaace

derdilla <derdilla06@gmail.com>
2023-07-27 09:37:16
animate graph
1 parent ca1d6a1
lib/components/consistent_future_builder.dart
@@ -30,5 +30,47 @@ class ConsistentFutureBuilder<T> extends StatelessWidget {
         }
       });
   }
+}
 
+class ConsistentAnimatedFutureBuilder<T> extends StatelessWidget {
+  final Future<T> future;
+  final Widget Function(BuildContext context, T result) onData;
+
+  final Widget? onNotStarted;
+  final Widget? onWaiting;
+  final Widget? Function(BuildContext context, String errorMsg)? onError;
+
+  final Duration duration;
+
+  const ConsistentAnimatedFutureBuilder({super.key, required this.future, this.onNotStarted, this.onWaiting, this.onError,
+    required this.onData, this.duration = const Duration(milliseconds: 300)});
+
+  @override
+  Widget build(BuildContext context) {
+    return FutureBuilder<T>(
+        future: future,
+        builder: (BuildContext context, AsyncSnapshot<T> snapshot) {
+          Widget child;
+          if (snapshot.hasError) {
+            child = Text(AppLocalizations.of(context)!.error(snapshot.error.toString()));
+          } else {
+            switch (snapshot.connectionState) {
+              case ConnectionState.none:
+                child = onNotStarted ?? Text(AppLocalizations.of(context)!.errNotStarted);
+                break;
+              case ConnectionState.waiting:
+              case ConnectionState.active:
+                child = onWaiting ?? Text(AppLocalizations.of(context)!.loading);
+                break;
+              case ConnectionState.done:
+                child = onData(context, snapshot.data as T);
+            }
+          }
+          return AnimatedSwitcher(
+            duration: duration,
+            child: child,
+          );
+
+        });
+  }
 }
\ No newline at end of file
lib/components/measurement_graph.dart
@@ -68,77 +68,31 @@ class _LineChartState extends State<_LineChart> {
                         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())));
-                                }
-                                ),
+                      
+                      return TweenAnimationBuilder<double>(
+                        duration: const Duration(milliseconds: 200), // interacts with LineChart duration property
+                        tween: Tween<double>(begin: 0, end: settings.graphLineThickness),
+                        builder: (context, value, child) {
+                          return LineChart(
+                            LineChartData(
+                                minY: settings.validateInputs ? 30 : 0,
+                                maxY: max(pulMax.toDouble(), max(diaMax.toDouble(), sysMax.toDouble())) + 5,
+                                titlesData: _buildFlTitlesData(settings),
+                                lineTouchData: const LineTouchData(
+                                    touchTooltipData: LineTouchTooltipData(
+                                        tooltipMargin: -200, tooltipRoundedRadius: 20)),
+                                lineBarsData: [
+                                  _buildBarData(value, sysSpots, settings.sysColor, true, settings.sysWarn.toDouble()),
+                                  _buildBarData(value, diaSpots, settings.diaColor, true, settings.diaWarn.toDouble()),
+                                  _buildBarData(value, pulSpots, settings.pulColor, false),
+                                  _buildRegressionLine(sysSpots),
+                                  _buildRegressionLine(diaSpots),
+                                  _buildRegressionLine(pulSpots),
+                                ]
                             ),
-                          ),
-                          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),
-                            _buildRegressionLine(sysSpots),
-                            _buildRegressionLine(diaSpots),
-                            _buildRegressionLine(pulSpots),
-                          ]
-                        )
+                            duration: const Duration(milliseconds: 200),
+                          );
+                        },
                       );
                     }
                   );
@@ -151,11 +105,69 @@ class _LineChartState extends State<_LineChart> {
     );
   }
 
-  LineChartBarData _buildBarData(Settings settings, List<FlSpot> spots, Color color, bool hasAreaData, [double? areaDataCutOff]) {
+  FlTitlesData _buildFlTitlesData(Settings settings) {
+    const noTitels = AxisTitles(sideTitles: SideTitles(reservedSize: 40, showTitles: false));
+    return 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())));
+          }
+        ),
+      ),
+    );
+  }
+
+  LineChartBarData _buildBarData(double lineThickness, List<FlSpot> spots, Color color, bool hasAreaData, [double? areaDataCutOff]) {
     return LineChartBarData(
         spots: spots,
         color: color,
-        barWidth: settings.graphLineThickness,
+        barWidth: lineThickness,
         dotData: const FlDotData(
           show: false,
         ),