Commit 1016dd218fd3f291b41cc482127758e974f9576c

Authored by 权海
1 parent 9c4410d2

feat(ui):活动消耗向上取整

... ... @@ -431,6 +431,10 @@ class HealthRawDataCoreService {
);
}
Future<int?> queryEarliestHrRawEndTime() {
return _localStore.earliestRealtimeRawEndTime(_userId);
}
Future<List<HealthRawDailyStressPoint>> queryDailyStressPoints({
required int startDate,
required int endDate,
... ... @@ -1555,6 +1559,10 @@ class HealthRawStressLocalStore {
return _latestRawEndTime(userId, realtimeStressResultsTable);
}
Future<int?> earliestRealtimeRawEndTime(int userId) {
return _earliestRawEndTime(userId, realtimeStressResultsTable);
}
Future<int?> latestSleepResultTime(int userId) async {
final db = await _database(userId);
final rows = await db.query(
... ... @@ -1878,6 +1886,18 @@ CREATE TABLE IF NOT EXISTS $sleepResultsTable (
return rows.first['raw_end_time'] as int;
}
Future<int?> _earliestRawEndTime(int userId, String table) async {
final db = await _database(userId);
final rows = await db.query(
table,
columns: ['raw_end_time'],
orderBy: 'raw_end_time ASC',
limit: 1,
);
if (rows.isEmpty) return null;
return rows.first['raw_end_time'] as int;
}
Future<void> _markUploaded({
required int userId,
required String table,
... ...
... ... @@ -447,7 +447,7 @@ class LocalHealthDataConvert {
.whereType<num>()
.toList(),
)?.floor(),
move: activitySummary.move.round(),
move: activitySummary.move.ceil(),
exercise: activitySummary.exerciseSeconds.round(),
stand: activitySummary.standHours.round(),
steps: activitySummary.steps.round(),
... ... @@ -492,7 +492,7 @@ class LocalHealthDataConvert {
hrAvg: _averageOrNull(
sleepHr.map((e) => e.value).whereType<num>().toList(),
)?.floor(),
move: activitySummary.move.round(),
move: activitySummary.move.ceil(),
exercise: activitySummary.exerciseSeconds.round(),
stand: activitySummary.standHours.round(),
steps: activitySummary.steps.round(),
... ...
... ... @@ -146,8 +146,13 @@ class LocalHealthDataSource implements HealthDataSource {
@override
Future<AppResult<V2HealthEverUploaded>> getHealthDataEverUploaded() async {
try {
final hasHealthData = await coreService.hasHealthData();
return AppSuccess(V2HealthEverUploaded(flag: hasHealthData));
final startTime = await coreService.queryEarliestHrRawEndTime();
return AppSuccess(
V2HealthEverUploaded(
flag: true,
startTime: startTime,
),
);
} catch (error) {
return AppFailure(AppUnknownError(error));
}
... ...
import 'package:doublefeel_flutter/core/result/app_result.dart';
import 'package:doublefeel_flutter/core/services/health_raw_data_core_service.dart';
import 'package:doublefeel_flutter/data/datasource/health/health_local_data_convert.dart';
import 'package:doublefeel_flutter/data/datasource/health/health_local_datasource.dart';
import 'package:doublefeel_flutter/data/models/enums/app_enums.dart';
import 'package:doublefeel_flutter/pigeon/health_kit_api.g.dart';
import 'package:doublefeel_flutter/pigeon/health_kit_raw_data_api.g.dart';
... ... @@ -411,6 +413,38 @@ void main() {
expect(api.sleepUploadCallCount, 1);
expect(rows.sleepRows.single['uploaded'], 1);
});
test('local data source returns earliest local hr start time', () async {
const base = 1800000000;
final api = _FakeHealthKitRawDataHostApi();
final store = _MemoryHealthRawStressLocalStore();
final service = HealthRawDataCoreService(
healthApi: _FakeHealthKitHostApi(),
rawDataApi: api,
localStore: store,
userIdProvider: () => 42,
uploadResultsAfterCalculation: false,
);
await store.upsertResult(
HealthRawStressCalculationResult(
userId: 42,
hrvStressPoints: const <HealthRawHrvStressPoint>[],
realtimeStressPoints: [
_realtimeStressPoint(base + 200),
_realtimeStressPoint(base + 100),
],
dailyStressPoints: const <HealthRawDailyStressPoint>[],
),
);
final result = await LocalHealthDataSource(coreService: service)
.getHealthDataEverUploaded();
expect(result, isA<AppSuccess>());
final data = (result as AppSuccess).data;
expect(data.flag, isTrue);
expect(data.startTime, base + 100);
});
}
HealthKitRawDataPoint _point(
... ... @@ -427,6 +461,17 @@ HealthKitRawDataPoint _point(
);
}
HealthRawRealtimeStressPoint _realtimeStressPoint(int time) {
return HealthRawRealtimeStressPoint(
userId: 42,
rawEndTime: time,
rawHr: 70,
result: 30,
sourceStartTime: time,
sourceEndTime: time,
);
}
class _FakeHealthKitRawDataHostApi extends HealthKitRawDataHostApi {
final Map<int, List<HealthKitRawDataPoint>> _pointsByType = {};
final List<HealthKitRawWorkoutDataPoint> _workoutPoints = [];
... ... @@ -436,6 +481,7 @@ class _FakeHealthKitRawDataHostApi extends HealthKitRawDataHostApi {
var workoutCallCount = 0;
var sleepUploadCallCount = 0;
var sleepUploadUntil = 0;
var hasData = true;
void setPoints(int dataType, List<HealthKitRawDataPoint> points) {
_pointsByType[dataType] = points;
... ... @@ -458,6 +504,9 @@ class _FakeHealthKitRawDataHostApi extends HealthKitRawDataHostApi {
}
@override
Future<bool> hasHealthData() async => hasData;
@override
Future<List<HealthKitRawDataPoint>> getHealthKitRawData(
int dataType,
int startTime,
... ... @@ -777,6 +826,13 @@ class _MemoryHealthRawStressLocalStore extends HealthRawStressLocalStore {
}
@override
Future<int?> earliestRealtimeRawEndTime(int userId) async {
final points = _realtime[userId];
if (points == null || points.isEmpty) return null;
return points.first.rawEndTime;
}
@override
Future<int?> latestSleepResultTime(int userId) async {
final results = _sleep[userId];
if (results == null || results.isEmpty) return null;
... ...