Commit 09bd0687c72ef4ca5c47031ede09e838bc056c99

Authored by 权海
1 parent 116979b3

feat(ui):移除HRV计算后的时间间隔判断

@@ -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),