Commit 6529d91b0f49707a695f977bfbbceb814b6acd90

Authored by 权海
1 parent 7321fbce

feat(ui):让计算结果的上传不要阻塞后续计算

@@ -784,7 +784,6 @@ class TodayController extends GetMaterialController { @@ -784,7 +784,6 @@ class TodayController extends GetMaterialController {
784 checkHealthDataAuthCardVisible(shouldCaculateAndUpload: true); 784 checkHealthDataAuthCardVisible(shouldCaculateAndUpload: true);
785 checkNotificationAuthorizationBannerVisible(); 785 checkNotificationAuthorizationBannerVisible();
786 _performHealthDataUpload(); 786 _performHealthDataUpload();
787 - // _startCoreCaculate();  
788 // unawaited(loadDataForDate(selectedDate.value)); 787 // unawaited(loadDataForDate(selectedDate.value));
789 } 788 }
790 } 789 }
@@ -355,24 +355,26 @@ class HealthRawDataCoreService { @@ -355,24 +355,26 @@ class HealthRawDataCoreService {
355 ), 355 ),
356 ); 356 );
357 await _localStore.upsertResult(newResult); 357 await _localStore.upsertResult(newResult);
358 - if (_uploadResultsAfterCalculation) {  
359 - await _uploadHrvResults();  
360 - await _uploadRealtimeStressResults();  
361 - } 358 + _scheduleResultUpload('upload hrv results', _uploadHrvResults);
  359 + _scheduleResultUpload(
  360 + 'upload realtime stress results',
  361 + _uploadRealtimeStressResults,
  362 + );
362 final dailyStressPoints = await _calculateAndStoreDailyStressPoints( 363 final dailyStressPoints = await _calculateAndStoreDailyStressPoints(
363 userId: userId, 364 userId: userId,
364 realtimePoints: newResult.realtimeStressPoints, 365 realtimePoints: newResult.realtimeStressPoints,
365 nowSeconds: effectiveEndTime, 366 nowSeconds: effectiveEndTime,
366 ); 367 );
  368 + _scheduleResultUpload(
  369 + 'upload daily stress results',
  370 + _uploadDailyStressResults,
  371 + );
367 final sleepResults = await _calculateAndStoreSleepResults( 372 final sleepResults = await _calculateAndStoreSleepResults(
368 userId: userId, 373 userId: userId,
369 sleepIntervals: sleepIntervals, 374 sleepIntervals: sleepIntervals,
370 latestSleepResultTime: latestSleepResultTime, 375 latestSleepResultTime: latestSleepResultTime,
371 ); 376 );
372 - if (_uploadResultsAfterCalculation) {  
373 - await _uploadDailyStressResults();  
374 - await _uploadSleepResults();  
375 - } 377 + _scheduleResultUpload('upload sleep results', _uploadSleepResults);
376 final storedResult = newResult.copyWith( 378 final storedResult = newResult.copyWith(
377 dailyStressPoints: dailyStressPoints, 379 dailyStressPoints: dailyStressPoints,
378 sleepResults: sleepResults, 380 sleepResults: sleepResults,
@@ -622,6 +624,24 @@ class HealthRawDataCoreService { @@ -622,6 +624,24 @@ class HealthRawDataCoreService {
622 ); 624 );
623 } 625 }
624 626
  627 + void _scheduleResultUpload(
  628 + String action,
  629 + Future<void> Function() upload,
  630 + ) {
  631 + if (!_uploadResultsAfterCalculation) {
  632 + return;
  633 + }
  634 + unawaited(
  635 + (() async {
  636 + try {
  637 + await upload();
  638 + } catch (error, stackTrace) {
  639 + _logError('$action failed', error, stackTrace);
  640 + }
  641 + })(),
  642 + );
  643 + }
  644 +
