Showing
3 changed files
with
14 additions
and
28 deletions
| @@ -14,7 +14,6 @@ import '../../pigeon/health_kit_api.g.dart'; | @@ -14,7 +14,6 @@ import '../../pigeon/health_kit_api.g.dart'; | ||
| 14 | import '../../pigeon/health_kit_raw_data_api.g.dart'; | 14 | import '../../pigeon/health_kit_raw_data_api.g.dart'; |
| 15 | import '../config/app_environment_config.dart'; | 15 | import '../config/app_environment_config.dart'; |
| 16 | import '../logging/app_logger.dart'; | 16 | import '../logging/app_logger.dart'; |
| 17 | -import '../util/app_toast.dart'; | ||
| 18 | import 'health_raw_local_notification.dart'; | 17 | import 'health_raw_local_notification.dart'; |
| 19 | import 'health_raw_stress_calculator.dart'; | 18 | import 'health_raw_stress_calculator.dart'; |
| 20 | import 'health_sleep_calculator.dart'; | 19 | import 'health_sleep_calculator.dart'; |
| @@ -281,8 +280,6 @@ class HealthRawDataCoreService { | @@ -281,8 +280,6 @@ class HealthRawDataCoreService { | ||
| 281 | final latestSleepResultTime = await _localStore.latestSleepResultTime( | 280 | final latestSleepResultTime = await _localStore.latestSleepResultTime( |
| 282 | userId, | 281 | userId, |
| 283 | ); | 282 | ); |
| 284 | - final isFirstCalculation = | ||
| 285 | - hrvContextStart == null && realtimeContextStart == null; | ||
| 286 | final hrvStartTime = math.max( | 283 | final hrvStartTime = math.max( |
| 287 | hrvContextStart ?? requestedStartTime, | 284 | hrvContextStart ?? requestedStartTime, |
| 288 | earliestStartTime, | 285 | earliestStartTime, |
| @@ -382,7 +379,7 @@ class HealthRawDataCoreService { | @@ -382,7 +379,7 @@ class HealthRawDataCoreService { | ||
| 382 | ); | 379 | ); |
| 383 | await _sendLocalNotificationsAfterCalculation( | 380 | await _sendLocalNotificationsAfterCalculation( |
| 384 | result: storedResult, | 381 | result: storedResult, |
| 385 | - previousHrvRawEndTime: latestHrvRawEndTime, | 382 | + hasExistingHrv: latestHrvRawEndTime != null, |
| 386 | ); | 383 | ); |
| 387 | final calculateFinishedAt = DateTime.now(); | 384 | final calculateFinishedAt = DateTime.now(); |
| 388 | _logInfo( | 385 | _logInfo( |
| @@ -393,7 +390,7 @@ class HealthRawDataCoreService { | @@ -393,7 +390,7 @@ class HealthRawDataCoreService { | ||
| 393 | 390 | ||
| 394 | Future<void> _sendLocalNotificationsAfterCalculation({ | 391 | Future<void> _sendLocalNotificationsAfterCalculation({ |
| 395 | required HealthRawStressCalculationResult result, | 392 | required HealthRawStressCalculationResult result, |
| 396 | - required int? previousHrvRawEndTime, | 393 | + required bool hasExistingHrv, |
| 397 | }) async { | 394 | }) async { |
| 398 | if (result.hrvStressPoints.isEmpty && | 395 | if (result.hrvStressPoints.isEmpty && |
| 399 | result.realtimeStressPoints.isEmpty && | 396 | result.realtimeStressPoints.isEmpty && |
| @@ -420,7 +417,7 @@ class HealthRawDataCoreService { | @@ -420,7 +417,7 @@ class HealthRawDataCoreService { | ||
| 420 | ); | 417 | ); |
| 421 | final notifications = HealthRawLocalNotificationBuilder(l10n).build( | 418 | final notifications = HealthRawLocalNotificationBuilder(l10n).build( |
| 422 | result: result, | 419 | result: result, |
| 423 | - previousHrvRawEndTime: previousHrvRawEndTime, | 420 | + hasExistingHrv: hasExistingHrv, |
| 424 | realtimeWindow: realtimeWindow, | 421 | realtimeWindow: realtimeWindow, |
| 425 | record: record, | 422 | record: record, |
| 426 | ); | 423 | ); |
| @@ -37,7 +37,6 @@ enum HealthRawLocalNotificationRecordType { | @@ -37,7 +37,6 @@ enum HealthRawLocalNotificationRecordType { | ||
| 37 | class HealthRawLocalNotificationBuilder { | 37 | class HealthRawLocalNotificationBuilder { |
| 38 | const HealthRawLocalNotificationBuilder(this.l10n); | 38 | const HealthRawLocalNotificationBuilder(this.l10n); |
| 39 | 39 | ||
| 40 | - static const int _hrvMinIntervalSeconds = 2 * 60 * 60; | ||
| 41 | static const int _realtimeWindowSeconds = 60 * 60; | 40 | static const int _realtimeWindowSeconds = 60 * 60; |
| 42 | static const int _realtimeMinPointCount = 10; | 41 | static const int _realtimeMinPointCount = 10; |
| 43 | 42 | ||
| @@ -45,18 +44,14 @@ class HealthRawLocalNotificationBuilder { | @@ -45,18 +44,14 @@ class HealthRawLocalNotificationBuilder { | ||
| 45 | 44 | ||
| 46 | List<HealthRawLocalNotification> build({ | 45 | List<HealthRawLocalNotification> build({ |
| 47 | required HealthRawStressCalculationResult result, | 46 | required HealthRawStressCalculationResult result, |
| 48 | - required int? previousHrvRawEndTime, | 47 | + required bool hasExistingHrv, |
| 49 | required List<HealthRawRealtimeStressPoint> realtimeWindow, | 48 | required List<HealthRawRealtimeStressPoint> realtimeWindow, |
| 50 | required HealthRawLocalNotificationRecord? record, | 49 | required HealthRawLocalNotificationRecord? record, |
| 51 | }) { | 50 | }) { |
| 52 | return [ | 51 | return [ |
| 53 | if (_sleepNotification(result.sleepResults) case final notification?) | 52 | if (_sleepNotification(result.sleepResults) case final notification?) |
| 54 | notification, | 53 | notification, |
| 55 | - if (_hrvNotification( | ||
| 56 | - result.hrvStressPoints, | ||
| 57 | - previousHrvRawEndTime, | ||
| 58 | - record, | ||
| 59 | - ) | 54 | + if (_hrvNotification(result.hrvStressPoints, hasExistingHrv, record) |
| 60 | case final notification?) | 55 | case final notification?) |
| 61 | notification, | 56 | notification, |
| 62 | if (_realtimeStressNotification(realtimeWindow, record) | 57 | if (_realtimeStressNotification(realtimeWindow, record) |
| @@ -85,20 +80,14 @@ class HealthRawLocalNotificationBuilder { | @@ -85,20 +80,14 @@ class HealthRawLocalNotificationBuilder { | ||
| 85 | 80 | ||
| 86 | HealthRawLocalNotification? _hrvNotification( | 81 | HealthRawLocalNotification? _hrvNotification( |
| 87 | List<HealthRawHrvStressPoint> hrvPoints, | 82 | List<HealthRawHrvStressPoint> hrvPoints, |
| 88 | - int? previousHrvRawEndTime, | 83 | + bool hasExistingHrv, |
| 89 | HealthRawLocalNotificationRecord? record, | 84 | HealthRawLocalNotificationRecord? record, |
| 90 | ) { | 85 | ) { |
| 86 | + if (!hasExistingHrv) return null; | ||
| 91 | if (hrvPoints.isEmpty) return null; | 87 | if (hrvPoints.isEmpty) return null; |
| 92 | final sorted = [...hrvPoints] | 88 | final sorted = [...hrvPoints] |
| 93 | ..sort((a, b) => a.rawEndTime.compareTo(b.rawEndTime)); | 89 | ..sort((a, b) => a.rawEndTime.compareTo(b.rawEndTime)); |
| 94 | final latest = sorted.last; | 90 | final latest = sorted.last; |
| 95 | - final previousTime = sorted.length >= 2 | ||
| 96 | - ? sorted[sorted.length - 2].rawEndTime | ||
| 97 | - : previousHrvRawEndTime; | ||
| 98 | - if (previousTime == null || | ||
| 99 | - latest.rawEndTime - previousTime < _hrvMinIntervalSeconds) { | ||
| 100 | - return null; | ||
| 101 | - } | ||
| 102 | if (record?.lastHrvTime == latest.rawEndTime) return null; | 91 | if (record?.lastHrvTime == latest.rawEndTime) return null; |
| 103 | 92 | ||
| 104 | return HealthRawLocalNotification( | 93 | return HealthRawLocalNotification( |
| @@ -26,7 +26,7 @@ void main() { | @@ -26,7 +26,7 @@ void main() { | ||
| 26 | ), | 26 | ), |
| 27 | ], | 27 | ], |
| 28 | ), | 28 | ), |
| 29 | - previousHrvRawEndTime: null, | 29 | + hasExistingHrv: false, |
| 30 | realtimeWindow: const [], | 30 | realtimeWindow: const [], |
| 31 | record: const HealthRawLocalNotificationRecord(), | 31 | record: const HealthRawLocalNotificationRecord(), |
| 32 | ); | 32 | ); |
| @@ -37,7 +37,7 @@ void main() { | @@ -37,7 +37,7 @@ void main() { | ||
| 37 | expect(notifications.single.link, healthRawTodayLink); | 37 | expect(notifications.single.link, healthRawTodayLink); |
| 38 | }); | 38 | }); |
| 39 | 39 | ||
| 40 | - test('builds hrv notification when previous hrv is at least two hours away', | 40 | + test('builds hrv notification when new hrv is calculated after first run', |
| 41 | () { | 41 | () { |
| 42 | final latestTime = _seconds(DateTime(2026, 1, 1, 10)); | 42 | final latestTime = _seconds(DateTime(2026, 1, 1, 10)); |
| 43 | final notifications = builder.build( | 43 | final notifications = builder.build( |
| @@ -49,7 +49,7 @@ void main() { | @@ -49,7 +49,7 @@ void main() { | ||
| 49 | realtimeStressPoints: const [], | 49 | realtimeStressPoints: const [], |
| 50 | dailyStressPoints: const [], | 50 | dailyStressPoints: const [], |
| 51 | ), | 51 | ), |
| 52 | - previousHrvRawEndTime: latestTime - Duration.secondsPerHour * 2, | 52 | + hasExistingHrv: true, |
| 53 | realtimeWindow: const [], | 53 | realtimeWindow: const [], |
| 54 | record: const HealthRawLocalNotificationRecord(), | 54 | record: const HealthRawLocalNotificationRecord(), |
| 55 | ); | 55 | ); |
| @@ -59,7 +59,7 @@ void main() { | @@ -59,7 +59,7 @@ void main() { | ||
| 59 | expect(notifications.single.link, healthRawHrvChangeLink); | 59 | expect(notifications.single.link, healthRawHrvChangeLink); |
| 60 | }); | 60 | }); |
| 61 | 61 | ||
| 62 | - test('skips hrv notification when previous hrv is too close', () { | 62 | + test('skips hrv notification on first calculation without existing hrv', () { |
| 63 | final latestTime = _seconds(DateTime(2026, 1, 1, 10)); | 63 | final latestTime = _seconds(DateTime(2026, 1, 1, 10)); |
| 64 | final notifications = builder.build( | 64 | final notifications = builder.build( |
| 65 | result: HealthRawStressCalculationResult( | 65 | result: HealthRawStressCalculationResult( |
| @@ -70,7 +70,7 @@ void main() { | @@ -70,7 +70,7 @@ void main() { | ||
| 70 | realtimeStressPoints: const [], | 70 | realtimeStressPoints: const [], |
| 71 | dailyStressPoints: const [], | 71 | dailyStressPoints: const [], |
| 72 | ), | 72 | ), |
| 73 | - previousHrvRawEndTime: latestTime - Duration.secondsPerHour * 2 + 1, | 73 | + hasExistingHrv: false, |
| 74 | realtimeWindow: const [], | 74 | realtimeWindow: const [], |
| 75 | record: const HealthRawLocalNotificationRecord(), | 75 | record: const HealthRawLocalNotificationRecord(), |
| 76 | ); | 76 | ); |
| @@ -87,7 +87,7 @@ void main() { | @@ -87,7 +87,7 @@ void main() { | ||
| 87 | realtimeStressPoints: [_realtimePoint(base + 9 * 300, 70)], | 87 | realtimeStressPoints: [_realtimePoint(base + 9 * 300, 70)], |
| 88 | dailyStressPoints: const [], | 88 | dailyStressPoints: const [], |
| 89 | ), | 89 | ), |
| 90 | - previousHrvRawEndTime: null, | 90 | + hasExistingHrv: false, |
| 91 | realtimeWindow: [ | 91 | realtimeWindow: [ |
| 92 | for (var i = 0; i < 10; i++) _realtimePoint(base + i * 300, 70), | 92 | for (var i = 0; i < 10; i++) _realtimePoint(base + i * 300, 70), |
| 93 | ], | 93 | ], |
| @@ -111,7 +111,7 @@ void main() { | @@ -111,7 +111,7 @@ void main() { | ||
| 111 | ], | 111 | ], |
| 112 | dailyStressPoints: const [], | 112 | dailyStressPoints: const [], |
| 113 | ), | 113 | ), |
| 114 | - previousHrvRawEndTime: null, | 114 | + hasExistingHrv: false, |
| 115 | realtimeWindow: [ | 115 | realtimeWindow: [ |
| 116 | for (var i = 0; i < 9; i++) _realtimePoint(base + i * 300, 70), | 116 | for (var i = 0; i < 9; i++) _realtimePoint(base + i * 300, 70), |
| 117 | _realtimePoint(base + 9 * 300, 70, isSleepLikely: true), | 117 | _realtimePoint(base + 9 * 300, 70, isSleepLikely: true), |
-
Please register or login to post a comment