Commit 422b5d5

derdilla <82763757+NobodyForNothing@users.noreply.github.com>
2024-08-20 11:37:52
implement graph load animation
Signed-off-by: derdilla <82763757+NobodyForNothing@users.noreply.github.com>
1 parent 272b72a
Changed files (2)
app
lib
features
statistics
screens
app/lib/features/statistics/value_graph.dart
@@ -3,6 +3,7 @@ import 'dart:ui' as ui;
 
 import 'package:blood_pressure_app/model/horizontal_graph_line.dart';
 import 'package:blood_pressure_app/model/storage/storage.dart';
+import 'package:blood_pressure_app/screens/loading_screen.dart';
 import 'package:collection/collection.dart';
 import 'package:flutter/material.dart';
 import 'package:health_data_store/health_data_store.dart';
@@ -24,6 +25,7 @@ class Tmp extends StatelessWidget {
           width: 1000,
           child: BloodPressureValueGraph(
             settings: Settings(
+              animationSpeed: 1000,
               /*drawRegressionLines: true,
               horizontalGraphLines: [
                 HorizontalGraphLine(Colors.blue, 117),
@@ -62,12 +64,9 @@ class BloodPressureValueGraph extends StatelessWidget {
     required this.records,
     required this.colors,
   }): assert(records.sysGraph().length >= 2
-        || records.diaGraph().length >= 2
-        || records.pulGraph().length >= 2),
-      assert(records.isSorted((a, b) => a.time.compareTo(b.time)));
-
-  // TODO Add new feature:
-  // - load lines animation
+      || records.diaGraph().length >= 2
+      || records.pulGraph().length >= 2),
+    assert(records.isSorted((a, b) => a.time.compareTo(b.time)));
 
   /// Data to draw lines and determine decorations from.
   ///
@@ -83,13 +82,18 @@ class BloodPressureValueGraph extends StatelessWidget {
   @override
   Widget build(BuildContext context) => Padding(
     padding: const EdgeInsets.only(top: 4.0),
-    child: CustomPaint(
-      painter: _ValueGraphPainter(
-        brightness: Theme.of(context).brightness,
-        settings: settings,
-        labelStyle: Theme.of(context).textTheme.bodySmall ?? TextStyle(),
-        records: records,
-        colors: colors,
+    child: TweenAnimationBuilder(
+      tween: Tween(begin: 0.0, end: 1.0),
+      duration: Duration(milliseconds: 8 * settings.animationSpeed),
+      builder: (BuildContext context, double value, Widget? child) => CustomPaint(
+        painter: _ValueGraphPainter(
+          brightness: Theme.of(context).brightness,
+          settings: settings,
+          labelStyle: Theme.of(context).textTheme.bodySmall ?? TextStyle(),
+          records: records,
+          colors: colors,
+          progress: value,
+        ),
       ),
     ),
   );
@@ -102,7 +106,8 @@ class _ValueGraphPainter extends CustomPainter {
     required this.labelStyle,
     required this.records,
     required this.colors,
-  });
+    required this.progress,
+  }): assert(1.0 >= progress && progress >= 0.0);
 
   final Settings settings;
 
@@ -120,6 +125,9 @@ class _ValueGraphPainter extends CustomPainter {
   static const double _kLeftLegendWidth = 35.0;
   static const double _kBottomLegendHeight = 50.0;
 
+  /// Percentage of data line rendering (from 0 to 1).
+  final double progress;
+
   void _paintDecorations(Canvas canvas, Size size, DateTimeRange range, double minY, double maxY) {
     assert(size.width > _kLeftLegendWidth && size.height > _kBottomLegendHeight);
 
@@ -261,6 +269,7 @@ class _ValueGraphPainter extends CustomPainter {
     }
 
     if (path == null) return;
+    path = subPath(path, progress);
 
     if (warnValue != null) {
       final graphPath = Path();
@@ -436,6 +445,7 @@ class _ValueGraphPainter extends CustomPainter {
 
   @override
   bool shouldRepaint(covariant CustomPainter oldDelegate) => oldDelegate is! _ValueGraphPainter
+    || oldDelegate.progress != progress
     || oldDelegate.brightness != brightness
     || oldDelegate.settings.preferredPressureUnit != settings.preferredPressureUnit
     || oldDelegate.settings.sysColor != settings.sysColor
app/lib/screens/loading_screen.dart
@@ -64,46 +64,46 @@ class _LogoPainter extends CustomPainter {
     path.lineTo(size.width * 0.82, size.height * 0.42);
     path.lineTo(size.width * 0.818, size.height * 0.45);
     path.lineTo(size.width * 0.65, size.height * 0.65);
-    canvas.drawPath(_subPath(path, progress), paint);
+    canvas.drawPath(subPath(path, progress), paint);
   }
 
   @override
   bool shouldRepaint(_LogoPainter oldDelegate) =>
       oldDelegate.progress != progress;
+}
 
-  /// Get a percentage of [originalPath].
-  ///
-  /// [animationPercent] is a value from 0 to 1.
-  Path _subPath(Path originalPath, double animationPercent,) {
-    final totalLength = originalPath
-        .computeMetrics()
-        .fold(0.0, (double prev, PathMetric metric) => prev + metric.length);
-
-    return _extractPathUntilLength(originalPath, totalLength * animationPercent);
-  }
+/// Get a percentage of [originalPath].
+///
+/// [animationPercent] is a value from 0 to 1.
+Path subPath(Path originalPath, double animationPercent) {
+  final totalLength = originalPath
+      .computeMetrics()
+      .fold(0.0, (double prev, PathMetric metric) => prev + metric.length);
 
-  Path _extractPathUntilLength(Path originalPath, double length,) {
-    final path = Path();
+  return _extractPathUntilLength(originalPath, totalLength * animationPercent);
+}
 
-    final metricsIterator = originalPath.computeMetrics().iterator;
-    var isLastSegment = false;
-    var currentLength = 0.0;
+Path _extractPathUntilLength(Path originalPath, double length,) {
+  final path = Path();
 
-    while (metricsIterator.moveNext() && !isLastSegment) {
-      final metric = metricsIterator.current;
+  final metricsIterator = originalPath.computeMetrics().iterator;
+  var isLastSegment = false;
+  var currentLength = 0.0;
 
-      final nextLength = currentLength + metric.length;
-      isLastSegment = (nextLength > length);
+  while (metricsIterator.moveNext() && !isLastSegment) {
+    final metric = metricsIterator.current;
 
-      assert(length - currentLength >= 0);
-      final pathSegment = metric.extractPath(0.0,
-          min(length - currentLength, metric.length),);
+    final nextLength = currentLength + metric.length;
+    isLastSegment = (nextLength > length);
 
-      path.addPath(pathSegment, Offset.zero);
+    assert(length - currentLength >= 0);
+    final pathSegment = metric.extractPath(0.0,
+      min(length - currentLength, metric.length),);
 
-      currentLength = nextLength;
-    }
+    path.addPath(pathSegment, Offset.zero);
 
-    return path;
+    currentLength = nextLength;
   }
+
+  return path;
 }