@@ -33,13 +33,20 @@ class MeasurementStats {
3333 /// get dates for stats range
3434 ({DateTime ? from, DateTime ? to}) get _dates => _statsRange.dates;
3535
36+ /// cached measurements in stats range
37+ Vector ? _measurements;
38+
3639 /// get measurements in stats range
37- Vector get _measurements =>
38- ip.measured (from: _dates.from, to: _dates.to).measurements;
40+ Vector get measurements => _measurements ?? = ip
41+ .measured (from: _dates.from, to: _dates.to)
42+ .measurements;
43+
44+ /// cached weights in stats range
45+ Vector ? _weights;
3946
4047 /// get weights in stats range
41- Vector get _weights =>
42- ip.measurementsInRange (from: _dates.from, to: _dates.to);
48+ Vector get weights =>
49+ _weights ?? = ip.measurementsInRange (from: _dates.from, to: _dates.to);
4350
4451 /// get toDate, default to now if null
4552 DateTime get toDate => _dates.to ?? DateTime .now ();
@@ -48,18 +55,20 @@ class MeasurementStats {
4855 DateTime get fromDate => _dates.from ?? db.firstDate;
4956
5057 /// get number of measurements in stats range
51- int get nMeasurements => _measurements .length;
58+ int get nMeasurements => measurements .length;
5259
5360 /// Content-based hash combining date range and interpolation state.
5461 int get hashCode => Object .hash (toDate, fromDate, ip.hashCode);
5562
5663 /// re initialize database
5764 void reinit () {
58- _streakList = null ;
65+ _globalStreakList = null ;
5966 _deltaWeightLastWeek = null ;
6067 _deltaWeightLastMonth = null ;
6168 _deltaWeightLastYear = null ;
62- // recalculate all vectors
69+ _measurements = null ;
70+ _weights = null ;
71+
6372 init ();
6473 }
6574
@@ -79,22 +88,22 @@ class MeasurementStats {
7988 }
8089
8190 /// get max weight
82- double ? get maxWeight => _measurements .max ();
91+ double ? get maxWeight => measurements .max ();
8392
8493 /// get max interpolated weight in stats range
85- double ? get maxInterpolatedWeight => _weights .max ();
94+ double ? get maxInterpolatedWeight => weights .max ();
8695
8796 /// get min weight
88- double ? get minWeight => _measurements .min ();
97+ double ? get minWeight => measurements .min ();
8998
9099 /// get min interpolated weight in stats range
91- double ? get minInterpolatedWeight => _weights .min ();
100+ double ? get minInterpolatedWeight => weights .min ();
92101
93102 /// get mean weight
94- double ? get meanWeight => _measurements .mean ();
103+ double ? get meanWeight => measurements .mean ();
95104
96105 /// get mean interpolated weight in stats range
97- double ? get meanInterpolatedWeight => _weights .mean ();
106+ double ? get meanInterpolatedWeight => weights .mean ();
98107
99108 /// get current BMI
100109 double ? currentBMI (BuildContext context) {
@@ -126,25 +135,44 @@ class MeasurementStats {
126135 /// get time of records
127136 Duration get deltaTime => toDate.difference (fromDate);
128137
129- /// get current streak
130- Duration get currentStreak => ip.hasMeasurementOnDay (toDate)
131- ? Duration (days: streakList.last.round ())
138+ /// get frequency of taking measurements (in stats range) [/week]
139+ double ? get frequency => 7 * nMeasurements / (deltaTime.inDays + 1 );
140+
141+ ////////////////////////////////////////////////////////////////////
142+ // Global stats (always computed over the full measurement range) //
143+ ////////////////////////////////////////////////////////////////////
144+
145+ /// get total number of measurements (all time)
146+ int get globalNMeasurements => db.nMeasurements;
147+
148+ /// the start of the first measurement until now (all time)
149+ Duration get globalDeltaTime => DateTime .now ().difference (db.firstDate);
150+
151+ Vector ? _globalStreakList;
152+
153+ /// get list of all streaks (all time)
154+ Vector get globalStreakList => _globalStreakList ?? = _estimateStreakList ();
155+
156+ /// get current streak (all time)
157+ Duration get globalCurrentStreak => ip.hasMeasurementOnDay (DateTime .now ())
158+ ? Duration (days: globalStreakList.last.round ())
132159 : Duration .zero;
133160
134- /// get max streak
135- Duration get maxStreak => Duration (days: streakList.max ().round ());
161+ /// get max streak (all time)
162+ Duration get globalMaxStreak =>
163+ Duration (days: globalStreakList.max ().round ());
136164
137- Vector ? _streakList;
165+ /// get frequency of taking measurements (all time) [/week]
166+ double ? get globalFrequency =>
167+ 7 * globalNMeasurements / (globalDeltaTime.inDays + 1 );
138168
139- /// get list of all streaks
140- Vector get streakList => _streakList ?? = _estimateStreakList ();
169+ // ---- Shared helpers ----
170+
171+ /// Estimate streak list for a given date range.
141172 Vector _estimateStreakList () {
142173 int streak = 0 ;
143174 final List <int > streakList = < int > [0 ]; // catch for no measurements
144- for (final double isMS in ip.isMeasurementInRange (
145- from: fromDate,
146- to: toDate,
147- )) {
175+ for (final double isMS in ip.isMeasurement) {
148176 if (isMS.round () == 1 ) {
149177 streak++ ;
150178 } else if (streak > 0 ) {
@@ -155,9 +183,6 @@ class MeasurementStats {
155183 return Vector .fromList (streakList);
156184 }
157185
158- /// get frequency of taking measurements (in total) [/week]
159- double ? get frequency => 7 * nMeasurements / (deltaTime.inDays + 1 );
160-
161186 double ? _deltaWeightLastYear;
162187
163188 /// get weight change [kg] within last month from last measurement
0 commit comments