Commit c187bd363e7f071cd42faed6329a8ad2504ca5ee

Authored by 权海
1 parent 67c9e06c

feat(ui):修改同步数据流程逻辑

@@ -921,9 +921,13 @@ class TodayController extends GetxController with WidgetsBindingObserver { @@ -921,9 +921,13 @@ class TodayController extends GetxController with WidgetsBindingObserver {
921 // changeDate(today); 921 // changeDate(today);
922 checkAddFriendVisible(); 922 checkAddFriendVisible();
923 checkHrvAdBannerVisible(); 923 checkHrvAdBannerVisible();
  924 + final isSelectedToday = DateUtils.isSameDay(
  925 + DateUtils.dateOnly(selectedDate.value),
  926 + DateUtils.dateOnly(DateTime.now()),
  927 + );
924 checkHealthDataAuthCardVisible( 928 checkHealthDataAuthCardVisible(
925 isPullToRefresh: isPullToRefresh, 929 isPullToRefresh: isPullToRefresh,
926 - shouldCaculateAndUpload: isOhos(), 930 + shouldCaculateAndUpload: isOhos() && isSelectedToday,
927 ); 931 );
928 checkNotificationAuthorizationBannerVisible(); 932 checkNotificationAuthorizationBannerVisible();
929 // await loadDataForDate(selectedDate.value); 933 // await loadDataForDate(selectedDate.value);
@@ -210,17 +210,6 @@ class OHOSHealthRawDataCoreService { @@ -210,17 +210,6 @@ class OHOSHealthRawDataCoreService {
210 } 210 }
211 211
212 final userId = _userId; 212 final userId = _userId;
213 - final hasAuthorization = await _hasHealthReadAuthorization();  
214 - if (!hasAuthorization) {  
215 - _logInfo('skip calculate without OHOS health privacy authorization');  
216 - return HealthRawStressCalculationResult(  
217 - userId: userId,  
218 - hrvStressPoints: const <HealthRawHrvStressPoint>[],  
219 - realtimeStressPoints: const <HealthRawRealtimeStressPoint>[],  
220 - dailyStressPoints: const <HealthRawDailyStressPoint>[],  
221 - sleepResults: const <HealthRawSleepResult>[],  
222 - );  
223 - }  
224 await _localStore.ensureReadable(userId); 213 await _localStore.ensureReadable(userId);
225 final effectiveEndTime = 214 final effectiveEndTime =
226 endTime ?? DateTime.now().millisecondsSinceEpoch ~/ 1000; 215 endTime ?? DateTime.now().millisecondsSinceEpoch ~/ 1000;
@@ -233,10 +222,19 @@ class OHOSHealthRawDataCoreService { @@ -233,10 +222,19 @@ class OHOSHealthRawDataCoreService {
233 if (effectiveEndTime < requestedStartTime) { 222 if (effectiveEndTime < requestedStartTime) {
234 throw ArgumentError.value(endTime, 'endTime'); 223 throw ArgumentError.value(endTime, 'endTime');
235 } 224 }
236 - final syncResults = await _syncCalculationRawDataIfNeeded(  
237 - startTime: requestedStartTime,  
238 - endTime: effectiveEndTime,  
239 - ); 225 + final hasAuthorization = await _hasHealthReadAuthorization();
  226 + final syncResults = hasAuthorization
  227 + ? await _syncCalculationRawDataIfNeeded(
  228 + startTime: requestedStartTime,
  229 + endTime: effectiveEndTime,
  230 + )
  231 + : const <OhosHealthRawDataSyncResult>[];
  232 + if (!hasAuthorization) {
  233 + _logInfo(
  234 + 'skip OHOS raw data sync without health privacy authorization; '
  235 + 'continue calculate and upload from local database',
  236 + );
  237 + }
240 _logInfo( 238 _logInfo(
241 'calculate_sync_finish startTime=$requestedStartTime ' 239 'calculate_sync_finish startTime=$requestedStartTime '
242 'endTime=$effectiveEndTime syncResults=$syncResults', 240 'endTime=$effectiveEndTime syncResults=$syncResults',
@@ -495,9 +493,6 @@ class OHOSHealthRawDataCoreService { @@ -495,9 +493,6 @@ class OHOSHealthRawDataCoreService {
495 required int endTime, 493 required int endTime,
496 int readChunkDays = defaultReadChunkDays, 494 int readChunkDays = defaultReadChunkDays,
497 }) async { 495 }) async {
498 - if (!await _hasHealthReadAuthorization()) {  
499 - return const <HealthKitRawDataPoint>[];  
500 - }  
501 return _fetchRawDataInChunks( 496 return _fetchRawDataInChunks(
502 dataType, 497 dataType,
503 startTime, 498 startTime,
@@ -511,9 +506,6 @@ class OHOSHealthRawDataCoreService { @@ -511,9 +506,6 @@ class OHOSHealthRawDataCoreService {
511 required int endTime, 506 required int endTime,
512 int readChunkDays = defaultReadChunkDays, 507 int readChunkDays = defaultReadChunkDays,
513 }) async { 508 }) async {
514 - if (!await _hasHealthReadAuthorization()) {  
515 - return const <HealthKitRawDataPoint>[];  
516 - }  
517 return _fetchSleepIntervalsInChunks( 509 return _fetchSleepIntervalsInChunks(
518 startTime, 510 startTime,
519 endTime, 511 endTime,
@@ -525,9 +517,6 @@ class OHOSHealthRawDataCoreService { @@ -525,9 +517,6 @@ class OHOSHealthRawDataCoreService {
525 required int startTime, 517 required int startTime,
526 required int endTime, 518 required int endTime,
527 }) async { 519 }) async {
528 - if (!await _hasHealthReadAuthorization()) {  
529 - return const <HealthKitRawActivityDataPoint>[];  
530 - }  
531 final points = await _rawDataSource.getRawActivityData(startTime, endTime); 520 final points = await _rawDataSource.getRawActivityData(startTime, endTime);
532 return points 521 return points
533 .where((e) => e.endTime >= startTime && e.endTime <= endTime) 522 .where((e) => e.endTime >= startTime && e.endTime <= endTime)
@@ -581,6 +570,7 @@ class OHOSHealthRawDataCoreService { @@ -581,6 +570,7 @@ class OHOSHealthRawDataCoreService {
581 if (rawDataSource is! OhosHealthRawDataSource) { 570 if (rawDataSource is! OhosHealthRawDataSource) {
582 return const <OhosHealthRawDataSyncResult>[]; 571 return const <OhosHealthRawDataSyncResult>[];
583 } 572 }
  573 + await rawDataSource.getActivityGoal(refresh: true);
584 return rawDataSource.syncCalculationRawData( 574 return rawDataSource.syncCalculationRawData(
585 startTime: startTime, 575 startTime: startTime,
586 endTime: endTime, 576 endTime: endTime,
1 import 'dart:io'; 1 import 'dart:io';
2 2
3 import 'package:doublefeel_flutter/core/services/raw_data_service/health_raw_data_core_service.dart'; 3 import 'package:doublefeel_flutter/core/services/raw_data_service/health_raw_data_core_service.dart';
  4 +import 'package:doublefeel_flutter/core/services/raw_data_service/health_raw_data_source.dart';
4 import 'package:doublefeel_flutter/core/services/raw_data_service/platform_ios/apple_health_raw_data_core_service.dart'; 5 import 'package:doublefeel_flutter/core/services/raw_data_service/platform_ios/apple_health_raw_data_core_service.dart';
5 import 'package:doublefeel_flutter/core/services/raw_data_service/platform_ohos/ohos_health_raw_data_core_service.dart'; 6 import 'package:doublefeel_flutter/core/services/raw_data_service/platform_ohos/ohos_health_raw_data_core_service.dart';
  7 +import 'package:doublefeel_flutter/data/models/health/health_v2_models.dart';
  8 +import 'package:doublefeel_flutter/pigeon/health_kit_raw_data_api.g.dart';
6 import 'package:flutter/foundation.dart'; 9 import 'package:flutter/foundation.dart';
7 import 'package:flutter_test/flutter_test.dart'; 10 import 'package:flutter_test/flutter_test.dart';
8 11
@@ -57,6 +60,29 @@ void main() { @@ -57,6 +60,29 @@ void main() {
57 '${tempDir.path}/ohos_hrv_result_$userId.sqlite', 60 '${tempDir.path}/ohos_hrv_result_$userId.sqlite',
58 ); 61 );
59 }); 62 });
  63 +
  64 + test('OHOS local raw queries do not check remote authorization', () async {
  65 + var authCheckCount = 0;
  66 + final service = OHOSHealthRawDataCoreService(
  67 + rawDataSource: _FakeHealthRawDataSource(),
  68 + userIdProvider: () => 1,
  69 + uploadResultsAfterCalculation: false,
  70 + healthReadAuthorizationChecker: () async {
  71 + authCheckCount += 1;
  72 + return false;
  73 + },
  74 + );
  75 +
  76 + final points = await service.queryRawDataPoints(
  77 + dataType: 2,
  78 + startTime: 100,
  79 + endTime: 200,
  80 + );
  81 +
  82 + expect(authCheckCount, 0);
  83 + expect(points, hasLength(1));
  84 + expect(points.single.endTime, 123);
  85 + });
60 } 86 }
61 87
62 class _FakeAppleHealthRawDataCoreService extends AppleHealthRawDataCoreService { 88 class _FakeAppleHealthRawDataCoreService extends AppleHealthRawDataCoreService {
@@ -98,3 +124,57 @@ class _FakeOhosHealthRawDataCoreService extends OHOSHealthRawDataCoreService { @@ -98,3 +124,57 @@ class _FakeOhosHealthRawDataCoreService extends OHOSHealthRawDataCoreService {
98 return false; 124 return false;
99 } 125 }
100 } 126 }
  127 +
  128 +class _FakeHealthRawDataSource implements HealthRawDataSource {
  129 + @override
  130 + Future<V2ActivityTarget?> getActivityGoal({bool refresh = true}) async {
  131 + return null;
  132 + }
  133 +
  134 + @override
  135 + Future<List<HealthKitRawActivityDataPoint>> getRawActivityData(
  136 + int startTime,
  137 + int endTime,
  138 + ) async {
  139 + return [
  140 + HealthKitRawActivityDataPoint(endTime: 123, activeEnergyBurned: 10),
  141 + ];
  142 + }
  143 +
  144 + @override
  145 + Future<List<HealthKitRawDataPoint>> getRawData(
  146 + int dataType,
  147 + int startTime,
  148 + int endTime,
  149 + ) async {
  150 + return [
  151 + HealthKitRawDataPoint(
  152 + dataType: dataType,
  153 + startTime: 123,
  154 + endTime: 123,
  155 + value: 72,
  156 + ),
  157 + ];
  158 + }
  159 +
  160 + @override
  161 + Future<List<HealthKitRawSleepDataPoint>> getRawSleepData(
  162 + int startTime,
  163 + int endTime,
  164 + ) async {
  165 + return const <HealthKitRawSleepDataPoint>[];
  166 + }
  167 +
  168 + @override
  169 + Future<List<HealthKitRawWorkoutDataPoint>> getRawWorkoutData(
  170 + int startTime,
  171 + int endTime,
  172 + ) async {
  173 + return const <HealthKitRawWorkoutDataPoint>[];
  174 + }
  175 +
  176 + @override
  177 + Future<bool> hasHealthData() async {
  178 + return true;
  179 + }
  180 +}