625 Future<void> _uploadHrvResults() async { 645 Future<void> _uploadHrvResults() async {
626 if (_isUploadingHrvResults) { 646 if (_isUploadingHrvResults) {
627 return; 647 return;
  1 +import 'dart:async';
  2 +
1 import 'package:doublefeel_flutter/core/result/app_result.dart'; 3 import 'package:doublefeel_flutter/core/result/app_result.dart';
2 import 'package:doublefeel_flutter/core/services/health_raw_data_core_service.dart'; 4 import 'package:doublefeel_flutter/core/services/health_raw_data_core_service.dart';
3 import 'package:doublefeel_flutter/data/datasource/health/health_local_data_convert.dart'; 5 import 'package:doublefeel_flutter/data/datasource/health/health_local_data_convert.dart';
@@ -7,6 +9,12 @@ import 'package:doublefeel_flutter/pigeon/health_kit_api.g.dart'; @@ -7,6 +9,12 @@ import 'package:doublefeel_flutter/pigeon/health_kit_api.g.dart';
7 import 'package:doublefeel_flutter/pigeon/health_kit_raw_data_api.g.dart'; 9 import 'package:doublefeel_flutter/pigeon/health_kit_raw_data_api.g.dart';
8 import 'package:flutter_test/flutter_test.dart'; 10 import 'package:flutter_test/flutter_test.dart';
9 11
  12 +Future<void> _pumpAsyncUploads() async {
  13 + for (var i = 0; i < 6; i += 1) {
  14 + await Future<void>.delayed(Duration.zero);
  15 + }
  16 +}
  17 +
10 void main() { 18 void main() {
11 test('sync reads raw data, calculates, stores, and resumes with context', 19 test('sync reads raw data, calculates, stores, and resumes with context',
12 () async { 20 () async {
@@ -330,6 +338,7 @@ void main() { @@ -330,6 +338,7 @@ void main() {
330 endTime: startSeconds + 240, 338 endTime: startSeconds + 240,
331 readChunkDays: 1, 339 readChunkDays: 1,
332 ); 340 );
  341 + await _pumpAsyncUploads();
333 342
334 expect( 343 expect(
335 operationLog.indexOf('upsertDailyStressPoints'), 344 operationLog.indexOf('upsertDailyStressPoints'),
@@ -508,6 +517,7 @@ void main() { @@ -508,6 +517,7 @@ void main() {
508 )), 517 )),
509 readChunkDays: 1, 518 readChunkDays: 1,
510 ); 519 );
  520 + await _pumpAsyncUploads();
511 final rows = await store.debugQueryAllRows(42); 521 final rows = await store.debugQueryAllRows(42);
512 522
513 expect(api.sleepUploadCallCount, 1); 523 expect(api.sleepUploadCallCount, 1);
@@ -570,6 +580,7 @@ void main() { @@ -570,6 +580,7 @@ void main() {
570 endTime: base + 40, 580 endTime: base + 40,
571 readChunkDays: 1, 581 readChunkDays: 1,
572 ); 582 );
  583 + await _pumpAsyncUploads();
573 final rows = await store.debugQueryAllRows(42); 584 final rows = await store.debugQueryAllRows(42);
574 585
575 expect(result.hrvStressPoints, isEmpty); 586 expect(result.hrvStressPoints, isEmpty);
@@ -585,6 +596,52 @@ void main() { @@ -585,6 +596,52 @@ void main() {
585 expect(rows.sleepRows.single['uploaded'], 1); 596 expect(rows.sleepRows.single['uploaded'], 1);
586 }); 597 });
587 598
  599 + test('startCoreCaculate does not wait for pending uploads', () async {
  600 + const base = 1800000000;
  601 + final api = _FakeHealthKitRawDataHostApi()
  602 + ..hrvUploadCompleter = Completer<int>()
  603 + ..hrUploadCompleter = Completer<int>();
  604 + final store = _MemoryHealthRawStressLocalStore();
  605 + await store.upsertResult(
  606 + HealthRawStressCalculationResult(
  607 + userId: 42,
  608 + hrvStressPoints: [_hrvStressPoint(base + 10)],
  609 + realtimeStressPoints: [_realtimeStressPoint(base + 20)],
  610 + dailyStressPoints: const <HealthRawDailyStressPoint>[],
  611 + ),
  612 + );
  613 + final service = HealthRawDataCoreService(
  614 + healthApi: _FakeHealthKitHostApi(),
  615 + rawDataApi: api,
  616 + localStore: store,
  617 + userIdProvider: () => 42,
  618 + );
  619 +
  620 + final calculation = service.startCoreCaculate(
  621 + endTime: base + 40,
  622 + readChunkDays: 1,
  623 + );
  624 + await _pumpAsyncUploads();
  625 +
  626 + await expectLater(
  627 + calculation.timeout(const Duration(seconds: 1)),
  628 + completes,
  629 + );
  630 + expect(api.hrvUploadCallCount, 1);
  631 + expect(api.hrUploadCallCount, 1);
  632 + var rows = await store.debugQueryAllRows(42);
  633 + expect(rows.hrvRows.single['uploaded'], 0);
  634 + expect(rows.realtimeRows.single['uploaded'], 0);
  635 +
  636 + api.hrvUploadCompleter!.complete(base + 10);
  637 + api.hrUploadCompleter!.complete(base + 20);
  638 + await _pumpAsyncUploads();
  639 + rows = await store.debugQueryAllRows(42);
  640 +
  641 + expect(rows.hrvRows.single['uploaded'], 1);
  642 + expect(rows.realtimeRows.single['uploaded'], 1);
  643 + });
  644 +
588 test('local data source returns earliest local hr start time', () async { 645 test('local data source returns earliest local hr start time', () async {
589 const base = 1800000000; 646 const base = 1800000000;
590 final api = _FakeHealthKitRawDataHostApi(); 647 final api = _FakeHealthKitRawDataHostApi();
@@ -678,6 +735,8 @@ class _FakeHealthKitRawDataHostApi extends HealthKitRawDataHostApi { @@ -678,6 +735,8 @@ class _FakeHealthKitRawDataHostApi extends HealthKitRawDataHostApi {
678 var hrvUploadUntil = 0; 735 var hrvUploadUntil = 0;
679 var dailyStressUploadUntil = 0; 736 var dailyStressUploadUntil = 0;
680 var sleepUploadUntil = 0; 737 var sleepUploadUntil = 0;
  738 + Completer<int>? hrUploadCompleter;
  739 + Completer<int>? hrvUploadCompleter;
681 var hasData = true; 740 var hasData = true;
682 741
683 void setPoints(int dataType, List<HealthKitRawDataPoint> points) { 742 void setPoints(int dataType, List<HealthKitRawDataPoint> points) {
@@ -718,12 +777,20 @@ class _FakeHealthKitRawDataHostApi extends HealthKitRawDataHostApi { @@ -718,12 +777,20 @@ class _FakeHealthKitRawDataHostApi extends HealthKitRawDataHostApi {
718 @override 777 @override
719 Future<int> performHRDataUpload({required String sqliteFilePath}) async { 778 Future<int> performHRDataUpload({required String sqliteFilePath}) async {
720 hrUploadCallCount += 1; 779 hrUploadCallCount += 1;
  780 + final completer = hrUploadCompleter;
  781 + if (completer != null) {
  782 + return completer.future;
  783 + }
721 return hrUploadUntil; 784 return hrUploadUntil;
722 } 785 }
723 786
724 @override 787 @override
725 Future<int> performHRVDataUpload({required String sqliteFilePath}) async { 788 Future<int> performHRVDataUpload({required String sqliteFilePath}) async {
726 hrvUploadCallCount += 1; 789 hrvUploadCallCount += 1;
  790 + final completer = hrvUploadCompleter;
  791 + if (completer != null) {
  792 + return completer.future;
  793 + }
727 return hrvUploadUntil; 794 return hrvUploadUntil;
728 } 795 }
729 796