Commit cf671201b853d1a2c5f68ed95b829d28853cdb7b

Authored by 权海
1 parent 8cf44b6b

feat(ui):修改首页activity的获取参数

1 import Foundation 1 import Foundation
2 import HealthKit 2 import HealthKit
3 3
  4 +let kLocalAnchored = 0
  5 +
4 struct AnchoredHealthUploadSummary { 6 struct AnchoredHealthUploadSummary {
5 let sleepUploadSuccess: Bool 7 let sleepUploadSuccess: Bool
6 let errorMessage: String? 8 let errorMessage: String?
@@ -139,7 +139,7 @@ final class HealthKitQueryReader { @@ -139,7 +139,7 @@ final class HealthKitQueryReader {
139 return try await fetchRawQuantitySamples( 139 return try await fetchRawQuantitySamples(
140 identifier: .appleStandTime, 140 identifier: .appleStandTime,
141 dataType: .stand, 141 dataType: .stand,
142 - unit: .hour(), 142 + unit: .count(),
143 startDate: startDate, 143 startDate: startDate,
144 endDate: endDate 144 endDate: endDate
145 ) 145 )
@@ -209,7 +209,7 @@ final class HealthKitQueryReader { @@ -209,7 +209,7 @@ final class HealthKitQueryReader {
209 healthValueTimestamp: timestamp, 209 healthValueTimestamp: timestamp,
210 move: Int(summary.activeEnergyBurnedGoal.doubleValue(for: .kilocalorie())), 210 move: Int(summary.activeEnergyBurnedGoal.doubleValue(for: .kilocalorie())),
211 stand: Int(summary.appleStandHoursGoal.doubleValue(for: .count())), 211 stand: Int(summary.appleStandHoursGoal.doubleValue(for: .count())),
212 -// activityMoveMode: Self.activityMoveModeValue(from: summary), 212 + activityMoveMode: Self.activityMoveModeValue(from: summary),
213 activeEnergyBurned: summary.activeEnergyBurned.doubleValue(for: .kilocalorie()), 213 activeEnergyBurned: summary.activeEnergyBurned.doubleValue(for: .kilocalorie()),
214 activeEnergyBurnedGoal: summary.activeEnergyBurnedGoal.doubleValue(for: .kilocalorie()), 214 activeEnergyBurnedGoal: summary.activeEnergyBurnedGoal.doubleValue(for: .kilocalorie()),
215 appleMoveTime: Self.appleMoveTimeValue(from: summary), 215 appleMoveTime: Self.appleMoveTimeValue(from: summary),
@@ -132,7 +132,7 @@ struct NativeActivityTarget { @@ -132,7 +132,7 @@ struct NativeActivityTarget {
132 let healthValueTimestamp: TimeInterval? 132 let healthValueTimestamp: TimeInterval?
133 let move: Int? 133 let move: Int?
134 let stand: Int? 134 let stand: Int?
135 -// let activityMoveMode: Int? 135 + let activityMoveMode: Int?
136 // 千卡 136 // 千卡
137 let activeEnergyBurned: Double? 137 let activeEnergyBurned: Double?
138 let activeEnergyBurnedGoal: Double? 138 let activeEnergyBurnedGoal: Double?
@@ -251,6 +251,7 @@ struct HealthKitRawMotionDataPoint: Hashable { @@ -251,6 +251,7 @@ struct HealthKitRawMotionDataPoint: Hashable {
251 /// Generated class from Pigeon that represents data sent in messages. 251 /// Generated class from Pigeon that represents data sent in messages.
252 struct HealthKitRawActivityDataPoint: Hashable { 252 struct HealthKitRawActivityDataPoint: Hashable {
253 var endTime: Int64 253 var endTime: Int64
  254 + var activityMoveMode: Int64? = nil
254 var activeEnergyBurned: Double? = nil 255 var activeEnergyBurned: Double? = nil
255 var activeEnergyBurnedGoal: Double? = nil 256 var activeEnergyBurnedGoal: Double? = nil
256 var appleMoveTime: Double? = nil 257 var appleMoveTime: Double? = nil
@@ -264,17 +265,19 @@ struct HealthKitRawActivityDataPoint: Hashable { @@ -264,17 +265,19 @@ struct HealthKitRawActivityDataPoint: Hashable {
264 // swift-format-ignore: AlwaysUseLowerCamelCase 265 // swift-format-ignore: AlwaysUseLowerCamelCase
265 static func fromList(_ pigeonVar_list: [Any?]) -> HealthKitRawActivityDataPoint? { 266 static func fromList(_ pigeonVar_list: [Any?]) -> HealthKitRawActivityDataPoint? {
266 let endTime = pigeonVar_list[0] as! Int64 267 let endTime = pigeonVar_list[0] as! Int64
267 - let activeEnergyBurned: Double? = nilOrValue(pigeonVar_list[1])  
268 - let activeEnergyBurnedGoal: Double? = nilOrValue(pigeonVar_list[2])  
269 - let appleMoveTime: Double? = nilOrValue(pigeonVar_list[3])  
270 - let appleMoveTimeGoal: Double? = nilOrValue(pigeonVar_list[4])  
271 - let appleExerciseTime: Double? = nilOrValue(pigeonVar_list[5])  
272 - let exerciseTimeGoal: Double? = nilOrValue(pigeonVar_list[6])  
273 - let appleStandHours: Double? = nilOrValue(pigeonVar_list[7])  
274 - let standHoursGoal: Double? = nilOrValue(pigeonVar_list[8]) 268 + let activityMoveMode: Int64? = nilOrValue(pigeonVar_list[1])
  269 + let activeEnergyBurned: Double? = nilOrValue(pigeonVar_list[2])
  270 + let activeEnergyBurnedGoal: Double? = nilOrValue(pigeonVar_list[3])
  271 + let appleMoveTime: Double? = nilOrValue(pigeonVar_list[4])
  272 + let appleMoveTimeGoal: Double? = nilOrValue(pigeonVar_list[5])
  273 + let appleExerciseTime: Double? = nilOrValue(pigeonVar_list[6])
  274 + let exerciseTimeGoal: Double? = nilOrValue(pigeonVar_list[7])
  275 + let appleStandHours: Double? = nilOrValue(pigeonVar_list[8])
  276 + let standHoursGoal: Double? = nilOrValue(pigeonVar_list[9])
275 277
276 return HealthKitRawActivityDataPoint( 278 return HealthKitRawActivityDataPoint(
277 endTime: endTime, 279 endTime: endTime,
  280 + activityMoveMode: activityMoveMode,
278 activeEnergyBurned: activeEnergyBurned, 281 activeEnergyBurned: activeEnergyBurned,
279 activeEnergyBurnedGoal: activeEnergyBurnedGoal, 282 activeEnergyBurnedGoal: activeEnergyBurnedGoal,
280 appleMoveTime: appleMoveTime, 283 appleMoveTime: appleMoveTime,
@@ -288,6 +291,7 @@ struct HealthKitRawActivityDataPoint: Hashable { @@ -288,6 +291,7 @@ struct HealthKitRawActivityDataPoint: Hashable {
288 func toList() -> [Any?] { 291 func toList() -> [Any?] {
289 return [ 292 return [
290 endTime, 293 endTime,
  294 + activityMoveMode,
291 activeEnergyBurned, 295 activeEnergyBurned,
292 activeEnergyBurnedGoal, 296 activeEnergyBurnedGoal,
293 appleMoveTime, 297 appleMoveTime,
@@ -386,6 +390,16 @@ protocol HealthKitRawDataHostApi { @@ -386,6 +390,16 @@ protocol HealthKitRawDataHostApi {
386 func getHealthKitRawActivityData(startTime: Int64, endTime: Int64, completion: @escaping (Result<[HealthKitRawActivityDataPoint], Error>) -> Void) 390 func getHealthKitRawActivityData(startTime: Int64, endTime: Int64, completion: @escaping (Result<[HealthKitRawActivityDataPoint], Error>) -> Void)
387 /// 从从AppleHealth中读取锻炼数据 391 /// 从从AppleHealth中读取锻炼数据
388 func getHealthKitRawWorkoutData(startTime: Int64, endTime: Int64, completion: @escaping (Result<[HealthKitRawWorkoutDataPoint], Error>) -> Void) 392 func getHealthKitRawWorkoutData(startTime: Int64, endTime: Int64, completion: @escaping (Result<[HealthKitRawWorkoutDataPoint], Error>) -> Void)
  393 + /// 原生是否通知了flutter ,apple health数据变化,让native 记录这次调用记录
  394 + /// 需要保存引起此次计算的数据变化类型列表、当前时间
  395 + func saveNativeCallFlutterChange(relativeDataTypes: [Int64], completion: @escaping (Result<Bool, Error>) -> Void)
  396 + /// caculate 一旦完成,让native 存储这次的计算记录
  397 + /// 需要保存引起此次计算的数据变化类型列表、当前时间
  398 + func saveFlutterCaculateFinished(relativeDataTypes: [Int64], completion: @escaping (Result<Bool, Error>) -> Void)
  399 + /// 让原生分享出来本地的记录文件
  400 + func shareNativeAppleHealthObserverRecord(completion: @escaping (Result<Bool, Error>) -> Void)
  401 + /// 让原生分享出来flutter的记录文件
  402 + func shareFlutterObserverRecord(completion: @escaping (Result<Bool, Error>) -> Void)
389 } 403 }
390 404
391 /// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. 405 /// Generated setup class from Pigeon to handle messages through the `binaryMessenger`.
@@ -596,5 +610,75 @@ class HealthKitRawDataHostApiSetup { @@ -596,5 +610,75 @@ class HealthKitRawDataHostApiSetup {
596 } else { 610 } else {
597 getHealthKitRawWorkoutDataChannel.setMessageHandler(nil) 611 getHealthKitRawWorkoutDataChannel.setMessageHandler(nil)
598 } 612 }
  613 + /// 原生是否通知了flutter ,apple health数据变化,让native 记录这次调用记录
  614 + /// 需要保存引起此次计算的数据变化类型列表、当前时间
  615 + let saveNativeCallFlutterChangeChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.doublefeel_flutter.HealthKitRawDataHostApi.saveNativeCallFlutterChange\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
  616 + if let api = api {
  617 + saveNativeCallFlutterChangeChannel.setMessageHandler { message, reply in
  618 + let args = message as! [Any?]
  619 + let relativeDataTypesArg = args[0] as! [Int64]
  620 + api.saveNativeCallFlutterChange(relativeDataTypes: relativeDataTypesArg) { result in
  621 + switch result {
  622 + case .success(let res):
  623 + reply(wrapResult(res))
  624 + case .failure(let error):
  625 + reply(wrapError(error))
  626 + }
  627 + }
  628 + }
  629 + } else {
  630 + saveNativeCallFlutterChangeChannel.setMessageHandler(nil)
  631 + }
  632 + /// caculate 一旦完成,让native 存储这次的计算记录
  633 + /// 需要保存引起此次计算的数据变化类型列表、当前时间
  634 + let saveFlutterCaculateFinishedChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.doublefeel_flutter.HealthKitRawDataHostApi.saveFlutterCaculateFinished\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
  635 + if let api = api {
  636 + saveFlutterCaculateFinishedChannel.setMessageHandler { message, reply in
  637 + let args = message as! [Any?]
  638 + let relativeDataTypesArg = args[0] as! [Int64]
  639 + api.saveFlutterCaculateFinished(relativeDataTypes: relativeDataTypesArg) { result in
  640 + switch result {
  641 + case .success(let res):
  642 + reply(wrapResult(res))
  643 + case .failure(let error):
  644 + reply(wrapError(error))
  645 + }
  646 + }
  647 + }
  648 + } else {
  649 + saveFlutterCaculateFinishedChannel.setMessageHandler(nil)
  650 + }
  651 + /// 让原生分享出来本地的记录文件
  652 + let shareNativeAppleHealthObserverRecordChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.doublefeel_flutter.HealthKitRawDataHostApi.shareNativeAppleHealthObserverRecord\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
  653 + if let api = api {
  654 + shareNativeAppleHealthObserverRecordChannel.setMessageHandler { _, reply in
  655 + api.shareNativeAppleHealthObserverRecord { result in
  656 + switch result {
  657 + case .success(let res):
  658 + reply(wrapResult(res))
  659 + case .failure(let error):
  660 + reply(wrapError(error))
  661 + }
  662 + }
  663 + }
  664 + } else {
  665 + shareNativeAppleHealthObserverRecordChannel.setMessageHandler(nil)
  666 + }
  667 + /// 让原生分享出来flutter的记录文件
  668 + let shareFlutterObserverRecordChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.doublefeel_flutter.HealthKitRawDataHostApi.shareFlutterObserverRecord\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
  669 + if let api = api {
  670 + shareFlutterObserverRecordChannel.setMessageHandler { _, reply in
  671 + api.shareFlutterObserverRecord { result in
  672 + switch result {
  673 + case .success(let res):
  674 + reply(wrapResult(res))
  675 + case .failure(let error):
  676 + reply(wrapError(error))
  677 + }
  678 + }
  679 + }
  680 + } else {
  681 + shareFlutterObserverRecordChannel.setMessageHandler(nil)
  682 + }
599 } 683 }
600 } 684 }
1 import Foundation 1 import Foundation
2 2
3 final class HealthKitRawDataHostApiImpl: HealthKitRawDataHostApi { 3 final class HealthKitRawDataHostApiImpl: HealthKitRawDataHostApi {
  4 + func saveNativeCallFlutterChange(relativeDataTypes: [Int64], completion: @escaping (Result<Bool, any Error>) -> Void) {
  5 +
  6 + }
  7 +
  8 + func saveFlutterCaculateFinished(relativeDataTypes: [Int64], completion: @escaping (Result<Bool, any Error>) -> Void) {
  9 +
  10 + }
  11 +
  12 + func shareNativeAppleHealthObserverRecord(completion: @escaping (Result<Bool, any Error>) -> Void) {
  13 +
  14 + }
  15 +
  16 + func shareFlutterObserverRecord(completion: @escaping (Result<Bool, any Error>) -> Void) {
  17 +
  18 + }
  19 +
4 private let service: HealthKitService 20 private let service: HealthKitService
5 21
6 init(service: HealthKitService = .shared) { 22 init(service: HealthKitService = .shared) {
@@ -229,6 +245,7 @@ final class HealthKitRawDataHostApiImpl: HealthKitRawDataHostApi { @@ -229,6 +245,7 @@ final class HealthKitRawDataHostApiImpl: HealthKitRawDataHostApi {
229 } 245 }
230 return HealthKitRawActivityDataPoint( 246 return HealthKitRawActivityDataPoint(
231 endTime: Int64(endTime.rounded()), 247 endTime: Int64(endTime.rounded()),
  248 + activityMoveMode: target.activityMoveMode == nil ? nil : Int64(target.activityMoveMode!),
232 activeEnergyBurned: target.activeEnergyBurned, 249 activeEnergyBurned: target.activeEnergyBurned,
233 activeEnergyBurnedGoal: target.activeEnergyBurnedGoal, 250 activeEnergyBurnedGoal: target.activeEnergyBurnedGoal,
234 appleMoveTime: target.appleMoveTime, 251 appleMoveTime: target.appleMoveTime,
@@ -490,7 +490,7 @@ class TodayController extends GetMaterialController { @@ -490,7 +490,7 @@ class TodayController extends GetMaterialController {
490 case AppFailure(): 490 case AppFailure():
491 stressChartData.clear(); 491 stressChartData.clear();
492 } 492 }
493 - switch (await _healthApi.getV2ActivityTarget(friendUserId)) { 493 + switch (await _healthApi.getV2ActivityTarget(friendUserId, intDate)) {
494 case AppSuccess(:final data): 494 case AppSuccess(:final data):
495 v2ActivityTarget.value = data; 495 v2ActivityTarget.value = data;
496 case AppFailure(): 496 case AppFailure():
@@ -703,6 +703,8 @@ class TodayController extends GetMaterialController { @@ -703,6 +703,8 @@ class TodayController extends GetMaterialController {
703 checkAddFriendVisible(); 703 checkAddFriendVisible();
704 checkHrvAdBannerVisible(); 704 checkHrvAdBannerVisible();
705 checkHealthDataAuthCardVisible(); 705 checkHealthDataAuthCardVisible();
  706 + _performHealthDataUpload();
  707 + // _startCoreCaculate();
706 // unawaited(loadDataForDate(selectedDate.value)); 708 // unawaited(loadDataForDate(selectedDate.value));
707 } 709 }
708 } 710 }
@@ -718,6 +720,7 @@ class TodayController extends GetMaterialController { @@ -718,6 +720,7 @@ class TodayController extends GetMaterialController {
718 checkAddFriendVisible(); 720 checkAddFriendVisible();
719 checkHrvAdBannerVisible(); 721 checkHrvAdBannerVisible();
720 checkHealthDataAuthCardVisible(isPullToRefresh: isPullToRefresh); 722 checkHealthDataAuthCardVisible(isPullToRefresh: isPullToRefresh);
  723 + _performHealthDataUpload();
721 // await loadDataForDate(selectedDate.value); 724 // await loadDataForDate(selectedDate.value);
722 } 725 }
723 } 726 }
@@ -51,6 +51,7 @@ abstract interface class HealthDataSource { @@ -51,6 +51,7 @@ abstract interface class HealthDataSource {
51 51
52 Future<AppResult<V2ActivityTarget>> getV2ActivityTarget( 52 Future<AppResult<V2ActivityTarget>> getV2ActivityTarget(
53 int? queryUserId, 53 int? queryUserId,
  54 + int intDate,
54 ); 55 );
55 56
56 Future<AppResult<V2HealthEverUploaded>> getHealthDataEverUploaded(); 57 Future<AppResult<V2HealthEverUploaded>> getHealthDataEverUploaded();
@@ -79,13 +79,14 @@ class HealthDataSourceWrapper implements HealthDataSource { @@ -79,13 +79,14 @@ class HealthDataSourceWrapper implements HealthDataSource {
79 } 79 }
80 80
81 @override 81 @override
82 - Future<AppResult<V2ActivityTarget>> getV2ActivityTarget(int? queryUserId) { 82 + Future<AppResult<V2ActivityTarget>> getV2ActivityTarget(
  83 + int? queryUserId, int initDate) {
83 HealthDataSource dataSource = remoteDataSource; 84 HealthDataSource dataSource = remoteDataSource;
84 if (queryUserId == null || _myUserId == queryUserId) { 85 if (queryUserId == null || _myUserId == queryUserId) {
85 dataSource = localDataSource; 86 dataSource = localDataSource;
86 } 87 }
87 88
88 - return dataSource.getV2ActivityTarget(queryUserId); 89 + return dataSource.getV2ActivityTarget(queryUserId, initDate);
89 } 90 }
90 91
91 @override 92 @override
@@ -263,7 +263,7 @@ class LocalHealthDataConvert { @@ -263,7 +263,7 @@ class LocalHealthDataConvert {
263 263
264 final data = ActivityBurnStatisticsDataV2( 264 final data = ActivityBurnStatisticsDataV2(
265 totalMove: _sum(daily.map((e) => e.move).toList()), 265 totalMove: _sum(daily.map((e) => e.move).toList()),
266 - totalSteps: _sum(daily.map((e) => e.steps).toList()), 266 + totalSteps: 0,
267 totalStand: _sum(daily.map((e) => e.standHours).toList()), 267 totalStand: _sum(daily.map((e) => e.standHours).toList()),
268 totalExercise: _sum(daily.map((e) => e.exerciseSeconds).toList()), 268 totalExercise: _sum(daily.map((e) => e.exerciseSeconds).toList()),
269 avgMove: _averageOrNull(daily.map((e) => e.move).toList()), 269 avgMove: _averageOrNull(daily.map((e) => e.move).toList()),
@@ -399,8 +399,8 @@ class LocalHealthDataConvert { @@ -399,8 +399,8 @@ class LocalHealthDataConvert {
399 ); 399 );
400 return V2ActivityTarget( 400 return V2ActivityTarget(
401 userId: userId, 401 userId: userId,
402 - move: latestWithGoal?.activeEnergyBurnedGoal?.round(),  
403 - step: latestWithGoal?.appleMoveTimeGoal?.round(), 402 + move: latestWithGoal?.activeEnergyBurnedGoal?.ceil(),
  403 + step: 0,
404 stand: latestWithGoal?.standHoursGoal?.round(), 404 stand: latestWithGoal?.standHoursGoal?.round(),
405 exercise: latestWithGoal?.exerciseTimeGoal == null 405 exercise: latestWithGoal?.exerciseTimeGoal == null
406 ? null 406 ? null
@@ -451,7 +451,7 @@ class LocalHealthDataConvert { @@ -451,7 +451,7 @@ class LocalHealthDataConvert {
451 move: activitySummary.move.ceil(), 451 move: activitySummary.move.ceil(),
452 exercise: activitySummary.exerciseSeconds.round(), 452 exercise: activitySummary.exerciseSeconds.round(),
453 stand: activitySummary.standHours.round(), 453 stand: activitySummary.standHours.round(),
454 - steps: activitySummary.steps.round(), 454 + steps: 0,
455 sleepDuration: sleepSummary.durationSeconds.round(), 455 sleepDuration: sleepSummary.durationSeconds.round(),
456 sleepScore: sleepSummary.score?.toDouble(), 456 sleepScore: sleepSummary.score?.toDouble(),
457 sleepState: sleepSummary.state?.value, 457 sleepState: sleepSummary.state?.value,
@@ -496,7 +496,7 @@ class LocalHealthDataConvert { @@ -496,7 +496,7 @@ class LocalHealthDataConvert {
496 move: activitySummary.move.ceil(), 496 move: activitySummary.move.ceil(),
497 exercise: activitySummary.exerciseSeconds.round(), 497 exercise: activitySummary.exerciseSeconds.round(),
498 stand: activitySummary.standHours.round(), 498 stand: activitySummary.standHours.round(),
499 - steps: activitySummary.steps.round(), 499 + steps: 0,
500 sleepDuration: sleepResult == null ? 0 : sleepResult.sleepMinutes * 60, 500 sleepDuration: sleepResult == null ? 0 : sleepResult.sleepMinutes * 60,
501 sleepScore: sleepResult?.sleepScore.toDouble(), 501 sleepScore: sleepResult?.sleepScore.toDouble(),
502 sleepState: sleepResult?.sleepStateValue, 502 sleepState: sleepResult?.sleepStateValue,
@@ -521,22 +521,14 @@ class LocalHealthDataConvert { @@ -521,22 +521,14 @@ class LocalHealthDataConvert {
521 } 521 }
522 522
523 static V2LatestHrvData v2LatestHrvData( 523 static V2LatestHrvData v2LatestHrvData(
524 - List<HealthRawHrvStressPoint> hrvPoints, {  
525 - List<HealthRawHrvStressPoint> previousHrvPoints =  
526 - const <HealthRawHrvStressPoint>[],  
527 - }) { 524 + List<HealthRawHrvStressPoint> hrvPoints) {
528 final latest = _latestHrvByRawEndTime(hrvPoints); 525 final latest = _latestHrvByRawEndTime(hrvPoints);
529 return V2LatestHrvData( 526 return V2LatestHrvData(
530 latestHrv: (latest?.result ?? 0).floor().toDouble(), 527 latestHrv: (latest?.result ?? 0).floor().toDouble(),
531 latestDataTime: latest?.rawEndTime, 528 latestDataTime: latest?.rawEndTime,
532 state: latest?.state.value, 529 state: latest?.state.value,
533 tip: _latestHrvTip( 530 tip: _latestHrvTip(
534 - latest: latest,  
535 - previous: _previousHrvPoint(  
536 - latest: latest,  
537 - hrvPoints: hrvPoints,  
538 - previousHrvPoints: previousHrvPoints,  
539 - ), 531 + latest: latest
540 ), 532 ),
541 ); 533 );
542 } 534 }
@@ -581,13 +573,11 @@ class LocalHealthDataConvert { @@ -581,13 +573,11 @@ class LocalHealthDataConvert {
581 final latest = dayActivity.isEmpty ? null : dayActivity.last; 573 final latest = dayActivity.isEmpty ? null : dayActivity.last;
582 return _ActivityDaySummary( 574 return _ActivityDaySummary(
583 day: day, 575 day: day,
584 - move: latest?.activeEnergyBurned ?? 0,  
585 - steps: latest?.appleMoveTime ?? 0, 576 + move: (latest?.activeEnergyBurned ?? 0).ceil(),
586 standHours: latest?.appleStandHours ?? 0, 577 standHours: latest?.appleStandHours ?? 0,
587 exerciseSeconds: latest?.appleExerciseTime ?? 0, 578 exerciseSeconds: latest?.appleExerciseTime ?? 0,
588 - moveGoal: latest?.activeEnergyBurnedGoal,  
589 - stepGoal: latest?.appleMoveTimeGoal,  
590 - standGoal: latest?.standHoursGoal, 579 + moveGoal: latest?.activeEnergyBurnedGoal ?? 480,
  580 + standGoal: latest?.standHoursGoal ?? 8,
591 exerciseGoalSeconds: latest?.exerciseTimeGoal, 581 exerciseGoalSeconds: latest?.exerciseTimeGoal,
592 ); 582 );
593 } 583 }
@@ -627,11 +617,9 @@ class LocalHealthDataConvert { @@ -627,11 +617,9 @@ class LocalHealthDataConvert {
627 } 617 }
628 618
629 static String? _latestHrvTip({ 619 static String? _latestHrvTip({
630 - required HealthRawHrvStressPoint? latest,  
631 - required HealthRawHrvStressPoint? previous, 620 + required HealthRawHrvStressPoint? latest
632 }) { 621 }) {
633 - if (latest == null || previous == null) return null;  
634 - if (latest.rawEndTime - previous.rawEndTime < 2 * 60 * 60) return null; 622 + if (latest == null) return null;
635 623
636 final isAboveBaseline = latest.result >= latest.baselineHrv; 624 final isAboveBaseline = latest.result >= latest.baselineHrv;
637 return switch (latest.state) { 625 return switch (latest.state) {
@@ -665,7 +653,7 @@ class LocalHealthDataConvert { @@ -665,7 +653,7 @@ class LocalHealthDataConvert {
665 if (summary == null || !summary.hasGoal) return null; 653 if (summary == null || !summary.hasGoal) return null;
666 return ActivityTargetInfo( 654 return ActivityTargetInfo(
667 move: summary.moveGoal, 655 move: summary.moveGoal,
668 - step: summary.stepGoal, 656 + step: 0,
669 stand: summary.standGoal, 657 stand: summary.standGoal,
670 exercise: summary.exerciseGoalSeconds, 658 exercise: summary.exerciseGoalSeconds,
671 ); 659 );
@@ -963,28 +951,23 @@ class _ActivityDaySummary { @@ -963,28 +951,23 @@ class _ActivityDaySummary {
963 const _ActivityDaySummary({ 951 const _ActivityDaySummary({
964 required this.day, 952 required this.day,
965 required this.move, 953 required this.move,
966 - required this.steps,  
967 required this.standHours, 954 required this.standHours,
968 required this.exerciseSeconds, 955 required this.exerciseSeconds,
969 required this.moveGoal, 956 required this.moveGoal,
970 - required this.stepGoal,  
971 required this.standGoal, 957 required this.standGoal,
972 required this.exerciseGoalSeconds, 958 required this.exerciseGoalSeconds,
973 }); 959 });
974 960
975 final DateTime day; 961 final DateTime day;
976 final num move; 962 final num move;
977 - final num steps;  
978 final num standHours; 963 final num standHours;
979 final num exerciseSeconds; 964 final num exerciseSeconds;
980 final num? moveGoal; 965 final num? moveGoal;
981 - final num? stepGoal;  
982 final num? standGoal; 966 final num? standGoal;
983 final num? exerciseGoalSeconds; 967 final num? exerciseGoalSeconds;
984 968
985 bool get hasGoal => 969 bool get hasGoal =>
986 moveGoal != null || 970 moveGoal != null ||
987 - stepGoal != null ||  
988 standGoal != null || 971 standGoal != null ||
989 exerciseGoalSeconds != null; 972 exerciseGoalSeconds != null;
990 } 973 }
@@ -160,21 +160,20 @@ class LocalHealthDataSource implements HealthDataSource { @@ -160,21 +160,20 @@ class LocalHealthDataSource implements HealthDataSource {
160 160
161 @override 161 @override
162 Future<AppResult<V2ActivityTarget>> getV2ActivityTarget( 162 Future<AppResult<V2ActivityTarget>> getV2ActivityTarget(
163 - int? queryUserId) async { 163 + int? queryUserId, int intDate) async {
164 try { 164 try {
165 - final now = DateTime.now();  
166 - final queryStart = LocalHealthDataConvert.unixSeconds(  
167 - now.subtract(  
168 - const Duration(days: HealthRawDataCoreService.defaultLookbackDays)), 165 + final day = LocalHealthDataConvert.dateFromKey(intDate);
  166 + final queryStart = LocalHealthDataConvert.unixSeconds(day);
  167 + final queryEnd = LocalHealthDataConvert.unixSeconds(
  168 + day.add(const Duration(days: 1)),
169 ); 169 );
170 - final queryEnd = LocalHealthDataConvert.unixSeconds(now);  
171 final activity = await coreService.queryRawActivitySummaries( 170 final activity = await coreService.queryRawActivitySummaries(
172 startTime: queryStart, 171 startTime: queryStart,
173 endTime: queryEnd, 172 endTime: queryEnd,
174 ); 173 );
175 return AppSuccess( 174 return AppSuccess(
176 LocalHealthDataConvert.v2ActivityTarget( 175 LocalHealthDataConvert.v2ActivityTarget(
177 - userId: 0, 176 + userId: queryUserId ?? 0,
178 activity: activity, 177 activity: activity,
179 ), 178 ),
180 ); 179 );
@@ -249,21 +248,12 @@ class LocalHealthDataSource implements HealthDataSource { @@ -249,21 +248,12 @@ class LocalHealthDataSource implements HealthDataSource {
249 int? queryUserId, int intDate) async { 248 int? queryUserId, int intDate) async {
250 try { 249 try {
251 final (startTime, endTime) = _dayRange(intDate); 250 final (startTime, endTime) = _dayRange(intDate);
252 - final previousStartTime = startTime -  
253 - HealthRawDataCoreService.defaultLookbackDays * Duration.secondsPerDay;  
254 - final previousHrvPoints = await coreService.queryHrvStressPoints(  
255 - startTime: previousStartTime,  
256 - endTime: startTime - 1,  
257 - );  
258 final hrvPoints = await coreService.queryHrvStressPoints( 251 final hrvPoints = await coreService.queryHrvStressPoints(
259 startTime: startTime, 252 startTime: startTime,
260 endTime: endTime, 253 endTime: endTime,
261 ); 254 );
262 return AppSuccess( 255 return AppSuccess(
263 - LocalHealthDataConvert.v2LatestHrvData(  
264 - hrvPoints,  
265 - previousHrvPoints: previousHrvPoints,  
266 - ), 256 + LocalHealthDataConvert.v2LatestHrvData(hrvPoints),
267 ); 257 );
268 } catch (error) { 258 } catch (error) {
269 return AppFailure(AppUnknownError(error)); 259 return AppFailure(AppUnknownError(error));
@@ -95,6 +95,7 @@ class RemoteHealthDataSource implements HealthDataSource { @@ -95,6 +95,7 @@ class RemoteHealthDataSource implements HealthDataSource {
95 @override 95 @override
96 Future<AppResult<V2ActivityTarget>> getV2ActivityTarget( 96 Future<AppResult<V2ActivityTarget>> getV2ActivityTarget(
97 int? queryUserId, 97 int? queryUserId,
  98 + int initDate,
98 ) { 99 ) {
99 return _healthApi.getV2ActivityTarget(queryUserId); 100 return _healthApi.getV2ActivityTarget(queryUserId);
100 } 101 }
@@ -242,6 +242,7 @@ class HealthKitRawMotionDataPoint { @@ -242,6 +242,7 @@ class HealthKitRawMotionDataPoint {
242 class HealthKitRawActivityDataPoint { 242 class HealthKitRawActivityDataPoint {
243 HealthKitRawActivityDataPoint({ 243 HealthKitRawActivityDataPoint({
244 required this.endTime, 244 required this.endTime,
  245 + this.activityMoveMode,
245 this.activeEnergyBurned, 246 this.activeEnergyBurned,
246 this.activeEnergyBurnedGoal, 247 this.activeEnergyBurnedGoal,
247 this.appleMoveTime, 248 this.appleMoveTime,
@@ -254,6 +255,8 @@ class HealthKitRawActivityDataPoint { @@ -254,6 +255,8 @@ class HealthKitRawActivityDataPoint {
254 255
255 int endTime; 256 int endTime;
256 257
  258 + int? activityMoveMode;
  259 +
257 double? activeEnergyBurned; 260 double? activeEnergyBurned;
258 261
259 double? activeEnergyBurnedGoal; 262 double? activeEnergyBurnedGoal;
@@ -273,6 +276,7 @@ class HealthKitRawActivityDataPoint { @@ -273,6 +276,7 @@ class HealthKitRawActivityDataPoint {
273 List<Object?> _toList() { 276 List<Object?> _toList() {
274 return <Object?>[ 277 return <Object?>[
275 endTime, 278 endTime,
  279 + activityMoveMode,
276 activeEnergyBurned, 280 activeEnergyBurned,
277 activeEnergyBurnedGoal, 281 activeEnergyBurnedGoal,
278 appleMoveTime, 282 appleMoveTime,
@@ -291,14 +295,15 @@ class HealthKitRawActivityDataPoint { @@ -291,14 +295,15 @@ class HealthKitRawActivityDataPoint {
291 result as List<Object?>; 295 result as List<Object?>;
292 return HealthKitRawActivityDataPoint( 296 return HealthKitRawActivityDataPoint(
293 endTime: result[0]! as int, 297 endTime: result[0]! as int,
294 - activeEnergyBurned: result[1] as double?,  
295 - activeEnergyBurnedGoal: result[2] as double?,  
296 - appleMoveTime: result[3] as double?,  
297 - appleMoveTimeGoal: result[4] as double?,  
298 - appleExerciseTime: result[5] as double?,  
299 - exerciseTimeGoal: result[6] as double?,  
300 - appleStandHours: result[7] as double?,  
301 - standHoursGoal: result[8] as double?, 298 + activityMoveMode: result[1] as int?,
  299 + activeEnergyBurned: result[2] as double?,
  300 + activeEnergyBurnedGoal: result[3] as double?,
  301 + appleMoveTime: result[4] as double?,
  302 + appleMoveTimeGoal: result[5] as double?,
  303 + appleExerciseTime: result[6] as double?,
  304 + exerciseTimeGoal: result[7] as double?,
  305 + appleStandHours: result[8] as double?,
  306 + standHoursGoal: result[9] as double?,
302 ); 307 );
303 } 308 }
304 309
@@ -698,4 +703,122 @@ class HealthKitRawDataHostApi { @@ -698,4 +703,122 @@ class HealthKitRawDataHostApi {
698 return (pigeonVar_replyList[0] as List<Object?>?)!.cast<HealthKitRawWorkoutDataPoint>(); 703 return (pigeonVar_replyList[0] as List<Object?>?)!.cast<HealthKitRawWorkoutDataPoint>();
699 } 704 }
700 } 705 }
  706 +
  707 + /// 原生是否通知了flutter ,apple health数据变化,让native 记录这次调用记录
  708 + /// 需要保存引起此次计算的数据变化类型列表、当前时间
  709 + Future<bool> saveNativeCallFlutterChange({List<int> relativeDataTypes}) async {
  710 + final String pigeonVar_channelName = 'dev.flutter.pigeon.doublefeel_flutter.HealthKitRawDataHostApi.saveNativeCallFlutterChange$pigeonVar_messageChannelSuffix';
  711 + final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
  712 + pigeonVar_channelName,
  713 + pigeonChannelCodec,
  714 + binaryMessenger: pigeonVar_binaryMessenger,
  715 + );
  716 + final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(<Object?>[relativeDataTypes]);
  717 + final List<Object?>? pigeonVar_replyList =
  718 + await pigeonVar_sendFuture as List<Object?>?;
  719 + if (pigeonVar_replyList == null) {
  720 + throw _createConnectionError(pigeonVar_channelName);
  721 + } else if (pigeonVar_replyList.length > 1) {
  722 + throw PlatformException(
  723 + code: pigeonVar_replyList[0]! as String,
  724 + message: pigeonVar_replyList[1] as String?,
  725 + details: pigeonVar_replyList[2],
  726 + );
  727 + } else if (pigeonVar_replyList[0] == null) {
  728 + throw PlatformException(
  729 + code: 'null-error',
  730 + message: 'Host platform returned null value for non-null return value.',
  731 + );
  732 + } else {
  733 + return (pigeonVar_replyList[0] as bool?)!;
  734 + }
  735 + }
  736 +
  737 + /// caculate 一旦完成,让native 存储这次的计算记录
  738 + /// 需要保存引起此次计算的数据变化类型列表、当前时间
  739 + Future<bool> saveFlutterCaculateFinished({List<int> relativeDataTypes}) async {
  740 + final String pigeonVar_channelName = 'dev.flutter.pigeon.doublefeel_flutter.HealthKitRawDataHostApi.saveFlutterCaculateFinished$pigeonVar_messageChannelSuffix';
  741 + final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
  742 + pigeonVar_channelName,
  743 + pigeonChannelCodec,
  744 + binaryMessenger: pigeonVar_binaryMessenger,
  745 + );
  746 + final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(<Object?>[relativeDataTypes]);
  747 + final List<Object?>? pigeonVar_replyList =
  748 + await pigeonVar_sendFuture as List<Object?>?;
  749 + if (pigeonVar_replyList == null) {
  750 + throw _createConnectionError(pigeonVar_channelName);
  751 + } else if (pigeonVar_replyList.length > 1) {
  752 + throw PlatformException(
  753 + code: pigeonVar_replyList[0]! as String,
  754 + message: pigeonVar_replyList[1] as String?,
  755 + details: pigeonVar_replyList[2],
  756 + );
  757 + } else if (pigeonVar_replyList[0] == null) {
  758 + throw PlatformException(
  759 + code: 'null-error',
  760 + message: 'Host platform returned null value for non-null return value.',
  761 + );
  762 + } else {
  763 + return (pigeonVar_replyList[0] as bool?)!;
  764 + }
  765 + }
  766 +
  767 + /// 让原生分享出来本地的记录文件
  768 + Future<bool> shareNativeAppleHealthObserverRecord() async {
  769 + final String pigeonVar_channelName = 'dev.flutter.pigeon.doublefeel_flutter.HealthKitRawDataHostApi.shareNativeAppleHealthObserverRecord$pigeonVar_messageChannelSuffix';
  770 + final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
  771 + pigeonVar_channelName,
  772 + pigeonChannelCodec,
  773 + binaryMessenger: pigeonVar_binaryMessenger,
  774 + );
  775 + final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(null);
  776 + final List<Object?>? pigeonVar_replyList =
  777 + await pigeonVar_sendFuture as List<Object?>?;
  778 + if (pigeonVar_replyList == null) {
  779 + throw _createConnectionError(pigeonVar_channelName);
  780 + } else if (pigeonVar_replyList.length > 1) {
  781 + throw PlatformException(
  782 + code: pigeonVar_replyList[0]! as String,
  783 + message: pigeonVar_replyList[1] as String?,
  784 + details: pigeonVar_replyList[2],
  785 + );
  786 + } else if (pigeonVar_replyList[0] == null) {
  787 + throw PlatformException(
  788 + code: 'null-error',
  789 + message: 'Host platform returned null value for non-null return value.',
  790 + );
  791 + } else {
  792 + return (pigeonVar_replyList[0] as bool?)!;
  793 + }
  794 + }
  795 +
  796 + /// 让原生分享出来flutter的记录文件
  797 + Future<bool> shareFlutterObserverRecord() async {
  798 + final String pigeonVar_channelName = 'dev.flutter.pigeon.doublefeel_flutter.HealthKitRawDataHostApi.shareFlutterObserverRecord$pigeonVar_messageChannelSuffix';
  799 + final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
  800 + pigeonVar_channelName,
  801 + pigeonChannelCodec,
  802 + binaryMessenger: pigeonVar_binaryMessenger,
  803 + );
  804 + final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(null);
  805 + final List<Object?>? pigeonVar_replyList =
  806 + await pigeonVar_sendFuture as List<Object?>?;
  807 + if (pigeonVar_replyList == null) {
  808 + throw _createConnectionError(pigeonVar_channelName);
  809 + } else if (pigeonVar_replyList.length > 1) {
  810 + throw PlatformException(
  811 + code: pigeonVar_replyList[0]! as String,
  812 + message: pigeonVar_replyList[1] as String?,
  813 + details: pigeonVar_replyList[2],
  814 + );
  815 + } else if (pigeonVar_replyList[0] == null) {
  816 + throw PlatformException(
  817 + code: 'null-error',
  818 + message: 'Host platform returned null value for non-null return value.',
  819 + );
  820 + } else {
  821 + return (pigeonVar_replyList[0] as bool?)!;
  822 + }
  823 + }
701 } 824 }
@@ -51,6 +51,8 @@ class HealthKitRawMotionDataPoint { @@ -51,6 +51,8 @@ class HealthKitRawMotionDataPoint {
51 51
52 class HealthKitRawActivityDataPoint { 52 class HealthKitRawActivityDataPoint {
53 int endTime; 53 int endTime;
  54 +
  55 + int? activityMoveMode;
54 // 千卡 56 // 千卡
55 double? activeEnergyBurned; 57 double? activeEnergyBurned;
56 double? activeEnergyBurnedGoal; 58 double? activeEnergyBurnedGoal;
@@ -66,6 +68,7 @@ class HealthKitRawActivityDataPoint { @@ -66,6 +68,7 @@ class HealthKitRawActivityDataPoint {
66 68
67 HealthKitRawActivityDataPoint({ 69 HealthKitRawActivityDataPoint({
68 required this.endTime, 70 required this.endTime,
  71 + this.activityMoveMode,
69 this.activeEnergyBurned, 72 this.activeEnergyBurned,
70 this.activeEnergyBurnedGoal, 73 this.activeEnergyBurnedGoal,
71 this.appleMoveTime, 74 this.appleMoveTime,
@@ -140,4 +143,23 @@ abstract class HealthKitRawDataHostApi { @@ -140,4 +143,23 @@ abstract class HealthKitRawDataHostApi {
140 @async 143 @async
141 List<HealthKitRawWorkoutDataPoint> getHealthKitRawWorkoutData( 144 List<HealthKitRawWorkoutDataPoint> getHealthKitRawWorkoutData(
142 int startTime, int endTime); 145 int startTime, int endTime);
  146 +
  147 +// DEBUG
  148 + /// 原生是否通知了flutter ,apple health数据变化,让native 记录这次调用记录
  149 + /// 需要保存引起此次计算的数据变化类型列表、当前时间
  150 + @async
  151 + bool saveNativeCallFlutterChange({List<int> relativeDataTypes});
  152 +
  153 + /// caculate 一旦完成,让native 存储这次的计算记录
  154 + /// 需要保存引起此次计算的数据变化类型列表、当前时间
  155 + @async
  156 + bool saveFlutterCaculateFinished({List<int> relativeDataTypes});
  157 +
  158 + /// 让原生分享出来本地的记录文件
  159 + @async
  160 + bool shareNativeAppleHealthObserverRecord();
  161 +
  162 + /// 让原生分享出来flutter的记录文件
  163 + @async
  164 + bool shareFlutterObserverRecord();
143 } 165 }
@@ -447,6 +447,7 @@ void main() { @@ -447,6 +447,7 @@ void main() {
447 final activity = [ 447 final activity = [
448 HealthKitRawActivityDataPoint( 448 HealthKitRawActivityDataPoint(
449 endTime: endTime, 449 endTime: endTime,
  450 + activityMoveMode: 0,
450 activeEnergyBurned: 300, 451 activeEnergyBurned: 300,
451 activeEnergyBurnedGoal: 500, 452 activeEnergyBurnedGoal: 500,
452 appleMoveTime: 8000, 453 appleMoveTime: 8000,
@@ -502,14 +503,6 @@ void main() { @@ -502,14 +503,6 @@ void main() {
502 state: HealthRawStressState.excellent, 503 state: HealthRawStressState.excellent,
503 ), 504 ),
504 ], 505 ],
505 - previousHrvPoints: [  
506 - _hrvStressPoint(  
507 - rawEndTime: latestTime - 2 * 60 * 60,  
508 - result: 28,  
509 - baselineHrv: 30,  
510 - state: HealthRawStressState.normal,  
511 - ),  
512 - ],  
513 ); 506 );
514 507
515 expect(data.latestHrv, 35); 508 expect(data.latestHrv, 35);
@@ -528,9 +521,6 @@ void main() { @@ -528,9 +521,6 @@ void main() {
528 state: HealthRawStressState.attention, 521 state: HealthRawStressState.attention,
529 ), 522 ),
530 ], 523 ],
531 - previousHrvPoints: [  
532 - _hrvStressPoint(rawEndTime: latestTime - 3 * 60 * 60),  
533 - ],  
534 ); 524 );
535 525
536 expect(data.tip, contains('明显低于日常水平')); 526 expect(data.tip, contains('明显低于日常水平'));
@@ -548,9 +538,6 @@ void main() { @@ -548,9 +538,6 @@ void main() {
548 state: HealthRawStressState.excellent, 538 state: HealthRawStressState.excellent,
549 ), 539 ),
550 ], 540 ],
551 - previousHrvPoints: [  
552 - _hrvStressPoint(rawEndTime: latestTime - 60 * 60),  
553 - ],  
554 ); 541 );
555 542
556 expect(data.tip, isNull); 543 expect(data.tip, isNull);