Commit 7605ac95aa560718b72f1a8e65f7eafaf97a471e

Authored by 权海
1 parent 23e3ab2d

feat(ui):对齐目标值

@@ -1345,7 +1345,7 @@ class HealthRawDailyStressCalculator { @@ -1345,7 +1345,7 @@ class HealthRawDailyStressCalculator {
1345 .toList() 1345 .toList()
1346 ..sort(); 1346 ..sort();
1347 if (values.isEmpty) return null; 1347 if (values.isEmpty) return null;
1348 - final stressValue = _average(values); 1348 + final stressValue = _integerDouble(_average(values));
1349 final stressScore = _dailyStressScore(values).round().clamp(1, 100).toInt(); 1349 final stressScore = _dailyStressScore(values).round().clamp(1, 100).toInt();
1350 return HealthRawDailyStressPoint( 1350 return HealthRawDailyStressPoint(
1351 userId: userId, 1351 userId: userId,
@@ -1423,6 +1423,8 @@ class HealthRawDailyStressCalculator { @@ -1423,6 +1423,8 @@ class HealthRawDailyStressCalculator {
1423 math.max(min.toDouble(), math.min(max.toDouble(), value.toDouble())); 1423 math.max(min.toDouble(), math.min(max.toDouble(), value.toDouble()));
1424 1424
1425 static double _round(double value) => (value * 10).round() / 10; 1425 static double _round(double value) => (value * 10).round() / 10;
  1426 +
  1427 + static double _integerDouble(num value) => value.toInt().toDouble();
1426 } 1428 }
1427 1429
1428 HealthRawStressState healthRawRealtimeStressState(num value) { 1430 HealthRawStressState healthRawRealtimeStressState(num value) {
@@ -1447,6 +1449,8 @@ double? _positiveDouble(Object? value) { @@ -1447,6 +1449,8 @@ double? _positiveDouble(Object? value) {
1447 return result; 1449 return result;
1448 } 1450 }
1449 1451
  1452 +double _integerDouble(num value) => value.toInt().toDouble();
  1453 +
1450 HealthRawStressState? _stressStateFromDb(Object? value) { 1454 HealthRawStressState? _stressStateFromDb(Object? value) {
1451 final stateValue = value as int?; 1455 final stateValue = value as int?;
1452 if (stateValue == null) return null; 1456 if (stateValue == null) return null;
@@ -2096,7 +2100,7 @@ CREATE TABLE IF NOT EXISTS $sleepResultsTable ( @@ -2096,7 +2100,7 @@ CREATE TABLE IF NOT EXISTS $sleepResultsTable (
2096 'raw_end_time': point.rawEndTime, 2100 'raw_end_time': point.rawEndTime,
2097 'user_id': point.userId, 2101 'user_id': point.userId,
2098 'raw_hrv': point.rawHrv, 2102 'raw_hrv': point.rawHrv,
2099 - 'result': point.result, 2103 + 'result': _integerDouble(point.result),
2100 'source_start_time': point.sourceStartTime, 2104 'source_start_time': point.sourceStartTime,
2101 'source_end_time': point.sourceEndTime, 2105 'source_end_time': point.sourceEndTime,
2102 'state': point.state.value, 2106 'state': point.state.value,
@@ -2114,7 +2118,7 @@ CREATE TABLE IF NOT EXISTS $sleepResultsTable ( @@ -2114,7 +2118,7 @@ CREATE TABLE IF NOT EXISTS $sleepResultsTable (
2114 'raw_end_time': point.rawEndTime, 2118 'raw_end_time': point.rawEndTime,
2115 'user_id': point.userId, 2119 'user_id': point.userId,
2116 'raw_hr': point.rawHr, 2120 'raw_hr': point.rawHr,
2117 - 'result': point.result, 2121 + 'result': _integerDouble(point.result),
2118 'source_start_time': point.sourceStartTime, 2122 'source_start_time': point.sourceStartTime,
2119 'source_end_time': point.sourceEndTime, 2123 'source_end_time': point.sourceEndTime,
2120 ..._flagsRow(point.flags), 2124 ..._flagsRow(point.flags),
@@ -2126,7 +2130,7 @@ CREATE TABLE IF NOT EXISTS $sleepResultsTable ( @@ -2126,7 +2130,7 @@ CREATE TABLE IF NOT EXISTS $sleepResultsTable (
2126 return <String, Object?>{ 2130 return <String, Object?>{
2127 'date': point.date, 2131 'date': point.date,
2128 'user_id': point.userId, 2132 'user_id': point.userId,
2129 - 'stress_value': point.stressValue, 2133 + 'stress_value': _integerDouble(point.stressValue),
2130 'stress_score': point.stressScore, 2134 'stress_score': point.stressScore,
2131 'state': point.state.value, 2135 'state': point.state.value,
2132 'data_time': point.dataTime, 2136 'data_time': point.dataTime,
@@ -226,15 +226,16 @@ class HealthRawStressCalculator { @@ -226,15 +226,16 @@ class HealthRawStressCalculator {
226 ...hrWindow, 226 ...hrWindow,
227 ...restingHistory, 227 ...restingHistory,
228 ]); 228 ]);
  229 + final normalizedTrendHrv = _integerDouble(trendHrv);
229 results.add( 230 results.add(
230 HealthRawHrvStressPoint( 231 HealthRawHrvStressPoint(
231 userId: userId, 232 userId: userId,
232 rawEndTime: point.endTime, 233 rawEndTime: point.endTime,
233 rawHrv: pointValue, 234 rawHrv: pointValue,
234 - result: trendHrv, 235 + result: normalizedTrendHrv,
235 sourceStartTime: sourceRange.start, 236 sourceStartTime: sourceRange.start,
236 sourceEndTime: sourceRange.end, 237 sourceEndTime: sourceRange.end,
237 - state: _hrvState(trendHrv), 238 + state: _hrvState(normalizedTrendHrv),
238 baselineHrv: baselineHrv, 239 baselineHrv: baselineHrv,
239 baselineAwakeHrv: baselineAwakeHrv, 240 baselineAwakeHrv: baselineAwakeHrv,
240 baselineSleepHrv: isSleep ? baselineSleepHrv : null, 241 baselineSleepHrv: isSleep ? baselineSleepHrv : null,
@@ -355,7 +356,7 @@ class HealthRawStressCalculator { @@ -355,7 +356,7 @@ class HealthRawStressCalculator {
355 } 356 }
356 } 357 }
357 358
358 - final stress = _round(_clamp(adjustment.value, 1, 100), 1); 359 + final stress = _integerDouble(_clamp(adjustment.value, 1, 100));
359 final sourceRange = _sourceRangeForRealtime( 360 final sourceRange = _sourceRangeForRealtime(
360 hrWindow: hrWindow, 361 hrWindow: hrWindow,
361 restingHistory: restingHistory, 362 restingHistory: restingHistory,
@@ -571,6 +572,8 @@ class HealthRawStressCalculator { @@ -571,6 +572,8 @@ class HealthRawStressCalculator {
571 return (value * scale).round() / scale; 572 return (value * scale).round() / scale;
572 } 573 }
573 574
  575 + static double _integerDouble(num value) => value.toInt().toDouble();
  576 +
574 static List<int> _daysInRange(int startTime, int endTime) { 577 static List<int> _daysInRange(int startTime, int endTime) {
575 final start = DateTime.fromMillisecondsSinceEpoch(startTime * 1000); 578 final start = DateTime.fromMillisecondsSinceEpoch(startTime * 1000);
576 final end = DateTime.fromMillisecondsSinceEpoch(endTime * 1000); 579 final end = DateTime.fromMillisecondsSinceEpoch(endTime * 1000);
@@ -3,11 +3,14 @@ import 'dart:async'; @@ -3,11 +3,14 @@ import 'dart:async';
3 import 'package:flutter/foundation.dart'; 3 import 'package:flutter/foundation.dart';
4 import 'package:flutter/material.dart'; 4 import 'package:flutter/material.dart';
5 import 'package:flutter/services.dart'; 5 import 'package:flutter/services.dart';
  6 +import 'package:get/get.dart';
6 import 'package:intl/date_symbol_data_local.dart'; 7 import 'package:intl/date_symbol_data_local.dart';
7 8
8 import 'app/bootstrap/app_bootstrap.dart'; 9 import 'app/bootstrap/app_bootstrap.dart';
9 import 'app/double_feel_app.dart'; 10 import 'app/double_feel_app.dart';
  11 +import 'core/services/health_raw_data_core_service.dart';
10 import 'core/theme/app_theme.dart'; 12 import 'core/theme/app_theme.dart';
  13 +import 'data/local/user_preferences_storage.dart';
11 14
12 Future<void> main() async { 15 Future<void> main() async {
13 runZonedGuarded<Future<Null>>( 16 runZonedGuarded<Future<Null>>(
@@ -29,3 +32,99 @@ Future<void> main() async { @@ -29,3 +32,99 @@ Future<void> main() async {
29 }, 32 },
30 ); 33 );
31 } 34 }
  35 +
  36 +@pragma('vm:entry-point')
  37 +Future<void> healthBackgroundMain() async {
  38 + WidgetsFlutterBinding.ensureInitialized();
  39 + const channel = MethodChannel('doublefeel_flutter_health_background_channel');
  40 +
  41 + await AppBootstrap.init();
  42 +
  43 + channel.setMethodCallHandler((call) async {
  44 + switch (call.method) {
  45 + case 'runPendingHealthTasks':
  46 + await _runPendingHealthTasks(channel, call.arguments);
  47 + return true;
  48 + default:
  49 + return null;
  50 + }
  51 + });
  52 +
  53 + await channel.invokeMethod('healthBackgroundTaskReady', {
  54 + 'timestamp': DateTime.now().millisecondsSinceEpoch ~/ 1000,
  55 + });
  56 +}
  57 +
  58 +Future<void> _runPendingHealthTasks(
  59 + MethodChannel channel,
  60 + Object? arguments,
  61 +) async {
  62 + final tasks = _backgroundHealthTasksFromArguments(arguments);
  63 + if (tasks.isEmpty) return;
  64 +
  65 + for (final task in tasks) {
  66 + await channel.invokeMethod('healthBackgroundTaskReceived', {
  67 + 'taskId': task.taskId,
  68 + });
  69 + }
  70 +
  71 + final userPrefs = Get.find<UserPreferencesStorage>();
  72 + final userId = userPrefs.preferences.value.meUserInfo?.id ?? 0;
  73 + final token = userPrefs.accessToken;
  74 + if (userId <= 0 || token.isEmpty) {
  75 + for (final task in tasks) {
  76 + await channel.invokeMethod('healthBackgroundTaskFinished', {
  77 + 'taskId': task.taskId,
  78 + 'success': false,
  79 + 'retryable': true,
  80 + 'error': 'missingLogin',
  81 + });
  82 + }
  83 + return;
  84 + }
  85 +
  86 + try {
  87 + await Get.find<HealthRawDataCoreService>().startCoreCaculate();
  88 + for (final task in tasks) {
  89 + await channel.invokeMethod('healthBackgroundTaskFinished', {
  90 + 'taskId': task.taskId,
  91 + 'success': true,
  92 + });
  93 + }
  94 + } catch (error) {
  95 + for (final task in tasks) {
  96 + await channel.invokeMethod('healthBackgroundTaskFinished', {
  97 + 'taskId': task.taskId,
  98 + 'success': false,
  99 + 'retryable': true,
  100 + 'error': error.toString(),
  101 + });
  102 + }
  103 + }
  104 +}
  105 +
  106 +List<_BackgroundHealthTask> _backgroundHealthTasksFromArguments(
  107 + Object? arguments,
  108 +) {
  109 + final rawTasksValue =
  110 + arguments is Map<Object?, Object?> ? arguments['tasks'] : null;
  111 + final rawTasks =
  112 + rawTasksValue is List ? rawTasksValue.cast<Object?>() : const <Object?>[];
  113 + return rawTasks
  114 + .whereType<Map<Object?, Object?>>()
  115 + .map(_BackgroundHealthTask.fromMap)
  116 + .whereType<_BackgroundHealthTask>()
  117 + .toList(growable: false);
  118 +}
  119 +
  120 +class _BackgroundHealthTask {
  121 + const _BackgroundHealthTask({required this.taskId});
  122 +
  123 + final String taskId;
  124 +
  125 + static _BackgroundHealthTask? fromMap(Map<Object?, Object?> map) {
  126 + final taskId = map['taskId'];
  127 + if (taskId is! String || taskId.isEmpty) return null;
  128 + return _BackgroundHealthTask(taskId: taskId);
  129 + }
  130 +}